2017-08-30 00:00:16 +00:00
//////////////////////////////////////////////////////////////////////
2019-03-23 04:13:18 +00:00
// LibFile: transforms.scad
2020-02-01 01:03:41 +00:00
// Functions and modules for translation, rotation, reflection and skewing.
2021-01-05 09:20:01 +00:00
// Includes:
2019-04-19 07:25:10 +00:00
// include <BOSL2/std.scad>
2017-08-30 00:00:16 +00:00
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
2019-03-23 04:13:18 +00:00
// Section: Translations
2017-08-30 00:00:16 +00:00
//////////////////////////////////////////////////////////////////////
2019-05-27 01:14:26 +00:00
// Function&Module: move()
2021-02-26 21:07:11 +00:00
// Aliases: translate()
2019-03-23 04:13:18 +00:00
//
2019-05-27 01:14:26 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// move(<x=>, <y=>, <z=>) ...
2019-12-04 10:24:34 +00:00
// move(v) ...
2019-05-27 01:14:26 +00:00
// Usage: Translate Points
2019-12-04 10:24:34 +00:00
// pts = move(v, p);
2021-02-26 21:07:11 +00:00
// pts = move(<x=>, <y=>, <z=>, p=);
2019-05-27 01:14:26 +00:00
// Usage: Get Translation Matrix
2019-12-04 10:24:34 +00:00
// mat = move(v);
2021-02-26 21:07:11 +00:00
// mat = move(<x=>, <y=>, <z=>);
//
// Topics: Affine, Matrices, Transforms, Translation
// See Also: left(), right(), fwd(), back(), down(), up(), affine2d_translate(), affine3d_translate()
2019-12-04 10:24:34 +00:00
//
// Description:
// Translates position by the given amount.
// * Called as a module, moves/translates all children.
// * Called as a function with a point in the `p` argument, returns the translated point.
// * Called as a function with a list of points in the `p` argument, returns the translated list of points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the translated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the translated VNF.
// * Called as a function with the `p` argument, returns the translated point or list of points.
// * Called as a function without a `p` argument, with a 2D offset vector `v`, returns an affine2d translation matrix.
// * Called as a function without a `p` argument, with a 3D offset vector `v`, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2019-12-04 10:24:34 +00:00
// v = An [X,Y,Z] vector to translate by.
2021-02-26 21:07:11 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
// ---
2017-08-30 00:00:16 +00:00
// x = X axis translation.
// y = Y axis translation.
// z = Z axis translation.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// move([0,20,30]) sphere(d=10);
//
// Example:
// #sphere(d=10);
// move(y=20) sphere(d=10);
//
// Example:
// #sphere(d=10);
// move(x=-10, y=-5) sphere(d=10);
2019-05-27 01:14:26 +00:00
//
2019-12-04 10:24:34 +00:00
// Example(2D):
// path = square([50,30], center=true);
// #stroke(path, closed=true);
// stroke(move([10,20],p=path), closed=true);
//
2019-05-27 01:14:26 +00:00
// Example(NORENDER):
// pt1 = move([0,20,30], p=[15,23,42]); // Returns: [15, 43, 72]
// pt2 = move(y=10, p=[15,23,42]); // Returns: [15, 33, 42]
// pt3 = move([0,3,1], p=[[1,2,3],[4,5,6]]); // Returns: [[1,5,4], [4,8,7]]
// pt4 = move(y=11, p=[[1,2,3],[4,5,6]]); // Returns: [[1,13,3], [4,16,6]]
// mat2d = move([2,3]); // Returns: [[1,0,2],[0,1,3],[0,0,1]]
// mat3d = move([2,3,4]); // Returns: [[1,0,0,2],[0,1,0,3],[0,0,1,4],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module move ( v = [ 0 , 0 , 0 ] , p , x = 0 , y = 0 , z = 0 ) {
assert ( is_undef ( p ) , "Module form `move()` does not accept p= argument." ) ;
2020-05-30 02:04:34 +00:00
translate ( point3d ( v ) + [ x , y , z ] ) children ( ) ;
2017-08-30 00:00:16 +00:00
}
2021-02-26 21:07:11 +00:00
function move ( v = [ 0 , 0 , 0 ] , p , x = 0 , y = 0 , z = 0 ) =
2020-05-30 02:04:34 +00:00
is_undef ( p ) ? (
len ( v ) = = 2 ? affine2d_translate ( v + [ x , y ] ) :
affine3d_translate ( point3d ( v ) + [ x , y , z ] )
) : (
assert ( is_list ( p ) )
2021-02-26 21:07:11 +00:00
let ( v = point3d ( v ) + [ x , y , z ] )
2020-05-30 02:04:34 +00:00
is_num ( p . x ) ? p + v :
is_vnf ( p ) ? [ move ( v = v , p = p . x ) , p . y ] :
[ for ( l = p ) is_vector ( l ) ? l + v : move ( v = v , p = l ) ]
) ;
2019-05-27 01:14:26 +00:00
2019-12-04 10:24:34 +00:00
function translate ( v = [ 0 , 0 , 0 ] , p = undef ) = move ( v = v , p = p ) ;
2019-08-06 23:43:41 +00:00
2017-08-30 00:00:16 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: left()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// left(x) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = left(x, p);
// Usage: Get Translation Matrix
// mat = left(x);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), right(), fwd(), back(), down(), up(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children left (in the X- direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// x = Scalar amount to move left.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// left(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = left(20, p=[23,42]); // Returns: [3,42]
// pt2 = left(20, p=[15,23,42]); // Returns: [-5,23,42]
// pt3 = left(3, p=[[1,2,3],[4,5,6]]); // Returns: [[-2,2,3], [1,5,6]]
// mat3d = left(4); // Returns: [[1,0,0,-4],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module left ( x = 0 , p ) {
assert ( is_undef ( p ) , "Module form `left()` does not accept p= argument." ) ;
translate ( [ - x , 0 , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function left ( x = 0 , p ) = move ( [ - x , 0 , 0 ] , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: right()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// right(x) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = right(x, p);
// Usage: Get Translation Matrix
// mat = right(x);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), left(), fwd(), back(), down(), up(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children right (in the X+ direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// x = Scalar amount to move right.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// right(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = right(20, p=[23,42]); // Returns: [43,42]
// pt2 = right(20, p=[15,23,42]); // Returns: [35,23,42]
// pt3 = right(3, p=[[1,2,3],[4,5,6]]); // Returns: [[4,2,3], [7,5,6]]
// mat3d = right(4); // Returns: [[1,0,0,4],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module right ( x = 0 , p ) {
assert ( is_undef ( p ) , "Module form `right()` does not accept p= argument." ) ;
translate ( [ x , 0 , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function right ( x = 0 , p ) = move ( [ x , 0 , 0 ] , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: fwd()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// fwd(y) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = fwd(y, p);
// Usage: Get Translation Matrix
// mat = fwd(y);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), left(), right(), back(), down(), up(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children forward (in the Y- direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// y = Scalar amount to move forward.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// fwd(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = fwd(20, p=[23,42]); // Returns: [23,22]
// pt2 = fwd(20, p=[15,23,42]); // Returns: [15,3,42]
// pt3 = fwd(3, p=[[1,2,3],[4,5,6]]); // Returns: [[1,-1,3], [4,2,6]]
// mat3d = fwd(4); // Returns: [[1,0,0,0],[0,1,0,-4],[0,0,1,0],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module fwd ( y = 0 , p ) {
assert ( is_undef ( p ) , "Module form `fwd()` does not accept p= argument." ) ;
translate ( [ 0 , - y , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function fwd ( y = 0 , p ) = move ( [ 0 , - y , 0 ] , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: back()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// back(y) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = back(y, p);
// Usage: Get Translation Matrix
// mat = back(y);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), left(), right(), fwd(), down(), up(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children back (in the Y+ direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// y = Scalar amount to move back.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// back(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = back(20, p=[23,42]); // Returns: [23,62]
// pt2 = back(20, p=[15,23,42]); // Returns: [15,43,42]
// pt3 = back(3, p=[[1,2,3],[4,5,6]]); // Returns: [[1,5,3], [4,8,6]]
// mat3d = back(4); // Returns: [[1,0,0,0],[0,1,0,4],[0,0,1,0],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module back ( y = 0 , ) {
assert ( is_undef ( p ) , "Module form `back()` does not accept p= argument." ) ;
translate ( [ 0 , y , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function back ( y = 0 , p ) = move ( [ 0 , y , 0 ] , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: down()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// down(z) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = down(z, p);
// Usage: Get Translation Matrix
// mat = down(z);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), left(), right(), fwd(), back(), up(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children down (in the Z- direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// z = Scalar amount to move down.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #sphere(d=10);
// down(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = down(20, p=[15,23,42]); // Returns: [15,23,22]
// pt2 = down(3, p=[[1,2,3],[4,5,6]]); // Returns: [[1,2,0], [4,5,3]]
// mat3d = down(4); // Returns: [[1,0,0,0],[0,1,0,0],[0,0,1,-4],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module down ( z = 0 , p ) {
assert ( is_undef ( p ) , "Module form `down()` does not accept p= argument." ) ;
translate ( [ 0 , 0 , - z ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function down ( z = 0 , p ) = move ( [ 0 , 0 , - z ] , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-08-22 06:54:36 +00:00
// Function&Module: up()
2019-03-23 04:13:18 +00:00
//
2019-08-22 06:54:36 +00:00
// Usage: As Module
2019-03-23 04:13:18 +00:00
// up(z) ...
2019-08-22 06:54:36 +00:00
// Usage: Translate Points
// pts = up(z, p);
// Usage: Get Translation Matrix
// mat = up(z);
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Translation
// See Also: move(), left(), right(), fwd(), back(), down(), affine2d_translate(), affine3d_translate()
//
2019-08-22 06:54:36 +00:00
// Description:
// If called as a module, moves/translates all children up (in the Z+ direction) by the given amount.
// If called as a function with the `p` argument, returns the translated point or list of points.
// If called as a function without the `p` argument, returns an affine3d translation matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
// z = Scalar amount to move up.
2019-08-22 06:54:36 +00:00
// p = Either a point, or a list of points to be translated when used as a function.
2019-03-23 04:13:18 +00:00
//
// Example:
// #sphere(d=10);
// up(20) sphere(d=10);
2019-08-22 06:54:36 +00:00
//
// Example(NORENDER):
// pt1 = up(20, p=[15,23,42]); // Returns: [15,23,62]
// pt2 = up(3, p=[[1,2,3],[4,5,6]]); // Returns: [[1,2,6], [4,5,9]]
// mat3d = up(4); // Returns: [[1,0,0,0],[0,1,0,0],[0,0,1,4],[0,0,0,1]]
2021-02-26 21:07:11 +00:00
module up ( z = 0 , p ) {
assert ( is_undef ( p ) , "Module form `up()` does not accept p= argument." ) ;
translate ( [ 0 , 0 , z ] ) children ( ) ;
}
2017-08-30 00:00:16 +00:00
2021-02-26 21:07:11 +00:00
function up ( z = 0 , p ) = move ( [ 0 , 0 , z ] , p = p ) ;
2019-08-22 06:54:36 +00:00
2017-08-30 00:00:16 +00:00
2019-03-23 04:13:18 +00:00
//////////////////////////////////////////////////////////////////////
// Section: Rotations
//////////////////////////////////////////////////////////////////////
2017-08-30 00:00:16 +00:00
2019-05-27 01:14:26 +00:00
// Function&Module: rot()
2019-03-23 04:13:18 +00:00
//
2021-02-26 21:07:11 +00:00
// Usage: As a Module
// rot(a, <cp>, <reverse>) {...}
// rot([X,Y,Z], <cp>, <reverse>) {...}
// rot(a, v, <cp>, <reverse>) {...}
// rot(from, to, <a>, <reverse>) {...}
2021-03-09 21:47:26 +00:00
// Usage: As a Function to transform data in `p`
2021-02-26 21:07:11 +00:00
// pts = rot(a, p=, <cp=>, <reverse=>);
// pts = rot([X,Y,Z], p=, <cp=>, <reverse=>);
// pts = rot(a, v, p=, <cp=>, <reverse=>);
// pts = rot(<a>, from=, to=, p=, <reverse=>);
2021-03-09 21:47:26 +00:00
// Usage: As a Function to return a transform matrix
// M = rot(a, <cp=>, <reverse=>, <planar=>);
// M = rot([X,Y,Z], <cp=>, <reverse=>, <planar=>);
// M = rot(a, v, <cp=>, <reverse=>, <planar=>);
// M = rot(from=, to=, <a=>, <reverse=>, <planar=>);
2021-02-26 21:07:11 +00:00
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: xrot(), yrot(), zrot(), affine2d_zrot(), affine3d_xrot(), affine3d_yrot(), affine3d_zrot(), affine3d_rot_by_axis(), affine3d_rot_from_to()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Description:
// This is a shorthand version of the built-in `rotate()`, and operates similarly, with a few additional capabilities.
// You can specify the rotation to perform in one of several ways:
// * `rot(30)` or `rot(a=30)` rotates 30 degrees around the Z axis.
// * `rot([20,30,40])` or `rot(a=[20,30,40])` rotates 20 degrees around the X axis, then 30 degrees around the Y axis, then 40 degrees around the Z axis.
// * `rot(30, [1,1,0])` or `rot(a=30, v=[1,1,0])` rotates 30 degrees around the axis vector `[1,1,0]`.
2021-03-08 22:08:06 +00:00
// * `rot(from=[0,0,1], to=[1,0,0])` rotates the `from` vector to line up with the `to` vector, in this case the top to the right and hence equivalent to `rot(a=90,v=[0,1,0]`.
// * `rot(from=[0,1,1], to=[1,1,0], a=45)` rotates 45 degrees around the `from` vector ([0,1,1]) and then rotates the `from` vector to align with the `to` vector. Equivalent to `rot(from=[0,1,1],to=[1,1,0]) rot(a=45,v=[0,1,1])`. You can also regard `a` as as post-rotation around the `to` vector. For this form, `a` must be a scalar.
// * If the `cp` centerpoint argument is given, then rotations are performed around that centerpoint. So `rot(args...,cp=[1,2,3])` is equivalent to `move(-[1,2,3])rot(args...)move([1,2,3])`.
// * If the `reverse` argument is true, then the rotations performed will be exactly reversed.
// .
2019-12-04 10:24:34 +00:00
// The behavior and return value varies depending on how `rot()` is called:
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
2021-03-08 22:08:06 +00:00
// * Called as a function without a `p` argument, and `planar` is true, returns the affine2d rotational matrix. The angle `a` must be a scalar.
2019-12-04 10:24:34 +00:00
// * Called as a function without a `p` argument, and `planar` is false, returns the affine3d rotational matrix.
//
2019-03-23 04:13:18 +00:00
// Arguments:
2021-03-09 21:47:26 +00:00
// a = Scalar angle or vector of XYZ rotation angles to rotate by, in degrees. If `planar` is true or if `p` holds 2d data, or if you use the `from` and `to` arguments then `a` must be a scalar. Default: `0`
2019-04-19 06:32:17 +00:00
// v = vector for the axis of rotation. Default: [0,0,1] or UP
2021-02-26 21:07:11 +00:00
// ---
2019-01-25 21:47:14 +00:00
// cp = centerpoint to rotate around. Default: [0,0,0]
2019-03-23 04:13:18 +00:00
// from = Starting vector for vector-based rotations.
// to = Target vector for vector-based rotations.
// reverse = If true, exactly reverses the rotation, including axis rotation ordering. Default: false
2019-05-27 01:14:26 +00:00
// planar = If called as a function, this specifies if you want to work with 2D points.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2019-03-23 04:13:18 +00:00
//
2019-01-25 21:47:14 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #cube([2,4,9]);
2019-01-25 21:47:14 +00:00
// rot([30,60,0], cp=[0,0,9]) cube([2,4,9]);
2019-03-23 04:13:18 +00:00
//
// Example:
// #cube([2,4,9]);
2019-01-25 21:47:14 +00:00
// rot(30, v=[1,1,0], cp=[0,0,9]) cube([2,4,9]);
2019-03-23 04:13:18 +00:00
//
2019-02-27 11:52:59 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #cube([2,4,9]);
2019-04-19 06:32:17 +00:00
// rot(from=UP, to=LEFT+BACK) cube([2,4,9]);
2019-12-04 10:24:34 +00:00
//
// Example(2D):
// path = square([50,30], center=true);
// #stroke(path, closed=true);
// stroke(rot(30,p=path), closed=true);
2021-02-26 21:07:11 +00:00
module rot ( a = 0 , v , cp , from , to , reverse = false )
2019-03-23 04:13:18 +00:00
{
2020-05-30 02:04:34 +00:00
m = rot ( a = a , v = v , cp = cp , from = from , to = to , reverse = reverse , planar = false ) ;
multmatrix ( m ) children ( ) ;
2019-02-27 11:52:59 +00:00
}
2020-03-22 12:11:19 +00:00
function rot ( a = 0 , v , cp , from , to , reverse = false , planar = false , p , _m ) =
2020-05-30 02:04:34 +00:00
assert ( is_undef ( from ) = = is_undef ( to ) , "from and to must be specified together." )
2020-08-26 22:59:35 +00:00
assert ( is_undef ( from ) || is_vector ( from , zero = false ) , "'from' must be a non-zero vector." )
assert ( is_undef ( to ) || is_vector ( to , zero = false ) , "'to' must be a non-zero vector." )
assert ( is_undef ( v ) || is_vector ( v , zero = false ) , "'v' must be a non-zero vector." )
assert ( is_undef ( cp ) || is_vector ( cp ) , "'cp' must be a vector." )
assert ( is_finite ( a ) || is_vector ( a ) , "'a' must be a finite scalar or a vector." )
assert ( is_bool ( reverse ) )
assert ( is_bool ( planar ) )
2020-05-30 02:04:34 +00:00
is_undef ( p ) ? (
planar ? let (
2020-08-26 22:59:35 +00:00
check = assert ( is_num ( a ) ) ,
2020-05-30 02:04:34 +00:00
cp = is_undef ( cp ) ? cp : point2d ( cp ) ,
m1 = is_undef ( from ) ? affine2d_zrot ( a ) :
2020-08-26 22:59:35 +00:00
assert ( a = = 0 , "'from' and 'to' cannot be used with 'a' when 'planar' is true." )
assert ( approx ( point3d ( from ) . z , 0 ) , "'from' must be a 2D vector when 'planar' is true." )
assert ( approx ( point3d ( to ) . z , 0 ) , "'to' must be a 2D vector when 'planar' is true." )
2020-05-30 02:04:34 +00:00
affine2d_zrot (
2021-06-15 03:28:49 +00:00
v_theta ( to ) -
v_theta ( from )
2020-05-30 02:04:34 +00:00
) ,
m2 = is_undef ( cp ) ? m1 : ( move ( cp ) * m1 * move ( - cp ) ) ,
m3 = reverse ? matrix_inverse ( m2 ) : m2
) m3 : let (
from = is_undef ( from ) ? undef : point3d ( from ) ,
to = is_undef ( to ) ? undef : point3d ( to ) ,
cp = is_undef ( cp ) ? undef : point3d ( cp ) ,
m1 = ! is_undef ( from ) ? (
2020-08-26 22:59:35 +00:00
assert ( is_num ( a ) )
2021-03-08 22:51:23 +00:00
affine3d_rot_from_to ( from , to ) * affine3d_rot_by_axis ( from , a )
2020-05-30 02:04:34 +00:00
) :
2020-08-26 22:59:35 +00:00
! is_undef ( v ) ? assert ( is_num ( a ) ) affine3d_rot_by_axis ( v , a ) :
2020-05-30 02:04:34 +00:00
is_num ( a ) ? affine3d_zrot ( a ) :
affine3d_zrot ( a . z ) * affine3d_yrot ( a . y ) * affine3d_xrot ( a . x ) ,
m2 = is_undef ( cp ) ? m1 : ( move ( cp ) * m1 * move ( - cp ) ) ,
m3 = reverse ? matrix_inverse ( m2 ) : m2
) m3
) : (
assert ( is_list ( p ) )
let (
m = ! is_undef ( _m ) ? _m :
rot ( a = a , v = v , cp = cp , from = from , to = to , reverse = reverse , planar = planar ) ,
res = p = = [ ] ? [ ] :
is_vector ( p ) ? apply ( m , p ) :
is_vnf ( p ) ? [ apply ( m , p [ 0 ] ) , p [ 1 ] ] :
is_list ( p [ 0 ] ) ? [ for ( pp = p ) rot ( p = pp , _m = m ) ] :
assert ( false , "The p argument for rot() is not a point, path, patch, matrix, or VNF." )
) res
) ;
2019-05-27 01:14:26 +00:00
2019-02-27 11:52:59 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: xrot()
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As a function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = xrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As a function to return rotation matrix
2021-02-26 21:07:11 +00:00
// mat = xrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), yrot(), zrot(), affine2d_zrot(), affine3d_xrot(), affine3d_yrot(), affine3d_zrot()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Description:
// Rotates around the X axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, and `planar` is true, returns the affine2d rotational matrix.
// * Called as a function without a `p` argument, and `planar` is false, returns the affine3d rotational matrix.
//
2019-03-23 04:13:18 +00:00
// Arguments:
2018-12-10 20:11:34 +00:00
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-26 21:07:11 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #cylinder(h=50, r=10, center=true);
// xrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module xrot ( a = 0 , p , cp )
2019-03-23 04:13:18 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `xrot()` does not accept p= argument." ) ;
2020-05-30 02:04:34 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else if ( ! is_undef ( cp ) ) {
translate ( cp ) rotate ( [ a , 0 , 0 ] ) translate ( - cp ) children ( ) ;
} else {
rotate ( [ a , 0 , 0 ] ) children ( ) ;
}
2018-12-10 20:11:34 +00:00
}
2017-08-30 00:00:16 +00:00
2021-02-26 21:07:11 +00:00
function xrot ( a = 0 , p , cp ) = rot ( [ a , 0 , 0 ] , cp = cp , p = p ) ;
2017-08-30 00:00:16 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: yrot()
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// yrot(a, <cp=>) ...
2019-07-11 01:52:33 +00:00
// Usage: Rotate Points
2021-02-26 21:07:11 +00:00
// rotated = yrot(a, p, <cp=>);
2019-07-11 01:52:33 +00:00
// Usage: Get Rotation Matrix
2021-02-26 21:07:11 +00:00
// mat = yrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), zrot(), affine2d_zrot(), affine3d_xrot(), affine3d_yrot(), affine3d_zrot()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Description:
// Rotates around the Y axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, and `planar` is true, returns the affine2d rotational matrix.
// * Called as a function without a `p` argument, and `planar` is false, returns the affine3d rotational matrix.
//
2019-03-23 04:13:18 +00:00
// Arguments:
2018-12-10 20:11:34 +00:00
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-26 21:07:11 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #cylinder(h=50, r=10, center=true);
// yrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module yrot ( a = 0 , p , cp )
2019-03-23 04:13:18 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `yrot()` does not accept p= argument." ) ;
2020-05-30 02:04:34 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else if ( ! is_undef ( cp ) ) {
translate ( cp ) rotate ( [ 0 , a , 0 ] ) translate ( - cp ) children ( ) ;
} else {
rotate ( [ 0 , a , 0 ] ) children ( ) ;
}
2018-12-10 20:11:34 +00:00
}
2017-08-30 00:00:16 +00:00
2021-02-26 21:07:11 +00:00
function yrot ( a = 0 , p , cp ) = rot ( [ 0 , a , 0 ] , cp = cp , p = p ) ;
2017-08-30 00:00:16 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: zrot()
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// zrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As Function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = zrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As Function to return rotation matrix
2021-02-26 21:07:11 +00:00
// mat = zrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), yrot(), affine2d_zrot(), affine3d_xrot(), affine3d_yrot(), affine3d_zrot()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Description:
// Rotates around the Z axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, and `planar` is true, returns the affine2d rotational matrix.
// * Called as a function without a `p` argument, and `planar` is false, returns the affine3d rotational matrix.
//
2019-03-23 04:13:18 +00:00
// Arguments:
2018-12-10 20:11:34 +00:00
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-26 21:07:11 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
2019-03-23 04:13:18 +00:00
//
2017-08-30 00:00:16 +00:00
// Example:
2019-03-23 04:13:18 +00:00
// #cube(size=[60,20,40], center=true);
// zrot(90) cube(size=[60,20,40], center=true);
2021-02-26 21:07:11 +00:00
module zrot ( a = 0 , p , cp )
2019-03-23 04:13:18 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `zrot()` does not accept p= argument." ) ;
2020-05-30 02:04:34 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else if ( ! is_undef ( cp ) ) {
translate ( cp ) rotate ( a ) translate ( - cp ) children ( ) ;
} else {
rotate ( a ) children ( ) ;
}
2018-12-10 20:11:34 +00:00
}
2021-02-26 21:07:11 +00:00
function zrot ( a = 0 , p , cp ) = rot ( a , cp = cp , p = p ) ;
2017-08-30 00:00:16 +00:00
2021-02-15 08:28:36 +00:00
// Function&Module: xyrot()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xyrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As a Function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = xyrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As a Function to get rotation matrix
2021-02-26 21:07:11 +00:00
// mat = xyrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), yrot(), zrot(), xzrot(), yzrot(), xyzrot(), affine3d_rot_by_axis()
2021-02-15 08:28:36 +00:00
//
// Description:
// Rotates around the [1,1,0] vector axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, returns the affine3d rotational matrix.
//
// Arguments:
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-15 08:28:36 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
//
// Example:
// #cylinder(h=50, r=10, center=true);
// xyrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module xyrot ( a = 0 , p , cp )
2021-02-15 08:28:36 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `xyrot()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else {
2021-02-15 08:37:46 +00:00
mat = xyrot ( a = a , cp = cp ) ;
2021-02-15 08:28:36 +00:00
multmatrix ( mat ) children ( ) ;
}
}
function xyrot ( a = 0 , p , cp ) = rot ( a = a , v = [ 1 , 1 , 0 ] , cp = cp , p = p ) ;
// Function&Module: xzrot()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xzrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As Function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = xzrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As Function to return rotation matrix
2021-02-26 21:07:11 +00:00
// mat = xzrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), yrot(), zrot(), xyrot(), yzrot(), xyzrot(), affine3d_rot_by_axis()
2021-02-15 08:28:36 +00:00
//
// Description:
// Rotates around the [1,0,1] vector axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, returns the affine3d rotational matrix.
//
// Arguments:
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-15 08:28:36 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
//
// Example:
// #cylinder(h=50, r=10, center=true);
// xzrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module xzrot ( a = 0 , p , cp )
2021-02-15 08:28:36 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `xzrot()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else {
2021-02-15 08:37:46 +00:00
mat = xzrot ( a = a , cp = cp ) ;
2021-02-15 08:28:36 +00:00
multmatrix ( mat ) children ( ) ;
}
}
function xzrot ( a = 0 , p , cp ) = rot ( a = a , v = [ 1 , 0 , 1 ] , cp = cp , p = p ) ;
// Function&Module: yzrot()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// yzrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As Function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = yzrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As Function to return rotation matrix
2021-02-26 21:07:11 +00:00
// mat = yzrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), yrot(), zrot(), xyrot(), xzrot(), xyzrot(), affine3d_rot_by_axis()
2021-02-15 08:28:36 +00:00
//
// Description:
// Rotates around the [0,1,1] vector axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, returns the affine3d rotational matrix.
//
// Arguments:
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-15 08:28:36 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
//
// Example:
// #cylinder(h=50, r=10, center=true);
// yzrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module yzrot ( a = 0 , p , cp )
2021-02-15 08:28:36 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `yzrot()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else {
2021-02-15 08:37:46 +00:00
mat = yzrot ( a = a , cp = cp ) ;
2021-02-15 08:28:36 +00:00
multmatrix ( mat ) children ( ) ;
}
}
function yzrot ( a = 0 , p , cp ) = rot ( a = a , v = [ 0 , 1 , 1 ] , cp = cp , p = p ) ;
// Function&Module: xyzrot()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xyzrot(a, <cp=>) ...
2021-03-09 21:47:26 +00:00
// Usage: As Function to rotate points
2021-02-26 21:07:11 +00:00
// rotated = xyzrot(a, p, <cp=>);
2021-03-09 21:47:26 +00:00
// Usage: As Function to return rotation matrix
2021-02-26 21:07:11 +00:00
// mat = xyzrot(a, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Rotation
// See Also: rot(), xrot(), yrot(), zrot(), xyrot(), xzrot(), yzrot(), affine3d_rot_by_axis()
2021-02-15 08:28:36 +00:00
//
// Description:
// Rotates around the [1,1,1] vector axis by the given number of degrees. If `cp` is given, rotations are performed around that centerpoint.
// * Called as a module, rotates all children.
// * Called as a function with a `p` argument containing a point, returns the rotated point.
// * Called as a function with a `p` argument containing a list of points, returns the list of rotated points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the rotated patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the rotated VNF.
// * Called as a function without a `p` argument, returns the affine3d rotational matrix.
//
// Arguments:
// a = angle to rotate by in degrees.
2021-03-09 21:47:26 +00:00
// p = If called as a function, this contains data to rotate: a point, list of points, bezier patch or VNF.
2021-02-15 08:28:36 +00:00
// ---
// cp = centerpoint to rotate around. Default: [0,0,0]
//
// Example:
// #cylinder(h=50, r=10, center=true);
// xyzrot(90) cylinder(h=50, r=10, center=true);
2021-02-26 21:07:11 +00:00
module xyzrot ( a = 0 , p , cp )
2021-02-15 08:28:36 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `xyzrot()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
if ( a = = 0 ) {
children ( ) ; // May be slightly faster?
} else {
mat = xyzrot ( a = a , cp = cp ) ;
multmatrix ( mat ) children ( ) ;
}
}
function xyzrot ( a = 0 , p , cp ) = rot ( a = a , v = [ 1 , 1 , 1 ] , cp = cp , p = p ) ;
2019-03-23 04:13:18 +00:00
//////////////////////////////////////////////////////////////////////
// Section: Scaling and Mirroring
//////////////////////////////////////////////////////////////////////
2017-08-30 00:00:16 +00:00
2019-05-27 01:14:26 +00:00
// Function&Module: scale()
// Usage: As Module
2021-02-26 21:07:11 +00:00
// scale(SCALAR) ...
// scale([X,Y,Z]) ...
2019-05-27 01:14:26 +00:00
// Usage: Scale Points
2021-02-26 21:07:11 +00:00
// pts = scale(v, p, <cp=>);
2019-05-27 01:14:26 +00:00
// Usage: Get Scaling Matrix
2021-02-26 21:07:11 +00:00
// mat = scale(v, <cp=>);
// Topics: Affine, Matrices, Transforms, Scaling
2021-02-26 21:32:53 +00:00
// See Also: xscale(), yscale(), zscale(), affine2d_scale(), affine3d_scale()
2019-05-27 01:14:26 +00:00
// Description:
2019-12-04 10:24:34 +00:00
// Scales by the [X,Y,Z] scaling factors given in `v`. If `v` is given as a scalar number, all axes are scaled uniformly by that amount.
// * Called as the built-in module, scales all children.
// * Called as a function with a point in the `p` argument, returns the scaled point.
// * Called as a function with a list of points in the `p` argument, returns the list of scaled points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the scaled patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the scaled VNF.
// * Called as a function without a `p` argument, and a 2D list of scaling factors in `v`, returns an affine2d scaling matrix.
// * Called as a function without a `p` argument, and a 3D list of scaling factors in `v`, returns an affine3d scaling matrix.
2019-05-27 01:14:26 +00:00
// Arguments:
2019-12-04 10:24:34 +00:00
// v = Either a numeric uniform scaling factor, or a list of [X,Y,Z] scaling factors. Default: 1
2019-05-27 01:14:26 +00:00
// p = If called as a function, the point or list of points to scale.
2021-02-26 21:07:11 +00:00
// ---
// cp = If given, centers the scaling on the point `cp`.
2019-05-27 01:14:26 +00:00
// Example(NORENDER):
2019-06-12 05:26:09 +00:00
// pt1 = scale(3, p=[3,1,4]); // Returns: [9,3,12]
// pt2 = scale([2,3,4], p=[3,1,4]); // Returns: [6,3,16]
2019-05-27 01:14:26 +00:00
// pt3 = scale([2,3,4], p=[[1,2,3],[4,5,6]]); // Returns: [[2,6,12], [8,15,24]]
// mat2d = scale([2,3]); // Returns: [[2,0,0],[0,3,0],[0,0,1]]
// mat3d = scale([2,3,4]); // Returns: [[2,0,0,0],[0,3,0,0],[0,0,4,0],[0,0,0,1]]
2019-07-11 01:52:33 +00:00
// Example(2D):
// path = circle(d=50,$fn=12);
2019-12-04 10:24:34 +00:00
// #stroke(path,closed=true);
// stroke(scale([1.5,3],p=path),closed=true);
2021-02-26 21:07:11 +00:00
function scale ( v = 1 , p , cp = [ 0 , 0 , 0 ] ) =
2020-05-30 02:04:34 +00:00
assert ( is_num ( v ) || is_vector ( v ) )
assert ( is_undef ( p ) || is_list ( p ) )
2021-02-26 21:07:11 +00:00
assert ( is_vector ( cp ) )
2020-12-01 05:09:00 +00:00
let ( v = is_num ( v ) ? [ v , v , v ] : v )
2020-05-30 02:04:34 +00:00
is_undef ( p ) ? (
2020-12-01 05:09:00 +00:00
len ( v ) = = 2 ? (
cp = = [ 0 , 0 , 0 ] || cp = = [ 0 , 0 ] ? affine2d_scale ( v ) : (
affine2d_translate ( point2d ( cp ) ) *
affine2d_scale ( v ) *
affine2d_translate ( point2d ( - cp ) )
)
) : (
cp = = [ 0 , 0 , 0 ] ? affine3d_scale ( v ) : (
affine3d_translate ( point3d ( cp ) ) *
affine3d_scale ( v ) *
affine3d_translate ( point3d ( - cp ) )
)
)
2020-05-30 02:04:34 +00:00
) : (
assert ( is_list ( p ) )
2020-12-01 05:09:00 +00:00
let ( mat = scale ( v = v , cp = cp ) )
is_vector ( p ) ? apply ( mat , p ) :
2020-05-30 02:04:34 +00:00
is_vnf ( p ) ? let ( inv = product ( [ for ( x = v ) x < 0 ? - 1 : 1 ] ) ) [
2020-12-01 05:09:00 +00:00
apply ( mat , p [ 0 ] ) ,
2020-08-03 06:23:50 +00:00
inv >= 0 ? p [ 1 ] : [ for ( l = p [ 1 ] ) reverse ( l ) ]
2020-05-30 02:04:34 +00:00
] :
2020-12-01 05:09:00 +00:00
apply ( mat , p )
2020-05-30 02:04:34 +00:00
) ;
2019-05-27 01:14:26 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: xscale()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
//
2019-07-11 01:52:33 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xscale(x, <cp=>) ...
2019-07-11 01:52:33 +00:00
// Usage: Scale Points
2021-02-26 21:07:11 +00:00
// scaled = xscale(x, p, <cp=>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// mat = xscale(x, <cp=>, <planar=>);
//
// Topics: Affine, Matrices, Transforms, Scaling
2021-02-26 21:32:53 +00:00
// See Also: scale(), yscale(), zscale(), affine2d_scale(), affine3d_scale()
2019-07-11 01:52:33 +00:00
//
// Description:
2019-12-04 10:24:34 +00:00
// Scales along the X axis by the scaling factor `x`.
// * Called as the built-in module, scales all children.
// * Called as a function with a point in the `p` argument, returns the scaled point.
// * Called as a function with a list of points in the `p` argument, returns the list of scaled points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the scaled patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the scaled VNF.
// * Called as a function without a `p` argument, and a 2D list of scaling factors in `v`, returns an affine2d scaling matrix.
// * Called as a function without a `p` argument, and a 3D list of scaling factors in `v`, returns an affine3d scaling matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2019-07-11 01:52:33 +00:00
// x = Factor to scale by, along the X axis.
2020-12-01 05:09:00 +00:00
// p = A point, path, bezier patch, or VNF to scale, when called as a function.
2021-02-26 21:07:11 +00:00
// ---
// cp = If given as a point, centers the scaling on the point `cp`. If given as a scalar, centers scaling on the point `[cp,0,0]`
2019-07-11 01:52:33 +00:00
// planar = If true, and `p` is not given, then the matrix returned is an affine2d matrix instead of an affine3d matrix.
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Example: As Module
2019-03-23 04:13:18 +00:00
// xscale(3) sphere(r=10);
2019-07-11 01:52:33 +00:00
//
// Example(2D): Scaling Points
// path = circle(d=50,$fn=12);
2019-12-04 10:48:02 +00:00
// #stroke(path,closed=true);
// stroke(xscale(2,p=path),closed=true);
2021-02-26 21:07:11 +00:00
module xscale ( x = 1 , p , cp = 0 , planar ) {
assert ( is_undef ( p ) , "Module form `xscale()` does not accept p= argument." ) ;
assert ( is_undef ( planar ) , "Module form `xscale()` does not accept planar= argument." ) ;
2020-12-01 05:09:00 +00:00
cp = is_num ( cp ) ? [ cp , 0 , 0 ] : cp ;
if ( cp = = [ 0 , 0 , 0 ] ) {
scale ( [ x , 1 , 1 ] ) children ( ) ;
} else {
translate ( cp ) scale ( [ x , 1 , 1 ] ) translate ( - cp ) children ( ) ;
}
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function xscale ( x = 1 , p , cp = 0 , planar = false ) =
assert ( is_finite ( x ) )
assert ( is_undef ( p ) || is_list ( p ) )
assert ( is_finite ( cp ) || is_vector ( cp ) )
assert ( is_bool ( planar ) )
2020-12-01 05:09:00 +00:00
let ( cp = is_num ( cp ) ? [ cp , 0 , 0 ] : cp )
( planar || ( ! is_undef ( p ) && len ( p ) = = 2 ) )
? scale ( [ x , 1 ] , cp = cp , p = p )
: scale ( [ x , 1 , 1 ] , cp = cp , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: yscale()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// yscale(y, <cp=>) ...
2019-12-04 10:24:34 +00:00
// Usage: Scale Points
2021-02-26 21:07:11 +00:00
// scaled = yscale(y, p, <cp=>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// mat = yscale(y, <cp=>, <planar=>);
//
// Topics: Affine, Matrices, Transforms, Scaling
2021-02-26 21:32:53 +00:00
// See Also: scale(), xscale(), zscale(), affine2d_scale(), affine3d_scale()
2019-12-04 10:24:34 +00:00
//
// Description:
// Scales along the Y axis by the scaling factor `y`.
// * Called as the built-in module, scales all children.
// * Called as a function with a point in the `p` argument, returns the scaled point.
// * Called as a function with a list of points in the `p` argument, returns the list of scaled points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the scaled patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the scaled VNF.
// * Called as a function without a `p` argument, and a 2D list of scaling factors in `v`, returns an affine2d scaling matrix.
// * Called as a function without a `p` argument, and a 3D list of scaling factors in `v`, returns an affine3d scaling matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2019-07-11 01:52:33 +00:00
// y = Factor to scale by, along the Y axis.
2020-12-01 05:09:00 +00:00
// p = A point, path, bezier patch, or VNF to scale, when called as a function.
2021-02-26 21:07:11 +00:00
// ---
// cp = If given as a point, centers the scaling on the point `cp`. If given as a scalar, centers scaling on the point `[0,cp,0]`
2019-07-11 01:52:33 +00:00
// planar = If true, and `p` is not given, then the matrix returned is an affine2d matrix instead of an affine3d matrix.
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Example: As Module
2019-03-23 04:13:18 +00:00
// yscale(3) sphere(r=10);
2019-07-11 01:52:33 +00:00
//
// Example(2D): Scaling Points
// path = circle(d=50,$fn=12);
2019-12-04 10:48:02 +00:00
// #stroke(path,closed=true);
// stroke(yscale(2,p=path),closed=true);
2021-02-26 21:07:11 +00:00
module yscale ( y = 1 , p , cp = 0 , planar ) {
assert ( is_undef ( p ) , "Module form `yscale()` does not accept p= argument." ) ;
assert ( is_undef ( planar ) , "Module form `yscale()` does not accept planar= argument." ) ;
2020-12-01 05:09:00 +00:00
cp = is_num ( cp ) ? [ 0 , cp , 0 ] : cp ;
if ( cp = = [ 0 , 0 , 0 ] ) {
scale ( [ 1 , y , 1 ] ) children ( ) ;
} else {
translate ( cp ) scale ( [ 1 , y , 1 ] ) translate ( - cp ) children ( ) ;
}
}
2019-07-11 01:52:33 +00:00
2021-02-26 21:07:11 +00:00
function yscale ( y = 1 , p , cp = 0 , planar = false ) =
assert ( is_finite ( y ) )
assert ( is_undef ( p ) || is_list ( p ) )
assert ( is_finite ( cp ) || is_vector ( cp ) )
assert ( is_bool ( planar ) )
2020-12-01 05:09:00 +00:00
let ( cp = is_num ( cp ) ? [ 0 , cp , 0 ] : cp )
( planar || ( ! is_undef ( p ) && len ( p ) = = 2 ) )
2021-06-10 01:29:29 +00:00
? scale ( [ 1 , y ] , cp = cp , p = p )
: scale ( [ 1 , y , 1 ] , cp = cp , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-07-11 01:52:33 +00:00
// Function&Module: zscale()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// zscale(z, <cp=>) ...
2019-12-04 10:24:34 +00:00
// Usage: Scale Points
2021-02-26 21:07:11 +00:00
// scaled = zscale(z, p, <cp=>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// mat = zscale(z, <cp=>);
//
// Topics: Affine, Matrices, Transforms, Scaling
2021-02-26 21:32:53 +00:00
// See Also: scale(), xscale(), yscale(), affine2d_scale(), affine3d_scale()
2019-12-04 10:24:34 +00:00
//
// Description:
// Scales along the Z axis by the scaling factor `z`.
// * Called as the built-in module, scales all children.
// * Called as a function with a point in the `p` argument, returns the scaled point.
// * Called as a function with a list of points in the `p` argument, returns the list of scaled points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the scaled patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the scaled VNF.
// * Called as a function without a `p` argument, and a 2D list of scaling factors in `v`, returns an affine2d scaling matrix.
// * Called as a function without a `p` argument, and a 3D list of scaling factors in `v`, returns an affine3d scaling matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2019-07-11 01:52:33 +00:00
// z = Factor to scale by, along the Z axis.
2020-12-01 05:09:00 +00:00
// p = A point, path, bezier patch, or VNF to scale, when called as a function.
2021-02-26 21:07:11 +00:00
// ---
// cp = If given as a point, centers the scaling on the point `cp`. If given as a scalar, centers scaling on the point `[0,0,cp]`
2019-03-23 04:13:18 +00:00
//
2019-07-11 01:52:33 +00:00
// Example: As Module
2019-03-23 04:13:18 +00:00
// zscale(3) sphere(r=10);
2019-07-11 01:52:33 +00:00
//
// Example: Scaling Points
2020-04-26 11:29:21 +00:00
// path = xrot(90,p=path3d(circle(d=50,$fn=12)));
2020-11-17 01:50:08 +00:00
// #trace_path(path);
// trace_path(zscale(2,p=path));
2021-02-26 21:07:11 +00:00
module zscale ( z = 1 , p , cp = 0 ) {
assert ( is_undef ( p ) , "Module form `zscale()` does not accept p= argument." ) ;
2020-12-01 05:09:00 +00:00
cp = is_num ( cp ) ? [ 0 , 0 , cp ] : cp ;
if ( cp = = [ 0 , 0 , 0 ] ) {
scale ( [ 1 , 1 , z ] ) children ( ) ;
} else {
translate ( cp ) scale ( [ 1 , 1 , z ] ) translate ( - cp ) children ( ) ;
}
}
2019-07-11 01:52:33 +00:00
2021-02-26 21:07:11 +00:00
function zscale ( z = 1 , p , cp = 0 ) =
assert ( is_finite ( z ) )
assert ( is_undef ( p ) || is_list ( p ) )
assert ( is_finite ( cp ) || is_vector ( cp ) )
2020-12-01 05:09:00 +00:00
let ( cp = is_num ( cp ) ? [ 0 , 0 , cp ] : cp )
scale ( [ 1 , 1 , z ] , cp = cp , p = p ) ;
2019-03-23 04:13:18 +00:00
2019-12-04 10:24:34 +00:00
// Function&Module: mirror()
// Usage: As Module
// mirror(v) ...
// Usage: As Function
// pt = mirror(v, p);
// Usage: Get Reflection/Mirror Matrix
// mat = mirror(v);
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: xflip(), yflip(), zflip(), affine2d_mirror(), affine3d_mirror()
2019-03-23 04:13:18 +00:00
// Description:
2019-12-04 10:24:34 +00:00
// Mirrors/reflects across the plane or line whose normal vector is given in `v`.
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
// * Called as a function without a `p` argument, and with a 2D normal vector `v`, returns the affine2d 3x3 mirror matrix.
// * Called as a function without a `p` argument, and with a 3D normal vector `v`, returns the affine3d 4x4 mirror matrix.
// Arguments:
// v = The normal vector of the line or plane to mirror across.
// p = If called as a function, the point or list of points to scale.
// Example:
// n = [1,0,0];
// module obj() right(20) rotate([0,15,-15]) cube([40,30,20]);
// obj();
// mirror(n) obj();
// rot(a=atan2(n.y,n.x),from=UP,to=n) {
// color("red") anchor_arrow(s=20, flag=false);
// color("#7777") cube([75,75,0.1], center=true);
// }
// Example:
// n = [1,1,0];
// module obj() right(20) rotate([0,15,-15]) cube([40,30,20]);
// obj();
// mirror(n) obj();
// rot(a=atan2(n.y,n.x),from=UP,to=n) {
// color("red") anchor_arrow(s=20, flag=false);
// color("#7777") cube([75,75,0.1], center=true);
// }
// Example:
// n = [1,1,1];
// module obj() right(20) rotate([0,15,-15]) cube([40,30,20]);
// obj();
// mirror(n) obj();
// rot(a=atan2(n.y,n.x),from=UP,to=n) {
// color("red") anchor_arrow(s=20, flag=false);
// color("#7777") cube([75,75,0.1], center=true);
// }
// Example(2D):
// n = [0,1];
// path = rot(30, p=square([50,30]));
// color("gray") rot(from=[0,1],to=n) stroke([[-60,0],[60,0]]);
// color("red") stroke([[0,0],10*n],endcap2="arrow2");
// #stroke(path,closed=true);
// stroke(mirror(n, p=path),closed=true);
// Example(2D):
// n = [1,1];
// path = rot(30, p=square([50,30]));
// color("gray") rot(from=[0,1],to=n) stroke([[-60,0],[60,0]]);
// color("red") stroke([[0,0],10*n],endcap2="arrow2");
// #stroke(path,closed=true);
// stroke(mirror(n, p=path),closed=true);
function mirror ( v , p ) =
2020-05-30 02:04:34 +00:00
assert ( is_vector ( v ) )
assert ( is_undef ( p ) || is_list ( p ) )
let ( m = len ( v ) = = 2 ? affine2d_mirror ( v ) : affine3d_mirror ( v ) )
is_undef ( p ) ? m :
is_num ( p . x ) ? apply ( m , p ) :
is_vnf ( p ) ? [ mirror ( v = v , p = p [ 0 ] ) , [ for ( face = p [ 1 ] ) reverse ( face ) ] ] :
[ for ( l = p ) is_vector ( l ) ? apply ( m , l ) : mirror ( v = v , p = l ) ] ;
2019-12-04 10:24:34 +00:00
// Function&Module: xflip()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-15 08:28:36 +00:00
// xflip(<x>) ...
2019-12-04 10:24:34 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = xflip(p, <x>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// pt = xflip(<x>, <planar=>);
//
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), yflip(), zflip(), affine2d_mirror(), affine3d_mirror()
2019-12-04 10:24:34 +00:00
//
// Description:
// Mirrors/reflects across the origin [0,0,0], along the X axis. If `x` is given, reflects across [x,0,0] instead.
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
2021-02-15 08:28:36 +00:00
// * Called as a function without a `p` argument, and `planar=true`, returns the affine2d 3x3 mirror matrix.
// * Called as a function without a `p` argument, and `planar=false`, returns the affine3d 4x4 mirror matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2019-06-12 05:12:49 +00:00
// x = The X coordinate of the plane of reflection. Default: 0
2021-02-15 08:28:36 +00:00
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2021-02-26 21:07:11 +00:00
// ---
// planar = If true, and p is not given, returns a 2D affine transformation matrix. Function use only. Default: False
2019-03-23 04:13:18 +00:00
//
// Example:
// xflip() yrot(90) cylinder(d1=10, d2=0, h=20);
// color("blue", 0.25) cube([0.01,15,15], center=true);
// color("red", 0.333) yrot(90) cylinder(d1=10, d2=0, h=20);
//
// Example:
2019-06-12 05:12:49 +00:00
// xflip(x=-5) yrot(90) cylinder(d1=10, d2=0, h=20);
2019-03-23 04:13:18 +00:00
// color("blue", 0.25) left(5) cube([0.01,15,15], center=true);
// color("red", 0.333) yrot(90) cylinder(d1=10, d2=0, h=20);
2021-02-26 21:07:11 +00:00
module xflip ( p , x = 0 , planar ) {
assert ( is_undef ( p ) , "Module form `zflip()` does not accept p= argument." ) ;
assert ( is_undef ( planar ) , "Module form `zflip()` does not accept planar= argument." ) ;
translate ( [ x , 0 , 0 ] )
mirror ( [ 1 , 0 , 0 ] )
translate ( [ - x , 0 , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function xflip ( p , x = 0 , planar = false ) =
assert ( is_finite ( x ) )
assert ( is_bool ( planar ) )
assert ( is_undef ( p ) || is_list ( p ) )
2021-02-15 08:28:36 +00:00
let (
v = RIGHT ,
n = planar ? point2d ( v ) : v
)
x = = 0 ? mirror ( n , p = p ) :
let (
cp = x * n ,
mat = move ( cp ) * mirror ( n ) * move ( - cp )
) is_undef ( p ) ? mat : apply ( mat , p ) ;
2019-03-23 04:13:18 +00:00
2019-12-04 10:24:34 +00:00
2020-01-07 00:31:16 +00:00
// Function&Module: yflip()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-15 08:28:36 +00:00
// yflip(<y>) ...
2019-12-04 10:24:34 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = yflip(p, <y>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// pt = yflip(<y>, <planar=>);
//
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), xflip(), zflip(), affine2d_mirror(), affine3d_mirror()
2019-12-04 10:24:34 +00:00
//
// Description:
// Mirrors/reflects across the origin [0,0,0], along the Y axis. If `y` is given, reflects across [0,y,0] instead.
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
2021-02-15 08:28:36 +00:00
// * Called as a function without a `p` argument, and `planar=true`, returns the affine2d 3x3 mirror matrix.
// * Called as a function without a `p` argument, and `planar=false`, returns the affine3d 4x4 mirror matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2021-02-26 21:07:11 +00:00
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2019-06-12 05:12:49 +00:00
// y = The Y coordinate of the plane of reflection. Default: 0
2021-02-26 21:07:11 +00:00
// ---
2021-02-15 08:28:36 +00:00
// planar = If true, and p is not given, returns a 2D affine transformation matrix. Function use only. Default: False
2019-03-23 04:13:18 +00:00
//
// Example:
// yflip() xrot(90) cylinder(d1=10, d2=0, h=20);
// color("blue", 0.25) cube([15,0.01,15], center=true);
// color("red", 0.333) xrot(90) cylinder(d1=10, d2=0, h=20);
//
2018-11-27 03:55:18 +00:00
// Example:
2019-06-12 05:12:49 +00:00
// yflip(y=5) xrot(90) cylinder(d1=10, d2=0, h=20);
2019-03-23 04:13:18 +00:00
// color("blue", 0.25) back(5) cube([15,0.01,15], center=true);
// color("red", 0.333) xrot(90) cylinder(d1=10, d2=0, h=20);
2021-02-26 21:07:11 +00:00
module yflip ( p , y = 0 , planar ) {
assert ( is_undef ( p ) , "Module form `yflip()` does not accept p= argument." ) ;
assert ( is_undef ( planar ) , "Module form `yflip()` does not accept planar= argument." ) ;
translate ( [ 0 , y , 0 ] )
mirror ( [ 0 , 1 , 0 ] )
translate ( [ 0 , - y , 0 ] ) children ( ) ;
}
2019-03-23 04:13:18 +00:00
2021-02-26 21:07:11 +00:00
function yflip ( p , y = 0 , planar = false ) =
assert ( is_finite ( y ) )
assert ( is_bool ( planar ) )
assert ( is_undef ( p ) || is_list ( p ) )
2021-02-15 08:28:36 +00:00
let (
v = BACK ,
n = planar ? point2d ( v ) : v
)
y = = 0 ? mirror ( n , p = p ) :
let (
cp = y * n ,
mat = move ( cp ) * mirror ( n ) * move ( - cp )
) is_undef ( p ) ? mat : apply ( mat , p ) ;
2019-12-04 10:24:34 +00:00
// Function&Module: zflip()
2019-03-23 04:13:18 +00:00
//
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-15 08:28:36 +00:00
// zflip(<z>) ...
2019-12-04 10:24:34 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = zflip(p, <z>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-15 08:28:36 +00:00
// pt = zflip(<z>);
2019-12-04 10:24:34 +00:00
//
2021-02-26 21:07:11 +00:00
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), xflip(), yflip(), affine2d_mirror(), affine3d_mirror()
//
2019-12-04 10:24:34 +00:00
// Description:
// Mirrors/reflects across the origin [0,0,0], along the Z axis. If `z` is given, reflects across [0,0,z] instead.
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
2021-02-15 08:28:36 +00:00
// * Called as a function without a `p` argument, returns the affine3d 4x4 mirror matrix.
2019-03-23 04:13:18 +00:00
//
// Arguments:
2021-02-15 08:28:36 +00:00
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2021-02-26 21:07:11 +00:00
// z = The Z coordinate of the plane of reflection. Default: 0
2019-03-23 04:13:18 +00:00
//
// Example:
// zflip() cylinder(d1=10, d2=0, h=20);
// color("blue", 0.25) cube([15,15,0.01], center=true);
// color("red", 0.333) cylinder(d1=10, d2=0, h=20);
//
// Example:
2019-06-12 05:12:49 +00:00
// zflip(z=-5) cylinder(d1=10, d2=0, h=20);
2019-03-23 04:13:18 +00:00
// color("blue", 0.25) down(5) cube([15,15,0.01], center=true);
// color("red", 0.333) cylinder(d1=10, d2=0, h=20);
2021-02-26 21:07:11 +00:00
module zflip ( p , z = 0 ) {
assert ( is_undef ( p ) , "Module form `zflip()` does not accept p= argument." ) ;
translate ( [ 0 , 0 , z ] )
mirror ( [ 0 , 0 , 1 ] )
translate ( [ 0 , 0 , - z ] ) children ( ) ;
}
2017-08-30 00:00:16 +00:00
2021-02-26 21:07:11 +00:00
function zflip ( p , z = 0 ) =
assert ( is_finite ( z ) )
assert ( is_undef ( p ) || is_list ( p ) )
2020-05-30 02:04:34 +00:00
z = = 0 ? mirror ( [ 0 , 0 , 1 ] , p = p ) :
move ( [ 0 , 0 , z ] , p = mirror ( [ 0 , 0 , 1 ] , p = move ( [ 0 , 0 , - z ] , p = p ) ) ) ;
2019-12-04 10:24:34 +00:00
2017-08-30 00:00:16 +00:00
2021-02-15 08:28:36 +00:00
// Function&Module: xyflip()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xyflip(<cp>) ...
2021-02-15 08:28:36 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = xyflip(p, <cp>);
2021-02-15 08:28:36 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// pt = xyflip(<cp>, <planar=>);
//
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), xflip(), yflip(), zflip(), xzflip(), yzflip(), affine2d_mirror(), affine3d_mirror()
2021-02-15 08:28:36 +00:00
//
// Description:
// Mirrors/reflects across the origin [0,0,0], along the reflection plane where X=Y. If `cp` is given, the reflection plane passes through that point
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
// * Called as a function without a `p` argument, and `planer=true`, returns the affine2d 3x3 mirror matrix.
// * Called as a function without a `p` argument, and `planar=false`, returns the affine3d 4x4 mirror matrix.
//
// Arguments:
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2021-02-26 21:07:11 +00:00
// cp = The centerpoint of the plane of reflection, given either as a point, or as a scalar distance away from the origin.
2021-02-15 08:28:36 +00:00
// ---
// planar = If true, and p is not given, returns a 2D affine transformation matrix. Function use only. Default: False
//
// Example(2D):
// xyflip() text("Foobar", size=20, halign="center");
//
// Example:
// left(10) frame_ref();
// right(10) xyflip() frame_ref();
//
// Example:
// xyflip(cp=-15) frame_ref();
//
// Example:
// xyflip(cp=[10,10,10]) frame_ref();
//
// Example: Called as Function for a 3D matrix
// mat = xyflip();
// multmatrix(mat) frame_ref();
//
// Example(2D): Called as Function for a 2D matrix
// mat = xyflip(planar=true);
// multmatrix(mat) text("Foobar", size=20, halign="center");
2021-02-26 21:07:11 +00:00
module xyflip ( p , cp = 0 , planar ) {
assert ( is_undef ( p ) , "Module form `xyflip()` does not accept p= argument." ) ;
assert ( is_undef ( planar ) , "Module form `xyflip()` does not accept planar= argument." ) ;
2021-02-15 08:28:36 +00:00
mat = xyflip ( cp = cp ) ;
multmatrix ( mat ) children ( ) ;
}
2021-02-26 21:07:11 +00:00
function xyflip ( p , cp = 0 , planar = false ) =
assert ( is_finite ( cp ) || is_vector ( cp ) )
2021-02-15 08:28:36 +00:00
let (
v = unit ( [ - 1 , 1 , 0 ] ) ,
n = planar ? point2d ( v ) : v
)
cp = = 0 || cp = = [ 0 , 0 , 0 ] ? mirror ( n , p = p ) :
let (
cp = is_finite ( cp ) ? n * cp :
is_vector ( cp ) ? assert ( len ( cp ) = = len ( n ) ) cp :
assert ( is_finite ( cp ) || is_vector ( cp ) ) ,
mat = move ( cp ) * mirror ( n ) * move ( - cp )
) is_undef ( p ) ? mat : apply ( mat , p ) ;
// Function&Module: xzflip()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// xzflip(<cp>) ...
2021-02-15 08:28:36 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = xzflip(<cp>, p);
2021-02-15 08:28:36 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// pt = xzflip(<cp>);
//
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), xflip(), yflip(), zflip(), xyflip(), yzflip(), affine2d_mirror(), affine3d_mirror()
2021-02-15 08:28:36 +00:00
//
// Description:
// Mirrors/reflects across the origin [0,0,0], along the reflection plane where X=Y. If `cp` is given, the reflection plane passes through that point
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
// * Called as a function without a `p` argument, returns the affine3d 4x4 mirror matrix.
//
// Arguments:
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2021-02-26 21:07:11 +00:00
// cp = The centerpoint of the plane of reflection, given either as a point, or as a scalar distance away from the origin.
2021-02-15 08:28:36 +00:00
//
// Example:
// left(10) frame_ref();
// right(10) xzflip() frame_ref();
//
// Example:
// xzflip(cp=-15) frame_ref();
//
// Example:
// xzflip(cp=[10,10,10]) frame_ref();
//
// Example: Called as Function
// mat = xzflip();
// multmatrix(mat) frame_ref();
2021-02-26 21:07:11 +00:00
module xzflip ( p , cp = 0 ) {
assert ( is_undef ( p ) , "Module form `xzflip()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
mat = xzflip ( cp = cp ) ;
multmatrix ( mat ) children ( ) ;
}
2021-02-26 21:07:11 +00:00
function xzflip ( p , cp = 0 ) =
assert ( is_finite ( cp ) || is_vector ( cp ) )
2021-02-15 08:28:36 +00:00
let ( n = unit ( [ - 1 , 0 , 1 ] ) )
cp = = 0 || cp = = [ 0 , 0 , 0 ] ? mirror ( n , p = p ) :
let (
cp = is_finite ( cp ) ? n * cp :
is_vector ( cp , 3 ) ? cp :
assert ( is_finite ( cp ) || is_vector ( cp , 3 ) ) ,
mat = move ( cp ) * mirror ( n ) * move ( - cp )
) is_undef ( p ) ? mat : apply ( mat , p ) ;
// Function&Module: yzflip()
//
// Usage: As Module
2021-02-26 21:07:11 +00:00
// yzflip(<x=>) ...
2021-02-15 08:28:36 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pt = yzflip(p, <x=>);
2021-02-15 08:28:36 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// pt = yzflip(<x=>);
//
// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
// See Also: mirror(), xflip(), yflip(), zflip(), xyflip(), xzflip(), affine2d_mirror(), affine3d_mirror()
2021-02-15 08:28:36 +00:00
//
// Description:
// Mirrors/reflects across the origin [0,0,0], along the reflection plane where X=Y. If `cp` is given, the reflection plane passes through that point
// * Called as the built-in module, mirrors all children across the line/plane.
// * Called as a function with a point in the `p` argument, returns the point mirrored across the line/plane.
// * Called as a function with a list of points in the `p` argument, returns the list of points, with each one mirrored across the line/plane.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the mirrored patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the mirrored VNF.
// * Called as a function without a `p` argument, returns the affine3d 4x4 mirror matrix.
//
// Arguments:
// p = If given, the point, path, patch, or VNF to mirror. Function use only.
2021-02-26 21:07:11 +00:00
// cp = The centerpoint of the plane of reflection, given either as a point, or as a scalar distance away from the origin.
2021-02-15 08:28:36 +00:00
//
// Example:
// left(10) frame_ref();
// right(10) yzflip() frame_ref();
//
// Example:
// yzflip(cp=-15) frame_ref();
//
// Example:
// yzflip(cp=[10,10,10]) frame_ref();
//
// Example: Called as Function
// mat = yzflip();
// multmatrix(mat) frame_ref();
2021-02-26 21:07:11 +00:00
module yzflip ( p , cp = 0 ) {
assert ( is_undef ( p ) , "Module form `yzflip()` does not accept p= argument." ) ;
2021-02-15 08:28:36 +00:00
mat = yzflip ( cp = cp ) ;
multmatrix ( mat ) children ( ) ;
}
2021-02-26 21:07:11 +00:00
function yzflip ( p , cp = 0 ) =
assert ( is_finite ( cp ) || is_vector ( cp ) )
2021-02-15 08:28:36 +00:00
let ( n = unit ( [ 0 , - 1 , 1 ] ) )
cp = = 0 || cp = = [ 0 , 0 , 0 ] ? mirror ( n , p = p ) :
let (
cp = is_finite ( cp ) ? n * cp :
is_vector ( cp , 3 ) ? cp :
assert ( is_finite ( cp ) || is_vector ( cp , 3 ) ) ,
mat = move ( cp ) * mirror ( n ) * move ( - cp )
) is_undef ( p ) ? mat : apply ( mat , p ) ;
2019-03-23 04:13:18 +00:00
//////////////////////////////////////////////////////////////////////
// Section: Skewing
//////////////////////////////////////////////////////////////////////
2017-08-30 00:00:16 +00:00
2019-12-20 05:03:13 +00:00
// Function&Module: skew()
2019-12-04 10:24:34 +00:00
// Usage: As Module
2021-02-26 21:07:11 +00:00
// skew(<sxy=>, <sxz=>, <syx=>, <syz=>, <szx=>, <szy=>) ...
2019-12-04 10:24:34 +00:00
// Usage: As Function
2021-02-26 21:07:11 +00:00
// pts = skew(p, <sxy=>, <sxz=>, <syx=>, <syz=>, <szx=>, <szy=>);
2019-12-04 10:24:34 +00:00
// Usage: Get Affine Matrix
2021-02-26 21:07:11 +00:00
// mat = skew(<sxy=>, <sxz=>, <syx=>, <syz=>, <szx=>, <szy=>, <planar=>);
// Topics: Affine, Matrices, Transforms, Skewing
// See Also: affine2d_skew(), affine3d_skew(), affine3d_skew_xy(), affine3d_skew_xz(), affine3d_skew_yz()
//
2019-12-04 10:24:34 +00:00
// Description:
2019-12-20 05:03:13 +00:00
// Skews geometry by the given skew factors.
2019-12-04 10:24:34 +00:00
// * Called as the built-in module, skews all children.
// * Called as a function with a point in the `p` argument, returns the skewed point.
// * Called as a function with a list of points in the `p` argument, returns the list of skewed points.
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the skewed patch.
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the skewed VNF.
// * Called as a function without a `p` argument, and with `planar` true, returns the affine2d 3x3 skew matrix.
// * Called as a function without a `p` argument, and with `planar` false, returns the affine3d 4x4 skew matrix.
2019-12-20 05:03:13 +00:00
// Each skew factor is a multiplier. For example, if `sxy=2`, then it will skew along the X axis by 2x the value of the Y axis.
2019-03-23 04:13:18 +00:00
// Arguments:
2021-02-26 21:07:11 +00:00
// p = If given, the point, path, patch, or VNF to skew. Function use only.
// ---
2019-12-20 05:03:13 +00:00
// sxy = Skew factor multiplier for skewing along the X axis as you get farther from the Y axis. Default: 0
// sxz = Skew factor multiplier for skewing along the X axis as you get farther from the Z axis. Default: 0
// syx = Skew factor multiplier for skewing along the Y axis as you get farther from the X axis. Default: 0
// syz = Skew factor multiplier for skewing along the Y axis as you get farther from the Z axis. Default: 0
// szx = Skew factor multiplier for skewing along the Z axis as you get farther from the X axis. Default: 0
// szy = Skew factor multiplier for skewing along the Z axis as you get farther from the Y axis. Default: 0
// Example(2D): Skew along the X axis in 2D.
// skew(sxy=0.5) square(40, center=true);
// Example(2D): Skew along the Y axis in 2D.
// skew(syx=0.5) square(40, center=true);
// Example: Skew along the X axis in 3D as a factor of Y coordinate.
// skew(sxy=0.5) cube(40, center=true);
// Example: Skew along the X axis in 3D as a factor of Z coordinate.
// skew(sxz=0.5) cube(40, center=true);
// Example: Skew along the Y axis in 3D as a factor of X coordinate.
// skew(syx=0.5) cube(40, center=true);
// Example: Skew along the Y axis in 3D as a factor of Z coordinate.
// skew(syz=0.5) cube(40, center=true);
// Example: Skew along the Z axis in 3D as a factor of X coordinate.
// skew(szx=0.5) cube(40, center=true);
// Example: Skew along the Z axis in 3D as a factor of Y coordinate.
// skew(szy=0.75) cube(40, center=true);
2021-02-20 03:56:43 +00:00
// Example(FlatSpin,VPD=275): Skew Along Multiple Axes.
2019-12-20 05:03:13 +00:00
// skew(sxy=0.5, syx=0.3, szy=0.75) cube(40, center=true);
// Example(2D): Calling as a 2D Function
// pts = skew(p=square(40,center=true), sxy=0.5);
// color("yellow") stroke(pts, closed=true);
2020-03-25 01:31:22 +00:00
// color("blue") move_copies(pts) circle(d=3, $fn=8);
2021-02-20 03:56:43 +00:00
// Example(FlatSpin,VPD=175): Calling as a 3D Function
2019-12-20 05:03:13 +00:00
// pts = skew(p=path3d(square(40,center=true)), szx=0.5, szy=0.3);
2020-11-17 01:50:08 +00:00
// trace_path(close_path(pts), showpts=true);
2021-02-26 21:07:11 +00:00
module skew ( p , sxy = 0 , sxz = 0 , syx = 0 , syz = 0 , szx = 0 , szy = 0 )
2019-12-20 05:03:13 +00:00
{
2021-02-26 21:07:11 +00:00
assert ( is_undef ( p ) , "Module form `skew()` does not accept p= argument." )
2020-05-30 02:04:34 +00:00
multmatrix (
affine3d_skew ( sxy = sxy , sxz = sxz , syx = syx , syz = syz , szx = szx , szy = szy )
) children ( ) ;
2019-12-20 05:03:13 +00:00
}
2019-03-23 04:13:18 +00:00
2019-12-20 05:03:13 +00:00
function skew ( p , sxy = 0 , sxz = 0 , syx = 0 , syz = 0 , szx = 0 , szy = 0 , planar = false ) =
2021-02-26 21:07:11 +00:00
assert ( is_finite ( sxy ) )
assert ( is_finite ( sxz ) )
assert ( is_finite ( syx ) )
assert ( is_finite ( syz ) )
assert ( is_finite ( szx ) )
assert ( is_finite ( szy ) )
assert ( is_bool ( planar ) )
2020-05-30 02:04:34 +00:00
let (
planar = planar || ( is_list ( p ) && is_num ( p . x ) && len ( p ) = = 2 ) ,
m = planar ? [
[ 1 , sxy , 0 ] ,
[ syx , 1 , 0 ] ,
[ 0 , 0 , 1 ]
] : affine3d_skew ( sxy = sxy , sxz = sxz , syx = syx , syz = syz , szx = szx , szy = szy )
)
is_undef ( p ) ? m :
assert ( is_list ( p ) )
is_num ( p . x ) ? (
planar ?
point2d ( m * concat ( point2d ( p ) , [ 1 ] ) ) :
point3d ( m * concat ( point3d ( p ) , [ 1 ] ) )
) :
is_vnf ( p ) ? [ skew ( sxy = sxy , sxz = sxz , syx = syx , syz = syz , szx = szx , szy = szy , planar = planar , p = p . x ) , p . y ] :
[ for ( l = p ) skew ( sxy = sxy , sxz = sxz , syx = syx , syz = syz , szx = szx , szy = szy , planar = planar , p = l ) ] ;
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap