mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
commit
4c19981e97
10 changed files with 255 additions and 430 deletions
15
arrays.scad
15
arrays.scad
|
@ -1369,11 +1369,10 @@ function triplet(list, wrap=false) =
|
|||
// Function: combinations()
|
||||
// Usage:
|
||||
// list = combinations(l, [n]);
|
||||
// for (p = combinations(l, [n])) ...
|
||||
// Topics: List Handling, Iteration
|
||||
// See Also: idx(), enumerate(), pair(), triplet(), permutations()
|
||||
// Description:
|
||||
// Returns an ordered list of every unique permutation of `n` items out of the given list `l`.
|
||||
// Returns a list of all of the (unordered) combinations of `n` items out of the given list `l`.
|
||||
// For the list `[1,2,3,4]`, with `n=2`, this will return `[[1,2], [1,3], [1,4], [2,3], [2,4], [3,4]]`.
|
||||
// For the list `[1,2,3,4]`, with `n=3`, this will return `[[1,2,3], [1,2,4], [1,3,4], [2,3,4]]`.
|
||||
// Arguments:
|
||||
|
@ -1395,21 +1394,17 @@ function combinations(l,n=2,_s=0) =
|
|||
// Function: permutations()
|
||||
// Usage:
|
||||
// list = permutations(l, [n]);
|
||||
// for (p = permutations(l, [n])) ...
|
||||
// Topics: List Handling, Iteration
|
||||
// See Also: idx(), enumerate(), pair(), triplet(), combinations()
|
||||
// Description:
|
||||
// Returns an ordered list of every unique permutation of `n` items out of the given list `l`.
|
||||
// For the list `[1,2,3,4]`, with `n=2`, this will return `[[1,2], [1,3], [1,4], [2,3], [2,4], [3,4]]`.
|
||||
// For the list `[1,2,3,4]`, with `n=3`, this will return `[[1,2,3], [1,2,4], [1,3,4], [2,3,4]]`.
|
||||
// Returns a list of all of the (ordered) permutation `n` items out of the given list `l`.
|
||||
// For the list `[1,2,3]`, with `n=2`, this will return `[[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]`
|
||||
// For the list `[1,2,3]`, with `n=3`, this will return `[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]`
|
||||
// Arguments:
|
||||
// l = The list to provide permutations for.
|
||||
// n = The number of items in each permutation. Default: 2
|
||||
// Example:
|
||||
// pairs = permutations([3,4,5,6]); // Returns: [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]
|
||||
// triplets = permutations([3,4,5,6],n=3); // Returns: [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]
|
||||
// Example(2D):
|
||||
// for (p=permutations(regular_ngon(n=7,d=100))) stroke(p);
|
||||
// pairs = permutations([3,4,5,6]); // // Returns: [[3,4],[3,5],[3,6],[4,3],[4,5],[4,6],[5,3],[5,4],[5,6],[6,3],[6,4],[6,5]]
|
||||
function permutations(l,n=2) =
|
||||
assert(is_list(l), "Invalid list." )
|
||||
assert( is_finite(n) && n>=1 && n<=len(l), "Invalid number `n`." )
|
||||
|
|
|
@ -232,7 +232,7 @@ module attach(from, to, overlap, norot=false)
|
|||
}
|
||||
}
|
||||
|
||||
// Attachment Modifiers
|
||||
// Section: Attachment Modifiers
|
||||
|
||||
// Module: tags()
|
||||
// Usage:
|
||||
|
@ -1673,7 +1673,7 @@ function _find_anchor(anchor, geom) =
|
|||
for (t=triplet(path,true)) let(
|
||||
seg1 = [t[0],t[1]],
|
||||
seg2 = [t[1],t[2]],
|
||||
isect = ray_segment_intersection([[0,0],anchor], seg1),
|
||||
isect = line_intersection([[0,0],anchor], seg1,RAY,SEGMENT),
|
||||
n = is_undef(isect)? [0,1] :
|
||||
!approx(isect, t[1])? line_normal(seg1) :
|
||||
unit((line_normal(seg1)+line_normal(seg2))/2,[0,1]),
|
||||
|
@ -1708,7 +1708,7 @@ function _find_anchor(anchor, geom) =
|
|||
for (t=triplet(path,true)) let(
|
||||
seg1 = [t[0],t[1]],
|
||||
seg2 = [t[1],t[2]],
|
||||
isect = ray_segment_intersection([[0,0],xyanch], seg1),
|
||||
isect = line_intersection([[0,0],xyanch], seg1, RAY, SEGMENT),
|
||||
n = is_undef(isect)? [0,1] :
|
||||
!approx(isect, t[1])? line_normal(seg1) :
|
||||
unit((line_normal(seg1)+line_normal(seg2))/2,[0,1]),
|
||||
|
|
|
@ -1119,7 +1119,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient)
|
|||
[0,W/2]
|
||||
];
|
||||
|
||||
isect400 = [for(seg=pair(beadpts)) let(segisect = line_segment_intersection([[T/2,0],[T/2,1]] , seg)) if (is_def(segisect)) segisect.y];
|
||||
isect400 = [for(seg=pair(beadpts)) let(segisect = line_intersection([[T/2,0],[T/2,1]] , seg, LINE, SEGMENT)) if (is_def(segisect)) segisect.y];
|
||||
|
||||
extra_bot = type==400 && bead ? -min(subindex(beadpts,1))+max(isect400) : 0;
|
||||
bead_shift = type==400 ? H+max(isect400) : entry[5]+W/2; // entry[5] is L
|
||||
|
|
|
@ -190,4 +190,37 @@ CTR = CENTER;
|
|||
|
||||
|
||||
|
||||
// Constant: SEGMENT
|
||||
// Topics: Constants, Lines
|
||||
// See Also: RAY, LINE
|
||||
// Description: Treat a line as a segment. [true, true]
|
||||
// Example: Usage with line_intersection:
|
||||
// line1 = 10*[[9, 4], [5, 7]];
|
||||
// line2 = 10*[[2, 3], [6, 5]];
|
||||
// isect = line_intersection(line1, line2, SEGMENT, SEGMENT);
|
||||
SEGMENT = [true,true];
|
||||
|
||||
|
||||
// Constant: RAY
|
||||
// Topics: Constants, Lines
|
||||
// See Also: SEGMENT, LINE
|
||||
// Description: Treat a line as a ray, based at the first point. [true, false]
|
||||
// Example: Usage with line_intersection:
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// closest = line_closest_point(line,pt,RAY);
|
||||
RAY = [true, false];
|
||||
|
||||
|
||||
// Constant: LINE
|
||||
// Topics: Constants, Lines
|
||||
// See Also: RAY, SEGMENT
|
||||
// Description: Treat a line as an unbounded line. [false, false]
|
||||
// Example: Usage with line_intersection:
|
||||
// line1 = 10*[[9, 4], [5, 7]];
|
||||
// line2 = 10*[[2, 3], [6, 5]];
|
||||
// isect = line_intersection(line1, line2, LINE, SEGMENT);
|
||||
LINE = [false, false];
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
446
geometry.scad
446
geometry.scad
|
@ -8,9 +8,9 @@
|
|||
|
||||
// Section: Lines, Rays, and Segments
|
||||
|
||||
// Function: point_on_segment2d()
|
||||
// Function: point_on_segment()
|
||||
// Usage:
|
||||
// pt = point_on_segment2d(point, edge);
|
||||
// pt = point_on_segment(point, edge);
|
||||
// Topics: Geometry, Points, Segments
|
||||
// Description:
|
||||
// Determine if the point is on the line segment between two points.
|
||||
|
@ -19,9 +19,9 @@
|
|||
// point = The point to test.
|
||||
// edge = Array of two points forming the line segment to test against.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function point_on_segment2d(point, edge, eps=EPSILON) =
|
||||
function point_on_segment(point, edge, eps=EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
point_segment_distance(point, edge)<eps;
|
||||
point_line_distance(point, edge, SEGMENT)<eps;
|
||||
|
||||
|
||||
//Internal - distance from point `d` to the line passing through the origin with unit direction n
|
||||
|
@ -83,40 +83,28 @@ function collinear(a, b, c, eps=EPSILON) =
|
|||
|
||||
// Function: point_line_distance()
|
||||
// Usage:
|
||||
// pt = point_line_distance(line, pt);
|
||||
// pt = point_line_distance(line, pt, bounded);
|
||||
// Topics: Geometry, Points, Lines, Distance
|
||||
// Description:
|
||||
// Finds the perpendicular distance of a point `pt` from the line `line`.
|
||||
// Finds the shortest distance from the point `pt` to the specified line, segment or ray.
|
||||
// The bounded parameter specifies the whether the endpoints give a ray or segment.
|
||||
// By default assumes an unbounded line.
|
||||
// Arguments:
|
||||
// line = A list of two points, defining a line that both are on.
|
||||
// line = A list of two points defining a line.
|
||||
// pt = A point to find the distance of from the line.
|
||||
// bounded = a boolean or list of two booleans specifiying whether each end is bounded. Default: false
|
||||
// Example:
|
||||
// dist = point_line_distance([3,8], [[-10,0], [10,0]]); // Returns: 8
|
||||
function point_line_distance(pt, line) =
|
||||
// dist1 = point_line_distance([3,8], [[-10,0], [10,0]]); // Returns: 8
|
||||
// dist2 = point_line_distance([3,8], [[-10,0], [10,0]],SEGMENT); // Returns: 8
|
||||
// dist3 = point_line_distance([14,3], [[-10,0], [10,0]],SEGMENT); // Returns: 5
|
||||
function point_line_distance(pt, line, bounded=false) =
|
||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "\"bounded\" is invalid")
|
||||
assert( _valid_line(line) && is_vector(pt,len(line[0])),
|
||||
"Invalid line, invalid point or incompatible dimensions." )
|
||||
_dist2line(pt-line[0],unit(line[1]-line[0]));
|
||||
|
||||
|
||||
// Function: point_segment_distance()
|
||||
// Usage:
|
||||
// dist = point_segment_distance(pt, seg);
|
||||
// Topics: Geometry, Points, Segments, Distance
|
||||
// Description:
|
||||
// Returns the closest distance of the given point to the given line segment.
|
||||
// Arguments:
|
||||
// pt = The point to check the distance of.
|
||||
// seg = The two points representing the line segment to check the distance of.
|
||||
// Example:
|
||||
// dist = point_segment_distance([3,8], [[-10,0], [10,0]]); // Returns: 8
|
||||
// dist2 = point_segment_distance([14,3], [[-10,0], [10,0]]); // Returns: 5
|
||||
function point_segment_distance(pt, seg) =
|
||||
assert( is_matrix(concat([pt],seg),3),
|
||||
"Input should be a point and a valid segment with the dimension equal to the point." )
|
||||
norm(seg[0]-seg[1]) < EPSILON ? norm(pt-seg[0]) :
|
||||
norm(pt-segment_closest_point(seg,pt));
|
||||
|
||||
bounded == LINE ? _dist2line(pt-line[0],unit(line[1]-line[0]))
|
||||
: norm(pt-line_closest_point(line,pt,bounded));
|
||||
|
||||
|
||||
// Function: segment_distance()
|
||||
// Usage:
|
||||
// dist = segment_distance(seg1, seg2);
|
||||
|
@ -178,135 +166,79 @@ function _general_line_intersection(s1,s2,eps=EPSILON) =
|
|||
) [s1[0]+t*(s1[1]-s1[0]), t, u];
|
||||
|
||||
|
||||
|
||||
// Function: line_intersection()
|
||||
// Usage:
|
||||
// pt = line_intersection(l1, l2);
|
||||
// Topics: Geometry, Lines, Intersections
|
||||
// pt = line_intersection(line1, line2, [bounded1], [bounded2], [bounded=], [eps=]);
|
||||
// Description:
|
||||
// Returns the 2D intersection point of two unbounded 2D lines.
|
||||
// Returns `undef` if the lines are parallel.
|
||||
// Returns the intersection point of any two 2D lines, segments or rays. Returns undef
|
||||
// if they do not intersect. You specify a line by giving two distinct points on the
|
||||
// line. You specify rays or segments by giving a pair of points and indicating
|
||||
// bounded[0]=true to bound the line at the first point, creating rays based at l1[0] and l2[0],
|
||||
// or bounded[1]=true to bound the line at the second point, creating the reverse rays bounded
|
||||
// at l1[1] and l2[1]. If bounded=[true, true] then you have segments defined by their two
|
||||
// endpoints. By using bounded1 and bounded2 you can mix segments, rays, and lines as needed.
|
||||
// You can set the bounds parameters to true as a shorthand for [true,true] to sepcify segments.
|
||||
// Arguments:
|
||||
// l1 = First 2D line, given as a list of two 2D points on the line.
|
||||
// l2 = Second 2D line, given as a list of two 2D points on the line.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function line_intersection(l1,l2,eps=EPSILON) =
|
||||
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
||||
assert( _valid_line(l1,dim=2,eps=eps) &&_valid_line(l2,dim=2,eps=eps), "Invalid line(s)." )
|
||||
// line1 = List of two points in 2D defining the first line, segment or ray
|
||||
// line2 = List of two points in 2D defining the second line, segment or ray
|
||||
// bounded1 = boolean or list of two booleans defining which ends are bounded for line1. Default: [false,false]
|
||||
// bounded2 = boolean or list of two booleans defining which ends are bounded for line2. Default: [false,false]
|
||||
// ---
|
||||
// bounded = boolean or list of two booleans defining which ends are bounded for both lines. The bounded1 and bounded2 parameters override this if both are given.
|
||||
// eps = tolerance for geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
// Example(2D): The segments do not intersect but the lines do in this example.
|
||||
// line1 = 10*[[9, 4], [5, 7]];
|
||||
// line2 = 10*[[2, 3], [6, 5]];
|
||||
// stroke(line1, endcaps="arrow2");
|
||||
// stroke(line2, endcaps="arrow2");
|
||||
// isect = line_intersection(line1, line2);
|
||||
// color("red") translate(isect) circle(r=1,$fn=12);
|
||||
// Example(2D): Specifying a ray and segment using the shorthand variables.
|
||||
// line1 = 10*[[0, 2], [4, 7]];
|
||||
// line2 = 10*[[10, 4], [3, 4]];
|
||||
// stroke(line1);
|
||||
// stroke(line2, endcap2="arrow2");
|
||||
// isect = line_intersection(line1, line2, SEGMENT, RAY);
|
||||
// color("red") translate(isect) circle(r=1,$fn=12);
|
||||
// Example(2D): Here we use the same example as above, but specify two segments using the bounded argument.
|
||||
// line1 = 10*[[0, 2], [4, 7]];
|
||||
// line2 = 10*[[10, 4], [3, 4]];
|
||||
// stroke(line1);
|
||||
// stroke(line2);
|
||||
// isect = line_intersection(line1, line2, bounded=true); // Returns undef
|
||||
function line_intersection(line1, line2, bounded1, bounded2, bounded, eps=EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
let(isect = _general_line_intersection(l1,l2,eps=eps))
|
||||
isect[0];
|
||||
|
||||
|
||||
// Function: line_ray_intersection()
|
||||
// Usage:
|
||||
// pt = line_ray_intersection(line, ray);
|
||||
// Topics: Geometry, Lines, Rays, Intersections
|
||||
// Description:
|
||||
// Returns the 2D intersection point of an unbounded 2D line, and a half-bounded 2D ray.
|
||||
// Returns `undef` if they do not intersect.
|
||||
// Arguments:
|
||||
// line = The unbounded 2D line, defined by two 2D points on the line.
|
||||
// ray = The 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function line_ray_intersection(line,ray,eps=EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
assert( _valid_line(line,dim=2,eps=eps) && _valid_line(ray,dim=2,eps=eps), "Invalid line or ray." )
|
||||
let( isect = _general_line_intersection(line,ray,eps=eps) )
|
||||
assert( _valid_line(line1,dim=2,eps=eps), "First line invalid")
|
||||
assert( _valid_line(line2,dim=2,eps=eps), "Second line invalid")
|
||||
assert( is_undef(bounded) || is_bool(bounded) || is_bool_list(bounded,2), "Invalid value for \"bounded\"")
|
||||
assert( is_undef(bounded1) || is_bool(bounded1) || is_bool_list(bounded1,2), "Invalid value for \"bounded1\"")
|
||||
assert( is_undef(bounded2) || is_bool(bounded2) || is_bool_list(bounded2,2), "Invalid value for \"bounded2\"")
|
||||
let(isect = _general_line_intersection(line1,line2,eps=eps))
|
||||
is_undef(isect[0]) ? undef :
|
||||
(isect[2]<0-eps) ? undef :
|
||||
isect[0];
|
||||
|
||||
|
||||
// Function: line_segment_intersection()
|
||||
// Usage:
|
||||
// pt = line_segment_intersection(line, segment);
|
||||
// Topics: Geometry, Lines, Segments, Intersections
|
||||
// Description:
|
||||
// Returns the 2D intersection point of an unbounded 2D line, and a bounded 2D line segment.
|
||||
// Returns `undef` if they do not intersect.
|
||||
// Arguments:
|
||||
// line = The unbounded 2D line, defined by two 2D points on the line.
|
||||
// segment = The bounded 2D line segment, given as a list of the two 2D endpoints of the segment.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function line_segment_intersection(line,segment,eps=EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
assert( _valid_line(line, dim=2,eps=eps) &&_valid_line(segment,dim=2,eps=eps), "Invalid line or segment." )
|
||||
let( isect = _general_line_intersection(line,segment,eps=eps) )
|
||||
is_undef(isect[0]) ? undef :
|
||||
isect[2]<0-eps || isect[2]>1+eps ? undef :
|
||||
isect[0];
|
||||
|
||||
|
||||
// Function: ray_intersection()
|
||||
// Usage:
|
||||
// pt = ray_intersection(s1, s2);
|
||||
// Topics: Geometry, Lines, Rays, Intersections
|
||||
// Description:
|
||||
// Returns the 2D intersection point of two 2D line rays.
|
||||
// Returns `undef` if they do not intersect.
|
||||
// Arguments:
|
||||
// r1 = First 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
|
||||
// r2 = Second 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function ray_intersection(r1,r2,eps=EPSILON) =
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
assert( _valid_line(r1,dim=2,eps=eps) && _valid_line(r2,dim=2,eps=eps), "Invalid ray(s)." )
|
||||
let( isect = _general_line_intersection(r1,r2,eps=eps) )
|
||||
is_undef(isect[0]) ? undef :
|
||||
isect[1]<0-eps || isect[2]<0-eps ? undef :
|
||||
isect[0];
|
||||
|
||||
|
||||
// Function: ray_segment_intersection()
|
||||
// Usage:
|
||||
// pt = ray_segment_intersection(ray, segment);
|
||||
// Topics: Geometry, Rays, Segments, Intersections
|
||||
// Description:
|
||||
// Returns the 2D intersection point of a half-bounded 2D ray, and a bounded 2D line segment.
|
||||
// Returns `undef` if they do not intersect.
|
||||
// Arguments:
|
||||
// ray = The 2D ray, given as a list `[START,POINT]` of the 2D start-point START, and a 2D point POINT on the ray.
|
||||
// segment = The bounded 2D line segment, given as a list of the two 2D endpoints of the segment.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function ray_segment_intersection(ray,segment,eps=EPSILON) =
|
||||
assert( _valid_line(ray,dim=2,eps=eps) && _valid_line(segment,dim=2,eps=eps), "Invalid ray or segment." )
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
let( isect = _general_line_intersection(ray,segment,eps=eps) )
|
||||
is_undef(isect[0]) ? undef :
|
||||
isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
|
||||
isect[0];
|
||||
|
||||
|
||||
// Function: segment_intersection()
|
||||
// Usage:
|
||||
// pt = segment_intersection(s1, s2);
|
||||
// Topics: Geometry, Segments, Intersections
|
||||
// Description:
|
||||
// Returns the 2D intersection point of two 2D line segments.
|
||||
// Returns `undef` if they do not intersect.
|
||||
// Arguments:
|
||||
// s1 = First 2D segment, given as a list of the two 2D endpoints of the line segment.
|
||||
// s2 = Second 2D segment, given as a list of the two 2D endpoints of the line segment.
|
||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||
function segment_intersection(s1,s2,eps=EPSILON) =
|
||||
assert( _valid_line(s1,dim=2,eps=eps) && _valid_line(s2,dim=2,eps=eps), "Invalid segment(s)." )
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
let( isect = _general_line_intersection(s1,s2,eps=eps) )
|
||||
is_undef(isect[0]) ? undef :
|
||||
isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
|
||||
isect[0];
|
||||
|
||||
let(
|
||||
bounded1 = force_list(first_defined([bounded1,bounded,false]),2),
|
||||
bounded2 = force_list(first_defined([bounded2,bounded,false]),2),
|
||||
good = (!bounded1[0] || isect[1]>=0-eps)
|
||||
&& (!bounded1[1] || isect[1]<=1+eps)
|
||||
&& (!bounded2[0] || isect[2]>=0-eps)
|
||||
&& (!bounded2[1] || isect[2]<=1+eps)
|
||||
)
|
||||
good ? isect[0] : undef;
|
||||
|
||||
|
||||
// Function: line_closest_point()
|
||||
// Usage:
|
||||
// pt = line_closest_point(line,pt);
|
||||
// pt = line_closest_point(line, pt, [bounded]);
|
||||
// Topics: Geometry, Lines, Distance
|
||||
// Description:
|
||||
// Returns the point on the given 2D or 3D `line` that is closest to the given point `pt`.
|
||||
// The `line` and `pt` args should either both be 2D or both 3D.
|
||||
// Returns the point on the given 2D or 3D line, segment or ray that is closest to the given point `pt`.
|
||||
// The inputs `line` and `pt` args should either both be 2D or both 3D. The parameter bounded indicates
|
||||
// whether the points of `line` should be treated as endpoints.
|
||||
// Arguments:
|
||||
// line = A list of two points that are on the unbounded line.
|
||||
// pt = The point to find the closest point on the line to.
|
||||
// bounded = boolean or list of two booleans indicating that the line is bounded at that end. Default: [false,false]
|
||||
// Example(2D):
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [-32,-10];
|
||||
|
@ -314,169 +246,70 @@ function segment_intersection(s1,s2,eps=EPSILON) =
|
|||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// Example(2D): If the line is bounded on the left you get the endpoint instead
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [-5,0];
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// line = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [5,5,5];
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// line = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [-35,-15,0];
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// line = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [40,15,25];
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
function line_closest_point(line,pt) =
|
||||
assert(_valid_line(line), "Invalid line." )
|
||||
assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." )
|
||||
let( n = unit( line[0]- line[1]) )
|
||||
line[1] + ((pt- line[1]) * n) * n;
|
||||
|
||||
|
||||
// Function: ray_closest_point()
|
||||
// Usage:
|
||||
// pt = ray_closest_point(seg,pt);
|
||||
// Topics: Geometry, Rays, Distance
|
||||
// Description:
|
||||
// Returns the point on the given 2D or 3D ray `ray` that is closest to the given point `pt`.
|
||||
// The `ray` and `pt` args should either both be 2D or both 3D.
|
||||
// Arguments:
|
||||
// ray = The ray, given as a list `[START,POINT]` of the start-point START, and a point POINT on the ray.
|
||||
// pt = The point to find the closest point on the ray to.
|
||||
// Example(2D):
|
||||
// ray = [[-30,0],[30,30]];
|
||||
// pt = [-32,-10];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// p2 = line_closest_point(line,pt,bounded=[true,false]);
|
||||
// stroke(line, endcap2="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// ray = [[-30,0],[30,30]];
|
||||
// Example(2D): In this case it doesn't matter how bounded is set. Using SEGMENT is the most restrictive option.
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [-5,0];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// p2 = line_closest_point(line,pt,SEGMENT);
|
||||
// stroke(line);
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// ray = [[-30,0],[30,30]];
|
||||
// Example(2D): The result here is the same for a line or a ray.
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// p2 = line_closest_point(line,pt,RAY);
|
||||
// stroke(line, endcap2="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// ray = [[-30,-15,0],[30,15,30]];
|
||||
// Example(2D): But with a segment we get a different result
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// p2 = line_closest_point(line,pt,SEGMENT);
|
||||
// stroke(line);
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D): The shorthand RAY uses the first point as the base of the ray. But you can specify a reversed ray directly, and in this case the result is the same as the result above for the segment.
|
||||
// line = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// p2 = line_closest_point(line,pt,[false,true]);
|
||||
// stroke(line,endcap1="arrow2");
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]): A 3D example
|
||||
// line = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [5,5,5];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// p2 = line_closest_point(line,pt);
|
||||
// stroke(line, endcaps="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// ray = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [-35,-15,0];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// ray = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [40,15,25];
|
||||
// p2 = ray_closest_point(ray,pt);
|
||||
// stroke(ray, endcap2="arrow2");
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
function ray_closest_point(ray,pt) =
|
||||
assert( _valid_line(ray), "Invalid ray." )
|
||||
assert(is_vector(pt,len(ray[0])), "Invalid point or incompatible dimensions." )
|
||||
function line_closest_point(line, pt, bounded=false) =
|
||||
assert(_valid_line(line), "Invalid line")
|
||||
assert(is_vector(pt, len(line[0])), "Invalid point or incompatible dimensions.")
|
||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "Invalid value for \"bounded\"")
|
||||
let(
|
||||
seglen = norm(ray[1]-ray[0]),
|
||||
segvec = (ray[1]-ray[0])/seglen,
|
||||
projection = (pt-ray[0]) * segvec
|
||||
bounded = force_list(bounded,2)
|
||||
)
|
||||
projection<=0 ? ray[0] :
|
||||
ray[0] + projection*segvec;
|
||||
|
||||
|
||||
// Function: segment_closest_point()
|
||||
// Usage:
|
||||
// pt = segment_closest_point(seg,pt);
|
||||
// Topics: Geometry, Segments, Distance
|
||||
// Description:
|
||||
// Returns the point on the given 2D or 3D line segment `seg` that is closest to the given point `pt`.
|
||||
// The `seg` and `pt` args should either both be 2D or both 3D.
|
||||
// Arguments:
|
||||
// seg = A list of two points that are the endpoints of the bounded line segment.
|
||||
// pt = The point to find the closest point on the segment to.
|
||||
// Example(2D):
|
||||
// seg = [[-30,0],[30,30]];
|
||||
// pt = [-32,-10];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// seg = [[-30,0],[30,30]];
|
||||
// pt = [-5,0];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(2D):
|
||||
// seg = [[-30,0],[30,30]];
|
||||
// pt = [40,25];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) circle(r=1,$fn=12);
|
||||
// color("red") translate(p2) circle(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// seg = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [5,5,5];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// seg = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [-35,-15,0];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
// Example(FlatSpin,VPD=200,VPT=[0,0,15]):
|
||||
// seg = [[-30,-15,0],[30,15,30]];
|
||||
// pt = [40,15,25];
|
||||
// p2 = segment_closest_point(seg,pt);
|
||||
// stroke(seg);
|
||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||
function segment_closest_point(seg,pt) =
|
||||
assert( is_matrix(concat([pt],seg),3) ,
|
||||
"Invalid point or segment or incompatible dimensions." )
|
||||
pt + _closest_s1([seg[0]-pt, seg[1]-pt])[0];
|
||||
|
||||
bounded==[false,false] ?
|
||||
let( n = unit( line[0]- line[1]) )
|
||||
line[1] + ((pt- line[1]) * n) * n
|
||||
: bounded == [true,true] ?
|
||||
pt + _closest_s1([line[0]-pt, line[1]-pt])[0]
|
||||
:
|
||||
let(
|
||||
ray = bounded==[true,false] ? line : reverse(line),
|
||||
seglen = norm(ray[1]-ray[0]),
|
||||
segvec = (ray[1]-ray[0])/seglen,
|
||||
projection = (pt-ray[0]) * segvec
|
||||
)
|
||||
projection<=0 ? ray[0] :
|
||||
ray[0] + projection*segvec;
|
||||
|
||||
|
||||
// Function: line_from_points()
|
||||
// Usage:
|
||||
|
@ -1170,10 +1003,10 @@ function plane_point_nearest_origin(plane) =
|
|||
// Description:
|
||||
// Given a plane as [A,B,C,D] where the cartesian equation for that plane
|
||||
// is Ax+By+Cz=D, determines how far from that plane the given point is.
|
||||
// The returned distance will be positive if the point is in front of the
|
||||
// plane; on the same side of the plane as the normal of that plane points
|
||||
// towards. If the point is behind the plane, then the distance returned
|
||||
// will be negative. The normal of the plane is the same as [A,B,C].
|
||||
// The returned distance will be positive if the point is above the
|
||||
// plane, meaning on the side where the plane normal points.
|
||||
// If the point is below the plane, then the distance returned
|
||||
// will be negative. The normal of the plane is [A,B,C].
|
||||
// Arguments:
|
||||
// plane = The `[A,B,C,D]` plane definition where `Ax+By+Cz=D` is the formula of the plane.
|
||||
// point = The distance evaluation point.
|
||||
|
@ -1216,7 +1049,7 @@ function normalize_plane(plane) =
|
|||
// Topics: Geometry, Planes, Lines, Angle
|
||||
// Description:
|
||||
// Compute the angle between a plane [A, B, C, D] and a 3d line, specified as a pair of 3d points [p1,p2].
|
||||
// The resulting angle is signed, with the sign positive if the vector p2-p1 lies on
|
||||
// The resulting angle is signed, with the sign positive if the vector p2-p1 lies above the plane, on
|
||||
// the same side of the plane as the plane's normal vector.
|
||||
function plane_line_angle(plane, line) =
|
||||
assert( _valid_plane(plane), "Invalid plane." )
|
||||
|
@ -1393,7 +1226,7 @@ function points_on_plane(points, plane, eps=EPSILON) =
|
|||
_pointlist_greatest_distance(points,plane) < eps;
|
||||
|
||||
|
||||
// Function: in_front_of_plane()
|
||||
// Function: above_plane()
|
||||
// Usage:
|
||||
// test = in_front_of_plane(plane, point);
|
||||
// Topics: Geometry, Planes
|
||||
|
@ -1405,7 +1238,7 @@ function points_on_plane(points, plane, eps=EPSILON) =
|
|||
// Arguments:
|
||||
// plane = The [A,B,C,D] coefficients for the first plane equation `Ax+By+Cz=D`.
|
||||
// point = The 3D point to test.
|
||||
function in_front_of_plane(plane, point) =
|
||||
function above_plane(plane, point) =
|
||||
point_plane_distance(plane, point) > EPSILON;
|
||||
|
||||
|
||||
|
@ -1856,9 +1689,10 @@ function furthest_point(pt, points) =
|
|||
// area = polygon_area(poly);
|
||||
// Topics: Geometry, Polygons, Area
|
||||
// Description:
|
||||
// Given a 2D or 3D planar polygon, returns the area of that polygon.
|
||||
// If the polygon is self-crossing, the results are undefined. For non-planar 3D polygon the result is `undef`.
|
||||
// When `signed` is true, a signed area is returned; a positive area indicates a clockwise polygon.
|
||||
// Given a 2D or 3D simple planar polygon, returns the area of that polygon.
|
||||
// If the polygon is self-intersecting or non-planar, the result is `undef.`
|
||||
// When `signed` is true and the polygon is 2d, a signed area is returned: a positive area indicates a counter-clockwise polygon.
|
||||
// The area of 3d polygons is always nonnegative.
|
||||
// Arguments:
|
||||
// poly = Polygon to compute the area of.
|
||||
// signed = If true, a signed area is returned. Default: false.
|
||||
|
@ -1873,7 +1707,7 @@ function polygon_area(poly, signed=false) =
|
|||
let(
|
||||
n = plane_normal(plane),
|
||||
total =
|
||||
sum([ for(i=[1:1:len(poly)-2])
|
||||
-sum([ for(i=[1:1:len(poly)-2])
|
||||
cross(poly[i]-poly[0], poly[i+1]-poly[0])
|
||||
]) * n/2
|
||||
)
|
||||
|
@ -2071,7 +1905,7 @@ function point_in_polygon(point, poly, nonzero=true, eps=EPSILON) =
|
|||
for (i = [0:1:len(poly)-1])
|
||||
let( seg = select(poly,i,i+1) )
|
||||
if (!approx(seg[0],seg[1],eps) )
|
||||
point_on_segment2d(point, seg, eps=eps)? 1:0
|
||||
point_on_segment(point, seg, eps=eps)? 1:0
|
||||
]
|
||||
)
|
||||
sum(on_brd) > 0? 0 :
|
||||
|
@ -2577,4 +2411,4 @@ function _support_diff(p1,p2,d) =
|
|||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
|
@ -186,7 +186,7 @@ function hull3d_faces(points) =
|
|||
remaining = [for (i = [0:1:len(points)-1]) if (i!=a && i!=b && i!=c && i!=d) i],
|
||||
// Build an initial tetrahedron.
|
||||
// Swap b, c if d is in front of triangle t.
|
||||
ifop = in_front_of_plane(plane, points[d]),
|
||||
ifop = above_plane(plane, points[d]),
|
||||
bc = ifop? [c,b] : [b,c],
|
||||
b = bc[0],
|
||||
c = bc[1],
|
||||
|
|
|
@ -311,7 +311,7 @@ function path_trim_end(path,trim,_d=0,_i=undef) =
|
|||
// color("red") translate(closest[1]) circle(d=3, $fn=12);
|
||||
function path_closest_point(path, pt) =
|
||||
let(
|
||||
pts = [for (seg=idx(path)) segment_closest_point(select(path,seg,seg+1),pt)],
|
||||
pts = [for (seg=idx(path)) line_closest_point(select(path,seg,seg+1),pt,SEGMENT)],
|
||||
dists = [for (p=pts) norm(p-pt)],
|
||||
min_seg = min_index(dists)
|
||||
) [min_seg, pts[min_seg]];
|
||||
|
|
|
@ -656,7 +656,7 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
|
|||
let(
|
||||
first_dir=firstcut[2],
|
||||
next_dir=nextcut[2],
|
||||
corner = ray_intersection([firstcut[0], firstcut[0]-first_dir], [nextcut[0], nextcut[0]-next_dir])
|
||||
corner = line_intersection([firstcut[0], firstcut[0]-first_dir], [nextcut[0], nextcut[0]-next_dir],RAY,RAY)
|
||||
)
|
||||
assert(is_def(corner), str("Curve directions at cut points don't intersect in a corner when ",
|
||||
loop?"closing the path":str("adding path ",i+1)))
|
||||
|
@ -1641,7 +1641,7 @@ function _stroke_end(width,left, right, spec) =
|
|||
// returns [intersection_pt, index of first point in path after the intersection]
|
||||
function _path_line_intersection(path, line, ind=0) =
|
||||
ind==len(path)-1 ? undef :
|
||||
let(intersect=line_segment_intersection(line, select(path,ind,ind+1)))
|
||||
let(intersect=line_intersection(line, select(path,ind,ind+1),LINE,SEGMENT))
|
||||
// If it intersects the segment excluding it's final point, then we're done
|
||||
// The final point is treated as part of the next segment
|
||||
is_def(intersect) && intersect != path[ind+1]?
|
||||
|
@ -1694,8 +1694,10 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
let(
|
||||
prev_corner = prev_offset + abs(rtop_in)*in_prev,
|
||||
next_corner = next_offset + abs(rtop_in)*in_next,
|
||||
prev_degenerate = is_undef(ray_intersection(path2d([far_corner, far_corner+prev]), path2d([prev_offset, prev_offset+in_prev]))),
|
||||
next_degenerate = is_undef(ray_intersection(path2d([far_corner, far_corner+next]), path2d([next_offset, next_offset+in_next])))
|
||||
prev_degenerate = is_undef(line_intersection(path2d([far_corner, far_corner+prev]),
|
||||
path2d([prev_offset, prev_offset+in_prev]),RAY,RAY)),
|
||||
next_degenerate = is_undef(line_intersection(path2d([far_corner, far_corner+next]),
|
||||
path2d([next_offset, next_offset+in_next]),RAY,RAY))
|
||||
)
|
||||
[ prev_degenerate ? far_corner : prev_corner,
|
||||
far_corner,
|
||||
|
|
|
@ -6,22 +6,18 @@ include <../std.scad>
|
|||
|
||||
|
||||
|
||||
test_point_on_segment2d();
|
||||
test_point_on_segment();
|
||||
test_point_left_of_line2d();
|
||||
test_collinear();
|
||||
test_point_line_distance();
|
||||
test_point_segment_distance();
|
||||
test_segment_distance();
|
||||
test_line_normal();
|
||||
test_line_intersection();
|
||||
//test_line_ray_intersection();
|
||||
test_line_segment_intersection();
|
||||
//test_ray_intersection();
|
||||
//test_ray_segment_intersection();
|
||||
test_segment_intersection();
|
||||
//test_line_ray_intersection(); // should add this typ eof case
|
||||
//test_ray_intersection(); // should add this type of case
|
||||
//test_ray_segment_intersection(); // should add this type of case
|
||||
test_line_closest_point();
|
||||
//test_ray_closest_point();
|
||||
test_segment_closest_point();
|
||||
//test_ray_closest_point(); // should add this type of case
|
||||
test_line_from_points();
|
||||
test_tri_calc();
|
||||
//test_hyp_opp_to_adj();
|
||||
|
@ -36,7 +32,6 @@ test_tri_calc();
|
|||
//test_hyp_adj_to_ang();
|
||||
//test_hyp_opp_to_ang();
|
||||
//test_adj_opp_to_ang();
|
||||
test_triangle_area();
|
||||
test_plane3pt();
|
||||
test_plane3pt_indexed();
|
||||
test_plane_from_normal();
|
||||
|
@ -56,7 +51,7 @@ test_polygon_line_intersection();
|
|||
test_plane_intersection();
|
||||
test_coplanar();
|
||||
test_points_on_plane();
|
||||
test_in_front_of_plane();
|
||||
test_above_plane();
|
||||
test_circle_2tangents();
|
||||
test_circle_3points();
|
||||
test_circle_point_tangents();
|
||||
|
@ -302,35 +297,35 @@ module test_line_from_points() {
|
|||
}
|
||||
*test_line_from_points();
|
||||
|
||||
module test_point_on_segment2d() {
|
||||
assert(point_on_segment2d([-15,0], [[-10,0], [10,0]]) == false);
|
||||
assert(point_on_segment2d([-10,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment2d([-5,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment2d([0,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment2d([3,3], [[-10,0], [10,0]]) == false);
|
||||
assert(point_on_segment2d([5,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment2d([10,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment2d([15,0], [[-10,0], [10,0]]) == false);
|
||||
module test_point_on_segment() {
|
||||
assert(point_on_segment([-15,0], [[-10,0], [10,0]]) == false);
|
||||
assert(point_on_segment([-10,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment([-5,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment([0,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment([3,3], [[-10,0], [10,0]]) == false);
|
||||
assert(point_on_segment([5,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment([10,0], [[-10,0], [10,0]]) == true);
|
||||
assert(point_on_segment([15,0], [[-10,0], [10,0]]) == false);
|
||||
|
||||
assert(point_on_segment2d([0,-15], [[0,-10], [0,10]]) == false);
|
||||
assert(point_on_segment2d([0,-10], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment2d([0, -5], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment2d([0, 0], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment2d([3, 3], [[0,-10], [0,10]]) == false);
|
||||
assert(point_on_segment2d([0, 5], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment2d([0, 10], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment2d([0, 15], [[0,-10], [0,10]]) == false);
|
||||
assert(point_on_segment([0,-15], [[0,-10], [0,10]]) == false);
|
||||
assert(point_on_segment([0,-10], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment([0, -5], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment([0, 0], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment([3, 3], [[0,-10], [0,10]]) == false);
|
||||
assert(point_on_segment([0, 5], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment([0, 10], [[0,-10], [0,10]]) == true);
|
||||
assert(point_on_segment([0, 15], [[0,-10], [0,10]]) == false);
|
||||
|
||||
assert(point_on_segment2d([-15,-15], [[-10,-10], [10,10]]) == false);
|
||||
assert(point_on_segment2d([-10,-10], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment2d([ -5, -5], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment2d([ 0, 0], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment2d([ 0, 3], [[-10,-10], [10,10]]) == false);
|
||||
assert(point_on_segment2d([ 5, 5], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment2d([ 10, 10], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment2d([ 15, 15], [[-10,-10], [10,10]]) == false);
|
||||
assert(point_on_segment([-15,-15], [[-10,-10], [10,10]]) == false);
|
||||
assert(point_on_segment([-10,-10], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment([ -5, -5], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment([ 0, 0], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment([ 0, 3], [[-10,-10], [10,10]]) == false);
|
||||
assert(point_on_segment([ 5, 5], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment([ 10, 10], [[-10,-10], [10,10]]) == true);
|
||||
assert(point_on_segment([ 15, 15], [[-10,-10], [10,10]]) == false);
|
||||
}
|
||||
*test_point_on_segment2d();
|
||||
*test_point_on_segment();
|
||||
|
||||
|
||||
module test_point_left_of_line2d() {
|
||||
|
@ -359,17 +354,12 @@ module test_point_line_distance() {
|
|||
assert_approx(point_line_distance([-1,-1,-1], [[-10,-10,-10], [10,10,10]]), 0);
|
||||
assert_approx(point_line_distance([1,-1,0], [[-10,-10,-10], [10,10,10]]), sqrt(2));
|
||||
assert_approx(point_line_distance([8,-8,0], [[-10,-10,-10], [10,10,10]]), 8*sqrt(2));
|
||||
assert_approx(point_line_distance([3,8], [[-10,0], [10,0]],SEGMENT), 8);
|
||||
assert_approx(point_line_distance([14,3], [[-10,0], [10,0]],SEGMENT), 5);
|
||||
}
|
||||
*test_point_line_distance();
|
||||
|
||||
|
||||
module test_point_segment_distance() {
|
||||
assert_approx(point_segment_distance([3,8], [[-10,0], [10,0]]), 8);
|
||||
assert_approx(point_segment_distance([14,3], [[-10,0], [10,0]]), 5);
|
||||
}
|
||||
*test_point_segment_distance();
|
||||
|
||||
|
||||
module test_segment_distance() {
|
||||
assert_approx(segment_distance([[-14,3], [-14,9]], [[-10,0], [10,0]]), 5);
|
||||
assert_approx(segment_distance([[-14,3], [-15,9]], [[-10,0], [10,0]]), 5);
|
||||
|
@ -418,61 +408,35 @@ module test_line_intersection() {
|
|||
assert(line_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == [0,0]);
|
||||
assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
|
||||
assert(line_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
|
||||
assert(line_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]],LINE,SEGMENT) == [0,0]);
|
||||
assert(line_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]],LINE,SEGMENT) == [2,2]);
|
||||
assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ 1, -1]],LINE,SEGMENT) == undef);
|
||||
assert(line_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ -1, 1]],LINE,SEGMENT) == [0,0]);
|
||||
}
|
||||
*test_line_intersection();
|
||||
|
||||
|
||||
module test_segment_intersection() {
|
||||
assert(segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
|
||||
assert(segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
|
||||
assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
|
||||
assert(segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
|
||||
assert(segment_intersection([[-10, 10], [ -1, 1]], [[ 10, 10], [ 1, 1]]) == undef);
|
||||
assert(segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
|
||||
assert(segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
|
||||
assert(segment_intersection([[-10, 0], [ 0, 10]], [[ 0, 10], [ 10, 0]]) == [0,10]);
|
||||
assert(segment_intersection([[-10, 0], [ 0, 10]], [[-10, 20], [ 10, 0]]) == [0,10]);
|
||||
assert(segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
|
||||
assert(segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
|
||||
}
|
||||
*test_segment_intersection();
|
||||
|
||||
|
||||
module test_line_segment_intersection() {
|
||||
assert(line_segment_intersection([[-10,-10], [ -1,-10]], [[ 10,-10], [ 1,-10]]) == undef);
|
||||
assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 10, 0], [ 1, 0]]) == undef);
|
||||
assert(line_segment_intersection([[-10, 0], [ -1, 0]], [[ 1, 0], [ 10, 0]]) == undef);
|
||||
assert(line_segment_intersection([[-10, 0], [ 10, 0]], [[-10, 0], [ 10, 0]]) == undef);
|
||||
assert(line_segment_intersection([[-10, 10], [ 10, 10]], [[-10,-10], [ 10,-10]]) == undef);
|
||||
assert(line_segment_intersection([[-10,-10], [ -1, -1]], [[ 10,-10], [ 1, -1]]) == undef);
|
||||
assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [-10, 10]]) == [0,0]);
|
||||
assert(line_segment_intersection([[ -8, 0], [ 12, 4]], [[ 12, 0], [ -8, 4]]) == [2,2]);
|
||||
assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ 1, -1]]) == undef);
|
||||
assert(line_segment_intersection([[-10,-10], [ 10, 10]], [[ 10,-10], [ -1, 1]]) == [0,0]);
|
||||
}
|
||||
*test_line_segment_intersection();
|
||||
|
||||
|
||||
module test_line_closest_point() {
|
||||
assert(approx(line_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
|
||||
assert(approx(line_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [13,31]), [15,30]));
|
||||
assert(approx(line_closest_point([[-10,-10], [10,10]], [1,-1],SEGMENT), [0,0]));
|
||||
assert(approx(line_closest_point([[-10,-10], [10,10]], [-1,1],SEGMENT), [0,0]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1],SEGMENT), [1,2]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1],SEGMENT), [1,2]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [13,31],SEGMENT), [10,20]));
|
||||
assert(approx(line_closest_point([[-10,-20], [10,20]], [15,25],SEGMENT), [10,20]));
|
||||
}
|
||||
*test_line_closest_point();
|
||||
|
||||
|
||||
module test_segment_closest_point() {
|
||||
assert(approx(segment_closest_point([[-10,-10], [10,10]], [1,-1]), [0,0]));
|
||||
assert(approx(segment_closest_point([[-10,-10], [10,10]], [-1,1]), [0,0]));
|
||||
assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[-2,1]), [1,2]));
|
||||
assert(approx(segment_closest_point([[-10,-20], [10,20]], [1,2]+[2,-1]), [1,2]));
|
||||
assert(approx(segment_closest_point([[-10,-20], [10,20]], [13,31]), [10,20]));
|
||||
assert(approx(segment_closest_point([[-10,-20], [10,20]], [15,25]), [10,20]));
|
||||
}
|
||||
*test_segment_closest_point();
|
||||
|
||||
module test_circle_2tangents() {
|
||||
//** missing tests with arg tangent=true
|
||||
assert(approx(circle_2tangents([10,10],[0,0],[10,-10],r=10/sqrt(2))[0],[10,0]));
|
||||
|
@ -684,13 +648,6 @@ module test_hyp_opp_to_ang() nil(); // Covered in test_tri_functions()
|
|||
module test_adj_opp_to_ang() nil(); // Covered in test_tri_functions()
|
||||
|
||||
|
||||
module test_triangle_area() {
|
||||
assert(abs(triangle_area([0,0], [0,10], [10,0]) + 50) < EPSILON);
|
||||
assert(abs(triangle_area([0,0], [0,10], [0,15])) < EPSILON);
|
||||
assert(abs(triangle_area([0,0], [10,0], [0,10]) - 50) < EPSILON);
|
||||
}
|
||||
*test_triangle_area();
|
||||
|
||||
|
||||
module test_plane3pt() {
|
||||
assert_approx(plane3pt([0,0,20], [0,10,10], [0,0,0]), [1,0,0,0]);
|
||||
|
@ -797,17 +754,17 @@ module test_coplanar() {
|
|||
*test_coplanar();
|
||||
|
||||
|
||||
module test_in_front_of_plane() {
|
||||
module test_above_plane() {
|
||||
plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
|
||||
assert(in_front_of_plane(plane, [5,5,10]) == false);
|
||||
assert(in_front_of_plane(plane, [-5,0,0]) == true);
|
||||
assert(in_front_of_plane(plane, [5,0,0]) == false);
|
||||
assert(in_front_of_plane(plane, [0,-5,0]) == true);
|
||||
assert(in_front_of_plane(plane, [0,5,0]) == false);
|
||||
assert(in_front_of_plane(plane, [0,0,5]) == true);
|
||||
assert(in_front_of_plane(plane, [0,0,-5]) == false);
|
||||
assert(above_plane(plane, [5,5,10]) == false);
|
||||
assert(above_plane(plane, [-5,0,0]) == true);
|
||||
assert(above_plane(plane, [5,0,0]) == false);
|
||||
assert(above_plane(plane, [0,-5,0]) == true);
|
||||
assert(above_plane(plane, [0,5,0]) == false);
|
||||
assert(above_plane(plane, [0,0,5]) == true);
|
||||
assert(above_plane(plane, [0,0,-5]) == false);
|
||||
}
|
||||
*test_in_front_of_plane();
|
||||
*test_above_plane();
|
||||
|
||||
|
||||
module test_is_path() {
|
||||
|
@ -851,7 +808,11 @@ module test_polygon_area() {
|
|||
assert(approx(polygon_area(circle(r=50,$fn=1000),signed=true), -PI*50*50, eps=0.1));
|
||||
assert(approx(polygon_area(rot([13,27,75],
|
||||
p=path3d(circle(r=50,$fn=1000),fill=23)),
|
||||
signed=true), -PI*50*50, eps=0.1));
|
||||
signed=true), PI*50*50, eps=0.1));
|
||||
assert(abs(triangle_area([0,0], [0,10], [10,0]) + 50) < EPSILON);
|
||||
assert(abs(triangle_area([0,0], [0,10], [0,15])) < EPSILON);
|
||||
assert(abs(triangle_area([0,0], [10,0], [0,10]) - 50) < EPSILON);
|
||||
|
||||
}
|
||||
*test_polygon_area();
|
||||
|
||||
|
|
2
vnf.scad
2
vnf.scad
|
@ -899,7 +899,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
|
|||
c = varr[ic]
|
||||
)
|
||||
if (!approx(a,b) && !approx(b,c) && !approx(a,c)) let(
|
||||
pt = segment_closest_point([a,c],b)
|
||||
pt = line_closest_point([a,c],b,SEGMENT)
|
||||
)
|
||||
if (approx(pt,b))
|
||||
_vnf_validate_err("T_JUNCTION", [b])
|
||||
|
|
Loading…
Reference in a new issue