diff --git a/affine.scad b/affine.scad index 487c053..35c36e3 100644 --- a/affine.scad +++ b/affine.scad @@ -422,19 +422,38 @@ function affine3d_chain(affines, _m=undef, _i=0) = // Usage: // pts = apply(transform, points); // Description: -// Applies the specified transformation matrix to a point list (or single point). Both inputs can be 2d or 3d, and it is also allowed -// to supply 3d transformations with 2d data as long as the the only action on the z coordinate is a simple scaling. -// Examples: -// transformed = apply(xrot(45), path3d(circle(r=3))); // Rotates 3d circle data around x axis -// transformed = apply(rot(45), circle(r=3)); // Rotates 2d circle data by 45 deg -// transformed = apply(rot(45)*right(4)*scale(3), circle(r=3)); // Scales, translates and rotates 2d circle data +// Applies the specified transformation matrix to a point, pointlist, bezier patch or VNF. +// Both inputs can be 2D or 3D, and it is also allowed to supply 3D transformations with 2D +// data as long as the the only action on the z coordinate is a simple scaling. +// Arguments: +// transform = The 2D or 3D transformation matrix to apply to the point/points. +// points = The point, pointlist, bezier patch, or VNF to apply the transformation to. +// Example(3D): +// path1 = path3d(circle(r=40)); +// tmat = xrot(45); +// path2 = apply(tmat, path1); +// #stroke(path1,closed=true); +// stroke(path2,closed=true); +// Example(2D): +// path1 = circle(r=40); +// tmat = translate([10,5]); +// path2 = apply(tmat, path1); +// #stroke(path1,closed=true); +// stroke(path2,closed=true); +// Example(2D): +// path1 = circle(r=40); +// tmat = rot(30) * back(15) * scale([1.5,0.5,1]); +// path2 = apply(tmat, path1); +// #stroke(path1,closed=true); +// stroke(path2,closed=true); function apply(transform,points) = points==[] ? [] : - is_vector(points) ? apply(transform, [points])[0] : + is_vector(points) + ? /* Point */ apply(transform, [points])[0] : is_list(points) && len(points)==2 && is_path(points[0],3) && is_list(points[1]) && is_vector(points[1][0]) - ? [apply(transform, points[0]), points[1]] : + ? /* VNF */ [apply(transform, points[0]), points[1]] : is_list(points) && is_list(points[0]) && is_vector(points[0][0]) - ? [for (x=points) apply(transform,x)] : + ? /* BezPatch */ [for (x=points) apply(transform,x)] : let( tdim = len(transform[0])-1, datadim = len(points[0]) diff --git a/tests/test_affine.scad b/tests/test_affine.scad index b9a4e49..06872a3 100644 --- a/tests/test_affine.scad +++ b/tests/test_affine.scad @@ -236,6 +236,23 @@ module test_apply() { assert(approx(apply(affine3d_xrot(135),2*BACK+2*UP),2*sqrt(2)*FWD)); assert(approx(apply(affine3d_yrot(135),2*RIGHT+2*UP),2*sqrt(2)*DOWN)); assert(approx(apply(affine3d_zrot(45),2*BACK+2*RIGHT),2*sqrt(2)*BACK)); + + module check_path_apply(mat,path) + assert_approx(apply(mat,path),path3d([for (p=path) mat*concat(p,1)])); + + check_path_apply(xrot(45), path3d(rect(100,center=true))); + check_path_apply(yrot(45), path3d(rect(100,center=true))); + check_path_apply(zrot(45), path3d(rect(100,center=true))); + check_path_apply(rot([20,30,40])*scale([0.9,1.1,1])*move([10,20,30]), path3d(rect(100,center=true))); + + module check_patch_apply(mat,patch) + assert_approx(apply(mat,patch), [for (path=patch) path3d([for (p=path) mat*concat(p,1)])]); + + flat = [for (x=[-50:25:50]) [for (y=[-50:25:50]) [x,y,0]]]; + check_patch_apply(xrot(45), flat); + check_patch_apply(yrot(45), flat); + check_patch_apply(zrot(45), flat); + check_patch_apply(rot([20,30,40])*scale([0.9,1.1,1])*move([10,20,30]), flat); } test_apply(); diff --git a/version.scad b/version.scad index 5a08c55..f4833dc 100644 --- a/version.scad +++ b/version.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,531]; +BOSL_VERSION = [2,0,532]; // Section: BOSL Library Version Functions