SP
Sanjeev Prabhakar
Wed, Apr 13, 2022 3:29 PM
yes you are right, but that is true when the offset distance is small.
when you have radiuses on the original section and the offset distance is
more than the corner radiuses of the original section.
your method most likely will show self intersection (as in fig attached)
On Wed, 13 Apr 2022 at 20:28, nop head nop.head@gmail.com wrote:
Isn't offset just a matter of drawing circles around each vertex and
calculating the joining tangents. Something I have done in the NopSCADlib
rounded polygon.
If the vertex is concave then the tangents cross in front of the circle
so that intersection becomes the new vertex. So that is extra code.
I think this is how Skeinforge does offsets. Not particularly slow in
Python.
On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
Hi Adrian
Since the offset of so many stages is excessively time consuming.
Calculated the normals with 3 adjacent points here to achieve the
objective.
In the first and the last stage there would be some mismatch, but maybe
not significant.
By removing the option of "stop on first warning" f6 render done
successfully.
Not tried rendering along with cube, but an stl file can be generated
with this. Although the size of the stl file is huge 141mb
So it is assumed, this can be printed
Apart from this there could be several self intersecting sections and
presently don't know how to cure them.
But anyways it was a good learning exercise
On Wed, 13 Apr 2022, 16:54 Adrian Mariano, avm4@cornell.edu wrote:
Sanjeev, your code may be fast but it doesn't actually work. There seem
to be two problems, not counting the misplaced bracket. One is that it
fails render (F6) when I add cube(120) to the model. I assume this is
because it doesn't take into account that the offset surface will intersect
itself. Being able to do offset in 3d would be great, but offset in 2d
with correct handling of self-intersection is already difficult, and
checking for self-intersection is quadratic time. Going to a surface
offset means quadratic time over the whole surface point set, which will be
horribly slow. And then actually fixing the self-intersections will be
very difficult to code. Compare run time in openscad primitives of
offset() and minkowski(). I really don't understand how doing any
operation in 3d can be faster than 2d, so that behavior is puzzling. It
definitely seems to be fast.
The other problem I noticed with your version is that it does something
strange to the bottom, so the result isn't actually flat on the bottom.
That's presumably because you're using normals to the surface and they
point slightly down, so your inside is not aligned with your outside. It
wouldn't be printable in that form. It could be fixed with an
intersection, though that will add run time. Also, the model is supposed
to be a container---there should be a bottom layer, which you are not
including.
The version I posted that exploits symmetry uses a correct offset which
offsets by the right amount (unlike yours) and which deals properly with
the self-intersection of the offset curve so that the resulting model
doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
Jordan, I agree that a step size of 1 degree is not enough. When I
looked at 0.5 degrees I thought it looked adequate. In any case, my latest
code produces a model in a reasonable time even with 0.1 degree, so
assuming sufficient resources to render, it should be possible to use a
very tiny step size.
On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I have written a new function surf_offset(prism,d) for this
include <sprabhakar2006/
dependencies.scad>
function surf_offset(prism,d)=
[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
let(
j_plus=j<len(prism[0])-1?j+1:0,
p0=prism[i][j],
p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
v1=p1-p0,v2=p2-p0,
u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d
)p0+p3
]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,-2);
swp_prism_h(points_base,points_base_e);
with 1 deg angle step it takes 20 sec
with 0.1 deg angle step it took 3 minutes 34 sec
I am working now on a 7 year old computer windows laptop
On Wed, 13 Apr 2022, 11:06 Jordan Brown, openscad@jordan.maileater.net
wrote:
Another thing to think about is that you can design at a lower
resolution than you will eventually want. When I set stages=50,
stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
rough, but it conveys the shape reasonably well. When you're happy with
the shape, then set things for higher resolution.
[*] My desktop is almost ten years old and wasn't high-end even when
new.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
yes you are right, but that is true when the offset distance is small.
when you have radiuses on the original section and the offset distance is
more than the corner radiuses of the original section.
your method most likely will show self intersection (as in fig attached)
On Wed, 13 Apr 2022 at 20:28, nop head <nop.head@gmail.com> wrote:
> Isn't offset just a matter of drawing circles around each vertex and
> calculating the joining tangents. Something I have done in the NopSCADlib
> rounded polygon.
>
> If the vertex is concave then the tangents cross in front of the circle
> so that intersection becomes the new vertex. So that is extra code.
>
> I think this is how Skeinforge does offsets. Not particularly slow in
> Python.
>
> On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
> wrote:
>
>> Hi Adrian
>>
>> Since the offset of so many stages is excessively time consuming.
>> Calculated the normals with 3 adjacent points here to achieve the
>> objective.
>>
>> In the first and the last stage there would be some mismatch, but maybe
>> not significant.
>>
>> By removing the option of "stop on first warning" f6 render done
>> successfully.
>>
>> Not tried rendering along with cube, but an stl file can be generated
>> with this. Although the size of the stl file is huge 141mb
>>
>> So it is assumed, this can be printed
>>
>> Apart from this there could be several self intersecting sections and
>> presently don't know how to cure them.
>>
>> But anyways it was a good learning exercise
>>
>>
>> On Wed, 13 Apr 2022, 16:54 Adrian Mariano, <avm4@cornell.edu> wrote:
>>
>>> Sanjeev, your code may be fast but it doesn't actually work. There seem
>>> to be two problems, not counting the misplaced bracket. One is that it
>>> fails render (F6) when I add cube(120) to the model. I assume this is
>>> because it doesn't take into account that the offset surface will intersect
>>> itself. Being able to do offset in 3d would be great, but offset in 2d
>>> with correct handling of self-intersection is already difficult, and
>>> checking for self-intersection is quadratic time. Going to a surface
>>> offset means quadratic time over the whole surface point set, which will be
>>> horribly slow. And then actually fixing the self-intersections will be
>>> very difficult to code. Compare run time in openscad primitives of
>>> offset() and minkowski(). I really don't understand how doing any
>>> operation in 3d can be faster than 2d, so that behavior is puzzling. It
>>> definitely seems to be fast.
>>>
>>> The other problem I noticed with your version is that it does something
>>> strange to the bottom, so the result isn't actually flat on the bottom.
>>> That's presumably because you're using normals to the surface and they
>>> point slightly down, so your inside is not aligned with your outside. It
>>> wouldn't be printable in that form. It could be fixed with an
>>> intersection, though that will add run time. Also, the model is supposed
>>> to be a container---there should be a bottom layer, which you are not
>>> including.
>>>
>>> The version I posted that exploits symmetry uses a correct offset which
>>> offsets by the right amount (unlike yours) and which deals properly with
>>> the self-intersection of the offset curve so that the resulting model
>>> doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
>>> size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
>>>
>>> Jordan, I agree that a step size of 1 degree is not enough. When I
>>> looked at 0.5 degrees I thought it looked adequate. In any case, my latest
>>> code produces a model in a reasonable time even with 0.1 degree, so
>>> assuming sufficient resources to render, it should be possible to use a
>>> very tiny step size.
>>>
>>> On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
>>> sprabhakar2006@gmail.com> wrote:
>>>
>>>> I have written a new function surf_offset(prism,d) for this
>>>>
>>>> include <sprabhakar2006/
>>>>
>>>> dependencies.scad>
>>>> function surf_offset(prism,d)=
>>>> [for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
>>>> let(
>>>> j_plus=j<len(prism[0])-1?j+1:0,
>>>> p0=prism[i][j],
>>>> p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
>>>> p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
>>>> v1=p1-p0,v2=p2-p0,
>>>> u1=uv(v1),u2=uv(v2),
>>>> p3=cross(u1,u2)*d
>>>> )p0+p3
>>>> ]];
>>>>
>>>>
>>>> stages =200;
>>>>
>>>> stage_height = 1.25;
>>>>
>>>> rad = 50;
>>>>
>>>> f1 = 25;
>>>>
>>>> f2 = 25;
>>>>
>>>> phase1 = 0;
>>>>
>>>> phase2 = 180;
>>>>
>>>> height_depth=5;
>>>>
>>>> depth1 = 20;
>>>>
>>>> depth2 = 20;
>>>>
>>>> thickness = 2;
>>>>
>>>> bottom_thickness = 3;
>>>>
>>>> myslices = 5;
>>>>
>>>> angle_step=1;
>>>>
>>>> // generate outer points
>>>>
>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>
>>>> points_base_e=surf_offset(points_base,-2);
>>>>
>>>> swp_prism_h(points_base,points_base_e);
>>>>
>>>> with 1 deg angle step it takes 20 sec
>>>>
>>>> with 0.1 deg angle step it took 3 minutes 34 sec
>>>>
>>>> I am working now on a 7 year old computer windows laptop
>>>>
>>>> On Wed, 13 Apr 2022, 11:06 Jordan Brown, <openscad@jordan.maileater.net>
>>>> wrote:
>>>>
>>>>> Another thing to think about is that you can design at a lower
>>>>> resolution than you will eventually want. When I set stages=50,
>>>>> stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
>>>>> rough, but it conveys the shape reasonably well. When you're happy with
>>>>> the shape, *then* set things for higher resolution.
>>>>>
>>>>> [*] My desktop is almost ten years old and wasn't high-end even when
>>>>> new.
>>>>>
>>>>> _______________________________________________
>>>>> 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
>>>
>> _______________________________________________
>> 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
>
NH
nop head
Wed, Apr 13, 2022 3:37 PM
Yes, as I said when the tangents intersect that is the new vertex, rather
than the circle. I.e. concave corners are points and convex ones become
arcs.
On Wed, 13 Apr 2022 at 16:29, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
yes you are right, but that is true when the offset distance is small.
when you have radiuses on the original section and the offset distance is
more than the corner radiuses of the original section.
your method most likely will show self intersection (as in fig attached)
On Wed, 13 Apr 2022 at 20:28, nop head nop.head@gmail.com wrote:
Isn't offset just a matter of drawing circles around each vertex and
calculating the joining tangents. Something I have done in the NopSCADlib
rounded polygon.
If the vertex is concave then the tangents cross in front of the circle
so that intersection becomes the new vertex. So that is extra code.
I think this is how Skeinforge does offsets. Not particularly slow in
Python.
On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
Hi Adrian
Since the offset of so many stages is excessively time consuming.
Calculated the normals with 3 adjacent points here to achieve the
objective.
In the first and the last stage there would be some mismatch, but maybe
not significant.
By removing the option of "stop on first warning" f6 render done
successfully.
Not tried rendering along with cube, but an stl file can be generated
with this. Although the size of the stl file is huge 141mb
So it is assumed, this can be printed
Apart from this there could be several self intersecting sections and
presently don't know how to cure them.
But anyways it was a good learning exercise
On Wed, 13 Apr 2022, 16:54 Adrian Mariano, avm4@cornell.edu wrote:
Sanjeev, your code may be fast but it doesn't actually work. There
seem to be two problems, not counting the misplaced bracket. One is that
it fails render (F6) when I add cube(120) to the model. I assume this is
because it doesn't take into account that the offset surface will intersect
itself. Being able to do offset in 3d would be great, but offset in 2d
with correct handling of self-intersection is already difficult, and
checking for self-intersection is quadratic time. Going to a surface
offset means quadratic time over the whole surface point set, which will be
horribly slow. And then actually fixing the self-intersections will be
very difficult to code. Compare run time in openscad primitives of
offset() and minkowski(). I really don't understand how doing any
operation in 3d can be faster than 2d, so that behavior is puzzling. It
definitely seems to be fast.
The other problem I noticed with your version is that it does something
strange to the bottom, so the result isn't actually flat on the bottom.
That's presumably because you're using normals to the surface and they
point slightly down, so your inside is not aligned with your outside. It
wouldn't be printable in that form. It could be fixed with an
intersection, though that will add run time. Also, the model is supposed
to be a container---there should be a bottom layer, which you are not
including.
The version I posted that exploits symmetry uses a correct offset which
offsets by the right amount (unlike yours) and which deals properly with
the self-intersection of the offset curve so that the resulting model
doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
Jordan, I agree that a step size of 1 degree is not enough. When I
looked at 0.5 degrees I thought it looked adequate. In any case, my latest
code produces a model in a reasonable time even with 0.1 degree, so
assuming sufficient resources to render, it should be possible to use a
very tiny step size.
On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I have written a new function surf_offset(prism,d) for this
include <sprabhakar2006/
dependencies.scad>
function surf_offset(prism,d)=
[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
let(
j_plus=j<len(prism[0])-1?j+1:0,
p0=prism[i][j],
p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
v1=p1-p0,v2=p2-p0,
u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d
)p0+p3
]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,-2);
swp_prism_h(points_base,points_base_e);
with 1 deg angle step it takes 20 sec
with 0.1 deg angle step it took 3 minutes 34 sec
I am working now on a 7 year old computer windows laptop
On Wed, 13 Apr 2022, 11:06 Jordan Brown, <
openscad@jordan.maileater.net> wrote:
Another thing to think about is that you can design at a lower
resolution than you will eventually want. When I set stages=50,
stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
rough, but it conveys the shape reasonably well. When you're happy with
the shape, then set things for higher resolution.
[*] My desktop is almost ten years old and wasn't high-end even when
new.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Yes, as I said when the tangents intersect that is the new vertex, rather
than the circle. I.e. concave corners are points and convex ones become
arcs.
On Wed, 13 Apr 2022 at 16:29, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
wrote:
> yes you are right, but that is true when the offset distance is small.
>
> when you have radiuses on the original section and the offset distance is
> more than the corner radiuses of the original section.
>
> your method most likely will show self intersection (as in fig attached)
>
>
>
> On Wed, 13 Apr 2022 at 20:28, nop head <nop.head@gmail.com> wrote:
>
>> Isn't offset just a matter of drawing circles around each vertex and
>> calculating the joining tangents. Something I have done in the NopSCADlib
>> rounded polygon.
>>
>> If the vertex is concave then the tangents cross in front of the circle
>> so that intersection becomes the new vertex. So that is extra code.
>>
>> I think this is how Skeinforge does offsets. Not particularly slow in
>> Python.
>>
>> On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
>> wrote:
>>
>>> Hi Adrian
>>>
>>> Since the offset of so many stages is excessively time consuming.
>>> Calculated the normals with 3 adjacent points here to achieve the
>>> objective.
>>>
>>> In the first and the last stage there would be some mismatch, but maybe
>>> not significant.
>>>
>>> By removing the option of "stop on first warning" f6 render done
>>> successfully.
>>>
>>> Not tried rendering along with cube, but an stl file can be generated
>>> with this. Although the size of the stl file is huge 141mb
>>>
>>> So it is assumed, this can be printed
>>>
>>> Apart from this there could be several self intersecting sections and
>>> presently don't know how to cure them.
>>>
>>> But anyways it was a good learning exercise
>>>
>>>
>>> On Wed, 13 Apr 2022, 16:54 Adrian Mariano, <avm4@cornell.edu> wrote:
>>>
>>>> Sanjeev, your code may be fast but it doesn't actually work. There
>>>> seem to be two problems, not counting the misplaced bracket. One is that
>>>> it fails render (F6) when I add cube(120) to the model. I assume this is
>>>> because it doesn't take into account that the offset surface will intersect
>>>> itself. Being able to do offset in 3d would be great, but offset in 2d
>>>> with correct handling of self-intersection is already difficult, and
>>>> checking for self-intersection is quadratic time. Going to a surface
>>>> offset means quadratic time over the whole surface point set, which will be
>>>> horribly slow. And then actually fixing the self-intersections will be
>>>> very difficult to code. Compare run time in openscad primitives of
>>>> offset() and minkowski(). I really don't understand how doing any
>>>> operation in 3d can be faster than 2d, so that behavior is puzzling. It
>>>> definitely seems to be fast.
>>>>
>>>> The other problem I noticed with your version is that it does something
>>>> strange to the bottom, so the result isn't actually flat on the bottom.
>>>> That's presumably because you're using normals to the surface and they
>>>> point slightly down, so your inside is not aligned with your outside. It
>>>> wouldn't be printable in that form. It could be fixed with an
>>>> intersection, though that will add run time. Also, the model is supposed
>>>> to be a container---there should be a bottom layer, which you are not
>>>> including.
>>>>
>>>> The version I posted that exploits symmetry uses a correct offset which
>>>> offsets by the right amount (unlike yours) and which deals properly with
>>>> the self-intersection of the offset curve so that the resulting model
>>>> doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
>>>> size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
>>>>
>>>> Jordan, I agree that a step size of 1 degree is not enough. When I
>>>> looked at 0.5 degrees I thought it looked adequate. In any case, my latest
>>>> code produces a model in a reasonable time even with 0.1 degree, so
>>>> assuming sufficient resources to render, it should be possible to use a
>>>> very tiny step size.
>>>>
>>>> On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
>>>> sprabhakar2006@gmail.com> wrote:
>>>>
>>>>> I have written a new function surf_offset(prism,d) for this
>>>>>
>>>>> include <sprabhakar2006/
>>>>>
>>>>> dependencies.scad>
>>>>> function surf_offset(prism,d)=
>>>>> [for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
>>>>> let(
>>>>> j_plus=j<len(prism[0])-1?j+1:0,
>>>>> p0=prism[i][j],
>>>>> p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
>>>>> p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
>>>>> v1=p1-p0,v2=p2-p0,
>>>>> u1=uv(v1),u2=uv(v2),
>>>>> p3=cross(u1,u2)*d
>>>>> )p0+p3
>>>>> ]];
>>>>>
>>>>>
>>>>> stages =200;
>>>>>
>>>>> stage_height = 1.25;
>>>>>
>>>>> rad = 50;
>>>>>
>>>>> f1 = 25;
>>>>>
>>>>> f2 = 25;
>>>>>
>>>>> phase1 = 0;
>>>>>
>>>>> phase2 = 180;
>>>>>
>>>>> height_depth=5;
>>>>>
>>>>> depth1 = 20;
>>>>>
>>>>> depth2 = 20;
>>>>>
>>>>> thickness = 2;
>>>>>
>>>>> bottom_thickness = 3;
>>>>>
>>>>> myslices = 5;
>>>>>
>>>>> angle_step=1;
>>>>>
>>>>> // generate outer points
>>>>>
>>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>>
>>>>> points_base_e=surf_offset(points_base,-2);
>>>>>
>>>>> swp_prism_h(points_base,points_base_e);
>>>>>
>>>>> with 1 deg angle step it takes 20 sec
>>>>>
>>>>> with 0.1 deg angle step it took 3 minutes 34 sec
>>>>>
>>>>> I am working now on a 7 year old computer windows laptop
>>>>>
>>>>> On Wed, 13 Apr 2022, 11:06 Jordan Brown, <
>>>>> openscad@jordan.maileater.net> wrote:
>>>>>
>>>>>> Another thing to think about is that you can design at a lower
>>>>>> resolution than you will eventually want. When I set stages=50,
>>>>>> stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
>>>>>> rough, but it conveys the shape reasonably well. When you're happy with
>>>>>> the shape, *then* set things for higher resolution.
>>>>>>
>>>>>> [*] My desktop is almost ten years old and wasn't high-end even when
>>>>>> new.
>>>>>>
>>>>>> _______________________________________________
>>>>>> 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
>>>>
>>> _______________________________________________
>>> 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
>
SP
Sanjeev Prabhakar
Wed, Apr 13, 2022 3:47 PM
The problem is implementation.
maybe it is easier in python, which i don't have much experience with.
On Wed, 13 Apr 2022 at 21:09, nop head nop.head@gmail.com wrote:
Yes, as I said when the tangents intersect that is the new vertex, rather
than the circle. I.e. concave corners are points and convex ones become
arcs.
On Wed, 13 Apr 2022 at 16:29, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
yes you are right, but that is true when the offset distance is small.
when you have radiuses on the original section and the offset distance is
more than the corner radiuses of the original section.
your method most likely will show self intersection (as in fig attached)
On Wed, 13 Apr 2022 at 20:28, nop head nop.head@gmail.com wrote:
Isn't offset just a matter of drawing circles around each vertex and
calculating the joining tangents. Something I have done in the NopSCADlib
rounded polygon.
If the vertex is concave then the tangents cross in front of the circle
so that intersection becomes the new vertex. So that is extra code.
I think this is how Skeinforge does offsets. Not particularly slow in
Python.
On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
Hi Adrian
Since the offset of so many stages is excessively time consuming.
Calculated the normals with 3 adjacent points here to achieve the
objective.
In the first and the last stage there would be some mismatch, but maybe
not significant.
By removing the option of "stop on first warning" f6 render done
successfully.
Not tried rendering along with cube, but an stl file can be generated
with this. Although the size of the stl file is huge 141mb
So it is assumed, this can be printed
Apart from this there could be several self intersecting sections and
presently don't know how to cure them.
But anyways it was a good learning exercise
On Wed, 13 Apr 2022, 16:54 Adrian Mariano, avm4@cornell.edu wrote:
Sanjeev, your code may be fast but it doesn't actually work. There
seem to be two problems, not counting the misplaced bracket. One is that
it fails render (F6) when I add cube(120) to the model. I assume this is
because it doesn't take into account that the offset surface will intersect
itself. Being able to do offset in 3d would be great, but offset in 2d
with correct handling of self-intersection is already difficult, and
checking for self-intersection is quadratic time. Going to a surface
offset means quadratic time over the whole surface point set, which will be
horribly slow. And then actually fixing the self-intersections will be
very difficult to code. Compare run time in openscad primitives of
offset() and minkowski(). I really don't understand how doing any
operation in 3d can be faster than 2d, so that behavior is puzzling. It
definitely seems to be fast.
The other problem I noticed with your version is that it does
something strange to the bottom, so the result isn't actually flat on the
bottom. That's presumably because you're using normals to the surface and
they point slightly down, so your inside is not aligned with your outside.
It wouldn't be printable in that form. It could be fixed with an
intersection, though that will add run time. Also, the model is supposed
to be a container---there should be a bottom layer, which you are not
including.
The version I posted that exploits symmetry uses a correct offset
which offsets by the right amount (unlike yours) and which deals properly
with the self-intersection of the offset curve so that the resulting model
doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
Jordan, I agree that a step size of 1 degree is not enough. When I
looked at 0.5 degrees I thought it looked adequate. In any case, my latest
code produces a model in a reasonable time even with 0.1 degree, so
assuming sufficient resources to render, it should be possible to use a
very tiny step size.
On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I have written a new function surf_offset(prism,d) for this
include <sprabhakar2006/
dependencies.scad>
function surf_offset(prism,d)=
[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
let(
j_plus=j<len(prism[0])-1?j+1:0,
p0=prism[i][j],
p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
v1=p1-p0,v2=p2-p0,
u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d
)p0+p3
]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,-2);
swp_prism_h(points_base,points_base_e);
with 1 deg angle step it takes 20 sec
with 0.1 deg angle step it took 3 minutes 34 sec
I am working now on a 7 year old computer windows laptop
On Wed, 13 Apr 2022, 11:06 Jordan Brown, <
openscad@jordan.maileater.net> wrote:
Another thing to think about is that you can design at a lower
resolution than you will eventually want. When I set stages=50,
stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
rough, but it conveys the shape reasonably well. When you're happy with
the shape, then set things for higher resolution.
[*] My desktop is almost ten years old and wasn't high-end even when
new.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The problem is implementation.
maybe it is easier in python, which i don't have much experience with.
On Wed, 13 Apr 2022 at 21:09, nop head <nop.head@gmail.com> wrote:
> Yes, as I said when the tangents intersect that is the new vertex, rather
> than the circle. I.e. concave corners are points and convex ones become
> arcs.
>
> On Wed, 13 Apr 2022 at 16:29, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
> wrote:
>
>> yes you are right, but that is true when the offset distance is small.
>>
>> when you have radiuses on the original section and the offset distance is
>> more than the corner radiuses of the original section.
>>
>> your method most likely will show self intersection (as in fig attached)
>>
>>
>>
>> On Wed, 13 Apr 2022 at 20:28, nop head <nop.head@gmail.com> wrote:
>>
>>> Isn't offset just a matter of drawing circles around each vertex and
>>> calculating the joining tangents. Something I have done in the NopSCADlib
>>> rounded polygon.
>>>
>>> If the vertex is concave then the tangents cross in front of the circle
>>> so that intersection becomes the new vertex. So that is extra code.
>>>
>>> I think this is how Skeinforge does offsets. Not particularly slow in
>>> Python.
>>>
>>> On Wed, 13 Apr 2022 at 13:02, Sanjeev Prabhakar <
>>> sprabhakar2006@gmail.com> wrote:
>>>
>>>> Hi Adrian
>>>>
>>>> Since the offset of so many stages is excessively time consuming.
>>>> Calculated the normals with 3 adjacent points here to achieve the
>>>> objective.
>>>>
>>>> In the first and the last stage there would be some mismatch, but maybe
>>>> not significant.
>>>>
>>>> By removing the option of "stop on first warning" f6 render done
>>>> successfully.
>>>>
>>>> Not tried rendering along with cube, but an stl file can be generated
>>>> with this. Although the size of the stl file is huge 141mb
>>>>
>>>> So it is assumed, this can be printed
>>>>
>>>> Apart from this there could be several self intersecting sections and
>>>> presently don't know how to cure them.
>>>>
>>>> But anyways it was a good learning exercise
>>>>
>>>>
>>>> On Wed, 13 Apr 2022, 16:54 Adrian Mariano, <avm4@cornell.edu> wrote:
>>>>
>>>>> Sanjeev, your code may be fast but it doesn't actually work. There
>>>>> seem to be two problems, not counting the misplaced bracket. One is that
>>>>> it fails render (F6) when I add cube(120) to the model. I assume this is
>>>>> because it doesn't take into account that the offset surface will intersect
>>>>> itself. Being able to do offset in 3d would be great, but offset in 2d
>>>>> with correct handling of self-intersection is already difficult, and
>>>>> checking for self-intersection is quadratic time. Going to a surface
>>>>> offset means quadratic time over the whole surface point set, which will be
>>>>> horribly slow. And then actually fixing the self-intersections will be
>>>>> very difficult to code. Compare run time in openscad primitives of
>>>>> offset() and minkowski(). I really don't understand how doing any
>>>>> operation in 3d can be faster than 2d, so that behavior is puzzling. It
>>>>> definitely seems to be fast.
>>>>>
>>>>> The other problem I noticed with your version is that it does
>>>>> something strange to the bottom, so the result isn't actually flat on the
>>>>> bottom. That's presumably because you're using normals to the surface and
>>>>> they point slightly down, so your inside is not aligned with your outside.
>>>>> It wouldn't be printable in that form. It could be fixed with an
>>>>> intersection, though that will add run time. Also, the model is supposed
>>>>> to be a container---there should be a bottom layer, which you are not
>>>>> including.
>>>>>
>>>>> The version I posted that exploits symmetry uses a correct offset
>>>>> which offsets by the right amount (unlike yours) and which deals properly
>>>>> with the self-intersection of the offset curve so that the resulting model
>>>>> doesn't have self-intersection. It previews in 2.5 minutes with 0.1 step
>>>>> size. I tried to render but OpenSCAD crashed, maybe not enough RAM?
>>>>>
>>>>> Jordan, I agree that a step size of 1 degree is not enough. When I
>>>>> looked at 0.5 degrees I thought it looked adequate. In any case, my latest
>>>>> code produces a model in a reasonable time even with 0.1 degree, so
>>>>> assuming sufficient resources to render, it should be possible to use a
>>>>> very tiny step size.
>>>>>
>>>>> On Wed, Apr 13, 2022 at 4:00 AM Sanjeev Prabhakar <
>>>>> sprabhakar2006@gmail.com> wrote:
>>>>>
>>>>>> I have written a new function surf_offset(prism,d) for this
>>>>>>
>>>>>> include <sprabhakar2006/
>>>>>>
>>>>>> dependencies.scad>
>>>>>> function surf_offset(prism,d)=
>>>>>> [for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])
>>>>>> let(
>>>>>> j_plus=j<len(prism[0])-1?j+1:0,
>>>>>> p0=prism[i][j],
>>>>>> p1=i<len(prism)-1?prism[i][]j_plus:prism[i-1][j],
>>>>>> p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],
>>>>>> v1=p1-p0,v2=p2-p0,
>>>>>> u1=uv(v1),u2=uv(v2),
>>>>>> p3=cross(u1,u2)*d
>>>>>> )p0+p3
>>>>>> ]];
>>>>>>
>>>>>>
>>>>>> stages =200;
>>>>>>
>>>>>> stage_height = 1.25;
>>>>>>
>>>>>> rad = 50;
>>>>>>
>>>>>> f1 = 25;
>>>>>>
>>>>>> f2 = 25;
>>>>>>
>>>>>> phase1 = 0;
>>>>>>
>>>>>> phase2 = 180;
>>>>>>
>>>>>> height_depth=5;
>>>>>>
>>>>>> depth1 = 20;
>>>>>>
>>>>>> depth2 = 20;
>>>>>>
>>>>>> thickness = 2;
>>>>>>
>>>>>> bottom_thickness = 3;
>>>>>>
>>>>>> myslices = 5;
>>>>>>
>>>>>> angle_step=1;
>>>>>>
>>>>>> // generate outer points
>>>>>>
>>>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>>>
>>>>>> points_base_e=surf_offset(points_base,-2);
>>>>>>
>>>>>> swp_prism_h(points_base,points_base_e);
>>>>>>
>>>>>> with 1 deg angle step it takes 20 sec
>>>>>>
>>>>>> with 0.1 deg angle step it took 3 minutes 34 sec
>>>>>>
>>>>>> I am working now on a 7 year old computer windows laptop
>>>>>>
>>>>>> On Wed, 13 Apr 2022, 11:06 Jordan Brown, <
>>>>>> openscad@jordan.maileater.net> wrote:
>>>>>>
>>>>>>> Another thing to think about is that you can design at a lower
>>>>>>> resolution than you will eventually want. When I set stages=50,
>>>>>>> stage_height=5, and angle_step=1, I get a preview in ~6 seconds.[*] It's
>>>>>>> rough, but it conveys the shape reasonably well. When you're happy with
>>>>>>> the shape, *then* set things for higher resolution.
>>>>>>>
>>>>>>> [*] My desktop is almost ten years old and wasn't high-end even when
>>>>>>> new.
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> 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
>>>>>
>>>> _______________________________________________
>>>> 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
>>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
SP
Sanjeev Prabhakar
Wed, Apr 13, 2022 5:16 PM
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, sprabhakar2006@gmail.com
wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2) *
7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) * (var *
height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <sprabhakar2006@gmail.com>
wrote:
> there seems to be a syntax error in my last mail
>
> correct one is here:
>
> include <dependencies.scad>
>
> function
> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
> p3=cross(u1,u2)*d )p0+p3]];
>
> stages =200;
>
> stage_height = 1.25;
>
> rad = 50;
>
> f1 = 25;
>
> f2 = 25;
>
> phase1 = 0;
>
> phase2 = 180;
>
> height_depth=5;
>
> depth1 = 20;
>
> depth2 = 20;
>
> thickness = 2;
>
> bottom_thickness = 3;
>
> myslices = 5;
>
> angle_step=0.1;
>
> // generate outer points
>
> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2) *
> 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) * (var *
> height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>
> points_base_e=surf_offset(points_base,2);
>
> swp_prism_h(points_base,points_base_e);
>
> function pauw(x,p)=sign(x)*abs(x)^p;
>
>
>>>
NH
nop head
Wed, Apr 13, 2022 7:59 PM
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it to my
rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect the
intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, sprabhakar2006@gmail.com
wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2)
- 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) * (var *
height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
>The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it to my
rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect the
intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
wrote:
> I just tried this code on my macbook air m1
> It is wonderfully fast.
> 0.1 step angle f6 render successfully completed in 26 sec
>
> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <sprabhakar2006@gmail.com>
> wrote:
>
>> there seems to be a syntax error in my last mail
>>
>> correct one is here:
>>
>> include <dependencies.scad>
>>
>> function
>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>> p3=cross(u1,u2)*d )p0+p3]];
>>
>> stages =200;
>>
>> stage_height = 1.25;
>>
>> rad = 50;
>>
>> f1 = 25;
>>
>> f2 = 25;
>>
>> phase1 = 0;
>>
>> phase2 = 180;
>>
>> height_depth=5;
>>
>> depth1 = 20;
>>
>> depth2 = 20;
>>
>> thickness = 2;
>>
>> bottom_thickness = 3;
>>
>> myslices = 5;
>>
>> angle_step=0.1;
>>
>> // generate outer points
>>
>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2)
>> * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) * (var *
>> height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>
>> points_base_e=surf_offset(points_base,2);
>>
>> swp_prism_h(points_base,points_base_e);
>>
>> function pauw(x,p)=sign(x)*abs(x)^p;
>>
>>
>>>> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
AM
Adrian Mariano
Wed, Apr 13, 2022 9:02 PM
Sanjeev:
You are producing models that are invalid. It is possible that downstream
processing (the 3d print slicer) can handle a bogus model. Maybe. Maybe
not. The STL you save will have self-intersecting faces. Depending on
how big the self-intersecting bits are it could be pretty hard to deal with
downstream. My focus is on creating valid models. The point of running
render (f6) is to demonstrate that the model is valid. To do this you have
to include a second object, and usually you should have it intersect your
test object. I suggest that if you post self-intersecting models that you
warn people that they are self-intersecting. (Note that f6 render is
usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's faster.
Offset requires computing an intersection of two offset lines. You avoid
that by simply shifting the point based on a normal computed from some
adjacent points. You can also do the same thing in 2d and it should be
even faster. It's not going to 3d that made it fast but using this type of
approximate offset. It may in fact be a good approximation when the angle
step size is so very small, but of course, it's only going to give a valid
result if the offset is small enough. I would say that if you want to
pursue the fastest possible invalid model that the way to do it would be to
use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part. You
also have a formulation that to me seems overly complicated. Solving for
the tangent points of two circles appears to be a harder problem than the
intersection of two lines. I would formulate offset as follows: Given two
adjacent segments on the path, shift each one in its normal direction by
the offset distance. If the resulting shifted segments intersect, then you
clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are invalid.
There are extra loops. These extra loops cannot be detected locally, only
globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to the
original curve. There is a method that is more elegant and probably more
robust where you divide the offset into its polygon components and compute
the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head nop.head@gmail.com wrote:
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it to
my rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect the
intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, sprabhakar2006@gmail.com
wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2)
- 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) * (var *
height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
Sanjeev:
You are producing models that are invalid. It is possible that downstream
processing (the 3d print slicer) can handle a bogus model. Maybe. Maybe
not. The STL you save will have self-intersecting faces. Depending on
how big the self-intersecting bits are it could be pretty hard to deal with
downstream. My focus is on creating valid models. The point of running
render (f6) is to demonstrate that the model is valid. To do this you have
to include a second object, and usually you should have it intersect your
test object. I suggest that if you post self-intersecting models that you
warn people that they are self-intersecting. (Note that f6 render is
usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's faster.
Offset requires computing an intersection of two offset lines. You avoid
that by simply shifting the point based on a normal computed from some
adjacent points. You can also do the same thing in 2d and it should be
even faster. It's not going to 3d that made it fast but using this type of
approximate offset. It may in fact be a good approximation when the angle
step size is so very small, but of course, it's only going to give a valid
result if the offset is small enough. I would say that if you want to
pursue the fastest possible invalid model that the way to do it would be to
use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part. You
also have a formulation that to me seems overly complicated. Solving for
the tangent points of two circles appears to be a harder problem than the
intersection of two lines. I would formulate offset as follows: Given two
adjacent segments on the path, shift each one in its normal direction by
the offset distance. If the resulting shifted segments intersect, then you
clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are invalid.
There are extra loops. These extra loops cannot be detected locally, only
globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to the
original curve. There is a method that is more elegant and probably more
robust where you divide the offset into its polygon components and compute
the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head <nop.head@gmail.com> wrote:
> >The problem is implementation.
>
> Simply adding the offset as the radius for each vertex and passing it to
> my rounded polygon function gives this:
>
> [image: image.png]
>
> I.e. it is correct for convex corners but concave ones need to detect the
> intersection and remove the inner loop. That isn't hard and gives this:
>
> [image: image.png]
>
> Passing a negative offset also seems to just work. My rounded_polygon
> function uses negative radii to indicate concave corners. So now it goes
> wrong at the convex corners:
>
> [image: image.png]
>
> The same tangent intersection test fixes that as well.
>
> [image: image.png]
>
> So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
> don't know how robust my quick hack is as rounded_polygon was never
> designed for doing offsets.
>
>
> On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
> wrote:
>
>> I just tried this code on my macbook air m1
>> It is wonderfully fast.
>> 0.1 step angle f6 render successfully completed in 26 sec
>>
>> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <sprabhakar2006@gmail.com>
>> wrote:
>>
>>> there seems to be a syntax error in my last mail
>>>
>>> correct one is here:
>>>
>>> include <dependencies.scad>
>>>
>>> function
>>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>>> p3=cross(u1,u2)*d )p0+p3]];
>>>
>>> stages =200;
>>>
>>> stage_height = 1.25;
>>>
>>> rad = 50;
>>>
>>> f1 = 25;
>>>
>>> f2 = 25;
>>>
>>> phase1 = 0;
>>>
>>> phase2 = 180;
>>>
>>> height_depth=5;
>>>
>>> depth1 = 20;
>>>
>>> depth2 = 20;
>>>
>>> thickness = 2;
>>>
>>> bottom_thickness = 3;
>>>
>>> myslices = 5;
>>>
>>> angle_step=0.1;
>>>
>>> // generate outer points
>>>
>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages * 120),2)
>>> * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) * (var *
>>> height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>
>>> points_base_e=surf_offset(points_base,2);
>>>
>>> swp_prism_h(points_base,points_base_e);
>>>
>>> function pauw(x,p)=sign(x)*abs(x)^p;
>>>
>>>
>>>>> _______________________________________________
>> 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
>
NH
nop head
Wed, Apr 13, 2022 9:40 PM
Yes I suppose it only works if the offset is small compared to the distance
between vertices.
On Wed, 13 Apr 2022 at 22:02, Adrian Mariano avm4@cornell.edu wrote:
Sanjeev:
You are producing models that are invalid. It is possible that downstream
processing (the 3d print slicer) can handle a bogus model. Maybe. Maybe
not. The STL you save will have self-intersecting faces. Depending on
how big the self-intersecting bits are it could be pretty hard to deal with
downstream. My focus is on creating valid models. The point of running
render (f6) is to demonstrate that the model is valid. To do this you have
to include a second object, and usually you should have it intersect your
test object. I suggest that if you post self-intersecting models that you
warn people that they are self-intersecting. (Note that f6 render is
usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's faster.
Offset requires computing an intersection of two offset lines. You avoid
that by simply shifting the point based on a normal computed from some
adjacent points. You can also do the same thing in 2d and it should be
even faster. It's not going to 3d that made it fast but using this type of
approximate offset. It may in fact be a good approximation when the angle
step size is so very small, but of course, it's only going to give a valid
result if the offset is small enough. I would say that if you want to
pursue the fastest possible invalid model that the way to do it would be to
use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part. You
also have a formulation that to me seems overly complicated. Solving for
the tangent points of two circles appears to be a harder problem than the
intersection of two lines. I would formulate offset as follows: Given two
adjacent segments on the path, shift each one in its normal direction by
the offset distance. If the resulting shifted segments intersect, then you
clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are invalid.
There are extra loops. These extra loops cannot be detected locally, only
globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to the
original curve. There is a method that is more elegant and probably more
robust where you divide the offset into its polygon components and compute
the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head nop.head@gmail.com wrote:
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it to
my rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect the
intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, sprabhakar2006@gmail.com
wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
Yes I suppose it only works if the offset is small compared to the distance
between vertices.
On Wed, 13 Apr 2022 at 22:02, Adrian Mariano <avm4@cornell.edu> wrote:
> Sanjeev:
>
> You are producing models that are invalid. It is possible that downstream
> processing (the 3d print slicer) can handle a bogus model. Maybe. Maybe
> not. The STL you save will have self-intersecting faces. Depending on
> how big the self-intersecting bits are it could be pretty hard to deal with
> downstream. My focus is on creating valid models. The point of running
> render (f6) is to demonstrate that the model is valid. To do this you have
> to include a second object, and usually you should have it intersect your
> test object. I suggest that if you post self-intersecting models that you
> warn people that they are self-intersecting. (Note that f6 render is
> usually fast when your model contains just one polyhedron.)
>
> How much 3d printing have you done? I had an early experience where my
> model just wouldn't stick to the build plate. I ultimately discovered that
> the problem was I had used the hull of a sphere to construct the model, and
> due to the choice of $fn, the model was very slightly undersized. I don't
> know what you can get away with here. Clearly 0.1mm is is going to be a
> disaster. It seems like 0.01mm is probably ok. Again it may depend on
> what the slicer does iwth your model. So if your flaws/bumps on the bottom
> of the model are very very small it's maybe OK. I'd rather have a model
> that's actually correct, though. You could remove the extra stuff with an
> intersection or difference...except no, you can't, because the model is
> invalid.
>
> You ignored my observation that you don't include the bottom of the
> container. Since your model is invalid you can't do a union. How will you
> add the bottom? (Also union can be slow, so your run time numbers may
> need refinement.)
>
> I examined your code a bit and see what is happening and why it's faster.
> Offset requires computing an intersection of two offset lines. You avoid
> that by simply shifting the point based on a normal computed from some
> adjacent points. You can also do the same thing in 2d and it should be
> even faster. It's not going to 3d that made it fast but using this type of
> approximate offset. It may in fact be a good approximation when the angle
> step size is so very small, but of course, it's only going to give a valid
> result if the offset is small enough. I would say that if you want to
> pursue the fastest possible invalid model that the way to do it would be to
> use such an approximate 2d offset, working by layers. Then you can skip
> the two layers on the bottom of the inside so that the base is correct, and
> the whole model is a single (invalid) polyhedron that you can render to a
> (self-intersecting) STL.
>
> Nophead:
>
> You are doing the trivial part of offset and ignoring the hard part. You
> also have a formulation that to me seems overly complicated. Solving for
> the tangent points of two circles appears to be a harder problem than the
> intersection of two lines. I would formulate offset as follows: Given two
> adjacent segments on the path, shift each one in its normal direction by
> the offset distance. If the resulting shifted segments intersect, then you
> clip them at the intersection point. If they don't, you extend them
> somehow (arc, linear extension, whatever). Ok. That's the trivial part.
>
> The problem now is that parts of the path generated this way are invalid.
> There are extra loops. These extra loops cannot be detected locally, only
> globally.
> Image 1 below shows an example where there is a bogus loop in the red
> offset to the yellow path. I show two circles as per your description.
> The segment between their intersection points is part of the result that is
> obtained by that method. But that segment is not actually part of the
> answer, because that whole loop at the end is not part of the offset.
>
> The second image shows two circles giving rise to a green segment. The
> green segment is not part of the offset---only part of it is. To find
> which part you need to intersect it with another segment that can only be
> found globally. It depends on what is happening on the other side of the
> path. It can be arbitrarily far away along the path. I don't think
> there's any way to avoid running a quadratic algorithm to find all the
> self-intersections that result from the naive offset. Then you have to
> somehow decide which parts are valid. In python you can probably find all
> the self-intersections in n log n time using some kind of clever data
> structure, but in OpenSCAD clever data structures are impossible, so brute
> force is the only option.
>
> My method for doing this is to check whether segments are too close to the
> original curve. There is a method that is more elegant and probably more
> robust where you divide the offset into its polygon components and compute
> the winding number of each component. The problem I have with this
> algorithm is that it seems difficult to keep track of the point order so
> that I can map the offset points back to the original points. My use of
> the offset() function is almost always in constructing a polyhedron where I
> need to use this point-point relationship. The winding number method also
> doesn't work if you have a path instead of a polygon. For the model in
> this thread my fast method that uses symmetry does an offset of just part
> of the polygon, so it's not a closed path, and it's important to keep track
> of that mapping to link the offset paths together.
>
>
> On Wed, Apr 13, 2022 at 4:01 PM nop head <nop.head@gmail.com> wrote:
>
>> >The problem is implementation.
>>
>> Simply adding the offset as the radius for each vertex and passing it to
>> my rounded polygon function gives this:
>>
>> [image: image.png]
>>
>> I.e. it is correct for convex corners but concave ones need to detect the
>> intersection and remove the inner loop. That isn't hard and gives this:
>>
>> [image: image.png]
>>
>> Passing a negative offset also seems to just work. My rounded_polygon
>> function uses negative radii to indicate concave corners. So now it goes
>> wrong at the convex corners:
>>
>> [image: image.png]
>>
>> The same tangent intersection test fixes that as well.
>>
>> [image: image.png]
>>
>> So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
>> don't know how robust my quick hack is as rounded_polygon was never
>> designed for doing offsets.
>>
>>
>> On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <sprabhakar2006@gmail.com>
>> wrote:
>>
>>> I just tried this code on my macbook air m1
>>> It is wonderfully fast.
>>> 0.1 step angle f6 render successfully completed in 26 sec
>>>
>>> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <sprabhakar2006@gmail.com>
>>> wrote:
>>>
>>>> there seems to be a syntax error in my last mail
>>>>
>>>> correct one is here:
>>>>
>>>> include <dependencies.scad>
>>>>
>>>> function
>>>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>>>> p3=cross(u1,u2)*d )p0+p3]];
>>>>
>>>> stages =200;
>>>>
>>>> stage_height = 1.25;
>>>>
>>>> rad = 50;
>>>>
>>>> f1 = 25;
>>>>
>>>> f2 = 25;
>>>>
>>>> phase1 = 0;
>>>>
>>>> phase2 = 180;
>>>>
>>>> height_depth=5;
>>>>
>>>> depth1 = 20;
>>>>
>>>> depth2 = 20;
>>>>
>>>> thickness = 2;
>>>>
>>>> bottom_thickness = 3;
>>>>
>>>> myslices = 5;
>>>>
>>>> angle_step=0.1;
>>>>
>>>> // generate outer points
>>>>
>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>
>>>> points_base_e=surf_offset(points_base,2);
>>>>
>>>> swp_prism_h(points_base,points_base_e);
>>>>
>>>> function pauw(x,p)=sign(x)*abs(x)^p;
>>>>
>>>>
>>>>>> _______________________________________________
>>> 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
>
AM
Adrian Mariano
Wed, Apr 13, 2022 11:03 PM
Yes, that's correct, assuming by "distance between vertices" you mean the
global distance pairwise between all vertices, not the consecutive
difference between them. In other words, there's no simple way to even
predict when it will work.
On Wed, Apr 13, 2022 at 5:42 PM nop head nop.head@gmail.com wrote:
Yes I suppose it only works if the offset is small compared to the
distance between vertices.
On Wed, 13 Apr 2022 at 22:02, Adrian Mariano avm4@cornell.edu wrote:
Sanjeev:
You are producing models that are invalid. It is possible that
downstream processing (the 3d print slicer) can handle a bogus model.
Maybe. Maybe not. The STL you save will have self-intersecting faces.
Depending on how big the self-intersecting bits are it could be pretty hard
to deal with downstream. My focus is on creating valid models. The
point of running render (f6) is to demonstrate that the model is valid. To
do this you have to include a second object, and usually you should have it
intersect your test object. I suggest that if you post self-intersecting
models that you warn people that they are self-intersecting. (Note that
f6 render is usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's
faster. Offset requires computing an intersection of two offset lines.
You avoid that by simply shifting the point based on a normal computed from
some adjacent points. You can also do the same thing in 2d and it should
be even faster. It's not going to 3d that made it fast but using this type
of approximate offset. It may in fact be a good approximation when the
angle step size is so very small, but of course, it's only going to give a
valid result if the offset is small enough. I would say that if you want
to pursue the fastest possible invalid model that the way to do it would be
to use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part.
You also have a formulation that to me seems overly complicated. Solving
for the tangent points of two circles appears to be a harder problem than
the intersection of two lines. I would formulate offset as follows: Given
two adjacent segments on the path, shift each one in its normal direction
by the offset distance. If the resulting shifted segments intersect, then
you clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are
invalid. There are extra loops. These extra loops cannot be detected
locally, only globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to
the original curve. There is a method that is more elegant and probably
more robust where you divide the offset into its polygon components and
compute the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head nop.head@gmail.com wrote:
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it to
my rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect
the intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, sprabhakar2006@gmail.com
wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
Yes, that's correct, assuming by "distance between vertices" you mean the
global distance pairwise between all vertices, not the consecutive
difference between them. In other words, there's no simple way to even
predict when it will work.
On Wed, Apr 13, 2022 at 5:42 PM nop head <nop.head@gmail.com> wrote:
> Yes I suppose it only works if the offset is small compared to the
> distance between vertices.
>
> On Wed, 13 Apr 2022 at 22:02, Adrian Mariano <avm4@cornell.edu> wrote:
>
>> Sanjeev:
>>
>> You are producing models that are invalid. It is possible that
>> downstream processing (the 3d print slicer) can handle a bogus model.
>> Maybe. Maybe not. The STL you save will have self-intersecting faces.
>> Depending on how big the self-intersecting bits are it could be pretty hard
>> to deal with downstream. My focus is on creating valid models. The
>> point of running render (f6) is to demonstrate that the model is valid. To
>> do this you have to include a second object, and usually you should have it
>> intersect your test object. I suggest that if you post self-intersecting
>> models that you warn people that they are self-intersecting. (Note that
>> f6 render is usually fast when your model contains just one polyhedron.)
>>
>> How much 3d printing have you done? I had an early experience where my
>> model just wouldn't stick to the build plate. I ultimately discovered that
>> the problem was I had used the hull of a sphere to construct the model, and
>> due to the choice of $fn, the model was very slightly undersized. I don't
>> know what you can get away with here. Clearly 0.1mm is is going to be a
>> disaster. It seems like 0.01mm is probably ok. Again it may depend on
>> what the slicer does iwth your model. So if your flaws/bumps on the bottom
>> of the model are very very small it's maybe OK. I'd rather have a model
>> that's actually correct, though. You could remove the extra stuff with an
>> intersection or difference...except no, you can't, because the model is
>> invalid.
>>
>> You ignored my observation that you don't include the bottom of the
>> container. Since your model is invalid you can't do a union. How will you
>> add the bottom? (Also union can be slow, so your run time numbers may
>> need refinement.)
>>
>> I examined your code a bit and see what is happening and why it's
>> faster. Offset requires computing an intersection of two offset lines.
>> You avoid that by simply shifting the point based on a normal computed from
>> some adjacent points. You can also do the same thing in 2d and it should
>> be even faster. It's not going to 3d that made it fast but using this type
>> of approximate offset. It may in fact be a good approximation when the
>> angle step size is so very small, but of course, it's only going to give a
>> valid result if the offset is small enough. I would say that if you want
>> to pursue the fastest possible invalid model that the way to do it would be
>> to use such an approximate 2d offset, working by layers. Then you can skip
>> the two layers on the bottom of the inside so that the base is correct, and
>> the whole model is a single (invalid) polyhedron that you can render to a
>> (self-intersecting) STL.
>>
>> Nophead:
>>
>> You are doing the trivial part of offset and ignoring the hard part.
>> You also have a formulation that to me seems overly complicated. Solving
>> for the tangent points of two circles appears to be a harder problem than
>> the intersection of two lines. I would formulate offset as follows: Given
>> two adjacent segments on the path, shift each one in its normal direction
>> by the offset distance. If the resulting shifted segments intersect, then
>> you clip them at the intersection point. If they don't, you extend them
>> somehow (arc, linear extension, whatever). Ok. That's the trivial part.
>>
>> The problem now is that parts of the path generated this way are
>> invalid. There are extra loops. These extra loops cannot be detected
>> locally, only globally.
>> Image 1 below shows an example where there is a bogus loop in the red
>> offset to the yellow path. I show two circles as per your description.
>> The segment between their intersection points is part of the result that is
>> obtained by that method. But that segment is not actually part of the
>> answer, because that whole loop at the end is not part of the offset.
>>
>> The second image shows two circles giving rise to a green segment. The
>> green segment is not part of the offset---only part of it is. To find
>> which part you need to intersect it with another segment that can only be
>> found globally. It depends on what is happening on the other side of the
>> path. It can be arbitrarily far away along the path. I don't think
>> there's any way to avoid running a quadratic algorithm to find all the
>> self-intersections that result from the naive offset. Then you have to
>> somehow decide which parts are valid. In python you can probably find all
>> the self-intersections in n log n time using some kind of clever data
>> structure, but in OpenSCAD clever data structures are impossible, so brute
>> force is the only option.
>>
>> My method for doing this is to check whether segments are too close to
>> the original curve. There is a method that is more elegant and probably
>> more robust where you divide the offset into its polygon components and
>> compute the winding number of each component. The problem I have with this
>> algorithm is that it seems difficult to keep track of the point order so
>> that I can map the offset points back to the original points. My use of
>> the offset() function is almost always in constructing a polyhedron where I
>> need to use this point-point relationship. The winding number method also
>> doesn't work if you have a path instead of a polygon. For the model in
>> this thread my fast method that uses symmetry does an offset of just part
>> of the polygon, so it's not a closed path, and it's important to keep track
>> of that mapping to link the offset paths together.
>>
>>
>> On Wed, Apr 13, 2022 at 4:01 PM nop head <nop.head@gmail.com> wrote:
>>
>>> >The problem is implementation.
>>>
>>> Simply adding the offset as the radius for each vertex and passing it to
>>> my rounded polygon function gives this:
>>>
>>> [image: image.png]
>>>
>>> I.e. it is correct for convex corners but concave ones need to detect
>>> the intersection and remove the inner loop. That isn't hard and gives this:
>>>
>>> [image: image.png]
>>>
>>> Passing a negative offset also seems to just work. My rounded_polygon
>>> function uses negative radii to indicate concave corners. So now it goes
>>> wrong at the convex corners:
>>>
>>> [image: image.png]
>>>
>>> The same tangent intersection test fixes that as well.
>>>
>>> [image: image.png]
>>>
>>> So I think I have recreated Skeinforge's offset algorithm in OpenSCAD. I
>>> don't know how robust my quick hack is as rounded_polygon was never
>>> designed for doing offsets.
>>>
>>>
>>> On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
>>> sprabhakar2006@gmail.com> wrote:
>>>
>>>> I just tried this code on my macbook air m1
>>>> It is wonderfully fast.
>>>> 0.1 step angle f6 render successfully completed in 26 sec
>>>>
>>>> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <sprabhakar2006@gmail.com>
>>>> wrote:
>>>>
>>>>> there seems to be a syntax error in my last mail
>>>>>
>>>>> correct one is here:
>>>>>
>>>>> include <dependencies.scad>
>>>>>
>>>>> function
>>>>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>>>>> p3=cross(u1,u2)*d )p0+p3]];
>>>>>
>>>>> stages =200;
>>>>>
>>>>> stage_height = 1.25;
>>>>>
>>>>> rad = 50;
>>>>>
>>>>> f1 = 25;
>>>>>
>>>>> f2 = 25;
>>>>>
>>>>> phase1 = 0;
>>>>>
>>>>> phase2 = 180;
>>>>>
>>>>> height_depth=5;
>>>>>
>>>>> depth1 = 20;
>>>>>
>>>>> depth2 = 20;
>>>>>
>>>>> thickness = 2;
>>>>>
>>>>> bottom_thickness = 3;
>>>>>
>>>>> myslices = 5;
>>>>>
>>>>> angle_step=0.1;
>>>>>
>>>>> // generate outer points
>>>>>
>>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>>
>>>>> points_base_e=surf_offset(points_base,2);
>>>>>
>>>>> swp_prism_h(points_base,points_base_e);
>>>>>
>>>>> function pauw(x,p)=sign(x)*abs(x)^p;
>>>>>
>>>>>
>>>>>>> _______________________________________________
>>>> 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
>>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
>
NH
nop head
Thu, Apr 14, 2022 10:58 AM
I think it always works for convex shapes and a positive offset.
For concave shapes, or negative offsets, I think the offset has to be less
than half the width of the thinnest internal or external features. Not easy
to compute but easy to know when you are applying it to a known design.
On Thu, 14 Apr 2022 at 00:04, Adrian Mariano avm4@cornell.edu wrote:
Yes, that's correct, assuming by "distance between vertices" you mean the
global distance pairwise between all vertices, not the consecutive
difference between them. In other words, there's no simple way to even
predict when it will work.
On Wed, Apr 13, 2022 at 5:42 PM nop head nop.head@gmail.com wrote:
Yes I suppose it only works if the offset is small compared to the
distance between vertices.
On Wed, 13 Apr 2022 at 22:02, Adrian Mariano avm4@cornell.edu wrote:
Sanjeev:
You are producing models that are invalid. It is possible that
downstream processing (the 3d print slicer) can handle a bogus model.
Maybe. Maybe not. The STL you save will have self-intersecting faces.
Depending on how big the self-intersecting bits are it could be pretty hard
to deal with downstream. My focus is on creating valid models. The
point of running render (f6) is to demonstrate that the model is valid. To
do this you have to include a second object, and usually you should have it
intersect your test object. I suggest that if you post self-intersecting
models that you warn people that they are self-intersecting. (Note that
f6 render is usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's
faster. Offset requires computing an intersection of two offset lines.
You avoid that by simply shifting the point based on a normal computed from
some adjacent points. You can also do the same thing in 2d and it should
be even faster. It's not going to 3d that made it fast but using this type
of approximate offset. It may in fact be a good approximation when the
angle step size is so very small, but of course, it's only going to give a
valid result if the offset is small enough. I would say that if you want
to pursue the fastest possible invalid model that the way to do it would be
to use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part.
You also have a formulation that to me seems overly complicated. Solving
for the tangent points of two circles appears to be a harder problem than
the intersection of two lines. I would formulate offset as follows: Given
two adjacent segments on the path, shift each one in its normal direction
by the offset distance. If the resulting shifted segments intersect, then
you clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are
invalid. There are extra loops. These extra loops cannot be detected
locally, only globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to
the original curve. There is a method that is more elegant and probably
more robust where you divide the offset into its polygon components and
compute the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head nop.head@gmail.com wrote:
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it
to my rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect
the intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD.
I don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <
sprabhakar2006@gmail.com> wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
I think it always works for convex shapes and a positive offset.
For concave shapes, or negative offsets, I think the offset has to be less
than half the width of the thinnest internal or external features. Not easy
to compute but easy to know when you are applying it to a known design.
On Thu, 14 Apr 2022 at 00:04, Adrian Mariano <avm4@cornell.edu> wrote:
> Yes, that's correct, assuming by "distance between vertices" you mean the
> global distance pairwise between all vertices, not the consecutive
> difference between them. In other words, there's no simple way to even
> predict when it will work.
>
> On Wed, Apr 13, 2022 at 5:42 PM nop head <nop.head@gmail.com> wrote:
>
>> Yes I suppose it only works if the offset is small compared to the
>> distance between vertices.
>>
>> On Wed, 13 Apr 2022 at 22:02, Adrian Mariano <avm4@cornell.edu> wrote:
>>
>>> Sanjeev:
>>>
>>> You are producing models that are invalid. It is possible that
>>> downstream processing (the 3d print slicer) can handle a bogus model.
>>> Maybe. Maybe not. The STL you save will have self-intersecting faces.
>>> Depending on how big the self-intersecting bits are it could be pretty hard
>>> to deal with downstream. My focus is on creating valid models. The
>>> point of running render (f6) is to demonstrate that the model is valid. To
>>> do this you have to include a second object, and usually you should have it
>>> intersect your test object. I suggest that if you post self-intersecting
>>> models that you warn people that they are self-intersecting. (Note that
>>> f6 render is usually fast when your model contains just one polyhedron.)
>>>
>>> How much 3d printing have you done? I had an early experience where my
>>> model just wouldn't stick to the build plate. I ultimately discovered that
>>> the problem was I had used the hull of a sphere to construct the model, and
>>> due to the choice of $fn, the model was very slightly undersized. I don't
>>> know what you can get away with here. Clearly 0.1mm is is going to be a
>>> disaster. It seems like 0.01mm is probably ok. Again it may depend on
>>> what the slicer does iwth your model. So if your flaws/bumps on the bottom
>>> of the model are very very small it's maybe OK. I'd rather have a model
>>> that's actually correct, though. You could remove the extra stuff with an
>>> intersection or difference...except no, you can't, because the model is
>>> invalid.
>>>
>>> You ignored my observation that you don't include the bottom of the
>>> container. Since your model is invalid you can't do a union. How will you
>>> add the bottom? (Also union can be slow, so your run time numbers may
>>> need refinement.)
>>>
>>> I examined your code a bit and see what is happening and why it's
>>> faster. Offset requires computing an intersection of two offset lines.
>>> You avoid that by simply shifting the point based on a normal computed from
>>> some adjacent points. You can also do the same thing in 2d and it should
>>> be even faster. It's not going to 3d that made it fast but using this type
>>> of approximate offset. It may in fact be a good approximation when the
>>> angle step size is so very small, but of course, it's only going to give a
>>> valid result if the offset is small enough. I would say that if you want
>>> to pursue the fastest possible invalid model that the way to do it would be
>>> to use such an approximate 2d offset, working by layers. Then you can skip
>>> the two layers on the bottom of the inside so that the base is correct, and
>>> the whole model is a single (invalid) polyhedron that you can render to a
>>> (self-intersecting) STL.
>>>
>>> Nophead:
>>>
>>> You are doing the trivial part of offset and ignoring the hard part.
>>> You also have a formulation that to me seems overly complicated. Solving
>>> for the tangent points of two circles appears to be a harder problem than
>>> the intersection of two lines. I would formulate offset as follows: Given
>>> two adjacent segments on the path, shift each one in its normal direction
>>> by the offset distance. If the resulting shifted segments intersect, then
>>> you clip them at the intersection point. If they don't, you extend them
>>> somehow (arc, linear extension, whatever). Ok. That's the trivial part.
>>>
>>> The problem now is that parts of the path generated this way are
>>> invalid. There are extra loops. These extra loops cannot be detected
>>> locally, only globally.
>>> Image 1 below shows an example where there is a bogus loop in the red
>>> offset to the yellow path. I show two circles as per your description.
>>> The segment between their intersection points is part of the result that is
>>> obtained by that method. But that segment is not actually part of the
>>> answer, because that whole loop at the end is not part of the offset.
>>>
>>> The second image shows two circles giving rise to a green segment. The
>>> green segment is not part of the offset---only part of it is. To find
>>> which part you need to intersect it with another segment that can only be
>>> found globally. It depends on what is happening on the other side of the
>>> path. It can be arbitrarily far away along the path. I don't think
>>> there's any way to avoid running a quadratic algorithm to find all the
>>> self-intersections that result from the naive offset. Then you have to
>>> somehow decide which parts are valid. In python you can probably find all
>>> the self-intersections in n log n time using some kind of clever data
>>> structure, but in OpenSCAD clever data structures are impossible, so brute
>>> force is the only option.
>>>
>>> My method for doing this is to check whether segments are too close to
>>> the original curve. There is a method that is more elegant and probably
>>> more robust where you divide the offset into its polygon components and
>>> compute the winding number of each component. The problem I have with this
>>> algorithm is that it seems difficult to keep track of the point order so
>>> that I can map the offset points back to the original points. My use of
>>> the offset() function is almost always in constructing a polyhedron where I
>>> need to use this point-point relationship. The winding number method also
>>> doesn't work if you have a path instead of a polygon. For the model in
>>> this thread my fast method that uses symmetry does an offset of just part
>>> of the polygon, so it's not a closed path, and it's important to keep track
>>> of that mapping to link the offset paths together.
>>>
>>>
>>> On Wed, Apr 13, 2022 at 4:01 PM nop head <nop.head@gmail.com> wrote:
>>>
>>>> >The problem is implementation.
>>>>
>>>> Simply adding the offset as the radius for each vertex and passing it
>>>> to my rounded polygon function gives this:
>>>>
>>>> [image: image.png]
>>>>
>>>> I.e. it is correct for convex corners but concave ones need to detect
>>>> the intersection and remove the inner loop. That isn't hard and gives this:
>>>>
>>>> [image: image.png]
>>>>
>>>> Passing a negative offset also seems to just work. My rounded_polygon
>>>> function uses negative radii to indicate concave corners. So now it goes
>>>> wrong at the convex corners:
>>>>
>>>> [image: image.png]
>>>>
>>>> The same tangent intersection test fixes that as well.
>>>>
>>>> [image: image.png]
>>>>
>>>> So I think I have recreated Skeinforge's offset algorithm in OpenSCAD.
>>>> I don't know how robust my quick hack is as rounded_polygon was never
>>>> designed for doing offsets.
>>>>
>>>>
>>>> On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
>>>> sprabhakar2006@gmail.com> wrote:
>>>>
>>>>> I just tried this code on my macbook air m1
>>>>> It is wonderfully fast.
>>>>> 0.1 step angle f6 render successfully completed in 26 sec
>>>>>
>>>>> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <
>>>>> sprabhakar2006@gmail.com> wrote:
>>>>>
>>>>>> there seems to be a syntax error in my last mail
>>>>>>
>>>>>> correct one is here:
>>>>>>
>>>>>> include <dependencies.scad>
>>>>>>
>>>>>> function
>>>>>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>>>>>> p3=cross(u1,u2)*d )p0+p3]];
>>>>>>
>>>>>> stages =200;
>>>>>>
>>>>>> stage_height = 1.25;
>>>>>>
>>>>>> rad = 50;
>>>>>>
>>>>>> f1 = 25;
>>>>>>
>>>>>> f2 = 25;
>>>>>>
>>>>>> phase1 = 0;
>>>>>>
>>>>>> phase2 = 180;
>>>>>>
>>>>>> height_depth=5;
>>>>>>
>>>>>> depth1 = 20;
>>>>>>
>>>>>> depth2 = 20;
>>>>>>
>>>>>> thickness = 2;
>>>>>>
>>>>>> bottom_thickness = 3;
>>>>>>
>>>>>> myslices = 5;
>>>>>>
>>>>>> angle_step=0.1;
>>>>>>
>>>>>> // generate outer points
>>>>>>
>>>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>>>
>>>>>> points_base_e=surf_offset(points_base,2);
>>>>>>
>>>>>> swp_prism_h(points_base,points_base_e);
>>>>>>
>>>>>> function pauw(x,p)=sign(x)*abs(x)^p;
>>>>>>
>>>>>>
>>>>>>>> _______________________________________________
>>>>> 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
>>>
>> _______________________________________________
>> 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
>
SP
Sanjeev Prabhakar
Thu, Apr 14, 2022 12:48 PM
I wrote a function f_offset(sec,r) to handle offset which works most of the
time for me, but for this work, sharp corners are not allowed and a
minimum of 0.1 corner radius needs to be defined.
On Thu, 14 Apr 2022, 16:29 nop head, nop.head@gmail.com wrote:
I think it always works for convex shapes and a positive offset.
For concave shapes, or negative offsets, I think the offset has to be less
than half the width of the thinnest internal or external features. Not easy
to compute but easy to know when you are applying it to a known design.
On Thu, 14 Apr 2022 at 00:04, Adrian Mariano avm4@cornell.edu wrote:
Yes, that's correct, assuming by "distance between vertices" you mean the
global distance pairwise between all vertices, not the consecutive
difference between them. In other words, there's no simple way to even
predict when it will work.
On Wed, Apr 13, 2022 at 5:42 PM nop head nop.head@gmail.com wrote:
Yes I suppose it only works if the offset is small compared to the
distance between vertices.
On Wed, 13 Apr 2022 at 22:02, Adrian Mariano avm4@cornell.edu wrote:
Sanjeev:
You are producing models that are invalid. It is possible that
downstream processing (the 3d print slicer) can handle a bogus model.
Maybe. Maybe not. The STL you save will have self-intersecting faces.
Depending on how big the self-intersecting bits are it could be pretty hard
to deal with downstream. My focus is on creating valid models. The
point of running render (f6) is to demonstrate that the model is valid. To
do this you have to include a second object, and usually you should have it
intersect your test object. I suggest that if you post self-intersecting
models that you warn people that they are self-intersecting. (Note that
f6 render is usually fast when your model contains just one polyhedron.)
How much 3d printing have you done? I had an early experience where my
model just wouldn't stick to the build plate. I ultimately discovered that
the problem was I had used the hull of a sphere to construct the model, and
due to the choice of $fn, the model was very slightly undersized. I don't
know what you can get away with here. Clearly 0.1mm is is going to be a
disaster. It seems like 0.01mm is probably ok. Again it may depend on
what the slicer does iwth your model. So if your flaws/bumps on the bottom
of the model are very very small it's maybe OK. I'd rather have a model
that's actually correct, though. You could remove the extra stuff with an
intersection or difference...except no, you can't, because the model is
invalid.
You ignored my observation that you don't include the bottom of the
container. Since your model is invalid you can't do a union. How will you
add the bottom? (Also union can be slow, so your run time numbers may
need refinement.)
I examined your code a bit and see what is happening and why it's
faster. Offset requires computing an intersection of two offset lines.
You avoid that by simply shifting the point based on a normal computed from
some adjacent points. You can also do the same thing in 2d and it should
be even faster. It's not going to 3d that made it fast but using this type
of approximate offset. It may in fact be a good approximation when the
angle step size is so very small, but of course, it's only going to give a
valid result if the offset is small enough. I would say that if you want
to pursue the fastest possible invalid model that the way to do it would be
to use such an approximate 2d offset, working by layers. Then you can skip
the two layers on the bottom of the inside so that the base is correct, and
the whole model is a single (invalid) polyhedron that you can render to a
(self-intersecting) STL.
Nophead:
You are doing the trivial part of offset and ignoring the hard part.
You also have a formulation that to me seems overly complicated. Solving
for the tangent points of two circles appears to be a harder problem than
the intersection of two lines. I would formulate offset as follows: Given
two adjacent segments on the path, shift each one in its normal direction
by the offset distance. If the resulting shifted segments intersect, then
you clip them at the intersection point. If they don't, you extend them
somehow (arc, linear extension, whatever). Ok. That's the trivial part.
The problem now is that parts of the path generated this way are
invalid. There are extra loops. These extra loops cannot be detected
locally, only globally.
Image 1 below shows an example where there is a bogus loop in the red
offset to the yellow path. I show two circles as per your description.
The segment between their intersection points is part of the result that is
obtained by that method. But that segment is not actually part of the
answer, because that whole loop at the end is not part of the offset.
The second image shows two circles giving rise to a green segment. The
green segment is not part of the offset---only part of it is. To find
which part you need to intersect it with another segment that can only be
found globally. It depends on what is happening on the other side of the
path. It can be arbitrarily far away along the path. I don't think
there's any way to avoid running a quadratic algorithm to find all the
self-intersections that result from the naive offset. Then you have to
somehow decide which parts are valid. In python you can probably find all
the self-intersections in n log n time using some kind of clever data
structure, but in OpenSCAD clever data structures are impossible, so brute
force is the only option.
My method for doing this is to check whether segments are too close to
the original curve. There is a method that is more elegant and probably
more robust where you divide the offset into its polygon components and
compute the winding number of each component. The problem I have with this
algorithm is that it seems difficult to keep track of the point order so
that I can map the offset points back to the original points. My use of
the offset() function is almost always in constructing a polyhedron where I
need to use this point-point relationship. The winding number method also
doesn't work if you have a path instead of a polygon. For the model in
this thread my fast method that uses symmetry does an offset of just part
of the polygon, so it's not a closed path, and it's important to keep track
of that mapping to link the offset paths together.
On Wed, Apr 13, 2022 at 4:01 PM nop head nop.head@gmail.com wrote:
The problem is implementation.
Simply adding the offset as the radius for each vertex and passing it
to my rounded polygon function gives this:
[image: image.png]
I.e. it is correct for convex corners but concave ones need to detect
the intersection and remove the inner loop. That isn't hard and gives this:
[image: image.png]
Passing a negative offset also seems to just work. My rounded_polygon
function uses negative radii to indicate concave corners. So now it goes
wrong at the convex corners:
[image: image.png]
The same tangent intersection test fixes that as well.
[image: image.png]
So I think I have recreated Skeinforge's offset algorithm in OpenSCAD.
I don't know how robust my quick hack is as rounded_polygon was never
designed for doing offsets.
On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:
I just tried this code on my macbook air m1
It is wonderfully fast.
0.1 step angle f6 render successfully completed in 26 sec
On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <
sprabhakar2006@gmail.com> wrote:
there seems to be a syntax error in my last mail
correct one is here:
include <dependencies.scad>
function
surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
p3=cross(u1,u2)*d )p0+p3]];
stages =200;
stage_height = 1.25;
rad = 50;
f1 = 25;
f2 = 25;
phase1 = 0;
phase2 = 180;
height_depth=5;
depth1 = 20;
depth2 = 20;
thickness = 2;
bottom_thickness = 3;
myslices = 5;
angle_step=0.1;
// generate outer points
points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
120),2) * 7 + 1, var = 1 , a=((sin((i/stages360f)%360) * 0.5 + 0.5) *
(var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
(rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)*0.5+0.5)depth2(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
*f1+phase1),0.5)*0.5+0.5)depth1i/stages+(pauw(sin(j
*f2+phase2),0.5)0.5+0.5)depth2(1-i/stages)),istage_height]]];
points_base_e=surf_offset(points_base,2);
swp_prism_h(points_base,points_base_e);
function pauw(x,p)=sign(x)*abs(x)^p;
I wrote a function f_offset(sec,r) to handle offset which works most of the
time for me, but for this work, sharp corners are not allowed and a
minimum of 0.1 corner radius needs to be defined.
On Thu, 14 Apr 2022, 16:29 nop head, <nop.head@gmail.com> wrote:
> I think it always works for convex shapes and a positive offset.
>
> For concave shapes, or negative offsets, I think the offset has to be less
> than half the width of the thinnest internal or external features. Not easy
> to compute but easy to know when you are applying it to a known design.
>
> On Thu, 14 Apr 2022 at 00:04, Adrian Mariano <avm4@cornell.edu> wrote:
>
>> Yes, that's correct, assuming by "distance between vertices" you mean the
>> global distance pairwise between all vertices, not the consecutive
>> difference between them. In other words, there's no simple way to even
>> predict when it will work.
>>
>> On Wed, Apr 13, 2022 at 5:42 PM nop head <nop.head@gmail.com> wrote:
>>
>>> Yes I suppose it only works if the offset is small compared to the
>>> distance between vertices.
>>>
>>> On Wed, 13 Apr 2022 at 22:02, Adrian Mariano <avm4@cornell.edu> wrote:
>>>
>>>> Sanjeev:
>>>>
>>>> You are producing models that are invalid. It is possible that
>>>> downstream processing (the 3d print slicer) can handle a bogus model.
>>>> Maybe. Maybe not. The STL you save will have self-intersecting faces.
>>>> Depending on how big the self-intersecting bits are it could be pretty hard
>>>> to deal with downstream. My focus is on creating valid models. The
>>>> point of running render (f6) is to demonstrate that the model is valid. To
>>>> do this you have to include a second object, and usually you should have it
>>>> intersect your test object. I suggest that if you post self-intersecting
>>>> models that you warn people that they are self-intersecting. (Note that
>>>> f6 render is usually fast when your model contains just one polyhedron.)
>>>>
>>>> How much 3d printing have you done? I had an early experience where my
>>>> model just wouldn't stick to the build plate. I ultimately discovered that
>>>> the problem was I had used the hull of a sphere to construct the model, and
>>>> due to the choice of $fn, the model was very slightly undersized. I don't
>>>> know what you can get away with here. Clearly 0.1mm is is going to be a
>>>> disaster. It seems like 0.01mm is probably ok. Again it may depend on
>>>> what the slicer does iwth your model. So if your flaws/bumps on the bottom
>>>> of the model are very very small it's maybe OK. I'd rather have a model
>>>> that's actually correct, though. You could remove the extra stuff with an
>>>> intersection or difference...except no, you can't, because the model is
>>>> invalid.
>>>>
>>>> You ignored my observation that you don't include the bottom of the
>>>> container. Since your model is invalid you can't do a union. How will you
>>>> add the bottom? (Also union can be slow, so your run time numbers may
>>>> need refinement.)
>>>>
>>>> I examined your code a bit and see what is happening and why it's
>>>> faster. Offset requires computing an intersection of two offset lines.
>>>> You avoid that by simply shifting the point based on a normal computed from
>>>> some adjacent points. You can also do the same thing in 2d and it should
>>>> be even faster. It's not going to 3d that made it fast but using this type
>>>> of approximate offset. It may in fact be a good approximation when the
>>>> angle step size is so very small, but of course, it's only going to give a
>>>> valid result if the offset is small enough. I would say that if you want
>>>> to pursue the fastest possible invalid model that the way to do it would be
>>>> to use such an approximate 2d offset, working by layers. Then you can skip
>>>> the two layers on the bottom of the inside so that the base is correct, and
>>>> the whole model is a single (invalid) polyhedron that you can render to a
>>>> (self-intersecting) STL.
>>>>
>>>> Nophead:
>>>>
>>>> You are doing the trivial part of offset and ignoring the hard part.
>>>> You also have a formulation that to me seems overly complicated. Solving
>>>> for the tangent points of two circles appears to be a harder problem than
>>>> the intersection of two lines. I would formulate offset as follows: Given
>>>> two adjacent segments on the path, shift each one in its normal direction
>>>> by the offset distance. If the resulting shifted segments intersect, then
>>>> you clip them at the intersection point. If they don't, you extend them
>>>> somehow (arc, linear extension, whatever). Ok. That's the trivial part.
>>>>
>>>> The problem now is that parts of the path generated this way are
>>>> invalid. There are extra loops. These extra loops cannot be detected
>>>> locally, only globally.
>>>> Image 1 below shows an example where there is a bogus loop in the red
>>>> offset to the yellow path. I show two circles as per your description.
>>>> The segment between their intersection points is part of the result that is
>>>> obtained by that method. But that segment is not actually part of the
>>>> answer, because that whole loop at the end is not part of the offset.
>>>>
>>>> The second image shows two circles giving rise to a green segment. The
>>>> green segment is not part of the offset---only part of it is. To find
>>>> which part you need to intersect it with another segment that can only be
>>>> found globally. It depends on what is happening on the other side of the
>>>> path. It can be arbitrarily far away along the path. I don't think
>>>> there's any way to avoid running a quadratic algorithm to find all the
>>>> self-intersections that result from the naive offset. Then you have to
>>>> somehow decide which parts are valid. In python you can probably find all
>>>> the self-intersections in n log n time using some kind of clever data
>>>> structure, but in OpenSCAD clever data structures are impossible, so brute
>>>> force is the only option.
>>>>
>>>> My method for doing this is to check whether segments are too close to
>>>> the original curve. There is a method that is more elegant and probably
>>>> more robust where you divide the offset into its polygon components and
>>>> compute the winding number of each component. The problem I have with this
>>>> algorithm is that it seems difficult to keep track of the point order so
>>>> that I can map the offset points back to the original points. My use of
>>>> the offset() function is almost always in constructing a polyhedron where I
>>>> need to use this point-point relationship. The winding number method also
>>>> doesn't work if you have a path instead of a polygon. For the model in
>>>> this thread my fast method that uses symmetry does an offset of just part
>>>> of the polygon, so it's not a closed path, and it's important to keep track
>>>> of that mapping to link the offset paths together.
>>>>
>>>>
>>>> On Wed, Apr 13, 2022 at 4:01 PM nop head <nop.head@gmail.com> wrote:
>>>>
>>>>> >The problem is implementation.
>>>>>
>>>>> Simply adding the offset as the radius for each vertex and passing it
>>>>> to my rounded polygon function gives this:
>>>>>
>>>>> [image: image.png]
>>>>>
>>>>> I.e. it is correct for convex corners but concave ones need to detect
>>>>> the intersection and remove the inner loop. That isn't hard and gives this:
>>>>>
>>>>> [image: image.png]
>>>>>
>>>>> Passing a negative offset also seems to just work. My rounded_polygon
>>>>> function uses negative radii to indicate concave corners. So now it goes
>>>>> wrong at the convex corners:
>>>>>
>>>>> [image: image.png]
>>>>>
>>>>> The same tangent intersection test fixes that as well.
>>>>>
>>>>> [image: image.png]
>>>>>
>>>>> So I think I have recreated Skeinforge's offset algorithm in OpenSCAD.
>>>>> I don't know how robust my quick hack is as rounded_polygon was never
>>>>> designed for doing offsets.
>>>>>
>>>>>
>>>>> On Wed, 13 Apr 2022 at 18:17, Sanjeev Prabhakar <
>>>>> sprabhakar2006@gmail.com> wrote:
>>>>>
>>>>>> I just tried this code on my macbook air m1
>>>>>> It is wonderfully fast.
>>>>>> 0.1 step angle f6 render successfully completed in 26 sec
>>>>>>
>>>>>> On Wed, 13 Apr 2022, 16:41 Sanjeev Prabhakar, <
>>>>>> sprabhakar2006@gmail.com> wrote:
>>>>>>
>>>>>>> there seems to be a syntax error in my last mail
>>>>>>>
>>>>>>> correct one is here:
>>>>>>>
>>>>>>> include <dependencies.scad>
>>>>>>>
>>>>>>> function
>>>>>>> surf_offset(prism,d)=[for(i=[0:len(prism)-1])[for(j=[0:len(prism[0])-1])let(j_plus=j<len(prism[0])-1?j+1:0,p0=prism[i][j],p1=i<len(prism)-1?prism[i][j_plus]:prism[i-1][j],p2=i<len(prism)-1?prism[i+1][j]:prism[i][j_plus],v1=p1-p0,v2=p2-p0,u1=uv(v1),u2=uv(v2),
>>>>>>> p3=cross(u1,u2)*d )p0+p3]];
>>>>>>>
>>>>>>> stages =200;
>>>>>>>
>>>>>>> stage_height = 1.25;
>>>>>>>
>>>>>>> rad = 50;
>>>>>>>
>>>>>>> f1 = 25;
>>>>>>>
>>>>>>> f2 = 25;
>>>>>>>
>>>>>>> phase1 = 0;
>>>>>>>
>>>>>>> phase2 = 180;
>>>>>>>
>>>>>>> height_depth=5;
>>>>>>>
>>>>>>> depth1 = 20;
>>>>>>>
>>>>>>> depth2 = 20;
>>>>>>>
>>>>>>> thickness = 2;
>>>>>>>
>>>>>>> bottom_thickness = 3;
>>>>>>>
>>>>>>> myslices = 5;
>>>>>>>
>>>>>>> angle_step=0.1;
>>>>>>>
>>>>>>> // generate outer points
>>>>>>>
>>>>>>> points_base = [for (i = [0:1:stages]) let(f = pow(sin(i/stages *
>>>>>>> 120),2) * 7 + 1, var = 1 , a=((sin((i/stages*360*f)%360) * 0.5 + 0.5) *
>>>>>>> (var * height_depth))) [for(j = [0:angle_step:360-angle_step]) [sin(j) *
>>>>>>> (rad+a+(pauw(sin(j *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)), cos(j) *(rad+a+(pauw(sin(j
>>>>>>> *f1+phase1),0.5)*0.5+0.5)*depth1*i/stages+(pauw(sin(j
>>>>>>> *f2+phase2),0.5)*0.5+0.5)*depth2*(1-i/stages)),i*stage_height]]];
>>>>>>>
>>>>>>> points_base_e=surf_offset(points_base,2);
>>>>>>>
>>>>>>> swp_prism_h(points_base,points_base_e);
>>>>>>>
>>>>>>> function pauw(x,p)=sign(x)*abs(x)^p;
>>>>>>>
>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>> 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
>>>>
>>> _______________________________________________
>>> 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
>