discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Fwd: Re: how to randomness different loops?

RW
Raymond West
Tue, Oct 18, 2022 7:49 PM

Thanks, I'll have a look, but Bezier curves are a bit  fancy for me...

Anyway, I've moved the random end point generation out of the strand
generating loop, and I've attached is a screen grab of the result, **I
cannot tell the difference between the top half and the bottom half of
the large block. The bottom half is translated copies of the small
block, the top is one large block I've attached the script, too. I am
going through it slowly, adding variables instead of fixed values. This
will then sort of simulate various types of straight grained wood. In
the tests I've made, surface of a photo, is not realistic in appearance,
since colour becomes depth.

Modifying the script, to make the strand separation different, and then
linear extrude by a small amount, gives a far better representation. I'm
working on knots,  and other imperfections, using the similar method as
I used in my point of influence (gravity) experiments of a few months
ago. I will also be scaling it down by a factor of 10, that reduces
visible errors (but there aren't any now).  Adding knots, distorts the
strands, as it should, but it is not on an inverse square , something
more like a log curve. It also makes the block none squares, more pillow
shaped, which will need a complete rethink if trying to tessellate the
blocks. Also, every time a knot is added, another list of points is
generated. It may be expedient to limit it to, say, three knots per
block. Openscad is not ideal for this.

However, wood-grain  is one example of where the filament lay of an fdm
printer can be used to an advantage

Best wishes,

Ray

** I'm undecided about the random aspect of the ends of the joined
filaments. As is, if a few days later i want to add a bit more length to
the plank, say, then the strand end points will be generated
differently, and will not match up. If they are all set to 10, then it
hardly shows, since the neighbouring random points take your eye away
from it. It may be best to simply save a list of a thousand or so random
points, and load that each time I run the code.

On 18/10/2022 19:46, Jordan Brown wrote:

I don't know if it's helpful here, but just for fun I tried playing
with generating random wavy lines.

 function torect2(p) = [
      p[0] * cos(p[1]),
      p[0] * sin(p[1])
 ];

 // Bezier functions fromhttps://www.thingiverse.com/thing:8443
 // but that yielded either single points or a raft of triangles;
 // this yields a vector of points that you can then concatenate
 // with other pieces to form a single polygon.
 // If we were really clever, I think it would be possible to
 // automatically space the output points based on how linear
 // the curve is at that point.  But right now I'm not that clever.
 function BEZ03(u) = pow((1-u), 3);
 function BEZ13(u) = 3*u*(pow((1-u),2));
 function BEZ23(u) = 3*(pow(u,2))*(1-u);
 function BEZ33(u) = pow(u,3);

 function PointAlongBez4(p0, p1, p2, p3, u) = [
 	BEZ03(u)*p0[0]+BEZ13(u)*p1[0]+BEZ23(u)*p2[0]+BEZ33(u)*p3[0],
 	BEZ03(u)*p0[1]+BEZ13(u)*p1[1]+BEZ23(u)*p2[1]+BEZ33(u)*p3[1]];

 // p0 - start point
 // p1 - control point 1, line departs p0 headed this way
 // p2 - control point 2, line arrives at p3 from this way
 // p3 - end point
 // segs - number of segments
 function bez(p0, p1, p2, p3, segs) = [
      for (i = [0:segs]) PointAlongBez4(p0, p1, p2, p3, i/segs)
 ];

 function bezpolar(p0, p1, p2, p3, segs) =
      bez(p0, p0+torect2(p1), p3+torect2(p2), p3, segs);
      
 function rand1(a, b) = rands(a, b, 1)[0];
 function point(maxy, maxa, minc, maxc) = [
      rand1(0, maxy),
      rand1(-maxa, maxa),
      rand1(minc, maxc),
      rand1(minc, maxc)
 ];

 function steps(w, minstep, maxstep) = [
      0,
      for (x = rand1(minstep, maxstep);
          x + minstep < w;
          x = x + rand1(minstep, maxstep))
              x,
      w
 ];

 function wavy(w, minstep, maxstep, maxy, maxa, minc, maxc) =
      let (xvalues = steps(w, minstep, maxstep))
      let (controls = [
          for (i=[0:len(xvalues)-1])
              let(p = point(maxy, maxa, minc, maxc))
              [
                  [ xvalues[i], p[0] ], p[1], p[2], p[3]
              ]
      ])
      [
          for (i=[0:len(controls)-2])
              let(c = controls[i], next = controls[i+1])
              each bezpolar(
                  c[0],
                  [c[3], c[1]],
                  [next[2], 180+next[1]],
                  next[0],
                  10)
      ];

 w = 100;
 minstep = 10;
 maxstep = 30;
 maxy = 10;
 maxa = 30;
 minc = 3;
 maxc = 5;
 points = wavy(w, minstep, maxstep, maxy, maxa, minc, maxc);
 polygon([
      [0,0],
      each points,
      [w,0]
 ]);

The parameters to wavy() are:

  • w - the width of the wavy line
  • minstep - the minimum x distance between "reference points" where
    the line curvature changes
  • maxstep - the maximum x distance between reference points
  • maxy - the maximum y position at a reference point (minimum is zero)
  • maxa - the maximum angle that the line will have crossing the
    reference point (minimum is the negative of this)
  • minc - the minimum distance from the control point to the Bezier
    control point
  • maxc - the maximum distance from the control point to the Bezier
    control point

Here's some sample outputs, with the parameters above:

What it does is to pick randomly spaced X values that total up to the
desired width[*].  For each X value, it picks a Y value and two Bezier
control points, at the same random angle but different random
distances.  Then for each segment between two of those points, it
generates a Bezier curve using the first point and its right-side
control point and the second point and its left-side control point.

[*] When the next value would be less than the minimum from the end,
it stops, so the last step can be up to min+max long.  There's
probably a better way to stop.

Thanks, I'll have a look, but Bezier curves are a bit  fancy for me... Anyway, I've moved the random end point generation out of the strand generating loop, and I've attached is a screen grab of the result, **I cannot tell the difference between the top half and the bottom half of the large block. The bottom half is translated copies of the small block, the top is one large block I've attached the script, too. I am going through it slowly, adding variables instead of fixed values. This will then sort of simulate various types of straight grained wood. In the tests I've made, surface of a photo, is not realistic in appearance, since colour becomes depth. Modifying the script, to make the strand separation different, and then linear extrude by a small amount, gives a far better representation. I'm working on knots,  and other imperfections, using the similar method as I used in my point of influence (gravity) experiments of a few months ago. I will also be scaling it down by a factor of 10, that reduces visible errors (but there aren't any now).  Adding knots, distorts the strands, as it should, but it is not on an inverse square , something more like a log curve. It also makes the block none squares, more pillow shaped, which will need a complete rethink if trying to tessellate the blocks. Also, every time a knot is added, another list of points is generated. It may be expedient to limit it to, say, three knots per block. Openscad is not ideal for this. However, wood-grain  is one example of where the filament lay of an fdm printer can be used to an advantage Best wishes, Ray ** I'm undecided about the random aspect of the ends of the joined filaments. As is, if a few days later i want to add a bit more length to the plank, say, then the strand end points will be generated differently, and will not match up. If they are all set to 10, then it hardly shows, since the neighbouring random points take your eye away from it. It may be best to simply save a list of a thousand or so random points, and load that each time I run the code. On 18/10/2022 19:46, Jordan Brown wrote: > I don't know if it's helpful here, but just for fun I tried playing > with generating random wavy lines. > > function torect2(p) = [ > p[0] * cos(p[1]), > p[0] * sin(p[1]) > ]; > > // Bezier functions fromhttps://www.thingiverse.com/thing:8443 > // but that yielded either single points or a raft of triangles; > // this yields a vector of points that you can then concatenate > // with other pieces to form a single polygon. > // If we were really clever, I think it would be possible to > // automatically space the output points based on how linear > // the curve is at that point. But right now I'm not that clever. > function BEZ03(u) = pow((1-u), 3); > function BEZ13(u) = 3*u*(pow((1-u),2)); > function BEZ23(u) = 3*(pow(u,2))*(1-u); > function BEZ33(u) = pow(u,3); > > function PointAlongBez4(p0, p1, p2, p3, u) = [ > BEZ03(u)*p0[0]+BEZ13(u)*p1[0]+BEZ23(u)*p2[0]+BEZ33(u)*p3[0], > BEZ03(u)*p0[1]+BEZ13(u)*p1[1]+BEZ23(u)*p2[1]+BEZ33(u)*p3[1]]; > > // p0 - start point > // p1 - control point 1, line departs p0 headed this way > // p2 - control point 2, line arrives at p3 from this way > // p3 - end point > // segs - number of segments > function bez(p0, p1, p2, p3, segs) = [ > for (i = [0:segs]) PointAlongBez4(p0, p1, p2, p3, i/segs) > ]; > > function bezpolar(p0, p1, p2, p3, segs) = > bez(p0, p0+torect2(p1), p3+torect2(p2), p3, segs); > > function rand1(a, b) = rands(a, b, 1)[0]; > function point(maxy, maxa, minc, maxc) = [ > rand1(0, maxy), > rand1(-maxa, maxa), > rand1(minc, maxc), > rand1(minc, maxc) > ]; > > function steps(w, minstep, maxstep) = [ > 0, > for (x = rand1(minstep, maxstep); > x + minstep < w; > x = x + rand1(minstep, maxstep)) > x, > w > ]; > > function wavy(w, minstep, maxstep, maxy, maxa, minc, maxc) = > let (xvalues = steps(w, minstep, maxstep)) > let (controls = [ > for (i=[0:len(xvalues)-1]) > let(p = point(maxy, maxa, minc, maxc)) > [ > [ xvalues[i], p[0] ], p[1], p[2], p[3] > ] > ]) > [ > for (i=[0:len(controls)-2]) > let(c = controls[i], next = controls[i+1]) > each bezpolar( > c[0], > [c[3], c[1]], > [next[2], 180+next[1]], > next[0], > 10) > ]; > > w = 100; > minstep = 10; > maxstep = 30; > maxy = 10; > maxa = 30; > minc = 3; > maxc = 5; > points = wavy(w, minstep, maxstep, maxy, maxa, minc, maxc); > polygon([ > [0,0], > each points, > [w,0] > ]); > > The parameters to wavy() are: > > * w - the width of the wavy line > * minstep - the minimum x distance between "reference points" where > the line curvature changes > * maxstep - the maximum x distance between reference points > * maxy - the maximum y position at a reference point (minimum is zero) > * maxa - the maximum angle that the line will have crossing the > reference point (minimum is the negative of this) > * minc - the minimum distance from the control point to the Bezier > control point > * maxc - the maximum distance from the control point to the Bezier > control point > > Here's some sample outputs, with the parameters above: > > > > > > What it does is to pick randomly spaced X values that total up to the > desired width[*].  For each X value, it picks a Y value and two Bezier > control points, at the same random angle but different random > distances.  Then for each segment between two of those points, it > generates a Bezier curve using the first point and its right-side > control point and the second point and its left-side control point. > > [*] When the next value would be less than the minimum from the end, > it stops, so the last step can be up to min+max long.  There's > probably a better way to stop. >