# Mirror, rotations and sweep

3 messages
Open this post in threaded view
|

## Mirror, rotations and sweep

 I rarely use mirror. But I realized that any rotation can be expressed by two reflections and so mirror would have other uses. It would be useless to do what rotate() does. But it is useful for instance to get the minimum rotation that brings a vector to another: // the minimum angle rotation from di to do module rotFromTo(di,do)     if( norm(di-do)==0 || norm(di)==0 || norm(do)==0 )         children();     else         mirror(do/norm(do)+di/norm(di)) mirror(di) children(); This module has many uses as we will see. If the module mirror is useful we should define also a function mirror returning the matrix to produce its reflection: function fmirror(v) =     norm(v)==0 ? [[1,0,0],[0,1,0],[0,0,1]] :     let(u = v/norm(v))     [ [1,0,0] - 2*u[0]*u, [0,1,0] - 2*u[1]*u, [0,0,1] - 2*u[2]*u ]; The function fmirror() returns a 3x3 matrix that may be apllied to reflect points. If needed a function returning a 4x4 matrix may be written based on that one. With fmirror(), we can define a function counterpart of rotFromTo(): // function format of rotFromTo function frotFromTo(di,do) =     norm(di-do)==0 || norm(di)==0 || norm(do)==0 ?         [[1,0,0],[0,1,0],[0,0,1]] :         fmirror(do/norm(do)+di/norm(di)) * fmirror(di); The function frotFromTo() in a very different (and complex) code is central in Oskar Linde's sweep.scad where it is called rotate_from_to. Inspired by the code of the Celtic knot by Camacho, I have written a boolean operation based sweep code: function identity() = [[1,0,0],[0,1,0],[0,0,1]]; module sweep(p,ang=0) {     // tangents to the path p     tgts = concat(  [[0,0,1]],                     [4*p[1] -p[2] - 3*p[0]],                     [for(i=[1:len(p)-2]) p[i+1]-p[i-1]],                     [p[len(p)-3] + 3*p[len(p)-1]-4*p[len(p)-2]]);     // rotation between two steps     function localRot(j) = frotFromTo(tgts[j], tgts[j+1]);     // list of total rotation until step i     function totRots(i, j=0,  M=[identity()]) =         j>i ?             M :             totRots( i, j+1, concat(M, [ localRot(j)*M[j] ] ));         rots = totRots(len(p)-1);     for(i=[0:len(p)-2]) hull(){         translate(p[i])             multmatrix(rots[i+1])                 rotate(i*ang/(len(p)-1))                     linear_extrude(height=0.01)                         children();         translate(p[i+1])             multmatrix(rots[i+2])                 rotate((i+1)*ang/(len(p)-1))                     linear_extrude(height=0.01)                         children();     } } This version of sweep, different from Camacho's one, has some advantages over the Linde's original: it has less twist (and avoids some wild twists that happens due to the instability of rotFromTo) and it allows self-intersecting paths. Besides, the parameter ang may be used to increase or decrease the twist along the path. It is also possible to make it to close a path with good fitting between the two ends. It has its drawbacks, though: it relies on many boolean operations and very higher render times should be expected and it is restricted to convex shapes due to the internal hull.   A simple example of application of this sweep(): n=60; p = 1; q = 1; sphiral = 20*[for(i=[0:n])                 [ sin(180*i*p/n)*cos(360*i*q/n),                   sin(180*i*p/n)*sin(360*i*q/n),                   cos(180*i*p/n)]]; angi = 1.95+45; for(i=[0:4]) rotate(i*360/5) sweep(sphiral) rotate(angi) square(2,center=true); The second image was generated with p=2.