discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Making Strange Objects

GL
Greg Leonard
Fri, Feb 10, 2023 11:12 AM

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]) Y
Y>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: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 [2Plen-1,Plen-1,0,Plen]
polyhedron(PHP,concat(FaceSet,Top,Bot,[[2
Plen-1,Plen-1,0,Plen]]),10);

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);
J
jon
Fri, Feb 10, 2023 1:11 PM

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]) Y
Y>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: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 [2Plen-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

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=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
JW
Joe Weinpert
Fri, Feb 10, 2023 3:31 PM

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]) Y
Y>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: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 [2Plen-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

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 >
RW
Raymond West
Fri, Feb 10, 2023 4:43 PM

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

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
JW
Joe Weinpert
Fri, Feb 10, 2023 4:52 PM

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]) Y
Y>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: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 [2Plen-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 to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-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=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 to discuss-leave@lists.openscad.org > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
SL
Steve Lelievre
Fri, Feb 10, 2023 5:57 PM

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

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
JW
Joe Weinpert
Fri, Feb 10, 2023 6:18 PM

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

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 >
AM
Adrian Mariano
Fri, Feb 10, 2023 10:12 PM

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]) Y
Y>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: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 [2Plen-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 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=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 to discuss-leave@lists.openscad.org >