Merge pull request #128 from adrianVmariano/master

2 bug fixes
This commit is contained in:
Revar Desmera 2020-03-01 14:27:31 -08:00 committed by GitHub
commit f250f30044
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 91 additions and 83 deletions

View file

@ -259,6 +259,49 @@ function affine3d_rot_from_to(from, to) = let(
];
// Function: affine_frame_map()
// Usage: map = affine_frame_map(x=v1,y=v2);
// map = affine_frame_map(x=v1,z=v2);
// map = affine_frame_map(y=v1,y=v2);
// map = affine_frame_map(v1,v2,v3);
// Description:
// Returns a transformation that maps one coordinate frame to another. You must specify two or three of `x`, `y`, and `z`. The specified
// axes are mapped to the vectors you supplied. If you give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand coordinate system.
// If the vectors you give are orthogonal the result will be a rotation. The `reverse` parameter will supply the inverse map, which enables you
// to map two arbitrary coordinate systems two each other by using the canonical coordinate system as an intermediary.
// Arguments:
// x = Destination vector for x axis
// y = Destination vector for y axis
// z = Destination vector for z axis
// reverse = reverse direction of the map. Default: false
// Examples:
// T = affine_frame_map(x=[1,1,0], y=[-1,1]); // This map is just a rotation around the z axis
// T = affine_frame_map(x=[1,0,0], y=[1,1]); // This map is not a rotation because x and y aren't orthogonal
// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
// T = affine_frame_map(x=[0,1,1], y=[0,-1,1]) * affine_frame_map(x=[1,1,0], y=[-1,1,0],reverse=true);
function affine_frame_map(x,y,z, reverse=false) =
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
let(
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
)
assert(xvalid,"Input x must be a length 3 vector")
assert(yvalid,"Input y must be a length 3 vector")
assert(zvalid,"Input z must be a length 3 vector")
let(
x = is_def(x) ? normalize(x) : undef,
y = is_def(y) ? normalize(y) : undef,
z = is_def(z) ? normalize(z) : undef,
map = is_undef(x) ? [cross(y,z), y, z] :
is_undef(y) ? [x, cross(z,x), z] :
is_undef(z) ? [x, y, cross(x,y)] :
[x, y, z]
)
reverse ? affine2d_to_3d(map) : affine2d_to_3d(transpose(map));
// Function: affine3d_mirror()
// Usage:
// mat = affine3d_mirror(v);
@ -441,4 +484,7 @@ function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][
(t[2][2]==1 || !(t[0][0]==1 && t[0][1]==0 && t[1][0]==0 && t[1][1]==1)); // But rule out zscale()
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -1030,13 +1030,13 @@ function polygon_shift_to_closest_point(path, pt) =
// Usage:
// newpoly = reindex_polygon(reference, poly);
// Description:
// Rotates and possibly reverses the point order of a polygon path to optimize its pairwise point
// association with a reference polygon. The two polygons must have the same number of vertices.
// Rotates and possibly reverses the point order of a 2d or 3d polygon path to optimize its pairwise point
// association with a reference polygon. The two polygons must have the same number of vertices and be the same dimension.
// The optimization is done by computing the distance, norm(reference[i]-poly[i]), between
// corresponding pairs of vertices of the two polygons and choosing the polygon point order that
// makes the total sum over all pairs as small as possible. Returns the reindexed polygon. Note
// that the geometry of the polygon is not changed by this operation, just the labeling of its
// vertices. If the input polygon is oriented opposite the reference then its point order is
// vertices. If the input polygon is 2d and is oriented opposite the reference then its point order is
// flipped.
// Arguments:
// reference = reference polygon path

View file

@ -556,7 +556,7 @@ module dovetail(gender, length, l, width, w, height, h, angle, slope, taper, bac
reverse(concat(smallend_points, xflip(p=reverse(smallend_points)))),
reverse(concat(bigend_points, xflip(p=reverse(bigend_points))))
],
convexity=4, slices=0
slices=0, convexity=4
);
}
children();

View file

@ -532,6 +532,43 @@ function mean(v) = sum(v)/len(v);
// Section: Matrix math
// Function: linear_solve()
// Usage: linear_solve(A,b)
// Description:
// Solves the linear system Ax=b. If A is square and non-singular the unique solution is returned. If A is overdetermined
// the least squares solution is returned. If A is underdetermined, the minimal norm solution is returned.
// If A is rank deficient or singular then linear_solve returns `undef`.
function linear_solve(A,b) =
let(
dim = array_dim(A),
m=dim[0], n=dim[1]
)
assert(len(b)==m,str("Incompatible matrix and vector",dim,len(b)))
let (
qr = m<n ? qr_factor(transpose(A)) : qr_factor(A),
maxdim = max(n,m),
mindim = min(n,m),
Q = submatrix(qr[0],[0:maxdim-1], [0:mindim-1]),
R = submatrix(qr[1],[0:mindim-1], [0:mindim-1]),
zeros = [for(i=[0:mindim-1]) if (approx(R[i][i],0)) i]
)
zeros != [] ? undef :
m<n ? Q*back_substitute(R,b,transpose=true) :
back_substitute(R, transpose(Q)*b);
// Function: submatrix()
// Usage: submatrix(M, ind1, ind2)
// Description:
// Returns a submatrix with the specified index ranges or index sets.
function submatrix(M,ind1,ind2) =
[for(i=ind1)
[for(j=ind2)
M[i][j]
]
];
// Function: qr_factor()
// Usage: qr = qr_factor(A)
// Description:
@ -563,41 +600,6 @@ function _qr_factor(A,Q, column, m, n) =
_qr_factor(Qf*A, Q*Qf, column+1, m, n);
// Function: submatrix()
// Usage: submatrix(M, ind1, ind2)
// Description:
// Returns a submatrix with the specified index ranges or index sets.
function submatrix(M,ind1,ind2) =
[for(i=ind1)
[for(j=ind2)
M[i][j]
]
];
// Function: linear_solve()
// Usage: linear_solve(A,b)
// Description:
// Solves the linear system Ax=b. If A is square and non-singular the unique solution is returned. If A is overdetermined
// the least squares solution is returned. If A is underdetermined, the minimal norm solution is returned.
// If A is rank deficient or singular then linear_solve returns `undef`.
function linear_solve(A,b) =
let(
dim = array_dim(A),
m=dim[0], n=dim[1]
)
assert(len(b)==m,str("Incompatible matrix and vector",dim,len(b)))
let (
qr = m<n ? qr_factor(transpose(A)) : qr_factor(A),
maxdim = max(n,m),
mindim = min(n,m),
Q = submatrix(qr[0],[0:maxdim-1], [0:mindim-1]),
R = submatrix(qr[1],[0:mindim-1], [0:mindim-1]),
zeros = [for(i=[0:mindim-1]) if (approx(R[i][i],0)) i]
)
zeros != [] ? undef :
m<n ? Q*back_substitute(R,b,transpose=true) :
back_substitute(R, transpose(Q)*b);
// Function: back_substitute()
// Usage: back_substitute(R, b, [transpose])
@ -814,7 +816,7 @@ function count_true(l, nmax=undef, i=0, cnt=0) =
// Section: Calculus
// Function deriv()
// Function: deriv()
// Usage: deriv(data, [h], [closed])
// Description:
// Computes a numerical derivative estimate of the data, which may be scalar or vector valued.
@ -839,7 +841,7 @@ function deriv(data, h=1, closed=false) =
last/2/h];
// Function deriv2()
// Function: deriv2()
// Usage: deriv2(data, [h], [closed])
// Description:
// Computes a numerical esimate of the second derivative of the data, which may be scalar or vector valued.
@ -869,7 +871,7 @@ function deriv2(data, h=1, closed=false) =
// Function deriv3()
// Function: deriv3()
// Usage: deriv3(data, [h], [closed])
// Description:
// Computes a numerical third derivative estimate of the data, which may be scalar or vector valued.

View file

@ -779,46 +779,6 @@ module sweep(shape, transformations, closed=false, caps, convexity=10) {
vnf_polyhedron(sweep(shape, transformations, closed, caps), convexity=convexity);
}
// Function: affine_frame_map()
// Usage: map = affine_frame_map(x=v1,y=v2);
// map = affine_frame_map(x=v1,z=v2);
// map = affine_frame_map(y=v1,y=v2);
// map = affine_frame_map(v1,v2,v3);
// Description:
// Returns a transformation that maps one coordinate frame to another. You must specify two or three of `x`, `y`, and `z`. The specified
// axes are mapped to the vectors you supplied. If you give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand coordinate system.
// If the vectors you give are orthogonal the result will be a rotation. The `reverse` parameter will supply the inverse map, which enables you
// to map two arbitrary coordinate systems two each other by using the canonical coordinate system as an intermediary.
// Arguments:
// x = Destination vector for x axis
// y = Destination vector for y axis
// z = Destination vector for z axis
// reverse = reverse direction of the map. Default: false
// Examples:
// T = affine_frame_map(x=[1,1,0], y=[-1,1]); // This map is just a rotation around the z axis
// T = affine_frame_map(x=[1,0,0], y=[1,1]); // This map is not a rotation because x and y aren't orthogonal
// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
// T = affine_frame_map(x=[0,1,1], y=[0,-1,1]) * affine_frame_map(x=[1,1,0], y=[-1,1,0],reverse=true);
function affine_frame_map(x,y,z, reverse=false) =
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
let(
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
)
assert(xvalid,"Input x must be a length 3 vector")
assert(yvalid,"Input y must be a length 3 vector")
assert(zvalid,"Input z must be a length 3 vector")
let(
x = is_def(x) ? normalize(x) : undef,
y = is_def(y) ? normalize(y) : undef,
z = is_def(z) ? normalize(z) : undef,
map = is_undef(x) ? [cross(y,z), y, z] :
is_undef(y) ? [x, cross(z,x), z] :
is_undef(z) ? [x, y, cross(x,y)] :
[x, y, z]
)
reverse ? affine2d_to_3d(map) : affine2d_to_3d(transpose(map));
// Function&Module: path_sweep()
// Usage: path_sweep(shape, path, [method], [normal], [closed], [twist], [twist_by_length], [symmetry], [last_normal], [tangent], [relaxed], [caps], [convexity], [transforms])
@ -1091,7 +1051,7 @@ function affine_frame_map(x,y,z, reverse=false) =
// path_sweep(ushape,knot_path,normal=normals, method="manual", closed=true);
// Example: You can request the transformations and manipulate them before passing them on to sweep. Here we construct a tube that changes scale by first generating the transforms and then applying the scale factor and connecting the inside and outside. Note that the wall thickness varies because it is produced by scaling.
// shape = star(n=5, r=10, ir=5);
// rpath = arc(25, points=[[-30,0,0], [-3,1,7], [0,3,6]]);
// rpath = arc(25, points=[[29,6,-4], [3,4,6], [1,1,7]]);
// trans = path_sweep(shape, rpath, transforms=true);
// outside = [for(i=[0:len(trans)-1]) trans[i]*scale(lerp(1,1.5,i/(len(trans)-1)))];
// inside = [for(i=[len(trans)-1:-1:0]) trans[i]*scale(lerp(1.1,1.4,i/(len(trans)-1)))];