Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top surface,
and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat, then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top surface the
same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx length of
arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2PIRabs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999(T2-T1)/N) [ for (i = [T1 : DT : T2])
[X+Rcos(i),Y+Rsin(i)] ]
: [[X+Rcos(T1),Y+Rsin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon points to
3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list by Ang,
about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(XX+YY),A=atan2(Y,X))
[Rcos(A+Ang),Rsin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2Rcos(A);
X1=2Rsin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from +ve X
axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the index of
the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no value Y2
is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,YY) //
first one, therefore best so far
: let(Y=Poly[Next][1]) YY>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,YY); // best
so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one large
polygon - clockwise order
Bot = [[for(i = [Plen:2Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]]; //missing
the wrap around face
// wrap around is [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2Plen-1,Plen-1,0,Plen]]),10);
Interesting. Is it true that none of the libraries, like BOSL2, can do
this?
On 2/10/2023 6:12 AM, Greg Leonard wrote:
Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top
surface, and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat, then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top surface
the same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx length
of arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2PIRabs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999(T2-T1)/N) [ for (i = [T1 : DT : T2])
[X+Rcos(i),Y+Rsin(i)] ]
: [[X+Rcos(T1),Y+Rsin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon points
to 3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list by
Ang, about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(XX+YY),A=atan2(Y,X))
[Rcos(A+Ang),Rsin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2Rcos(A);
X1=2Rsin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from +ve
X axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the index
of the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no value
Y2 is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,YY) //
first one, therefore best so far
: let(Y=Poly[Next][1]) YY>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,YY); //
best so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one
large polygon - clockwise order
Bot = [[for(i = [Plen:2Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]];
//missing the wrap around face
// wrap around is [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2Plen-1,Plen-1,0,Plen]]),10);
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Understood. Nice dumbell, indeed!
My situation, however, is that each poly used in my wood carving projects
all have very oddball shapes derived from SVG beziers. The top poly will
always be different in size and points from the bottom poly.
On Fri, Feb 10, 2023 at 6:13 AM Greg Leonard greg@leonardresearch.co.uk
wrote:
Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top surface,
and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat, then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top surface the
same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx length of
arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2PIRabs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999(T2-T1)/N) [ for (i = [T1 : DT : T2])
[X+Rcos(i),Y+Rsin(i)] ]
: [[X+Rcos(T1),Y+Rsin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon points to
3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list by Ang,
about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(XX+YY),A=atan2(Y,X))
[Rcos(A+Ang),Rsin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2Rcos(A);
X1=2Rsin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from +ve X
axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the index of
the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no value Y2
is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,YY) //
first one, therefore best so far
: let(Y=Poly[Next][1]) YY>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,YY); // best
so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one large
polygon - clockwise order
Bot = [[for(i = [Plen:2Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]]; //missing
the wrap around face
// wrap around is [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2Plen-1,Plen-1,0,Plen]]),10);
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
if you import the svg's to openscad, then export as svg, you get the
same shape, but composed of straight lines only. Then, it is relatively
easy to get them into points on a polygon. You can then, perhaps, just
plot the points, or otherwise decide where to add extra points, if
needed to make both poly's be the same number of points. A bit hand
cranked, but works well enough (come to think of it, that is the method
more or less that I used to generate the points for the Whitworth thread
profile - generated it in openscad, saved as svg, then converted said
svg to points on a polygon - about 2 minutes search and replace in a
text editor.)
On 10/02/2023 15:31, Joe Weinpert wrote:
Understood. Nice dumbell, indeed!
My situation, however, is that each poly used in my wood carving
projects all have very oddball shapes derived from SVG beziers. The
top poly will always be different in size and points from the bottom poly.
On Fri, Feb 10, 2023 at 6:13 AM Greg Leonard
greg@leonardresearch.co.uk wrote:
Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top
surface,
and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat,
then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top
surface the
same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point
closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx
length of
arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from
angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2*PI*R*abs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999*(T2-T1)/N) [ for (i = [T1 : DT :
T2])
[X+R*cos(i),Y+R*sin(i)] ]
: [[X+R*cos(T1),Y+R*sin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon
points to
3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list
by Ang,
about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(X*X+Y*Y),A=atan2(Y,X))
[R*cos(A+Ang),R*sin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2*R*cos(A);
X1=2*R*sin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from
+ve X
axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the
index of
the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no
value Y2
is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative
X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,Y*Y) //
first one, therefore best so far
: let(Y=Poly[Next][1]) Y*Y>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,Y*Y);
// best
so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top
first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one
large
polygon - clockwise order
Bot = [[for(i = [Plen:2*Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]];
//missing
the wrap around face
// wrap around is [2*Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2*Plen-1,Plen-1,0,Plen]]),10);
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org
Interesting ... never thought of exporting from OpenSCAD to SVG. I will
try that.
Currently I create the shapes in Inkscape then use the
Extensions->Modify Path->Flatten beziers utility. It in itself has some
issues.
On Fri, Feb 10, 2023 at 11:43 AM Raymond West raywest@raywest.com wrote:
if you import the svg's to openscad, then export as svg, you get the same
shape, but composed of straight lines only. Then, it is relatively easy to
get them into points on a polygon. You can then, perhaps, just plot the
points, or otherwise decide where to add extra points, if needed to make
both poly's be the same number of points. A bit hand cranked, but works
well enough (come to think of it, that is the method more or less that I
used to generate the points for the Whitworth thread profile - generated it
in openscad, saved as svg, then converted said svg to points on a polygon -
about 2 minutes search and replace in a text editor.)
On 10/02/2023 15:31, Joe Weinpert wrote:
Understood. Nice dumbell, indeed!
My situation, however, is that each poly used in my wood carving projects
all have very oddball shapes derived from SVG beziers. The top poly will
always be different in size and points from the bottom poly.
On Fri, Feb 10, 2023 at 6:13 AM Greg Leonard greg@leonardresearch.co.uk
wrote:
Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top surface,
and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat, then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top surface the
same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx length of
arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2PIRabs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999(T2-T1)/N) [ for (i = [T1 : DT : T2])
[X+Rcos(i),Y+Rsin(i)] ]
: [[X+Rcos(T1),Y+Rsin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon points to
3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list by Ang,
about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(XX+YY),A=atan2(Y,X))
[Rcos(A+Ang),Rsin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2Rcos(A);
X1=2Rsin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from +ve X
axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the index of
the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no value Y2
is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,YY) //
first one, therefore best so far
: let(Y=Poly[Next][1]) YY>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,YY); // best
so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one large
polygon - clockwise order
Bot = [[for(i = [Plen:2Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]]; //missing
the wrap around face
// wrap around is [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2Plen-1,Plen-1,0,Plen]]),10);
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On 2023-02-10 8:52 a.m., Joe Weinpert wrote:
Interesting ... never thought of exporting from OpenSCAD to SVG. I
will try that.
It is a good tip, but note: depending on the shape that you're working
on, the OpenSCAD import/export method can result in loads more nodes
that Inkscape Flatten Beziers method.
For example: (sorry for blurry images, they clipped from screenshots)
Inkscape original
Flatten Beziers (using 0.1 for parameter)
OpenSCAD import then export, viewed back in Inkscape
Thanks for the tip!
On Fri, Feb 10, 2023 at 12:58 PM Steve Lelievre <
steve.lelievre.canada@gmail.com> wrote:
On 2023-02-10 8:52 a.m., Joe Weinpert wrote:
Interesting ... never thought of exporting from OpenSCAD to SVG. I will
try that.
It is a good tip, but note: depending on the shape that you're working on,
the OpenSCAD import/export method can result in loads more nodes that
Inkscape Flatten Beziers method.
For example: (sorry for blurry images, they clipped from screenshots)
Inkscape original
Flatten Beziers (using 0.1 for parameter)
OpenSCAD import then export, viewed back in Inkscape
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The BOSL2 skin() function provides this functionality, without the
constraint that the point counts match. If they match you can use
vnf_vertex_array().
On Fri, Feb 10, 2023 at 8:12 AM jon jon@jonbondy.com wrote:
Interesting. Is it true that none of the libraries, like BOSL2, can do
this?
On 2/10/2023 6:12 AM, Greg Leonard wrote:
Posted initially by Joe Weinpert.
I find polyhedron works quite well. Start with polygon for top
surface, and another for the bottom - EQUAL number of points.
The join is made by quadrilateral faces (if the face is not flat, then
polyhedron automatically splits it into triangles)
In the example below, I use a dumbell shape and make the top surface
the same, but rotated.
The basic dumbell polygon points start on the +ve X axis, and the top
polygon points are shifted in the list to make the first point closest
to the +ve X axis.
ArcMin = 5; // for PolyArc segmments - approx length
of arc minimum in mm
Nmax = 100; // max number of facets in the arc
//-----------------------------------------------------------------------
function PolyArc(X,Y,R,T1,T2) // Circular ard with radius R from angle
T1 to angle T2
= // echo("PolyArc ",X,Y,R,T1,T2)
R<= 0 ? [] // no point
: let(Alen=2PIRabs(T2-T1)/360,N=floor(Alen/ArcMin)<Nmax ?
floor(Alen/ArcMin) :Nmax)
//echo("PA",R,N)
abs(T1-T2)>0 ? let(DT=0.9999(T2-T1)/N) [ for (i = [T1 : DT : T2])
[X+Rcos(i),Y+Rsin(i)] ]
: [[X+Rcos(T1),Y+Rsin(T1)]];
//--------------------------------------------------------------------------------
function Two2Three(Poly,Z) // converts 2D polygon points
to 3D at height Z
= [for (i = [0:len(Poly)-1]) [Poly[i][0],Poly[i][1],Z]];
//------------------------------------------------------------------------
function RotateList(List,Ang) // rotate X,Y points in list by
Ang, about point 0,0
= [for (i = [0:len(List)-1])
let(X=List[i][0],Y=List[i][1],R=sqrt(XX+YY),A=atan2(Y,X))
[Rcos(A+Ang),Rsin(A+Ang)]];
//------------------------------------------------------------------------
// dumbell shape
R=40; // arc radius
A=35; // tasngent angle for arcs
G=5; // gap angle between successive arcs
Y2=2Rcos(A);
X1=2Rsin(A);
PP1 = concat( PolyArc(X1,0,R,0,90+A-G), // anti-clockwise from +ve
X axis
PolyArc(0,Y2,R,270+A,270+G-A),
PolyArc(-X1,0,R,90-A,270-G+A),
PolyArc(0,-Y2,R,90+A,90+G-A),
PolyArc(X1,0,R,270-A,350-G)
);
// PP1 start on the +ve X axis
PP2 = RotateList(PP1,60); // rotate by 60 degrees
//color("skyblue")polygon(PP1);
//translate([0,0,R])color("hotpink")polygon(PP2);
// Need a function which will scan polygon points, and find the index
of the point nearest the +ve X axis
//
function BestIndex(Next,Poly,Best,Y2) //Next - index to try, Best -
index so far, Y2 - Y squared at Best
= Next < 0 // Starting conditio: no value
Y2 is Best off the end of Poly
? [Best,Y2] // Finished, so
return Best and Y2
: Poly[Next][0] < 0 // check X
? BestIndex(Next-1,Poly,Best,Y2) // negative X, so
keep looking
: Best >= len(Poly) // positive X,
check whether we have started
? let(Y=Poly[Next][1]) BestIndex(Next-1,Poly,Next,YY) //
first one, therefore best so far
: let(Y=Poly[Next][1]) YY>Y2
? BestIndex(Next-1,Poly,Best,Y2) //
worse Y, so keep looking
: BestIndex(Next-1,Poly,Next,YY); //
best so far. Keep looking
//
// now to re-arrage the PP2 to start at the selected start index
SP = BestIndex(len(PP2)-1,PP2,len(PP2),0); // SP[0] is the index
for the new point 0
PP3A = [for (i = [SP[0]:len(PP2)-1]) PP2[i] ]; // forst part
PP3B = [for (i = [0:SP[0]-1]) PP2[i] ]; // second part
PP3 = concat(PP3A,PP3B); // PP3 start
nearedt point to +ve X axis
Plen = len(PP3);
//
// Polyhedron faces have points in CLOCKWISE order when seen from the
outside
// Our polygons are organised ANTI-CLOCKWISE seen from on top
// POLYHEDRON POINTS Make top face at height R (could be anything)
PHP = concat(Two2Three(PP3,R),Two2Three(PP1,0)); // top first
// now for the faces
Top = [[for(i = [Plen-1:-1:0]) i]]; // one
large polygon - clockwise order
Bot = [[for(i = [Plen:2Plen-1]) i]]; // ditto
FaceSet = [for (i = [0:Plen-2]) [Plen+i,i,i+1,Plen+1+i]];
//missing the wrap around face
// wrap around is [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2Plen-1,Plen-1,0,Plen]]),10);
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org