DS
Dan Shriver
Fri, Jan 26, 2018 11:22 PM
I'm having trouble understanding how I should tackle a problem.
I think I should be using skin() for my problem but I am confused how it
works and how I should present things to it.
I was trying to look at some examples like:
https://github.com/openscad/list-comprehension-demos/issues/3
atartanian https://github.com/atartanian gave a good example but I don't
see how it works
myLen = len(path)-1;
trans = [ for (i=[0:len(path)-1]) transform(path[i],
rounded_rectangle_profile([4,4], i/myLen*2)) ];
translate([0,10,0])
skin(trans);
so I see in the code and the picture that it ends with a
rounded_rectangle_profile; but I don't understand why it starts with a
square one since that isn't specified in the skin example (it is in the
sweep example)
Basically I want to alter from one shape to another over a path (which I
think is what skin is for). I'm a bit confused how I should do this.
I'll include a picture and some code.
[image: Inline image 1]
On the picture the central figure is "basically" the "path" I want in the
x/y plane, along that path I want to gradually change from an ogee (similar
to one third of the central figure) to a roman arch (pictured below the
central figure). I say "basically" the "path" because really those three
ogees would seem to be bulging out periodically (like two sine waves out of
synch 90 degrees) owing to the fact that the roman arch is wider.
I'm not quite sure how I should be making things to present this info to
skin().
An alternative approach would be to make functions that generate points and
use these as vertices for polygons.
I'm attaching the code I used to generate these shapes (the code uses stuff
like pie_slice() which I got from hints on this list)
//roman arch type
module romanArchHalf(angle, size, thickness) {
difference () {
translate([(-(cos(angle)*size)),0,0]) {
pie_slice(size, 0, angle);
}
translate([-(cos(angle)*size),0,0]) {
pie_slice((size - thickness), 0, angle);
}
translate([-size2, 0, 0]) {
square([size2,size*2],false);
}
}
}
translate([0,-(sin(70)*30),0]) {
mirror([0,1,0]) {
romanArchHalf(70,15,1);
mirror([1,0,0])
romanArchHalf(70,15,1);
}
}
Ogee(15,15,1,100,0,0,0,45);
rotate([0,0,120]) {
Ogee(15,15,1,100,0,0,0,45);
}
rotate([0,0,240]) {
Ogee(15,15,1,100,0,0,0,45);
}
module Ogee(r1,r2,width,fnNum,yoffset=0,elongate=0, xoffset=0,angle=45) {
hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
mirror(0,1,0) {
hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
}
}
module hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle) {
difference() {
halfPieOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
translate([(-0.5*width),0,0]) {
square([width,r2],center=true);
square([width,r1],center=true);
}
}
}
module halfPieOgee(r1,r2,width,fnNum,offset,elongate,xoffset,firstAngle=45)
{
r1a = r1 + elongate;
translate([0,offset,0]) {
translate([((r2)-((r2)cos(45)))-width,(r2(sin(45))),0]) {
rotate( [0,0,-firstAngle] ){
difference() {
translate([(-r1a+width+xoffset),0,0]) {
pie_slice(r1a,0,firstAngle,fnNum);
}
translate([-r1a+xoffset,0,0]) {
pie_slice(r1a,0,firstAngle,fnNum);
}
}
translate([r2,0,0]) {
mirror( [0,1,0]) mirror( [1,0,0]) {
difference() {
pie_slice(r2,0,45,fnNum);
pie_slice((r2-width),0,45,fnNum);
}
}
}
}
}
}
}
module point(x,y) translate([x,y]) circle(0.01);
module pie_slice(r, a0, a1, fnNum) {
//$fa = 5;
R = r * sqrt(2) + 1;
intersection() {
circle(r, $fn=fnNum);
hull() {
point(0,0);
for(i = [0:4])
//a = (((4 - i) * a0 + i * a1) / 4);
point(R * cos((((4 - i) * a0 + i * a1) / 4)), R *
sin((((4 - i) * a0 + i * a1) / 4)));
}
}
}
https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=icon
Virus-free.
www.avast.com
https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=link
<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
I'm having trouble understanding how I should tackle a problem.
I think I should be using skin() for my problem but I am confused how it
works and how I should present things to it.
I was trying to look at some examples like:
https://github.com/openscad/list-comprehension-demos/issues/3
*atartanian <https://github.com/atartanian> gave a good example but I don't
see how it works*
myLen = len(path)-1;
trans = [ for (i=[0:len(path)-1]) transform(path[i],
rounded_rectangle_profile([4,4], i/myLen*2)) ];
translate([0,10,0])
skin(trans);
so I see in the code and the picture that it ends with a
rounded_rectangle_profile; but I don't understand why it starts with a
square one since that isn't specified in the skin example (it is in the
sweep example)
---------------
Basically I want to alter from one shape to another over a path (which I
think is what skin is for). I'm a bit confused how I should do this.
I'll include a picture and some code.
[image: Inline image 1]
On the picture the central figure is "basically" the "path" I want in the
x/y plane, along that path I want to gradually change from an ogee (similar
to one third of the central figure) to a roman arch (pictured below the
central figure). I say "basically" the "path" because really those three
ogees would seem to be bulging out periodically (like two sine waves out of
synch 90 degrees) owing to the fact that the roman arch is wider.
I'm not quite sure how I should be making things to present this info to
skin().
An alternative approach would be to make functions that generate points and
use these as vertices for polygons.
I'm attaching the code I used to generate these shapes (the code uses stuff
like pie_slice() which I got from hints on this list)
-------------
//roman arch type
module romanArchHalf(angle, size, thickness) {
difference () {
translate([(-(cos(angle)*size)),0,0]) {
pie_slice(size, 0, angle);
}
translate([-(cos(angle)*size),0,0]) {
pie_slice((size - thickness), 0, angle);
}
translate([-size*2, 0, 0]) {
square([size*2,size*2],false);
}
}
}
translate([0,-(sin(70)*30),0]) {
mirror([0,1,0]) {
romanArchHalf(70,15,1);
mirror([1,0,0])
romanArchHalf(70,15,1);
}
}
Ogee(15,15,1,100,0,0,0,45);
rotate([0,0,120]) {
Ogee(15,15,1,100,0,0,0,45);
}
rotate([0,0,240]) {
Ogee(15,15,1,100,0,0,0,45);
}
module Ogee(r1,r2,width,fnNum,yoffset=0,elongate=0, xoffset=0,angle=45) {
hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
mirror(0,1,0) {
hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
}
}
module hpOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle) {
difference() {
halfPieOgee(r1,r2,width,fnNum,yoffset,elongate,xoffset,angle);
translate([(-0.5*width),0,0]) {
square([width,r2],center=true);
square([width,r1],center=true);
}
}
}
module halfPieOgee(r1,r2,width,fnNum,offset,elongate,xoffset,firstAngle=45)
{
r1a = r1 + elongate;
translate([0,offset,0]) {
translate([((r2)-((r2)*cos(45)))-width,(r2*(sin(45))),0]) {
rotate( [0,0,-firstAngle] ){
difference() {
translate([(-r1a+width+xoffset),0,0]) {
pie_slice(r1a,0,firstAngle,fnNum);
}
translate([-r1a+xoffset,0,0]) {
pie_slice(r1a,0,firstAngle,fnNum);
}
}
translate([r2,0,0]) {
mirror( [0,1,0]) mirror( [1,0,0]) {
difference() {
pie_slice(r2,0,45,fnNum);
pie_slice((r2-width),0,45,fnNum);
}
}
}
}
}
}
}
module point(x,y) translate([x,y]) circle(0.01);
module pie_slice(r, a0, a1, fnNum) {
//$fa = 5;
R = r * sqrt(2) + 1;
intersection() {
circle(r, $fn=fnNum);
hull() {
point(0,0);
for(i = [0:4])
//a = (((4 - i) * a0 + i * a1) / 4);
point(R * cos((((4 - i) * a0 + i * a1) / 4)), R *
sin((((4 - i) * a0 + i * a1) / 4)));
}
}
}
<https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=icon>
Virus-free.
www.avast.com
<https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=link>
<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
N
NateTG
Sat, Jan 27, 2018 3:27 AM
The trick with skin() and sweep() is that they don't use the geometry engine,
and do calculations in "user space" instead. That means that they don't
really play well with other stuff. In particular, you can't use them with
geometry that's produced by 'module' constructions.
This might be a simpler example to look at for how they work:
https://github.com/openscad/list-comprehension-demos/blob/master/sweep-path.scad
I see in the code and the picture that it ends with a
rounded_rectangle_profile; but I don't understand why it starts with a
square one since that isn't specified in the skin example ...
The trick with skin() and sweep() is that they don't use the geometry engine,
and do calculations in "user space" instead. That means that they don't
really play well with other stuff. In particular, you can't use them with
geometry that's produced by 'module' constructions.
This might be a simpler example to look at for how they work:
https://github.com/openscad/list-comprehension-demos/blob/master/sweep-path.scad
> I see in the code and the picture that it ends with a
> rounded_rectangle_profile; but I don't understand why it starts with a
> square one since that isn't specified in the skin example ...
The function rounded_rectangle_profile() generates a rectangle with rounded
corners. In the example you quote, the "i/mylen*2" changes the radius of
the rounded corners from being 0 (so they're sharp) to being 2 (so that the
'square' is now only rounded corners.) It's not just generating the start
and end points, but also a bunch of intermediate ones.
You can see what rounded_rectangle_profile() does here:
https://github.com/openscad/list-comprehension-demos/blob/dec3fc3037f0107e5d9da79cb5b36b3e1ad9ce22/extrusion.scad
--
Sent from: http://forum.openscad.org/
P
Parkinbot
Sat, Jan 27, 2018 12:52 PM
skin() and sweep() explicitly knit a polyhedron from given data. Thus they
create module objects that can be combined by use of Boolean operations with
any other modules like cylinder. While they offer you a lot of expressive
power, you have to take special care to create valid manifolds with no
self-intersection only, if you want to get valid STLs at the end.
skin() and sweep() differ in the data you have to provide and thus in
operation and usage scope.
The original version of sweep() you are referring to, expects a geometric
primitive like a square and a transformation sequence (which is difficult to
compose and also limited to affine transformations) to be applied to this
primitive.
skin() in contrast expects a vector of polygons already placed in 3D space
to be skinned. This is much less restrictive, because you can create any
transitions for any 2D-shapes you like, without being limited to a common 2D
shape and affine transformations - but at the price of additional care:
valid (= simple) polygons, proper sequencing with no mutual intersections of
any polygons allowed.
When I started to play with sweep() some years ago, my aim was to define
smooth transitions between different airfoils. I immediately saw, that
sweep() will not do the job and started to implement my own sweep() which
later turned out to be (almost) semantically equivalent to skin(). I
collected all the stuff (mainly affine operations) needed to place 2D-shapes
into 3D space and knit them together into a polyhedron and stuffed it into a
library which I called Naca_sweep(). Thus the main function is called
sweep() but behaves like skin(). Because I am a fan of short notations I
called the affine operations operating over a polygon (or 2D-shape with
z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
The following code example shows you what happens, when this library is used
to generate a Moebius strip with a sinusoidal radius function.
- Write a parametrized function that composes your 2D shape (here circle
but any simple polygon is allowed - e.g. airfoil)
- Write a parametrized function that composes a sequence of polygons (my
sweep() expects all polygons to have the same # of vertices, skin() doen't
care) properly placed in 3D space.
- call sweep() or skin()
My sweep() implementiation provides a showslices parameter. Setting it
true will show you the polygons' placement. Try it out.
The problem is: how will you close the strip into a ring? You could either
change sweep() to account for the twistm when closing the ring, which is
hard stuff and not very general, or you just do a Boolean union of two half
sweeps ... try the modify the example code, good exercise.
use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
// use <skin.scad> // alternative
// skin(Moebius());
sweep(Moebius(), showslices = true); // show, what happens
sweep(Moebius()); // same semantics as skin
function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
let(ang = 360/Mi)
Ry_(ang, // rotate to ring
Tx_(R, // shift triag
Rz_(ang/edges, // rotate triag
circle(r=5sin(2*ang)+10, N=edges))))]; // generate circle with moduluated
radius
function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/Ni), sin(360/Ni),
0]];
--
Sent from: http://forum.openscad.org/
skin() and sweep() explicitly knit a polyhedron from given data. Thus they
create module objects that can be combined by use of Boolean operations with
any other modules like cylinder. While they offer you a lot of expressive
power, you have to take special care to create valid manifolds with no
self-intersection only, if you want to get valid STLs at the end.
skin() and sweep() differ in the data you have to provide and thus in
operation and usage scope.
The original version of sweep() you are referring to, expects a geometric
primitive like a square and a transformation sequence (which is difficult to
compose and also limited to affine transformations) to be applied to this
primitive.
skin() in contrast expects a vector of polygons already placed in 3D space
to be skinned. This is much less restrictive, because you can create any
transitions for any 2D-shapes you like, without being limited to a common 2D
shape and affine transformations - but at the price of additional care:
valid (= simple) polygons, proper sequencing with no mutual intersections of
any polygons allowed.
When I started to play with sweep() some years ago, my aim was to define
smooth transitions between different airfoils. I immediately saw, that
sweep() will not do the job and started to implement my own sweep() which
later turned out to be (almost) semantically equivalent to skin(). I
collected all the stuff (mainly affine operations) needed to place 2D-shapes
into 3D space and knit them together into a polyhedron and stuffed it into a
library which I called Naca_sweep(). Thus the main function is called
sweep() but behaves like skin(). Because I am a fan of short notations I
called the affine operations operating over a polygon (or 2D-shape with
z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
The following code example shows you what happens, when this library is used
to generate a Moebius strip with a sinusoidal radius function.
1. Write a parametrized function that composes your 2D shape (here circle
but any simple polygon is allowed - e.g. airfoil)
2. Write a parametrized function that composes a sequence of polygons (my
sweep() expects all polygons to have the same # of vertices, skin() doen't
care) properly placed in 3D space.
3. call sweep() or skin()
My sweep() implementiation provides a *showslices* parameter. Setting it
true will show you the polygons' placement. Try it out.
The problem is: how will you close the strip into a ring? You could either
change sweep() to account for the twistm when closing the ring, which is
hard stuff and not very general, or you just do a Boolean union of two half
sweeps ... try the modify the example code, good exercise.
use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
// use <skin.scad> // alternative
// skin(Moebius());
sweep(Moebius(), showslices = true); // show, what happens
sweep(Moebius()); // same semantics as skin
function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
let(ang = 360/M*i)
Ry_(ang, // rotate to ring
Tx_(R, // shift triag
Rz_(ang/edges, // rotate triag
circle(r=5*sin(2*ang)+10, N=edges))))]; // generate circle with moduluated
radius
function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/N*i), sin(360/N*i),
0]];
--
Sent from: http://forum.openscad.org/
DS
Dan Shriver
Fri, Feb 2, 2018 6:20 PM
Thanks again for all the help you guys have been giving me. I'm sorry that
I still don't fully understand the advice I'm getting. As a result I think
I'll phrase my questions slightly differently (maybe the specific answers
might be more clear to me)
Given the following:
- I have a polygon x and a polygon y
- the two polygons have the same number of points
- I wish to morph one polygon into another (interpolate between them,
probably doing it in a non-linear way (like a trig function to get a
pleasing curve))
- I wish to place these polygons (and their interpolations) along another
offset determined by a curve
What is the general suggestion on how to do it?
-
I could do everything at a low level (manipulating lists of points). I
am almost inclined to go this route but the "problems" I face are:
a) I'm not fully getting the list operation tools. Is there a good
clean way to take a list and add an offset to every member (#4 from the
previous givens); same with taking two lists and generating a third (via an
interpolation scheme)
b) once I have those lists I still need to define things so the system
can cover the surface with polygons correctly. I have been given code on
things like this before but find it very opaque (I don't see how they take
the points and create the polygons) not sure if there are simple examples
that walk one through the magic
-
I could use higher level tools such as hull(), linear_extrude(),
skin(),.... I don't know what the advantages / disadvantages to the
various was are except that it is obvious to me that linear_extrude() is an
inelegant way for me to go (since I am trying to place the whole construct
on a curve, linear_extrude() would just approximate it with a bunch of
steps). Are some computationally more expensive than others? Does hull()
work with points in space (or do I have to do something slightly unpleasant
and create infinitesimal 3D objects at each point?
To allow for either skin() or doing things low level I am now making
functions rather than modules and spitting out defined polygons of points.
I have an example of one curve via points below (it is slightly off and I
need to debug the third curve, but I'll do that).
function innerAngle(radius, thickness, angle) = angle -asin(thickness *
sin(90 - angle)/radius);
function stepAngle(angle, points) = angle / points;
function archFourthQuarterx(radius, thickness, angle, pointNum, points) =
(radius-thickness) * cos((innerAngle(radius, thickness,angle)) -
(stepAngle(innerAngle(radius, thickness,angle), (points/4)) * (pointNum -
(3*points/4)))) - radius * (cos(angle));
function archThirdQuarterx(radius, thickness, angle, pointNum, points) =
-((radius-thickness) * cos( stepAngle(innerAngle(radius, thickness,angle),
(points/4)) * (pointNum - (points/2))) - radius * (cos(angle)));
function archSecondQuarterx(radius, angle, pointNum, points) = -(radius *
cos(angle - (stepAngle(angle, (points/4)) * (pointNum - (points/4)))) -
radius * (cos(angle)));
function archFirstQuarterx(radius, angle, pointNum, points) = radius *
cos(stepAngle(angle, (points/4)) * pointNum) - radius * (cos(angle));
function archLastHalfx(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuarterx(radius, thickness, angle,
pointNum, points) : archFourthQuarterx(radius, thickness, angle, pointNum,
points);
function archFirstHalfx(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuarterx(radius, angle, pointNum, points) :
archSecondQuarterx(radius, angle, pointNum, points);
function archX(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfx(radius,angle,pointNum, points) :
archLastHalfx(radius, thickness, angle, pointNum, points);
function archFourthQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin( innerAngle(radius, thickness, angle) -
stepAngle(innerAngle(radius, thickness, angle), (points/4)) * (pointNum -
(3 * points/4)));
function archThirdQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin(stepAngle(innerAngle(radius, thickness, angle),
(points/4)) * (pointNum - points/2));
function archSecondQuartery(radius, angle, pointNum, points) = radius *
sin( angle - stepAngle(angle, (points/4)) * (pointNum - (points/4)));
function archFirstQuartery(radius, angle, pointNum, points) = radius * sin(
stepAngle(angle, (points/4)) * pointNum);
function archLastHalfy(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuartery(radius, thickness, angle,
pointNum, points) : archFourthQuartery(radius, thickness, angle, pointNum,
points);
function archFirstHalfy(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuartery(radius, angle, pointNum, points) :
archSecondQuartery(radius, angle, pointNum, points);
function archY(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfy(radius,angle,pointNum, points) :
archLastHalfy(radius, thickness, angle, pointNum, points);
//note if points is NOT a multiple of 4 things might be ugly...
module romanArch(radius, thickness, angle, pointCnt) {
points = [ for (i = [0:pointCnt]) [archX(radius, thickness, angle, i,
pointCnt), archY(radius, thickness, angle, i, pointCnt)] ];
polygon(points);
}
romanArch(20, 1, 70, 200);
On Sat, Jan 27, 2018 at 7:52 AM, Parkinbot rudolf@parkinbot.com wrote:
skin() and sweep() explicitly knit a polyhedron from given data. Thus they
create module objects that can be combined by use of Boolean operations
with
any other modules like cylinder. While they offer you a lot of expressive
power, you have to take special care to create valid manifolds with no
self-intersection only, if you want to get valid STLs at the end.
skin() and sweep() differ in the data you have to provide and thus in
operation and usage scope.
The original version of sweep() you are referring to, expects a geometric
primitive like a square and a transformation sequence (which is difficult
to
compose and also limited to affine transformations) to be applied to this
primitive.
skin() in contrast expects a vector of polygons already placed in 3D space
to be skinned. This is much less restrictive, because you can create any
transitions for any 2D-shapes you like, without being limited to a common
2D
shape and affine transformations - but at the price of additional care:
valid (= simple) polygons, proper sequencing with no mutual intersections
of
any polygons allowed.
When I started to play with sweep() some years ago, my aim was to define
smooth transitions between different airfoils. I immediately saw, that
sweep() will not do the job and started to implement my own sweep() which
later turned out to be (almost) semantically equivalent to skin(). I
collected all the stuff (mainly affine operations) needed to place
2D-shapes
into 3D space and knit them together into a polyhedron and stuffed it into
a
library which I called Naca_sweep(). Thus the main function is called
sweep() but behaves like skin(). Because I am a fan of short notations I
called the affine operations operating over a polygon (or 2D-shape with
z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
The following code example shows you what happens, when this library is
used
to generate a Moebius strip with a sinusoidal radius function.
- Write a parametrized function that composes your 2D shape (here circle
but any simple polygon is allowed - e.g. airfoil)
- Write a parametrized function that composes a sequence of polygons (my
sweep() expects all polygons to have the same # of vertices, skin() doen't
care) properly placed in 3D space.
- call sweep() or skin()
My sweep() implementiation provides a showslices parameter. Setting it
true will show you the polygons' placement. Try it out.
The problem is: how will you close the strip into a ring? You could either
change sweep() to account for the twistm when closing the ring, which is
hard stuff and not very general, or you just do a Boolean union of two half
sweeps ... try the modify the example code, good exercise.
use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
// use <skin.scad> // alternative
// skin(Moebius());
sweep(Moebius(), showslices = true); // show, what happens
sweep(Moebius()); // same semantics as skin
function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
let(ang = 360/Mi)
Ry_(ang, // rotate to ring
Tx_(R, // shift triag
Rz_(ang/edges, // rotate triag
circle(r=5sin(2*ang)+10, N=edges))))]; // generate circle with
moduluated
radius
function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/Ni), sin(360/Ni),
0]];
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Thanks again for all the help you guys have been giving me. I'm sorry that
I still don't fully understand the advice I'm getting. As a result I think
I'll phrase my questions slightly differently (maybe the specific answers
might be more clear to me)
Given the following:
1) I have a polygon x and a polygon y
2) the two polygons have the same number of points
3) I wish to morph one polygon into another (interpolate between them,
probably doing it in a non-linear way (like a trig function to get a
pleasing curve))
4) I wish to place these polygons (and their interpolations) along another
offset determined by a curve
What is the general suggestion on how to do it?
1) I could do everything at a low level (manipulating lists of points). I
am almost inclined to go this route but the "problems" I face are:
a) I'm not fully getting the list operation tools. Is there a good
clean way to take a list and add an offset to every member (#4 from the
previous givens); same with taking two lists and generating a third (via an
interpolation scheme)
b) once I have those lists I still need to define things so the system
can cover the surface with polygons correctly. I have been given code on
things like this before but find it very opaque (I don't see how they take
the points and create the polygons) not sure if there are simple examples
that walk one through the magic
2) I could use higher level tools such as hull(), linear_extrude(),
skin(),.... I don't know what the advantages / disadvantages to the
various was are except that it is obvious to me that linear_extrude() is an
inelegant way for me to go (since I am trying to place the whole construct
on a curve, linear_extrude() would just approximate it with a bunch of
steps). Are some computationally more expensive than others? Does hull()
work with points in space (or do I have to do something slightly unpleasant
and create infinitesimal 3D objects at each point?
To allow for either skin() or doing things low level I am now making
functions rather than modules and spitting out defined polygons of points.
I have an example of one curve via points below (it is slightly off and I
need to debug the third curve, but I'll do that).
---------
function innerAngle(radius, thickness, angle) = angle -asin(thickness *
sin(90 - angle)/radius);
function stepAngle(angle, points) = angle / points;
function archFourthQuarterx(radius, thickness, angle, pointNum, points) =
(radius-thickness) * cos((innerAngle(radius, thickness,angle)) -
(stepAngle(innerAngle(radius, thickness,angle), (points/4)) * (pointNum -
(3*points/4)))) - radius * (cos(angle));
function archThirdQuarterx(radius, thickness, angle, pointNum, points) =
-((radius-thickness) * cos( stepAngle(innerAngle(radius, thickness,angle),
(points/4)) * (pointNum - (points/2))) - radius * (cos(angle)));
function archSecondQuarterx(radius, angle, pointNum, points) = -(radius *
cos(angle - (stepAngle(angle, (points/4)) * (pointNum - (points/4)))) -
radius * (cos(angle)));
function archFirstQuarterx(radius, angle, pointNum, points) = radius *
cos(stepAngle(angle, (points/4)) * pointNum) - radius * (cos(angle));
function archLastHalfx(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuarterx(radius, thickness, angle,
pointNum, points) : archFourthQuarterx(radius, thickness, angle, pointNum,
points);
function archFirstHalfx(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuarterx(radius, angle, pointNum, points) :
archSecondQuarterx(radius, angle, pointNum, points);
function archX(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfx(radius,angle,pointNum, points) :
archLastHalfx(radius, thickness, angle, pointNum, points);
function archFourthQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin( innerAngle(radius, thickness, angle) -
stepAngle(innerAngle(radius, thickness, angle), (points/4)) * (pointNum -
(3 * points/4)));
function archThirdQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin(stepAngle(innerAngle(radius, thickness, angle),
(points/4)) * (pointNum - points/2));
function archSecondQuartery(radius, angle, pointNum, points) = radius *
sin( angle - stepAngle(angle, (points/4)) * (pointNum - (points/4)));
function archFirstQuartery(radius, angle, pointNum, points) = radius * sin(
stepAngle(angle, (points/4)) * pointNum);
function archLastHalfy(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuartery(radius, thickness, angle,
pointNum, points) : archFourthQuartery(radius, thickness, angle, pointNum,
points);
function archFirstHalfy(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuartery(radius, angle, pointNum, points) :
archSecondQuartery(radius, angle, pointNum, points);
function archY(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfy(radius,angle,pointNum, points) :
archLastHalfy(radius, thickness, angle, pointNum, points);
//note if points is NOT a multiple of 4 things might be ugly...
module romanArch(radius, thickness, angle, pointCnt) {
points = [ for (i = [0:pointCnt]) [archX(radius, thickness, angle, i,
pointCnt), archY(radius, thickness, angle, i, pointCnt)] ];
polygon(points);
}
romanArch(20, 1, 70, 200);
On Sat, Jan 27, 2018 at 7:52 AM, Parkinbot <rudolf@parkinbot.com> wrote:
> skin() and sweep() explicitly knit a polyhedron from given data. Thus they
> create module objects that can be combined by use of Boolean operations
> with
> any other modules like cylinder. While they offer you a lot of expressive
> power, you have to take special care to create valid manifolds with no
> self-intersection only, if you want to get valid STLs at the end.
>
> skin() and sweep() differ in the data you have to provide and thus in
> operation and usage scope.
>
> The original version of sweep() you are referring to, expects a geometric
> primitive like a square and a transformation sequence (which is difficult
> to
> compose and also limited to affine transformations) to be applied to this
> primitive.
>
> skin() in contrast expects a vector of polygons already placed in 3D space
> to be skinned. This is much less restrictive, because you can create any
> transitions for any 2D-shapes you like, without being limited to a common
> 2D
> shape and affine transformations - but at the price of additional care:
> valid (= simple) polygons, proper sequencing with no mutual intersections
> of
> any polygons allowed.
>
> When I started to play with sweep() some years ago, my aim was to define
> smooth transitions between different airfoils. I immediately saw, that
> sweep() will not do the job and started to implement my own sweep() which
> later turned out to be (almost) semantically equivalent to skin(). I
> collected all the stuff (mainly affine operations) needed to place
> 2D-shapes
> into 3D space and knit them together into a polyhedron and stuffed it into
> a
> library which I called Naca_sweep(). Thus the main function is called
> sweep() but behaves like skin(). Because I am a fan of short notations I
> called the affine operations operating over a polygon (or 2D-shape with
> z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
>
> The following code example shows you what happens, when this library is
> used
> to generate a Moebius strip with a sinusoidal radius function.
> 1. Write a parametrized function that composes your 2D shape (here circle
> but any simple polygon is allowed - e.g. airfoil)
> 2. Write a parametrized function that composes a sequence of polygons (my
> sweep() expects all polygons to have the same # of vertices, skin() doen't
> care) properly placed in 3D space.
> 3. call sweep() or skin()
>
> My sweep() implementiation provides a *showslices* parameter. Setting it
> true will show you the polygons' placement. Try it out.
>
> The problem is: how will you close the strip into a ring? You could either
> change sweep() to account for the twistm when closing the ring, which is
> hard stuff and not very general, or you just do a Boolean union of two half
> sweeps ... try the modify the example code, good exercise.
>
>
> use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
>
> // use <skin.scad> // alternative
> // skin(Moebius());
>
> sweep(Moebius(), showslices = true); // show, what happens
> sweep(Moebius()); // same semantics as skin
>
> function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
> let(ang = 360/M*i)
> Ry_(ang, // rotate to ring
> Tx_(R, // shift triag
> Rz_(ang/edges, // rotate triag
> circle(r=5*sin(2*ang)+10, N=edges))))]; // generate circle with
> moduluated
> radius
>
> function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/N*i), sin(360/N*i),
> 0]];
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
RP
Ronaldo Persiano
Fri, Feb 2, 2018 8:49 PM
Step by step:
a) write the code of a morphing function with the form:
function morph(A, B, s) = ...
where A and B are a simple 2D polygons with the same number of vertices and
s is a morphing parameter in the range 0..1. The function output should be
the list of vertices of a simple 2D polygon with the same number of
vertices and it should reproduce the incoming polygons:
morph(A, B, 0) == A
morph(A, B, 1) == B
A simple linear morph is:
function morph(A,B,s) =
[for(i=[0:len(A)-1]) (1-s)A[i] + sB[i] ];
b) define the sweep path Path, that is a list of points in 3D space
belonging to some curve.
c) generate a list of morphed polygons, one for each point of Path, for
instance:
morphPoly = [ for(i=[0:len(Path)-1]) morph(A, B, i/(len(Path)-1) ) ];
d) generate a list of transforms to position the morphed polygons along the
points of Path;
a function that does exactly that is found in sweep.scad either:
https://github.com/openscad/list-comprehension-demos/blob/master/sweep.scad
or
https://github.com/RonaldoCMP/list-comprehension-demos/blob/master/sweep.scad
transfs = construct_transform_path(Path);
you will need to include the following libraries to do this step:
include <scad-utils/linalg.scad> include
<scad-utils/transformations.scad> include
<sweep.scad>
e) generate the list of vertices of all transformed polygons:
poly3D = [ for(i=[0:len( morphPoly )-1]) to3d(morphPoly[i]) ]; // adds a
z=0 coordinate to points
sections = [for (i=[0:len(Path)-1]) transform(transfs [i], poly3D[i] )]; //
transform the polygons
the function to3d() and transform() are defined in the library
transformations.scad
f) finally you will get the skin of the set of 3D located polygons by
calling:
sweep(sections);
this last sweep is not the one defined in sweep.scad but the Parkinbot's
one defined in
skin.scad (see his message). To apply the correct sweep, the inclusion of
skin.scad should appear after the inclusion of sweep.scad
Alternatively, this last step may be:
skin(sections);
including the library skin.scad found in
https://github.com/openscad/list-comprehension-demos/blob/master/skin.scad
instead of Parkinbot's sweep.scad
2018-02-02 16:20 GMT-02:00 Dan Shriver tabbydan@gmail.com:
Thanks again for all the help you guys have been giving me. I'm sorry
that I still don't fully understand the advice I'm getting. As a result I
think I'll phrase my questions slightly differently (maybe the specific
answers might be more clear to me)
Given the following:
- I have a polygon x and a polygon y
- the two polygons have the same number of points
- I wish to morph one polygon into another (interpolate between them,
probably doing it in a non-linear way (like a trig function to get a
pleasing curve))
- I wish to place these polygons (and their interpolations) along another
offset determined by a curve
What is the general suggestion on how to do it?
-
I could do everything at a low level (manipulating lists of points). I
am almost inclined to go this route but the "problems" I face are:
a) I'm not fully getting the list operation tools. Is there a good
clean way to take a list and add an offset to every member (#4 from the
previous givens); same with taking two lists and generating a third (via an
interpolation scheme)
b) once I have those lists I still need to define things so the system
can cover the surface with polygons correctly. I have been given code on
things like this before but find it very opaque (I don't see how they take
the points and create the polygons) not sure if there are simple examples
that walk one through the magic
-
I could use higher level tools such as hull(), linear_extrude(),
skin(),.... I don't know what the advantages / disadvantages to the
various was are except that it is obvious to me that linear_extrude() is an
inelegant way for me to go (since I am trying to place the whole construct
on a curve, linear_extrude() would just approximate it with a bunch of
steps). Are some computationally more expensive than others? Does hull()
work with points in space (or do I have to do something slightly unpleasant
and create infinitesimal 3D objects at each point?
To allow for either skin() or doing things low level I am now making
functions rather than modules and spitting out defined polygons of points.
I have an example of one curve via points below (it is slightly off and I
need to debug the third curve, but I'll do that).
function innerAngle(radius, thickness, angle) = angle -asin(thickness *
sin(90 - angle)/radius);
function stepAngle(angle, points) = angle / points;
function archFourthQuarterx(radius, thickness, angle, pointNum, points) =
(radius-thickness) * cos((innerAngle(radius, thickness,angle)) -
(stepAngle(innerAngle(radius, thickness,angle), (points/4)) * (pointNum -
(3*points/4)))) - radius * (cos(angle));
function archThirdQuarterx(radius, thickness, angle, pointNum, points) =
-((radius-thickness) * cos( stepAngle(innerAngle(radius, thickness,angle),
(points/4)) * (pointNum - (points/2))) - radius * (cos(angle)));
function archSecondQuarterx(radius, angle, pointNum, points) = -(radius *
cos(angle - (stepAngle(angle, (points/4)) * (pointNum - (points/4)))) -
radius * (cos(angle)));
function archFirstQuarterx(radius, angle, pointNum, points) = radius *
cos(stepAngle(angle, (points/4)) * pointNum) - radius * (cos(angle));
function archLastHalfx(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuarterx(radius, thickness, angle,
pointNum, points) : archFourthQuarterx(radius, thickness, angle, pointNum,
points);
function archFirstHalfx(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuarterx(radius, angle, pointNum, points) :
archSecondQuarterx(radius, angle, pointNum, points);
function archX(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfx(radius,angle,pointNum, points) :
archLastHalfx(radius, thickness, angle, pointNum, points);
function archFourthQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin( innerAngle(radius, thickness, angle) -
stepAngle(innerAngle(radius, thickness, angle), (points/4)) * (pointNum -
(3 * points/4)));
function archThirdQuartery(radius, thickness, angle, pointNum, points) =
(radius - thickness) * sin(stepAngle(innerAngle(radius, thickness,
angle), (points/4)) * (pointNum - points/2));
function archSecondQuartery(radius, angle, pointNum, points) = radius *
sin( angle - stepAngle(angle, (points/4)) * (pointNum - (points/4)));
function archFirstQuartery(radius, angle, pointNum, points) = radius *
sin( stepAngle(angle, (points/4)) * pointNum);
function archLastHalfy(radius, thickness, angle, pointNum, points) =
pointNum < (3 * points)/ 4 ? archThirdQuartery(radius, thickness, angle,
pointNum, points) : archFourthQuartery(radius, thickness, angle, pointNum,
points);
function archFirstHalfy(radius, angle, pointNum, points) = pointNum <
points/4 ? archFirstQuartery(radius, angle, pointNum, points) :
archSecondQuartery(radius, angle, pointNum, points);
function archY(radius, thickness, angle, pointNum, points) = pointNum <
points/2 ? archFirstHalfy(radius,angle,pointNum, points) :
archLastHalfy(radius, thickness, angle, pointNum, points);
//note if points is NOT a multiple of 4 things might be ugly...
module romanArch(radius, thickness, angle, pointCnt) {
points = [ for (i = [0:pointCnt]) [archX(radius, thickness, angle, i,
pointCnt), archY(radius, thickness, angle, i, pointCnt)] ];
polygon(points);
}
romanArch(20, 1, 70, 200);
On Sat, Jan 27, 2018 at 7:52 AM, Parkinbot rudolf@parkinbot.com wrote:
skin() and sweep() explicitly knit a polyhedron from given data. Thus they
create module objects that can be combined by use of Boolean operations
with
any other modules like cylinder. While they offer you a lot of expressive
power, you have to take special care to create valid manifolds with no
self-intersection only, if you want to get valid STLs at the end.
skin() and sweep() differ in the data you have to provide and thus in
operation and usage scope.
The original version of sweep() you are referring to, expects a geometric
primitive like a square and a transformation sequence (which is difficult
to
compose and also limited to affine transformations) to be applied to this
primitive.
skin() in contrast expects a vector of polygons already placed in 3D space
to be skinned. This is much less restrictive, because you can create any
transitions for any 2D-shapes you like, without being limited to a common
2D
shape and affine transformations - but at the price of additional care:
valid (= simple) polygons, proper sequencing with no mutual intersections
of
any polygons allowed.
When I started to play with sweep() some years ago, my aim was to define
smooth transitions between different airfoils. I immediately saw, that
sweep() will not do the job and started to implement my own sweep() which
later turned out to be (almost) semantically equivalent to skin(). I
collected all the stuff (mainly affine operations) needed to place
2D-shapes
into 3D space and knit them together into a polyhedron and stuffed it
into a
library which I called Naca_sweep(). Thus the main function is called
sweep() but behaves like skin(). Because I am a fan of short notations I
called the affine operations operating over a polygon (or 2D-shape with
z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
The following code example shows you what happens, when this library is
used
to generate a Moebius strip with a sinusoidal radius function.
- Write a parametrized function that composes your 2D shape (here circle
but any simple polygon is allowed - e.g. airfoil)
- Write a parametrized function that composes a sequence of polygons (my
sweep() expects all polygons to have the same # of vertices, skin() doen't
care) properly placed in 3D space.
- call sweep() or skin()
My sweep() implementiation provides a showslices parameter. Setting it
true will show you the polygons' placement. Try it out.
The problem is: how will you close the strip into a ring? You could either
change sweep() to account for the twistm when closing the ring, which is
hard stuff and not very general, or you just do a Boolean union of two
half
sweeps ... try the modify the example code, good exercise.
use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
// use <skin.scad> // alternative
// skin(Moebius());
sweep(Moebius(), showslices = true); // show, what happens
sweep(Moebius()); // same semantics as skin
function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
let(ang = 360/Mi)
Ry_(ang, // rotate to ring
Tx_(R, // shift triag
Rz_(ang/edges, // rotate triag
circle(r=5sin(2*ang)+10, N=edges))))]; // generate circle with
moduluated
radius
function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/Ni),
sin(360/Ni),
0]];
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Step by step:
a) write the code of a morphing function with the form:
function morph(A, B, s) = ...
where A and B are a simple 2D polygons with the same number of vertices and
s is a morphing parameter in the range 0..1. The function output should be
the list of vertices of a simple 2D polygon with the same number of
vertices and it should reproduce the incoming polygons:
morph(A, B, 0) == A
morph(A, B, 1) == B
A simple linear morph is:
function morph(A,B,s) =
[for(i=[0:len(A)-1]) (1-s)*A[i] + s*B[i] ];
b) define the sweep path Path, that is a list of points in 3D space
belonging to some curve.
c) generate a list of morphed polygons, one for each point of Path, for
instance:
morphPoly = [ for(i=[0:len(Path)-1]) morph(A, B, i/(len(Path)-1) ) ];
d) generate a list of transforms to position the morphed polygons along the
points of Path;
a function that does exactly that is found in sweep.scad either:
https://github.com/openscad/list-comprehension-demos/blob/master/sweep.scad
or
https://github.com/RonaldoCMP/list-comprehension-demos/blob/master/sweep.scad
transfs = construct_transform_path(Path);
you will need to include the following libraries to do this step:
include <scad-utils/linalg.scad> include
<scad-utils/transformations.scad> include
<sweep.scad>
e) generate the list of vertices of all transformed polygons:
poly3D = [ for(i=[0:len( morphPoly )-1]) to3d(morphPoly[i]) ]; // adds a
z=0 coordinate to points
sections = [for (i=[0:len(Path)-1]) transform(transfs [i], poly3D[i] )]; //
transform the polygons
the function to3d() and transform() are defined in the library
transformations.scad
f) finally you will get the skin of the set of 3D located polygons by
calling:
sweep(sections);
this last sweep is not the one defined in sweep.scad but the Parkinbot's
one defined in
skin.scad (see his message). To apply the correct sweep, the inclusion of
skin.scad should appear after the inclusion of sweep.scad
Alternatively, this last step may be:
skin(sections);
including the library skin.scad found in
https://github.com/openscad/list-comprehension-demos/blob/master/skin.scad
instead of Parkinbot's sweep.scad
2018-02-02 16:20 GMT-02:00 Dan Shriver <tabbydan@gmail.com>:
> Thanks again for all the help you guys have been giving me. I'm sorry
> that I still don't fully understand the advice I'm getting. As a result I
> think I'll phrase my questions slightly differently (maybe the specific
> answers might be more clear to me)
>
> Given the following:
>
> 1) I have a polygon x and a polygon y
> 2) the two polygons have the same number of points
> 3) I wish to morph one polygon into another (interpolate between them,
> probably doing it in a non-linear way (like a trig function to get a
> pleasing curve))
> 4) I wish to place these polygons (and their interpolations) along another
> offset determined by a curve
>
> What is the general suggestion on how to do it?
>
> 1) I could do everything at a low level (manipulating lists of points). I
> am almost inclined to go this route but the "problems" I face are:
> a) I'm not fully getting the list operation tools. Is there a good
> clean way to take a list and add an offset to every member (#4 from the
> previous givens); same with taking two lists and generating a third (via an
> interpolation scheme)
> b) once I have those lists I still need to define things so the system
> can cover the surface with polygons correctly. I have been given code on
> things like this before but find it very opaque (I don't see how they take
> the points and create the polygons) not sure if there are simple examples
> that walk one through the magic
>
> 2) I could use higher level tools such as hull(), linear_extrude(),
> skin(),.... I don't know what the advantages / disadvantages to the
> various was are except that it is obvious to me that linear_extrude() is an
> inelegant way for me to go (since I am trying to place the whole construct
> on a curve, linear_extrude() would just approximate it with a bunch of
> steps). Are some computationally more expensive than others? Does hull()
> work with points in space (or do I have to do something slightly unpleasant
> and create infinitesimal 3D objects at each point?
>
> To allow for either skin() or doing things low level I am now making
> functions rather than modules and spitting out defined polygons of points.
>
> I have an example of one curve via points below (it is slightly off and I
> need to debug the third curve, but I'll do that).
> ---------
>
> function innerAngle(radius, thickness, angle) = angle -asin(thickness *
> sin(90 - angle)/radius);
>
> function stepAngle(angle, points) = angle / points;
>
> function archFourthQuarterx(radius, thickness, angle, pointNum, points) =
> (radius-thickness) * cos((innerAngle(radius, thickness,angle)) -
> (stepAngle(innerAngle(radius, thickness,angle), (points/4)) * (pointNum -
> (3*points/4)))) - radius * (cos(angle));
>
> function archThirdQuarterx(radius, thickness, angle, pointNum, points) =
> -((radius-thickness) * cos( stepAngle(innerAngle(radius, thickness,angle),
> (points/4)) * (pointNum - (points/2))) - radius * (cos(angle)));
>
> function archSecondQuarterx(radius, angle, pointNum, points) = -(radius *
> cos(angle - (stepAngle(angle, (points/4)) * (pointNum - (points/4)))) -
> radius * (cos(angle)));
>
> function archFirstQuarterx(radius, angle, pointNum, points) = radius *
> cos(stepAngle(angle, (points/4)) * pointNum) - radius * (cos(angle));
>
> function archLastHalfx(radius, thickness, angle, pointNum, points) =
> pointNum < (3 * points)/ 4 ? archThirdQuarterx(radius, thickness, angle,
> pointNum, points) : archFourthQuarterx(radius, thickness, angle, pointNum,
> points);
>
> function archFirstHalfx(radius, angle, pointNum, points) = pointNum <
> points/4 ? archFirstQuarterx(radius, angle, pointNum, points) :
> archSecondQuarterx(radius, angle, pointNum, points);
>
> function archX(radius, thickness, angle, pointNum, points) = pointNum <
> points/2 ? archFirstHalfx(radius,angle,pointNum, points) :
> archLastHalfx(radius, thickness, angle, pointNum, points);
>
> function archFourthQuartery(radius, thickness, angle, pointNum, points) =
> (radius - thickness) * sin( innerAngle(radius, thickness, angle) -
> stepAngle(innerAngle(radius, thickness, angle), (points/4)) * (pointNum -
> (3 * points/4)));
>
> function archThirdQuartery(radius, thickness, angle, pointNum, points) =
> (radius - thickness) * sin(stepAngle(innerAngle(radius, thickness,
> angle), (points/4)) * (pointNum - points/2));
>
> function archSecondQuartery(radius, angle, pointNum, points) = radius *
> sin( angle - stepAngle(angle, (points/4)) * (pointNum - (points/4)));
>
> function archFirstQuartery(radius, angle, pointNum, points) = radius *
> sin( stepAngle(angle, (points/4)) * pointNum);
>
> function archLastHalfy(radius, thickness, angle, pointNum, points) =
> pointNum < (3 * points)/ 4 ? archThirdQuartery(radius, thickness, angle,
> pointNum, points) : archFourthQuartery(radius, thickness, angle, pointNum,
> points);
>
> function archFirstHalfy(radius, angle, pointNum, points) = pointNum <
> points/4 ? archFirstQuartery(radius, angle, pointNum, points) :
> archSecondQuartery(radius, angle, pointNum, points);
>
> function archY(radius, thickness, angle, pointNum, points) = pointNum <
> points/2 ? archFirstHalfy(radius,angle,pointNum, points) :
> archLastHalfy(radius, thickness, angle, pointNum, points);
>
> //note if points is NOT a multiple of 4 things might be ugly...
> module romanArch(radius, thickness, angle, pointCnt) {
> points = [ for (i = [0:pointCnt]) [archX(radius, thickness, angle, i,
> pointCnt), archY(radius, thickness, angle, i, pointCnt)] ];
>
> polygon(points);
> }
>
> romanArch(20, 1, 70, 200);
>
>
> On Sat, Jan 27, 2018 at 7:52 AM, Parkinbot <rudolf@parkinbot.com> wrote:
>
>> skin() and sweep() explicitly knit a polyhedron from given data. Thus they
>> create module objects that can be combined by use of Boolean operations
>> with
>> any other modules like cylinder. While they offer you a lot of expressive
>> power, you have to take special care to create valid manifolds with no
>> self-intersection only, if you want to get valid STLs at the end.
>>
>> skin() and sweep() differ in the data you have to provide and thus in
>> operation and usage scope.
>>
>> The original version of sweep() you are referring to, expects a geometric
>> primitive like a square and a transformation sequence (which is difficult
>> to
>> compose and also limited to affine transformations) to be applied to this
>> primitive.
>>
>> skin() in contrast expects a vector of polygons already placed in 3D space
>> to be skinned. This is much less restrictive, because you can create any
>> transitions for any 2D-shapes you like, without being limited to a common
>> 2D
>> shape and affine transformations - but at the price of additional care:
>> valid (= simple) polygons, proper sequencing with no mutual intersections
>> of
>> any polygons allowed.
>>
>> When I started to play with sweep() some years ago, my aim was to define
>> smooth transitions between different airfoils. I immediately saw, that
>> sweep() will not do the job and started to implement my own sweep() which
>> later turned out to be (almost) semantically equivalent to skin(). I
>> collected all the stuff (mainly affine operations) needed to place
>> 2D-shapes
>> into 3D space and knit them together into a polyhedron and stuffed it
>> into a
>> library which I called Naca_sweep(). Thus the main function is called
>> sweep() but behaves like skin(). Because I am a fan of short notations I
>> called the affine operations operating over a polygon (or 2D-shape with
>> z-coordinate) Rx_(), Ry_(), Ry_(), Tx_(), ... Sx_().
>>
>> The following code example shows you what happens, when this library is
>> used
>> to generate a Moebius strip with a sinusoidal radius function.
>> 1. Write a parametrized function that composes your 2D shape (here circle
>> but any simple polygon is allowed - e.g. airfoil)
>> 2. Write a parametrized function that composes a sequence of polygons (my
>> sweep() expects all polygons to have the same # of vertices, skin() doen't
>> care) properly placed in 3D space.
>> 3. call sweep() or skin()
>>
>> My sweep() implementiation provides a *showslices* parameter. Setting it
>> true will show you the polygons' placement. Try it out.
>>
>> The problem is: how will you close the strip into a ring? You could either
>> change sweep() to account for the twistm when closing the ring, which is
>> hard stuff and not very general, or you just do a Boolean union of two
>> half
>> sweeps ... try the modify the example code, good exercise.
>>
>>
>> use <naca_sweep.scad> // https://www.thingiverse.com/thing:900137
>>
>> // use <skin.scad> // alternative
>> // skin(Moebius());
>>
>> sweep(Moebius(), showslices = true); // show, what happens
>> sweep(Moebius()); // same semantics as skin
>>
>> function Moebius(R = 30, edges = 3, M=50) = [for(i=[0:M-1])
>> let(ang = 360/M*i)
>> Ry_(ang, // rotate to ring
>> Tx_(R, // shift triag
>> Rz_(ang/edges, // rotate triag
>> circle(r=5*sin(2*ang)+10, N=edges))))]; // generate circle with
>> moduluated
>> radius
>>
>> function circle(r=10, N=3) = [for(i=[0:N-1]) r*[cos(360/N*i),
>> sin(360/N*i),
>> 0]];
>>
>>
>>
>>
>> --
>> Sent from: http://forum.openscad.org/
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> Discuss@lists.openscad.org
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
>