It may be difficult - but only because of the artificial restriction that all points lie in "slices".
If you commit to triangles vs quads, then 1 quad (4 vertices) becomes 4 triangles (5 vertices). The one extra vertex is at the center of each quad.
The core of the problem is starting with quads in the first place. A secondary problem is in triangulating "slice-by-slice" rather than globally. I understand that this is "more efficient".
On the third hand, OpenSCAD is (to me) most useful for building solid models intended for 3D printing. The appearance of the on-screen mock-ups is of secondary importance (to me).
For those interested in the picture as the final product, I would suggest a post-processing step to optimize the triangulation. This might be hampered by a lack of knowledge of the "true surface" being triangulated. For example, you can't invent new vertices and evaluate their location wrt to the underlying surface. But, you might be able to smooth the surface a bit. If you are willing to give up some precision in the absolute location of the vertices, you might even generate new vertices that lead to a better rendering. (or, perhaps just use Phong shading)
Essentially - you have a crude, piecewise planar representation of a surface that you expect to be "smooth". It's NOT smooth.
Finally, note that choosing the "shorter diagonal" does not work if the triangulation is scaled non-isotropically.
I suppose it would be a SMALL improvement to select the shorter diagonal on the initial triangulation. But, I would not expect it to be perfect, or even a significant improvement for most users.
--
Kenneth Sloan
KennethRSloan@gmail.com
Vision is the art of seeing what is invisible to others.
Finally, note that choosing the "shorter diagonal" does not work if the
triangulation is scaled non-isotropically.
Can you explain that please.
With linear_extrude it doesn't matter how many slices you have. It is the
twist direction that determines the shortest diagonal. I.e. with short fat
quads or tall thin quads.
The reason we are start with quads is that we are extruding or sweeping a
polygon, so each slice has the same vertices. Joining the vertices that
match on each layer gives quads and then we have to pick the correct
diagonal to give triangles.
On Fri, 25 Jan 2019 at 15:24, Kenneth Sloan kennethrsloan@gmail.com wrote:
It may be difficult - but only because of the artificial restriction that
all points lie in "slices".
If you commit to triangles vs quads, then 1 quad (4 vertices) becomes 4
triangles (5 vertices). The one extra vertex is at the center of each quad.
The core of the problem is starting with quads in the first place. A
secondary problem is in triangulating "slice-by-slice" rather than
globally. I understand that this is "more efficient".
On the third hand, OpenSCAD is (to me) most useful for building solid
models intended for 3D printing. The appearance of the on-screen mock-ups
is of secondary importance (to me).
For those interested in the picture as the final product, I would suggest
a post-processing step to optimize the triangulation. This might be
hampered by a lack of knowledge of the "true surface" being triangulated.
For example, you can't invent new vertices and evaluate their location wrt
to the underlying surface. But, you might be able to smooth the surface a
bit. If you are willing to give up some precision in the absolute location
of the vertices, you might even generate new vertices that lead to a better
rendering. (or, perhaps just use Phong shading)
Essentially - you have a crude, piecewise planar representation of a
surface that you expect to be "smooth". It's NOT smooth.
Finally, note that choosing the "shorter diagonal" does not work if the
triangulation is scaled non-isotropically.
I suppose it would be a SMALL improvement to select the shorter diagonal
on the initial triangulation. But, I would not expect it to be perfect, or
even a significant improvement for most users.
--
Kenneth Sloan
KennethRSloan@gmail.com
Vision is the art of seeing what is invisible to others.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
nophead wrote
Actually linear extrude seems to chose the longest diagonal. It definitely
looks bad for negative twists but less so for positive ones. I wonder what
it would look like if it choose the shortest on positive twists.
I don't see much difference, to be honest, left is my simulation of
linear_extrude with sweep:
http://forum.openscad.org/file/t887/rectquad.png
I also changed my springs code to get more lengthy quads.
http://forum.openscad.org/file/t887/springquad.png
Of course, the less crooked the rects are, the less negative effects you
get. So better design your code to produce almost rect quads.
According to Kenneth' proposal, linear_extrude could subdivide a polygon
before applying a twist. I also tried that: If you feed the polygon of a
subdivided square in linear_extrude(), OpenSCAD will discard any vertices
inserted by subdivision before extrusion. So no obviously change to the
right side. So I used sweep to show how this looks.
http://forum.openscad.org/file/t887/rectquad1.png
--
Sent from: http://forum.openscad.org/
As expected the twist looks way better in higher resolutions. The square has
64 vertices. So it would definitely make sense to introduce a subdivide
parameter to linear_extrude().
http://forum.openscad.org/file/t887/rectquad2.png
--
Sent from: http://forum.openscad.org/
I have been doing all my tests on cylinders.
Yes the square is terrible without subdivision. I do that myself by
generating a square with extra vertices along the sides, slightly
perturbed, so they don't get removed.
I think the polygon should be subdivided depending on height / slices, so
that the quads are roughly square.
On Fri, 25 Jan 2019 at 17:35, Parkinbot rudolf@digitaldocument.de wrote:
As expected the twist looks way better in higher resolutions. The square
has
64 vertices. So it would definitely make sense to introduce a subdivide
parameter to linear_extrude().
http://forum.openscad.org/file/t887/rectquad2.png
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
I have been experimenting with sweeping and found a curious fact: If I use
the absolute minimum rotation angle method then a sweep that orbits the Z
axis gets twisted. If I use the relative method then it doesn't, my spiral
springs are no longer twisted around the wire's axis.
[image: image.png]
By absolute I mean each slice is rotated from flat to align it with the
tangent. This is the result. It goes wrong when the tangent points straight
down as there is no minimum rotation from up to down, they are all the
same.
[image: image.png]
By relative I mean calculate the rotation from each tangent to the next one
and accumulate those rotations by multiplication. That of course has the
advantage that it doesn't go wrong when the path points straight down as a
smooth path never fully doubles back on itself.
A consequence is that closed loops don't always meet at the same rotation,
see the knot below. It is less twisty but it needs to twist 180 to meet
properly.
[image: image.png]
Looking at Ronaldo's solution he ensures it twists the right amount to meet
properly when the path is closed by distributing a calculated axial
rotation.
I was surprised that the absolute rotation gives a different result to the
accumulated relative rotations. I expected them to be mathematically
equivalent, but obviously they are not. I think it is because the absolute
one sort of takes a short cut when it does the minimum rotation all in one
go so arrives at a different orientation around the tangent than it does if
it follows the path of rotations. On the other hand the absolute method
always lines up where it meets because the absolute rotations for the start
and the end must give the same twist as they are the same rotation.
One thing to note is that it is possible to accumulate the rotations in a C
style for loop now. It no longer requires a recursive function.
function skin_points(profile, path, loop) =
let(len = len(path),
n = len - 1,
tangents = [for(i = [0 : n], b = loop ? (i + n) % len : max(i - 1,
0), a = loop ? (i + 1) % len : min(i + 1, n)) path[a] - path[b]],
rotations = [for(i = 0, m = rotate_from_to([0,0,1], tangents[0]); i
< len; m = rotate_from_to(tangents[i], tangents[(i + 1) % len]) * m, i = i
I am probably reinventing the wheel but I get to understand it a lot more.
On Thu, 24 Jan 2019 at 16:26, Ronaldo Persiano rcmpersiano@gmail.com
wrote:
nop head nop.head@gmail.com wrote:
How do you get rid of the twist?
Just calculate the total section angular rotation about its "center" and
distribute this total angle along the path. It is an aproximation because
the twist rate may vary along the path but it works very fine with
helicoidal paths. You can accesses my version in:
https://github.com/RonaldoCMP/list-comprehension-demos/blob/master/sweep.scad
https://github.com/RonaldoCMP/list-comprehension-demos/blob/master/sweep.scad
The untwist is done by construct_transform_path().
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
nophead,
when I designed my Naca_sweep I also tried to setup a conventional sweep
that extrudes a polygon along a trajectory, like you seem to use. Due to
insurmountable numerical problems I revised my approach into a more direct
approach that transfers all responsibilty to arrange the polygons in 3D
space completely to the user.
The problems with the conventional approach can be seen in your images: The
rotation matrix tends to have a bad condition at certain angles (i.e.
rotations close to 90°) where the tangens freaks out. You get inf and undef
values (and errors on that) or at least numerical inaccuracies, whenever
your extrusion happens to pass near such an angle. The second is problem is
more subtle and concerns facet arrangement.
Let me characterize the problematic approach: The challenge is that you have
to deduce for each polygon in the sequence a translation and a rotation from
a given trajectory that rotates and translates copies of the given polygon
into 3D.
The translation is simply given through the trajectory TR, provided your
polygon is centered at [0,0,0].
The rotation you get e.g. i) by using the difference of two subsequent
trajectory points (better TR[i+1]-TR[i-1] as normal and ii) supplementing an
normalized orthogonal system for it which will provide the rotation matrix.
You can do this in an absolut manner, where you run into the 90° problem
with the tangens, or you can do this in a relative manner, where you
accumulate numerical errors and get unpreditable results.
Further: Rotating a plane onto a given normal vector is not well defined
because it has a free dimension and you have to additionally determine a z
rotation that will finally define how the corresponding vertices of the
polygon sequence are aligned in space. You can do this by i) cycling the
vertices within the polygon so that corresponding vertices keep an as short
as can distance ii) calculating a z-rotation under the premise that e.g. the
first vertix of subsequent polygons will have shortest distance. Using
strategy i) will introduce funny twists and facet aligning while ii)
provides a "best" solution which the user even might not want to see, e.g.
when he is extruding a moebius or a non-symmetric shape.
In this sense Naca_sweep is the most general approach. It avoids all this
problems, because it lets the user define all three rotations and
translations explicitly and additionally lets him parameterize (i.e. morph)
the polygon along the extrusion path.
--
Sent from: http://forum.openscad.org/
nop head nop.head@gmail.com wrote:
I was surprised that the absolute rotation gives a different result to the
accumulated relative rotations. I expected them to be mathematically
equivalent, but obviously they are not. I think it is because the absolute
one sort of takes a short cut when it does the minimum rotation all in one
go so arrives at a different orientation around the tangent than it does if
it follows the path of rotations. On the other hand the absolute method
always lines up where it meets because the absolute rotations for the start
and the end must give the same twist as they are the same rotation.
Any rotation is a minimum rotation for a pair of directions in a specific
set: those in the plane orthogonal to the rotation axis. So, if you compose
a minimum rotation from a to b with the minimum rotation from b to c, the
resulting rotation will be a minimum rotation from a to c if and only if
vectors a, b and c are coplanar, that is they all have the same rotation
axis. I haven't test it but I would expect that the global (absolute) and
local (relative) methods would have the same result if all path tangent
vectors are in a plane (and no twist adjustment is needed for closed
paths). Otherwise, they would differ.
Parkinbot,
Your approach to sweep is very general. It includes the possibility of loft
(skin). And it saves the user the burden of stitching triangles for
polyhedron. But that is all because you leave to the user the task of
calculating the intermediate section positions and rotations in a simple
sweep and all the headaches your considerations against sweep.scad bring.
I agree that the global method that computes the minimum rotation from a
fixed initial section position to each path position is not well defined
for some directions. However, the local minimum rotation has not the same
instability.
But, I accept that the composition of a large number of local minimum
rotations may show a degenerescence. To check it I have executed the
following simple code where m is the number of compositions:
m = 100000;
Rm = [for( a = 360/m,
i = 0,
R = Rz(0);
i<=m;
R = R*Rz(a),
i = i+1 ) if(i==m) R ][0];
echo(Rm=Rm);
echo(error=matrixNorm(Rz(0)-Rm));
function Rz(a)= let(c=cos(a), s=sin(a)) [[c,s,0],[-s,c,0],[0,0,1]];
function matrixNorm(M) = norm([for(Mi=M) norm(Mi)]);
The error after 100000 transitions is of the order of 1e-12 and the final
matrix is not a pure rotation. I would not expect so many applications of
OpenSCAD with that size of path and requiring a better precision.
Anyway, I guess that here is a place to use quaternions instead of rotation
matrices. Quaternions are considered very stable for long compositions.
Yes I appreciate that there are an infinite number of ways to specify the
rotation. I am aiming for the simplest code to draw springs and wires, etc,
so I want to specify just the path and let the code work out the rotations.
Speed is more important to me than numerical accuracy.
I was using a mixture of the absolute minimum angle method and
Frenet-Serret for different sections of this ribbon cable depending on
which broke. I.e. up and down are a problem for the former and
discontinuous curvature for the latter.
By moving to the relative mode it all seems stable and doesn't have wild
twists when the curve changes direction, so I can ditch Frenet-Serret
unless I want to design a roller coaster!
[image: image.png]
So thanks for all your help.
On Tue, 29 Jan 2019 at 18:02, Ronaldo Persiano rcmpersiano@gmail.com
wrote:
Parkinbot,
Your approach to sweep is very general. It includes the possibility of
loft (skin). And it saves the user the burden of stitching triangles for
polyhedron. But that is all because you leave to the user the task of
calculating the intermediate section positions and rotations in a simple
sweep and all the headaches your considerations against sweep.scad bring.
I agree that the global method that computes the minimum rotation from a
fixed initial section position to each path position is not well defined
for some directions. However, the local minimum rotation has not the same
instability.
But, I accept that the composition of a large number of local minimum
rotations may show a degenerescence. To check it I have executed the
following simple code where m is the number of compositions:
m = 100000;
Rm = [for( a = 360/m,
i = 0,
R = Rz(0);
i<=m;
R = R*Rz(a),
i = i+1 ) if(i==m) R ][0];
echo(Rm=Rm);
echo(error=matrixNorm(Rz(0)-Rm));
function Rz(a)= let(c=cos(a), s=sin(a)) [[c,s,0],[-s,c,0],[0,0,1]];
function matrixNorm(M) = norm([for(Mi=M) norm(Mi)]);
The error after 100000 transitions is of the order of 1e-12 and the final
matrix is not a pure rotation. I would not expect so many applications of
OpenSCAD with that size of path and requiring a better precision.
Anyway, I guess that here is a place to use quaternions instead of
rotation matrices. Quaternions are considered very stable for long
compositions.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org