discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

BOSL2: subdivide_path() with method "maximum segment length"?

CF
Carsten Fuchs
Tue, Mar 16, 2021 9:07 AM

Hello,

with a polygon like this:

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

path = round_corners(
[ [0, 0], [0, 30], [30, 0] ],
cut=[4, 0, 0]
);

polygon(path);
move_copies(path) circle(r=0.5, $fn=32);

I would like to subdivide the long edges so that there are no segments that are longer than some given number "max_segment_length".

(The goal is to pre-refine the polygon before it is used with skin(), avoiding the problem of long, sharp triangles as is currently discussed in thread "Fixed number of points with BOSL2 round_corners()?" and other threads about linear_extrude() with twist.)

I was looking at https://github.com/revarbat/BOSL2/wiki/paths.scad#function-subdivide_path, but it seems that this function could also affect the short segments at the rounded corner.

Is there a function that works like:

For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`.

?

Best regards,
Carsten

Hello, with a polygon like this: include <BOSL2/std.scad> include <BOSL2/rounding.scad> path = round_corners( [ [0, 0], [0, 30], [30, 0] ], cut=[4, 0, 0] ); polygon(path); move_copies(path) circle(r=0.5, $fn=32); I would like to subdivide the long edges so that there are no segments that are longer than some given number "max_segment_length". (The goal is to pre-refine the polygon before it is used with `skin()`, avoiding the problem of long, sharp triangles as is currently discussed in thread "Fixed number of points with BOSL2 round_corners()?" and other threads about `linear_extrude()` with twist.) I was looking at <https://github.com/revarbat/BOSL2/wiki/paths.scad#function-subdivide_path>, but it seems that this function could also affect the short segments at the rounded corner. Is there a function that works like: For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`. ? Best regards, Carsten
CF
Carsten Fuchs
Wed, Mar 17, 2021 2:31 PM

Am 16.03.21 um 10:07 schrieb Carsten Fuchs:

Is there a function that works like:

For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`.

?

Just for the fun of it, here is my custom implementation:

// For a polygon segment (edge) that is made of the points a and b,
// this function returns a list of points [a0, a1, a2, …] that subdivide the
// original segment into smaller segments of equal length such that all segments
// are shorter than (or at most equal to) msl.
// Note that a0 == a and that the returned list does not  include the last
// point, which would be equal to b. Also note that if a == b, the empty
// list is returned.
function get_subdivs(a, b, msl) =
let (
l = path_length([a, b]),
num_segments = ceil(l / msl)
)
[
for (i = [0 : num_segments-1])
let(
s1 = i/num_segments,
s2 = 1.0 - s1
)
as2 + bs1
];

// Makes sure that no segment of the given path is longer than msl,
// the "maximum segment length".
// The input path is assumed to be "open", i.e. the last point is not
// understood to have an edge back to the first point.
function subdivide_segments(path, msl) =
assert(msl > 1.0)
// echo("path len", len(path), "points", path)
len(path) <= 1
? path
: concat(
get_subdivs(path[0], path[1], msl),
subdivide_segments([for (i = [1 : len(path)-1]) path[i]], msl)
);

I'm sure that this can be improved, but this reflects my level of proficiency of the OpenSCAD language.  ;-)

Best regards,
Carsten

Am 16.03.21 um 10:07 schrieb Carsten Fuchs: > Is there a function that works like: > > For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`. > > ? Just for the fun of it, here is my custom implementation: // For a polygon segment (edge) that is made of the points `a` and `b`, // this function returns a list of points `[a0, a1, a2, …]` that subdivide the // original segment into smaller segments of equal length such that all segments // are shorter than (or at most equal to) `msl`. // Note that `a0 == a` and that the returned list does *not* include the last // point, which would be equal to `b`. Also note that if `a == b`, the empty // list is returned. function get_subdivs(a, b, msl) = let ( l = path_length([a, b]), num_segments = ceil(l / msl) ) [ for (i = [0 : num_segments-1]) let( s1 = i/num_segments, s2 = 1.0 - s1 ) a*s2 + b*s1 ]; // Makes sure that no segment of the given path is longer than `msl`, // the "maximum segment length". // The input path is assumed to be "open", i.e. the last point is not // understood to have an edge back to the first point. function subdivide_segments(path, msl) = assert(msl > 1.0) // echo("path len", len(path), "points", path) len(path) <= 1 ? path : concat( get_subdivs(path[0], path[1], msl), subdivide_segments([for (i = [1 : len(path)-1]) path[i]], msl) ); I'm sure that this can be improved, but this reflects my level of proficiency of the OpenSCAD language. ;-) Best regards, Carsten
RD
Revar Desmera
Wed, Mar 17, 2021 6:40 PM

Off the top of my head, the simple implementation with BOSL2 should look something like:

function subdivide_max_seglen(path, maxlen, closed=false) =
assert(is_path(path))
assert(is_finite(maxlen))
assert(is_bool(closed))
[
for (p=pair(path,closed)) let(
steps = ceil(norm(p[1]-p[0])/maxlen)
) each lerp(p[0],p[1],[0:1/steps:1-EPSILON]),
if (!closed) last(path)
];

  • Revar

On Mar 17, 2021, at 7:31 AM, Carsten Fuchs carsten.fuchs@cafu.de wrote:

Am 16.03.21 um 10:07 schrieb Carsten Fuchs:

Is there a function that works like:

For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`.

?

Just for the fun of it, here is my custom implementation:

// For a polygon segment (edge) that is made of the points a and b,
// this function returns a list of points [a0, a1, a2, …] that subdivide the
// original segment into smaller segments of equal length such that all segments
// are shorter than (or at most equal to) msl.
// Note that a0 == a and that the returned list does not  include the last
// point, which would be equal to b. Also note that if a == b, the empty
// list is returned.
function get_subdivs(a, b, msl) =
let (
l = path_length([a, b]),
num_segments = ceil(l / msl)
)
[
for (i = [0 : num_segments-1])
let(
s1 = i/num_segments,
s2 = 1.0 - s1
)
as2 + bs1
];

// Makes sure that no segment of the given path is longer than msl,
// the "maximum segment length".
// The input path is assumed to be "open", i.e. the last point is not
// understood to have an edge back to the first point.
function subdivide_segments(path, msl) =
assert(msl > 1.0)
// echo("path len", len(path), "points", path)
len(path) <= 1
? path
: concat(
get_subdivs(path[0], path[1], msl),
subdivide_segments([for (i = [1 : len(path)-1]) path[i]], msl)
);

I'm sure that this can be improved, but this reflects my level of proficiency of the OpenSCAD language.  ;-)

Best regards,
Carsten


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Off the top of my head, the simple implementation with BOSL2 should look something like: function subdivide_max_seglen(path, maxlen, closed=false) = assert(is_path(path)) assert(is_finite(maxlen)) assert(is_bool(closed)) [ for (p=pair(path,closed)) let( steps = ceil(norm(p[1]-p[0])/maxlen) ) each lerp(p[0],p[1],[0:1/steps:1-EPSILON]), if (!closed) last(path) ]; - Revar > On Mar 17, 2021, at 7:31 AM, Carsten Fuchs <carsten.fuchs@cafu.de> wrote: > > Am 16.03.21 um 10:07 schrieb Carsten Fuchs: >> Is there a function that works like: >> >> For each edge that is longer than `max_segment_length`, replace the edge with several colinear edges that are all of the same length that is at most `max_segment_length`. >> >> ? > > Just for the fun of it, here is my custom implementation: > > > > // For a polygon segment (edge) that is made of the points `a` and `b`, > // this function returns a list of points `[a0, a1, a2, …]` that subdivide the > // original segment into smaller segments of equal length such that all segments > // are shorter than (or at most equal to) `msl`. > // Note that `a0 == a` and that the returned list does *not* include the last > // point, which would be equal to `b`. Also note that if `a == b`, the empty > // list is returned. > function get_subdivs(a, b, msl) = > let ( > l = path_length([a, b]), > num_segments = ceil(l / msl) > ) > [ > for (i = [0 : num_segments-1]) > let( > s1 = i/num_segments, > s2 = 1.0 - s1 > ) > a*s2 + b*s1 > ]; > > // Makes sure that no segment of the given path is longer than `msl`, > // the "maximum segment length". > // The input path is assumed to be "open", i.e. the last point is not > // understood to have an edge back to the first point. > function subdivide_segments(path, msl) = > assert(msl > 1.0) > // echo("path len", len(path), "points", path) > len(path) <= 1 > ? path > : concat( > get_subdivs(path[0], path[1], msl), > subdivide_segments([for (i = [1 : len(path)-1]) path[i]], msl) > ); > > > > I'm sure that this can be improved, but this reflects my level of proficiency of the OpenSCAD language. ;-) > > Best regards, > Carsten > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
A
adrianv
Wed, Mar 17, 2021 10:09 PM

I don't think there is such a function already in the library.

Note that I would probably use turtle() for what you're trying to do.  With
turtle you can easily control exactly how many steps are in each line
segment so that you can make the curves you are trying to skin line up the
way you want.  In other words, something like:

turtle(["move", 10,                // one step of length 10
"repeat", 5, ["move", 1],  // five little steps of length 1
"arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10
steps
...

Carsten Fuchs wrote

Hello,

with a polygon like this:

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

path = round_corners(
[ [0, 0], [0, 30], [30, 0] ],
cut=[4, 0, 0]
);

polygon(path);
move_copies(path) circle(r=0.5, $fn=32);

I would like to subdivide the long edges so that there are no segments
that are longer than some given number "max_segment_length".

(The goal is to pre-refine the polygon before it is used with skin(),
avoiding the problem of long, sharp triangles as is currently discussed in
thread "Fixed number of points with BOSL2 round_corners()?" and other
threads about linear_extrude() with twist.)

I was looking at
<https://github.com/revarbat/BOSL2/wiki/paths.scad#function-subdivide_path>,
but it seems that this function could also affect the short segments at
the rounded corner.

Is there a function that works like:

For each edge that is longer than `max_segment_length`, replace the edge

with several colinear edges that are all of the same length that is at
most max_segment_length.

?

Best regards,
Carsten


OpenSCAD mailing list
To unsubscribe send an email to

discuss-leave@.openscad

I don't think there is such a function already in the library. Note that I would probably use turtle() for what you're trying to do. With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want. In other words, something like: turtle(["move", 10, // one step of length 10 "repeat", 5, ["move", 1], // five little steps of length 1 "arcsteps", 10, "arcright", 5, 75, // radius 5 turn, 75 deg, 10 steps ... Carsten Fuchs wrote > Hello, > > with a polygon like this: > > > include &lt;BOSL2/std.scad&gt; > include &lt;BOSL2/rounding.scad&gt; > > path = round_corners( > [ [0, 0], [0, 30], [30, 0] ], > cut=[4, 0, 0] > ); > > polygon(path); > move_copies(path) circle(r=0.5, $fn=32); > > > I would like to subdivide the long edges so that there are no segments > that are longer than some given number "max_segment_length". > > (The goal is to pre-refine the polygon before it is used with `skin()`, > avoiding the problem of long, sharp triangles as is currently discussed in > thread "Fixed number of points with BOSL2 round_corners()?" and other > threads about `linear_extrude()` with twist.) > > I was looking at > &lt;https://github.com/revarbat/BOSL2/wiki/paths.scad#function-subdivide_path&gt;, > but it seems that this function could also affect the short segments at > the rounded corner. > > Is there a function that works like: > > For each edge that is longer than `max_segment_length`, replace the edge > with several colinear edges that are all of the same length that is at > most `max_segment_length`. > > ? > > Best regards, > Carsten > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to > discuss-leave@.openscad -- Sent from: http://forum.openscad.org/
CF
Carsten Fuchs
Thu, Mar 18, 2021 6:39 AM

Am 17.03.21 um 19:40 schrieb Revar Desmera:

Off the top of my head, the simple implementation with BOSL2 should look something like:

 function subdivide_max_seglen(path, maxlen, closed=false) =
     assert(is_path(path))
     assert(is_finite(maxlen))
     assert(is_bool(closed))
     [
         for (p=pair(path,closed)) let(
             steps = ceil(norm(p[1]-p[0])/maxlen)
         ) each lerp(p[0],p[1],[0:1/steps:1-EPSILON]),
         if (!closed) last(path)
     ];

Thank you!

Best regards,
Carsten

Am 17.03.21 um 19:40 schrieb Revar Desmera: > Off the top of my head, the simple implementation with BOSL2 should look something like: > > function subdivide_max_seglen(path, maxlen, closed=false) = >     assert(is_path(path)) >     assert(is_finite(maxlen)) >     assert(is_bool(closed)) >     [ >         for (p=pair(path,closed)) let( >             steps = ceil(norm(p[1]-p[0])/maxlen) >         ) each lerp(p[0],p[1],[0:1/steps:1-EPSILON]), >         if (!closed) last(path) >     ]; > > Thank you! Best regards, Carsten
CF
Carsten Fuchs
Thu, Mar 18, 2021 7:01 AM

Am 17.03.21 um 23:09 schrieb adrianv:

I don't think there is such a function already in the library.  

Maybe a useful method for subdivide_path()?

Much easier to use than the other methods.  ;-)

Note that I would probably use turtle() for what you're trying to do.  With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want.  In other words, something like:

turtle(["move", 10,                 // one step of length 10
          "repeat", 5, ["move", 1],   // five little steps of length 1
          "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10 steps
    ...

Thanks. While I appreciate the beauty of the turle() function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like round_corners() and subdivide_path().

turtle() seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try turtle() first.

Best regards,
Carsten

--
Dipl.-Inf. Carsten Fuchs
Industriegebiet 3 ℅ Rofu
55768 Hoppstädten-Weiersbach
https://www.cafu.de

Am 17.03.21 um 23:09 schrieb adrianv: > I don't think there is such a function already in the library.   Maybe a useful method for `subdivide_path()`? Much easier to use than the other methods. ;-) > Note that I would probably use turtle() for what you're trying to do.  With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want.  In other words, something like: > > turtle(["move", 10,                 // one step of length 10 >           "repeat", 5, ["move", 1],   // five little steps of length 1 >           "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10 steps >     ... Thanks. While I appreciate the beauty of the `turle()` function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like `round_corners()` and `subdivide_path()`. `turtle()` seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try `turtle()` first. Best regards, Carsten -- Dipl.-Inf. Carsten Fuchs Industriegebiet 3 ℅ Rofu 55768 Hoppstädten-Weiersbach https://www.cafu.de
RD
Revar Desmera
Thu, Mar 18, 2021 8:15 AM

I’ve added subdivide_long_segments() to the library.

-Revar

On Mar 18, 2021, at 12:01 AM, Carsten Fuchs carsten.fuchs@cafu.de wrote:

Am 17.03.21 um 23:09 schrieb adrianv:

I don't think there is such a function already in the library.

Maybe a useful method for subdivide_path()?

Much easier to use than the other methods.  ;-)

Note that I would probably use turtle() for what you're trying to do.  With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want.  In other words, something like:

turtle(["move", 10,                // one step of length 10
"repeat", 5, ["move", 1],  // five little steps of length 1
"arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10 steps
...

Thanks. While I appreciate the beauty of the turle() function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like round_corners() and subdivide_path().

turtle() seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try turtle() first.

Best regards,
Carsten

--
Dipl.-Inf. Carsten Fuchs
Industriegebiet 3 ℅ Rofu
55768 Hoppstädten-Weiersbach
https://www.cafu.de


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I’ve added `subdivide_long_segments()` to the library. -Revar > On Mar 18, 2021, at 12:01 AM, Carsten Fuchs <carsten.fuchs@cafu.de> wrote: > > Am 17.03.21 um 23:09 schrieb adrianv: >> I don't think there is such a function already in the library. > > Maybe a useful method for `subdivide_path()`? > > Much easier to use than the other methods. ;-) > >> Note that I would probably use turtle() for what you're trying to do. With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want. In other words, something like: >> >> turtle(["move", 10, // one step of length 10 >> "repeat", 5, ["move", 1], // five little steps of length 1 >> "arcsteps", 10, "arcright", 5, 75, // radius 5 turn, 75 deg, 10 steps >> ... > > Thanks. While I appreciate the beauty of the `turle()` function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like `round_corners()` and `subdivide_path()`. > > `turtle()` seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try `turtle()` first. > > Best regards, > Carsten > > > > -- > Dipl.-Inf. Carsten Fuchs > Industriegebiet 3 ℅ Rofu > 55768 Hoppstädten-Weiersbach > https://www.cafu.de > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
A
adrianv
Thu, Mar 18, 2021 12:47 PM

The problem I see for the shape you've been working with is that I think for
a good skin result you need to add points in some places and not in others
and you need a lot of control over where you add the points, and how many
points you get.  That kind of point insertion is hard to do on a shape after
you've smoothed the corners with round_corners.  I used debug_polygon to
find where the long sides are and then I could apply subdivide_path with an
appropriate vector valued N to divide just the desired segment, but then if
I change my $fn for smoothing, everything needs to be redone.  I suppose you
could calculate the positions of the segments based on the $fn value.  The
new subdivide_long_segments doesn't give enough control, since I think you
need to carefully divide the segments so that they match up with the arcs,
which means you need to specify the number of points, not the maximum
length.  And you might find it useful to subdivide just half of a long
segment.

With turtle you can avoid this complication because you can directly specify
the point repetition where you need it and you can edit the point count in
the middle of a shape without changing other parts of the shape.  I think
also you missed something about turtle.  You would not use turtle and then
invoke round_corners on the result.  That would create the same problem as
above where you don't know the index you want to operate on.  Instead you
would use turtle to create the finished shape, rounded corners included.
That was why I mentioned the "arcleft" turtle command, which will make a
rounded corner.

The one problem I see in pondering how this works is that it's hard to make
an arc in turtle that corresponds to a known segment length.  That is, you
have to specify the radius when "joint" would be better.  I wonder if I
need to add some different way of using the "arc" commands to make it easier
to round a corner with a known vertex position, but I'm not sure what that
would be.

Carsten Fuchs wrote

Am 17.03.21 um 23:09 schrieb adrianv:

I don't think there is such a function already in the library.  

Maybe a useful method for subdivide_path()?

Much easier to use than the other methods.  ;-)

Note that I would probably use turtle() for what you're trying to do.
 With turtle you can easily control exactly how many steps are in each
line segment so that you can make the curves you are trying to skin line
up the way you want.  In other words, something like:

turtle(["move", 10,                 // one step of length 10
          "repeat", 5, ["move", 1],   // five little steps of length 1
          "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg,
10 steps
    ...

Thanks. While I appreciate the beauty of the turle() function, I'm not
sure if it really makes things easier in practice: For the parts that I
make, I usually have a physical object in mind of which I take measures,
dimensions, sometime angles, etc. In my current project (my first larger
one) it was self-suggesting to work with cross-sections that never rotate
out of their original plane, but change their shape and lateral position
along the path of extrusion. When modeling such a cross-section it seems
natural to start with a hand-crafted path, especially if it is to be
parametrized, followed by post-processing steps like round_corners() and
subdivide_path().

turtle() seems to make some tasks easier (and thus thank you for
pointing it out, I was in fact not aware of its potential!), but it also
seems to make some tasks harder, e.g. rounding corners with method
"smooth". Reconsidering, I think that you're right though: For my next
comparable polygon, I'll definitively try turtle() first.

Best regards,
Carsten

--
Dipl.-Inf. Carsten Fuchs
Industriegebiet 3 ℅ Rofu
55768 Hoppstädten-Weiersbach
https://www.cafu.de


OpenSCAD mailing list
To unsubscribe send an email to

discuss-leave@.openscad

The problem I see for the shape you've been working with is that I think for a good skin result you need to add points in some places and not in others and you need a lot of control over where you add the points, and how many points you get. That kind of point insertion is hard to do on a shape after you've smoothed the corners with round_corners. I used debug_polygon to find where the long sides are and then I could apply subdivide_path with an appropriate vector valued N to divide just the desired segment, but then if I change my $fn for smoothing, everything needs to be redone. I suppose you could calculate the positions of the segments based on the $fn value. The new subdivide_long_segments doesn't give enough control, since I think you need to carefully divide the segments so that they match up with the arcs, which means you need to specify the number of points, not the maximum length. And you might find it useful to subdivide just half of a long segment. With turtle you can avoid this complication because you can directly specify the point repetition where you need it and you can edit the point count in the middle of a shape without changing other parts of the shape. I think also you missed something about turtle. You would not use turtle and then invoke round_corners on the result. That would create the same problem as above where you don't know the index you want to operate on. Instead you would use turtle to create the finished shape, rounded corners included. That was why I mentioned the "arcleft" turtle command, which will make a rounded corner. The one problem I see in pondering how this works is that it's hard to make an arc in turtle that corresponds to a known segment length. That is, you have to specify the radius when "joint" would be better. I wonder if I need to add some different way of using the "arc" commands to make it easier to round a corner with a known vertex position, but I'm not sure what that would be. Carsten Fuchs wrote > Am 17.03.21 um 23:09 schrieb adrianv: >> I don't think there is such a function already in the library.   > > Maybe a useful method for `subdivide_path()`? > > Much easier to use than the other methods. ;-) > >> Note that I would probably use turtle() for what you're trying to do. >>  With turtle you can easily control exactly how many steps are in each >> line segment so that you can make the curves you are trying to skin line >> up the way you want.  In other words, something like: >> >> turtle(["move", 10,                 // one step of length 10 >>           "repeat", 5, ["move", 1],   // five little steps of length 1 >>           "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, >> 10 steps >>     ... > > Thanks. While I appreciate the beauty of the `turle()` function, I'm not > sure if it really makes things easier in practice: For the parts that I > make, I usually have a physical object in mind of which I take measures, > dimensions, sometime angles, etc. In my current project (my first larger > one) it was self-suggesting to work with cross-sections that never rotate > out of their original plane, but change their shape and lateral position > along the path of extrusion. When modeling such a cross-section it seems > natural to start with a hand-crafted path, especially if it is to be > parametrized, followed by post-processing steps like `round_corners()` and > `subdivide_path()`. > > `turtle()` seems to make some tasks easier (and thus thank you for > pointing it out, I was in fact not aware of its potential!), but it also > seems to make some tasks harder, e.g. rounding corners with method > "smooth". Reconsidering, I think that you're right though: For my next > comparable polygon, I'll definitively try `turtle()` first. > > Best regards, > Carsten > > > > -- > Dipl.-Inf. Carsten Fuchs > Industriegebiet 3 ℅ Rofu > 55768 Hoppstädten-Weiersbach > https://www.cafu.de > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to > discuss-leave@.openscad -- Sent from: http://forum.openscad.org/
CF
Carsten Fuchs
Fri, Mar 19, 2021 9:11 AM

Hello,

Am 18.03.21 um 13:47 schrieb adrianv:

The problem I see for the shape you've been working with is that I think for a good skin result you need to add points in some places and not in others and you need a lot of control over where you add the points, and how many points you get.  That kind of point insertion is hard to do on a shape after you've smoothed the corners with round_corners.

Yes, thanks, that's a very accurate summary of the problem!

 I used debug_polygon to find where the long sides are and then I could apply subdivide_path with an appropriate vector valued N to divide just the desired segment, but then if I change my $fn for smoothing, everything needs to be redone.

For this problem, I now consider looping over the segments and identify the relevant ones by checking their length for some minimum value, checking their slope etc.. This is similar to the new subdivide_long_segments(), but customized to my specific use case – which, unfortunately, somewhat defeats it purpose and just confirms the unfortunate nature of the problem.

 I suppose you could calculate the positions of the segments based on the $fn value.  The new subdivide_long_segments doesn't give enough control, since I think you need to carefully divide the segments so that they match up with the arcs, which means you need to specify the number of points, not the maximum length.  And you might find it useful to subdivide just half of a long segment.

Exactly. Unfortunately, subdivide_long_segments() did not turn out to be the all-in-one general purpose solution that I hoped it would be. In fact, as you say, I have to have exact control over the number of vertices used.

With turtle you can avoid this complication because you can directly specify the point repetition where you need it and you can edit the point count in the middle of a shape without changing other parts of the shape.  I think also you missed something about turtle.  You would not use turtle and then invoke round_corners on the result.  That would create the same problem as above where you don't know the index you want to operate on.  Instead you would use turtle to create the finished shape, rounded corners included.  That was why I mentioned the "arcleft" turtle command, which will make a rounded corner.

While I understand your description, I still cannot see how it helps. Please consider this example:

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

turtle_path = turtle([
"ymove", 30,
// "arcsteps", 10,
// "arcrightto", 5, 280,
"jump", [35, 0],
"xmove", -35
]);

stroke(turtle_path, width=0.8);

What I would like to achieve is to round the triangle's top and right corners and to subdivide its sides, all with a constant number of points that doesn't change if the shape of the triangle changes. I've so far not found a way to achieve that without doing a lot of math calculations by hand.

The one problem I see in pondering how this works is that it's hard to make an arc in turtle that corresponds to a known segment length.  That is, you have to specify the radius when "joint" would be better.   I wonder if I need to add some different way of using the "arc" commands to make it easier to round a corner with a known vertex position, but I'm not sure what that would be.  

Maybe some turtle command like "take this and the two previous vertices, back off, and use the three vertices as input to round_corners() (with a given $fn)" ?
It still would not help with the above example, though.

Best regards,
Carsten

 Carsten Fuchs wrote
 Am 17.03.21 um 23:09 schrieb adrianv:

I don't think there is such a function already in the library.  

 Maybe a useful method for `subdivide_path()`?

 Much easier to use than the other methods.  ;-)

Note that I would probably use turtle() for what you're trying to do.  With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want.  In other words, something like:

turtle(["move", 10,                 // one step of length 10
          "repeat", 5, ["move", 1],   // five little steps of length 1
          "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10 steps
    ...

 Thanks. While I appreciate the beauty of the `turle()` function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like `round_corners()` and `subdivide_path()`.

 `turtle()` seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try `turtle()` first.

 Best regards,
 Carsten
Hello, Am 18.03.21 um 13:47 schrieb adrianv: > The problem I see for the shape you've been working with is that I think for a good skin result you need to add points in some places and not in others and you need a lot of control over where you add the points, and how many points you get.  That kind of point insertion is hard to do on a shape after you've smoothed the corners with round_corners. Yes, thanks, that's a very accurate summary of the problem! >  I used debug_polygon to find where the long sides are and then I could apply subdivide_path with an appropriate vector valued N to divide just the desired segment, but then if I change my $fn for smoothing, everything needs to be redone. For this problem, I now consider looping over the segments and identify the relevant ones by checking their length for some minimum value, checking their slope etc.. This is similar to the new `subdivide_long_segments()`, but customized to my specific use case – which, unfortunately, somewhat defeats it purpose and just confirms the unfortunate nature of the problem. >  I suppose you could calculate the positions of the segments based on the $fn value.  The new subdivide_long_segments doesn't give enough control, since I think you need to carefully divide the segments so that they match up with the arcs, which means you need to specify the number of points, not the maximum length.  And you might find it useful to subdivide just half of a long segment. Exactly. Unfortunately, `subdivide_long_segments()` did not turn out to be the all-in-one general purpose solution that I hoped it would be. In fact, as you say, I have to have exact control over the number of vertices used. > With turtle you can avoid this complication because you can directly specify the point repetition where you need it and you can edit the point count in the middle of a shape without changing other parts of the shape.  I think also you missed something about turtle.  You would not use turtle and then invoke round_corners on the result.  That would create the same problem as above where you don't know the index you want to operate on.  Instead you would use turtle to create the finished shape, rounded corners included.  That was why I mentioned the "arcleft" turtle command, which will make a rounded corner. While I understand your description, I still cannot see how it helps. Please consider this example: include <BOSL2/std.scad> include <BOSL2/rounding.scad> turtle_path = turtle([ "ymove", 30, // "arcsteps", 10, // "arcrightto", 5, 280, "jump", [35, 0], "xmove", -35 ]); stroke(turtle_path, width=0.8); What I would like to achieve is to round the triangle's top and right corners and to subdivide its sides, all with a constant number of points that doesn't change if the shape of the triangle changes. I've so far not found a way to achieve that without doing a lot of math calculations by hand. > The one problem I see in pondering how this works is that it's hard to make an arc in turtle that corresponds to a known segment length.  That is, you have to specify the radius when "joint" would be better.   I wonder if I need to add some different way of using the "arc" commands to make it easier to round a corner with a known vertex position, but I'm not sure what that would be.   Maybe some turtle command like "take this and the two previous vertices, back off, and use the three vertices as input to `round_corners()` (with a given $fn)" ? It still would not help with the above example, though. Best regards, Carsten > > Carsten Fuchs wrote > Am 17.03.21 um 23:09 schrieb adrianv: > > I don't think there is such a function already in the library.   > > Maybe a useful method for `subdivide_path()`? > > Much easier to use than the other methods.  ;-) > > > Note that I would probably use turtle() for what you're trying to do.  With turtle you can easily control exactly how many steps are in each line segment so that you can make the curves you are trying to skin line up the way you want.  In other words, something like: > > > > turtle(["move", 10,                 // one step of length 10 > >           "repeat", 5, ["move", 1],   // five little steps of length 1 > >           "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 deg, 10 steps > >     ... > > Thanks. While I appreciate the beauty of the `turle()` function, I'm not sure if it really makes things easier in practice: For the parts that I make, I usually have a physical object in mind of which I take measures, dimensions, sometime angles, etc. In my current project (my first larger one) it was self-suggesting to work with cross-sections that never rotate out of their original plane, but change their shape and lateral position along the path of extrusion. When modeling such a cross-section it seems natural to start with a hand-crafted path, especially if it is to be parametrized, followed by post-processing steps like `round_corners()` and `subdivide_path()`. > > `turtle()` seems to make some tasks easier (and thus thank you for pointing it out, I was in fact not aware of its potential!), but it also seems to make some tasks harder, e.g. rounding corners with method "smooth". Reconsidering, I think that you're right though: For my next comparable polygon, I'll definitively try `turtle()` first. > > Best regards, > Carsten >
A
adrianv
Fri, Mar 19, 2021 1:55 PM

Your idea to use round_corners with flat "corners" seems like it could be a
good approach if you can figure out how to match the two shapes this way.
It enables you to insert points along a flat length in your shape.

With regards to the turtle command, I wonder if you are familiar with the
turtle concept.
https://en.wikipedia.org/wiki/Turtle_graphics
The reason I wonder about this is that you jumped immediately to the
"non-turtle" commands that turtle() supports to give some added flexibility
beyond true turtle graphics.  Turtle is meant to be relative, not absolute.
The absolute commands, especially "jump" will not integrate well with the
relative commands and allow you to use "arcleft" or "arcright".

The suggestion of passing three points to round_corners from turtle doesn't
fit the turtle framework well because it requires changing the past.

You ask how you can make a rounded triangle.  Yes, it requires doing some
math, though not a tremendous amount.  The tricky bit is that to make a
roundover with joint length d you need the radius to be d*tan(angle/2).  I
am wondering about how I could make a new way to use "arcleft" in turtle
that would do this automatically.  But for now, we do it with math.  The
other problem is that you give a triangle apparently by height and width.
So we need to know the length of the hypotenuse and the angles at the
corner.  So here's the answer to your question of arbitrary triangle:

h = 30;  // triangle height
w = 35;  // triangle width
top_angle = atan(w/h);      // angle at top corner
right_angle = atan(h/w);    // angle at right corner
hypot = sqrt(hh+ww);      // hypotenuse length
N=8;                        // points to add on sides

joint_top=5;    // joint length for top roundover
joint_bot=8;    // joint length for bottom roundover

path = turtle(["left",  // point up
"repeat", N, ["move", (h-joint_top)/N],
"arcsteps", 5,
"arcright", joint_toptan(top_angle/2), 180-top_angle,
"repeat", N, ["move", (hypot-joint_top-joint_bot)/N],
"arcright", joint_bot
tan(right_angle/2), 180-right_angle,
"repeat", N, ["move", (w-joint_bot)/N]
]);

move_copies(path) circle(r=.5,$fn=8);

It looks like arcsteps is giving you a total of 5 points counting both
endpoints, so it's really only making 4 new points.  Probably that's a bug.

I am wondering what would be the best way to solve this problem in general.
Assuming you have some threshold length you could write a function that
divides long segments into N parts while leaving short segments as they are.
The N input could be a vector enabling different divisions for different
long segments.  Another idea is to write a function that enumerates the long
segments so that you can then do something to them.  (Perhaps the former
invokes the latter.)

Carsten Fuchs wrote

Hello,

Am 18.03.21 um 13:47 schrieb adrianv:

Exactly. Unfortunately, subdivide_long_segments() did not turn out to be
the all-in-one general purpose solution that I hoped it would be. In fact,
as you say, I have to have exact control over the number of vertices used.

With turtle you can avoid this complication because you can directly
specify the point repetition where you need it and you can edit the point
count in the middle of a shape without changing other parts of the shape.
 I think also you missed something about turtle.  You would not use
turtle and then invoke round_corners on the result.  That would create
the same problem as above where you don't know the index you want to
operate on.  Instead you would use turtle to create the finished shape,
rounded corners included.  That was why I mentioned the "arcleft" turtle
command, which will make a rounded corner.

While I understand your description, I still cannot see how it helps.
Please consider this example:

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

turtle_path = turtle([
"ymove", 30,
// "arcsteps", 10,
// "arcrightto", 5, 280,
"jump", [35, 0],
"xmove", -35
]);

stroke(turtle_path, width=0.8);

What I would like to achieve is to round the triangle's top and right
corners and to subdivide its sides, all with a constant number of points
that doesn't change if the shape of the triangle changes. I've so far not
found a way to achieve that without doing a lot of math calculations by
hand.

The one problem I see in pondering how this works is that it's hard to
make an arc in turtle that corresponds to a known segment length.  That
is, you have to specify the radius when "joint" would be better.   I
wonder if I need to add some different way of using the "arc" commands to
make it easier to round a corner with a known vertex position, but I'm
not sure what that would be.  

Maybe some turtle command like "take this and the two previous vertices,
back off, and use the three vertices as input to round_corners() (with a
given $fn)" ?
It still would not help with the above example, though.

Best regards,
Carsten

 Carsten Fuchs wrote
 Am 17.03.21 um 23:09 schrieb adrianv:

I don't think there is such a function already in the library.  

 Maybe a useful method for `subdivide_path()`?

 Much easier to use than the other methods.  ;-)

Note that I would probably use turtle() for what you're trying to

do.  With turtle you can easily control exactly how many steps are in
each line segment so that you can make the curves you are trying to skin
line up the way you want.  In other words, something like:

turtle(["move", 10,                 // one step of length 10
          "repeat", 5, ["move", 1],   // five little steps of

length 1

          "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75

deg, 10 steps

    ...

 Thanks. While I appreciate the beauty of the `turle()` function, I'm

not sure if it really makes things easier in practice: For the parts that
I make, I usually have a physical object in mind of which I take
measures, dimensions, sometime angles, etc. In my current project (my
first larger one) it was self-suggesting to work with cross-sections that
never rotate out of their original plane, but change their shape and
lateral position along the path of extrusion. When modeling such a
cross-section it seems natural to start with a hand-crafted path,
especially if it is to be parametrized, followed by post-processing steps
like round_corners() and subdivide_path().

 `turtle()` seems to make some tasks easier (and thus thank you for

pointing it out, I was in fact not aware of its potential!), but it also
seems to make some tasks harder, e.g. rounding corners with method
"smooth". Reconsidering, I think that you're right though: For my next
comparable polygon, I'll definitively try turtle() first.

 Best regards,
 Carsten

OpenSCAD mailing list
To unsubscribe send an email to

discuss-leave@.openscad

Your idea to use round_corners with flat "corners" seems like it could be a good approach if you can figure out how to match the two shapes this way. It enables you to insert points along a flat length in your shape. With regards to the turtle command, I wonder if you are familiar with the turtle concept. https://en.wikipedia.org/wiki/Turtle_graphics The reason I wonder about this is that you jumped immediately to the "non-turtle" commands that turtle() supports to give some added flexibility beyond true turtle graphics. Turtle is meant to be relative, not absolute. The absolute commands, especially "jump" will not integrate well with the relative commands and allow you to use "arcleft" or "arcright". The suggestion of passing three points to round_corners from turtle doesn't fit the turtle framework well because it requires changing the past. You ask how you can make a rounded triangle. Yes, it requires doing some math, though not a tremendous amount. The tricky bit is that to make a roundover with joint length d you need the radius to be d*tan(angle/2). I am wondering about how I could make a new way to use "arcleft" in turtle that would do this automatically. But for now, we do it with math. The other problem is that you give a triangle apparently by height and width. So we need to know the length of the hypotenuse and the angles at the corner. So here's the answer to your question of arbitrary triangle: h = 30; // triangle height w = 35; // triangle width top_angle = atan(w/h); // angle at top corner right_angle = atan(h/w); // angle at right corner hypot = sqrt(h*h+w*w); // hypotenuse length N=8; // points to add on sides joint_top=5; // joint length for top roundover joint_bot=8; // joint length for bottom roundover path = turtle(["left", // point up "repeat", N, ["move", (h-joint_top)/N], "arcsteps", 5, "arcright", joint_top*tan(top_angle/2), 180-top_angle, "repeat", N, ["move", (hypot-joint_top-joint_bot)/N], "arcright", joint_bot*tan(right_angle/2), 180-right_angle, "repeat", N, ["move", (w-joint_bot)/N] ]); move_copies(path) circle(r=.5,$fn=8); It looks like arcsteps is giving you a total of 5 points counting both endpoints, so it's really only making 4 new points. Probably that's a bug. I am wondering what would be the best way to solve this problem in general. Assuming you have some threshold length you could write a function that divides long segments into N parts while leaving short segments as they are. The N input could be a vector enabling different divisions for different long segments. Another idea is to write a function that enumerates the long segments so that you can then do something to them. (Perhaps the former invokes the latter.) Carsten Fuchs wrote > Hello, > > Am 18.03.21 um 13:47 schrieb adrianv: > > Exactly. Unfortunately, `subdivide_long_segments()` did not turn out to be > the all-in-one general purpose solution that I hoped it would be. In fact, > as you say, I have to have exact control over the number of vertices used. > >> With turtle you can avoid this complication because you can directly >> specify the point repetition where you need it and you can edit the point >> count in the middle of a shape without changing other parts of the shape. >>  I think also you missed something about turtle.  You would not use >> turtle and then invoke round_corners on the result.  That would create >> the same problem as above where you don't know the index you want to >> operate on.  Instead you would use turtle to create the finished shape, >> rounded corners included.  That was why I mentioned the "arcleft" turtle >> command, which will make a rounded corner. > > While I understand your description, I still cannot see how it helps. > Please consider this example: > > > include &lt;BOSL2/std.scad&gt; > include &lt;BOSL2/rounding.scad&gt; > > turtle_path = turtle([ > "ymove", 30, > // "arcsteps", 10, > // "arcrightto", 5, 280, > "jump", [35, 0], > "xmove", -35 > ]); > > stroke(turtle_path, width=0.8); > > > What I would like to achieve is to round the triangle's top and right > corners and to subdivide its sides, all with a constant number of points > that doesn't change if the shape of the triangle changes. I've so far not > found a way to achieve that without doing a lot of math calculations by > hand. > >> The one problem I see in pondering how this works is that it's hard to >> make an arc in turtle that corresponds to a known segment length.  That >> is, you have to specify the radius when "joint" would be better.   I >> wonder if I need to add some different way of using the "arc" commands to >> make it easier to round a corner with a known vertex position, but I'm >> not sure what that would be.   > > Maybe some turtle command like "take this and the two previous vertices, > back off, and use the three vertices as input to `round_corners()` (with a > given $fn)" ? > It still would not help with the above example, though. > > Best regards, > Carsten > > > >> >> Carsten Fuchs wrote >> Am 17.03.21 um 23:09 schrieb adrianv: >> > I don't think there is such a function already in the library.   >> >> Maybe a useful method for `subdivide_path()`? >> >> Much easier to use than the other methods.  ;-) >> >> > Note that I would probably use turtle() for what you're trying to >> do.  With turtle you can easily control exactly how many steps are in >> each line segment so that you can make the curves you are trying to skin >> line up the way you want.  In other words, something like: >> > >> > turtle(["move", 10,                 // one step of length 10 >> >           "repeat", 5, ["move", 1],   // five little steps of >> length 1 >> >           "arcsteps", 10, "arcright", 5, 75,  // radius 5 turn, 75 >> deg, 10 steps >> >     ... >> >> Thanks. While I appreciate the beauty of the `turle()` function, I'm >> not sure if it really makes things easier in practice: For the parts that >> I make, I usually have a physical object in mind of which I take >> measures, dimensions, sometime angles, etc. In my current project (my >> first larger one) it was self-suggesting to work with cross-sections that >> never rotate out of their original plane, but change their shape and >> lateral position along the path of extrusion. When modeling such a >> cross-section it seems natural to start with a hand-crafted path, >> especially if it is to be parametrized, followed by post-processing steps >> like `round_corners()` and `subdivide_path()`. >> >> `turtle()` seems to make some tasks easier (and thus thank you for >> pointing it out, I was in fact not aware of its potential!), but it also >> seems to make some tasks harder, e.g. rounding corners with method >> "smooth". Reconsidering, I think that you're right though: For my next >> comparable polygon, I'll definitively try `turtle()` first. >> >> Best regards, >> Carsten >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to > discuss-leave@.openscad -- Sent from: http://forum.openscad.org/
loading...