Add "is" to geometry.scad predicates

This commit is contained in:
Adrian Mariano 2021-09-15 19:01:34 -04:00
parent ea7b947bcb
commit d78eb5213e
8 changed files with 105 additions and 132 deletions

View file

@ -217,7 +217,7 @@ function xy_to_polar(x,y=undef) = let(
// stroke(xypath,closed=true);
function project_plane(plane,p) =
is_matrix(plane,3,3) && is_undef(p) ? // no data, 3 points given
assert(!collinear(plane),"Points defining the plane must not be collinear")
assert(!is_collinear(plane),"Points defining the plane must not be collinear")
let(
v = plane[2]-plane[0],
y = unit(plane[1]-plane[0]), // y axis goes to point b
@ -242,7 +242,7 @@ function project_plane(plane,p) =
[for(plist=p) project_plane(plane,plist)]
: assert(is_vector(p,3) || is_path(p,3),str("Data must be a 3d point, path, region, vnf or bezier patch",p))
is_matrix(plane,3,3) ?
assert(!collinear(plane),"Points defining the plane must not be collinear")
assert(!is_collinear(plane),"Points defining the plane must not be collinear")
let(
v = plane[2]-plane[0],
y = unit(plane[1]-plane[0]), // y axis goes to point b

View file

@ -11,9 +11,9 @@
// Section: Lines, Rays, and Segments
// Function: point_on_line()
// Function: is_point_on_line()
// Usage:
// pt = point_on_line(point, line, [bounded], [eps]);
// pt = is_point_on_line(point, line, [bounded], [eps]);
// Topics: Geometry, Points, Segments
// Description:
// Determine if the point is on the line segment, ray or segment defined by the two between two points.
@ -25,7 +25,7 @@
// line = Array of two points defining the line, ray, or segment to test against.
// bounded = boolean or list of two booleans defining endpoint conditions for the line. If false treat the line as an unbounded line. If true treat it as a segment. If [true,false] treat as a ray, based at the first endpoint. Default: false
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
function point_on_line(point, line, bounded=false, eps=EPSILON) =
function is_point_on_line(point, line, bounded=false, eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
point_line_distance(point, line, bounded)<eps;
@ -66,9 +66,9 @@ function _point_left_of_line2d(point, line) =
cross(line[0]-point, line[1]-line[0]);
// Function: collinear()
// Function: is_collinear()
// Usage:
// test = collinear(a, [b, c], [eps]);
// test = is_collinear(a, [b, c], [eps]);
// Topics: Geometry, Points, Collinearity
// Description:
// Returns true if the points `a`, `b` and `c` are co-linear or if the list of points `a` is collinear.
@ -77,7 +77,7 @@ function _point_left_of_line2d(point, line) =
// b = Second point or undef; it should be undef if `c` is undef
// c = Third point or undef.
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
function collinear(a, b, c, eps=EPSILON) =
function is_collinear(a, b, c, eps=EPSILON) =
assert( is_path([a,b,c],dim=undef)
|| ( is_undef(b) && is_undef(c) && is_path(a,dim=undef) ),
"Input should be 3 points or a list of points with same dimension.")
@ -336,7 +336,7 @@ function line_from_points(points, fast=false, eps=EPSILON) =
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
let( pb = furthest_point(points[0],points) )
norm(points[pb]-points[0])<eps*max(norm(points[pb]),norm(points[0])) ? undef :
fast || collinear(points)
fast || is_collinear(points)
? [points[pb], points[0]]
: undef;
@ -345,16 +345,16 @@ function line_from_points(points, fast=false, eps=EPSILON) =
// Section: Planes
// Function: coplanar()
// Function: is_coplanar()
// Usage:
// test = coplanar(points,[eps]);
// test = is_coplanar(points,[eps]);
// Topics: Geometry, Coplanarity
// Description:
// Returns true if the given 3D points are non-collinear and are on a plane.
// Arguments:
// points = The points to test.
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
function coplanar(points, eps=EPSILON) =
function is_coplanar(points, eps=EPSILON) =
assert( is_path(points,dim=3) , "Input should be a list of 3D points." )
assert( is_finite(eps) && eps>=0, "The tolerance should be a non-negative value." )
len(points)<=2 ? false
@ -539,7 +539,7 @@ function plane_from_polygon(poly, fast=false, eps=EPSILON) =
let(
plane = plane_from_normal(poly_normal, poly[0])
)
fast? plane: points_on_plane(poly, plane, eps=eps)? plane: [];
fast? plane: are_points_on_plane(poly, plane, eps=eps)? plane: [];
// Function: plane_normal()
@ -926,9 +926,9 @@ function _pointlist_greatest_distance(points,plane) =
abs(max( max(pt_nrm) - plane[3], -min(pt_nrm) + plane[3])) / norm(normal);
// Function: points_on_plane()
// Function: are_points_on_plane()
// Usage:
// test = points_on_plane(points, plane, [eps]);
// test = are_points_on_plane(points, plane, [eps]);
// Topics: Geometry, Planes, Points
// Description:
// Returns true if the given 3D points are on the given plane.
@ -936,14 +936,14 @@ function _pointlist_greatest_distance(points,plane) =
// plane = The plane to test the points on.
// points = The list of 3D points to test.
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
function points_on_plane(points, plane, eps=EPSILON) =
function are_points_on_plane(points, plane, eps=EPSILON) =
assert( _valid_plane(plane), "Invalid plane." )
assert( is_matrix(points,undef,3) && len(points)>0, "Invalid pointlist." ) // using is_matrix it accepts len(points)==1
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
_pointlist_greatest_distance(points,plane) < eps;
// Function: above_plane()
// Function: is_above_plane()
// Usage:
// test = in_front_of_plane(plane, point);
// Topics: Geometry, Planes
@ -955,7 +955,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 above_plane(plane, point) =
function is_above_plane(plane, point) =
point_plane_distance(plane, point) > EPSILON;
@ -1074,7 +1074,7 @@ function circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
"Invalid input points." )
is_undef(pt2)
? circle_2tangents(pt1[0], pt1[1], pt1[2], r=r, tangents=tangents)
: collinear(pt1, pt2, pt3)? undef :
: is_collinear(pt1, pt2, pt3)? undef :
let(
v1 = unit(pt1 - pt2),
v2 = unit(pt3 - pt2),
@ -1159,7 +1159,7 @@ function circle_3points(pt1, pt2, pt3) =
: assert( is_vector(pt1) && is_vector(pt2) && is_vector(pt3)
&& max(len(pt1),len(pt2),len(pt3))<=3 && min(len(pt1),len(pt2),len(pt3))>=2,
"Invalid point(s)." )
collinear(pt1,pt2,pt3)? [undef,undef,undef] :
is_collinear(pt1,pt2,pt3)? [undef,undef,undef] :
let(
v = [ point3d(pt1), point3d(pt2), point3d(pt3) ], // triangle vertices
ed = [for(i=[0:2]) v[(i+1)%3]-v[i] ], // triangle edge vectors
@ -1530,7 +1530,7 @@ function point_in_polygon(point, poly, nonzero=false, 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_line(point, seg, SEGMENT, eps=eps)? 1:0
is_point_on_line(point, seg, SEGMENT, eps=eps)? 1:0
]
)
sum(on_brd) > 0? 0 :
@ -1752,6 +1752,7 @@ function reverse_polygon(poly) =
// Topics: Geometry, Polygons
// Description:
// Given a polygon `poly`, rotates the point ordering so that the first point in the polygon path is the one at index `i`.
// This is identical to `list_rotate` except that it checks for doubled endpoints and removed them if present.
// Arguments:
// poly = The list of points in the polygon path.
// i = The index of the point to shift to the front of the path.
@ -1762,24 +1763,6 @@ function polygon_shift(poly, i) =
list_rotate(cleanup_path(poly), i);
// Function: polygon_shift_to_closest_point()
// Usage:
// newpoly = polygon_shift_to_closest_point(path, pt);
// Topics: Geometry, Polygons
// Description:
// Given a polygon `poly`, rotates the point ordering so that the first point in the path is the one closest to the given point `pt`.
// Arguments:
// poly = The list of points in the polygon path.
// pt = The reference point.
function polygon_shift_to_closest_point(poly, pt) =
assert(is_vector(pt), "Invalid point." )
assert(is_path(poly,dim=len(pt)), "Invalid polygon or incompatible dimension with the point." )
let(
poly = cleanup_path(poly),
dists = [for (p=poly) norm(p-pt)],
closest = min_index(dists)
) select(poly,closest,closest+len(poly)-1);
// Function: reindex_polygon()
// Usage:

View file

@ -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 = above_plane(plane, points[d]),
ifop = is_above_plane(plane, points[d]),
bc = ifop? [c,b] : [b,c],
b = bc[0],
c = bc[1],
@ -245,7 +245,7 @@ function _remove_internal_edges(halfedges) = [
];
function _find_first_noncoplanar(plane, points, i=0) =
(i >= len(points) || !points_on_plane([points[i]],plane))? i :
(i >= len(points) || !are_points_on_plane([points[i]],plane))? i :
_find_first_noncoplanar(plane, points, i+1);

View file

@ -121,7 +121,7 @@ function simplify_path(path, eps=EPSILON) =
indices = [
0,
for (i=[1:1:len(path)-2])
if (!collinear(path[i-1], path[i], path[i+1], eps=eps)) i,
if (!is_collinear(path[i-1], path[i], path[i+1], eps=eps)) i,
len(path)-1
]
) [for (i=indices) path[i]];
@ -148,7 +148,7 @@ function simplify_path_indexed(points, indices, eps=EPSILON) =
i1 = indices[i-1],
i2 = indices[i],
i3 = indices[i+1]
) if (!collinear(points[i1], points[i2], points[i3], eps=eps))
) if (!is_collinear(points[i1], points[i2], points[i3], eps=eps))
indices[i]
],
indices[len(indices)-1]
@ -604,7 +604,7 @@ function path_add_jitter(path, dist=1/512, closed=true) =
path[0],
for (i=idx(path,s=1,e=closed?-1:-2)) let(
n = line_normal([path[i-1],path[i]])
) path[i] + n * (collinear(select(path,i-1,i+1))? (dist * ((i%2)*2-1)) : 0),
) path[i] + n * (is_collinear(select(path,i-1,i+1))? (dist * ((i%2)*2-1)) : 0),
if (!closed) last(path)
];
@ -1004,7 +1004,7 @@ function _path_cuts_normals(path, cuts, dirs, closed=false) =
// to define the plane of the path.
function _path_plane(path, ind, i,closed) =
i<(closed?-1:0) ? undef :
!collinear(path[ind],path[ind-1], select(path,i))?
!is_collinear(path[ind],path[ind-1], select(path,i))?
[select(path,i)-path[ind-1],path[ind]-path[ind-1]] :
_path_plane(path, ind, i-1);

View file

@ -1865,16 +1865,16 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
assert(jsvecok || jssingleok,
str("Argument joint_sides is invalid. All entries must be nonnegative, and it must be a number, 2-vector, or a length ",N," list those."))
assert(is_num(k_sides) || is_vector(k_sides,N), str("Curvature parameter k_sides must be a number or length ",N," vector"))
assert(coplanar(bottom))
assert(coplanar(top))
assert(is_coplanar(bottom))
assert(is_coplanar(top))
assert(!is_num(k_sides) || (k_sides>=0 && k_sides<=1), "Curvature parameter k_sides must be in interval [0,1]")
let(
non_coplanar=[for(i=[0:N-1]) if (!coplanar(concat(select(top,i,i+1), select(bottom,i,i+1)))) [i,(i+1)%N]],
non_coplanar=[for(i=[0:N-1]) if (!is_coplanar(concat(select(top,i,i+1), select(bottom,i,i+1)))) [i,(i+1)%N]],
k_sides_vec = is_num(k_sides) ? repeat(k_sides, N) : k_sides,
kbad = [for(i=[0:N-1]) if (k_sides_vec[i]<0 || k_sides_vec[i]>1) i],
joint_sides_vec = jssingleok ? repeat(joint_sides,N) : joint_sides,
top_collinear = [for(i=[0:N-1]) if (collinear(select(top,i-1,i+1))) i],
bot_collinear = [for(i=[0:N-1]) if (collinear(select(bottom,i-1,i+1))) i]
top_collinear = [for(i=[0:N-1]) if (is_collinear(select(top,i-1,i+1))) i],
bot_collinear = [for(i=[0:N-1]) if (is_collinear(select(bottom,i-1,i+1))) i]
)
assert(non_coplanar==[], str("Side faces are non-coplanar at edges: ",non_coplanar))
assert(top_collinear==[], str("Top has collinear or duplicated points at indices: ",top_collinear))
@ -1940,14 +1940,14 @@ function rounded_prism(bottom, top, joint_bot=0, joint_top=0, joint_sides=0, k_b
vline = concat(select(subindex(top_patch[i],j),2,4),
select(subindex(bot_patch[i],j),2,4))
)
if (!collinear(vline)) [i,j]],
if (!is_collinear(vline)) [i,j]],
//verify horiz edges
verify_horiz=[for(i=[0:N-1], j=[0:4])
let(
hline_top = concat(select(top_patch[i][j],2,4), select(select(top_patch, i+1)[j],0,2)),
hline_bot = concat(select(bot_patch[i][j],2,4), select(select(bot_patch, i+1)[j],0,2))
)
if (!collinear(hline_top) || !collinear(hline_bot)) [i,j]]
if (!is_collinear(hline_top) || !is_collinear(hline_bot)) [i,j]]
)
assert(debug || top_intersections==[],
"Roundovers interfere with each other on top face: either input is self intersecting or top joint length is too large")

View file

@ -618,7 +618,7 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
arc(N,cp=cp,r=r,start=atan2(v1.y,v1.x),angle=final_angle,wedge=wedge)
) : (
// Final case is arc passing through three points, starting at point[0] and ending at point[3]
let(col = collinear(points[0],points[1],points[2]))
let(col = is_collinear(points[0],points[1],points[2]))
assert(!col, "Collinear inputs do not define an arc")
let(
cp = line_intersection(_normal_segment(points[0],points[1]),_normal_segment(points[1],points[2])),

View file

@ -6,8 +6,8 @@ include <../std.scad>
test_point_on_line();
test_collinear();
test_is_point_on_line();
test_is_collinear();
test_point_line_distance();
test_segment_distance();
test_line_normal();
@ -33,9 +33,9 @@ test_plane_line_angle();
test_plane_line_intersection();
test_polygon_line_intersection();
test_plane_intersection();
test_coplanar();
test_points_on_plane();
test_above_plane();
test_is_coplanar();
test_are_points_on_plane();
test_is_above_plane();
test_circle_2tangents();
test_circle_3points();
test_circle_point_tangents();
@ -44,7 +44,6 @@ test_noncollinear_triple();
test_polygon_area();
test_is_polygon_convex();
test_polygon_shift();
test_polygon_shift_to_closest_point();
test_reindex_polygon();
test_align_polygon();
test_centroid();
@ -223,7 +222,7 @@ module test__general_plane_line_intersection() {
*test__general_plane_line_intersection();
module test_points_on_plane() {
module test_are_points_on_plane() {
pts = [for(i=[0:40]) rands(-1,1,3) ];
dir = rands(-10,10,3);
normal0 = [1,2,3];
@ -232,10 +231,10 @@ module test_points_on_plane() {
plane = [each normal, normal*dir];
prj_pts = plane_closest_point(plane,pts);
info = info_str([["pts = ",pts],["dir = ",dir],["ang = ",ang]]);
assert(points_on_plane(prj_pts,plane),info);
assert(!points_on_plane(concat(pts,[normal-dir]),plane),info);
assert(are_points_on_plane(prj_pts,plane),info);
assert(!are_points_on_plane(concat(pts,[normal-dir]),plane),info);
}
*test_points_on_plane();
*test_are_points_on_plane();
module test_plane_closest_point(){
ang = rands(0,360,1)[0];
@ -266,43 +265,43 @@ module test_line_from_points() {
}
*test_line_from_points();
module test_point_on_line() {
assert(point_on_line([-15,0], [[-10,0], [10,0]],SEGMENT) == false);
assert(point_on_line([-10,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(point_on_line([-5,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(point_on_line([0,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(point_on_line([3,3], [[-10,0], [10,0]],SEGMENT) == false);
assert(point_on_line([5,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(point_on_line([10,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(point_on_line([15,0], [[-10,0], [10,0]],SEGMENT) == false);
module test_is_point_on_line() {
assert(is_point_on_line([-15,0], [[-10,0], [10,0]],SEGMENT) == false);
assert(is_point_on_line([-10,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(is_point_on_line([-5,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(is_point_on_line([0,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(is_point_on_line([3,3], [[-10,0], [10,0]],SEGMENT) == false);
assert(is_point_on_line([5,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(is_point_on_line([10,0], [[-10,0], [10,0]],SEGMENT) == true);
assert(is_point_on_line([15,0], [[-10,0], [10,0]],SEGMENT) == false);
assert(point_on_line([0,-15], [[0,-10], [0,10]],SEGMENT) == false);
assert(point_on_line([0,-10], [[0,-10], [0,10]],SEGMENT) == true);
assert(point_on_line([0, -5], [[0,-10], [0,10]],SEGMENT) == true);
assert(point_on_line([0, 0], [[0,-10], [0,10]],SEGMENT) == true);
assert(point_on_line([3, 3], [[0,-10], [0,10]],SEGMENT) == false);
assert(point_on_line([0, 5], [[0,-10], [0,10]],SEGMENT) == true);
assert(point_on_line([0, 10], [[0,-10], [0,10]],SEGMENT) == true);
assert(point_on_line([0, 15], [[0,-10], [0,10]],SEGMENT) == false);
assert(is_point_on_line([0,-15], [[0,-10], [0,10]],SEGMENT) == false);
assert(is_point_on_line([0,-10], [[0,-10], [0,10]],SEGMENT) == true);
assert(is_point_on_line([0, -5], [[0,-10], [0,10]],SEGMENT) == true);
assert(is_point_on_line([0, 0], [[0,-10], [0,10]],SEGMENT) == true);
assert(is_point_on_line([3, 3], [[0,-10], [0,10]],SEGMENT) == false);
assert(is_point_on_line([0, 5], [[0,-10], [0,10]],SEGMENT) == true);
assert(is_point_on_line([0, 10], [[0,-10], [0,10]],SEGMENT) == true);
assert(is_point_on_line([0, 15], [[0,-10], [0,10]],SEGMENT) == false);
assert(point_on_line([-15,-15], [[-10,-10], [10,10]],SEGMENT) == false);
assert(point_on_line([-10,-10], [[-10,-10], [10,10]],SEGMENT) == true);
assert(point_on_line([ -5, -5], [[-10,-10], [10,10]],SEGMENT) == true);
assert(point_on_line([ 0, 0], [[-10,-10], [10,10]],SEGMENT) == true);
assert(point_on_line([ 0, 3], [[-10,-10], [10,10]],SEGMENT) == false);
assert(point_on_line([ 5, 5], [[-10,-10], [10,10]],SEGMENT) == true);
assert(point_on_line([ 10, 10], [[-10,-10], [10,10]],SEGMENT) == true);
assert(point_on_line([ 15, 15], [[-10,-10], [10,10]],SEGMENT) == false);
assert(is_point_on_line([-15,-15], [[-10,-10], [10,10]],SEGMENT) == false);
assert(is_point_on_line([-10,-10], [[-10,-10], [10,10]],SEGMENT) == true);
assert(is_point_on_line([ -5, -5], [[-10,-10], [10,10]],SEGMENT) == true);
assert(is_point_on_line([ 0, 0], [[-10,-10], [10,10]],SEGMENT) == true);
assert(is_point_on_line([ 0, 3], [[-10,-10], [10,10]],SEGMENT) == false);
assert(is_point_on_line([ 5, 5], [[-10,-10], [10,10]],SEGMENT) == true);
assert(is_point_on_line([ 10, 10], [[-10,-10], [10,10]],SEGMENT) == true);
assert(is_point_on_line([ 15, 15], [[-10,-10], [10,10]],SEGMENT) == false);
assert(point_on_line([10,10], [[0,0],[5,5]]) == true);
assert(point_on_line([4,4], [[0,0],[5,5]]) == true);
assert(point_on_line([-2,-2], [[0,0],[5,5]]) == true);
assert(point_on_line([5,5], [[0,0],[5,5]]) == true);
assert(point_on_line([10,10], [[0,0],[5,5]],RAY) == true);
assert(point_on_line([0,0], [[0,0],[5,5]],RAY) == true);
assert(point_on_line([3,3], [[0,0],[5,5]],RAY) == true);
assert(is_point_on_line([10,10], [[0,0],[5,5]]) == true);
assert(is_point_on_line([4,4], [[0,0],[5,5]]) == true);
assert(is_point_on_line([-2,-2], [[0,0],[5,5]]) == true);
assert(is_point_on_line([5,5], [[0,0],[5,5]]) == true);
assert(is_point_on_line([10,10], [[0,0],[5,5]],RAY) == true);
assert(is_point_on_line([0,0], [[0,0],[5,5]],RAY) == true);
assert(is_point_on_line([3,3], [[0,0],[5,5]],RAY) == true);
}
*test_point_on_line();
*test_is_point_on_line();
module test__point_left_of_line2d() {
@ -312,18 +311,18 @@ module test__point_left_of_line2d() {
}
test__point_left_of_line2d();
module test_collinear() {
assert(collinear([-10,-10], [-15, -16], [10,10]) == false);
assert(collinear([[-10,-10], [-15, -16], [10,10]]) == false);
assert(collinear([-10,-10], [-15, -15], [10,10]) == true);
assert(collinear([[-10,-10], [-15, -15], [10,10]]) == true);
assert(collinear([-10,-10], [ -3, 0], [10,10]) == false);
assert(collinear([-10,-10], [ 0, 0], [10,10]) == true);
assert(collinear([-10,-10], [ 3, 0], [10,10]) == false);
assert(collinear([-10,-10], [ 15, 15], [10,10]) == true);
assert(collinear([-10,-10], [ 15, 16], [10,10]) == false);
module test_is_collinear() {
assert(is_collinear([-10,-10], [-15, -16], [10,10]) == false);
assert(is_collinear([[-10,-10], [-15, -16], [10,10]]) == false);
assert(is_collinear([-10,-10], [-15, -15], [10,10]) == true);
assert(is_collinear([[-10,-10], [-15, -15], [10,10]]) == true);
assert(is_collinear([-10,-10], [ -3, 0], [10,10]) == false);
assert(is_collinear([-10,-10], [ 0, 0], [10,10]) == true);
assert(is_collinear([-10,-10], [ 3, 0], [10,10]) == false);
assert(is_collinear([-10,-10], [ 15, 15], [10,10]) == true);
assert(is_collinear([-10,-10], [ 15, 16], [10,10]) == false);
}
*test_collinear();
*test_is_collinear();
module test_point_line_distance() {
@ -730,26 +729,26 @@ module test_polygon_line_intersection() {
*test_polygon_line_intersection();
module test_coplanar() {
assert(coplanar([ [5,5,1],[0,0,1],[-1,-1,1] ]) == false);
assert(coplanar([ [5,5,1],[0,0,0],[-1,-1,1] ]) == true);
assert(coplanar([ [0,0,0],[1,0,1],[1,1,1], [0,1,2] ]) == false);
assert(coplanar([ [0,0,0],[1,0,1],[1,1,2], [0,1,1] ]) == true);
module test_is_coplanar() {
assert(is_coplanar([ [5,5,1],[0,0,1],[-1,-1,1] ]) == false);
assert(is_coplanar([ [5,5,1],[0,0,0],[-1,-1,1] ]) == true);
assert(is_coplanar([ [0,0,0],[1,0,1],[1,1,1], [0,1,2] ]) == false);
assert(is_coplanar([ [0,0,0],[1,0,1],[1,1,2], [0,1,1] ]) == true);
}
*test_coplanar();
*test_is_coplanar();
module test_above_plane() {
module test_is_above_plane() {
plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
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);
assert(is_above_plane(plane, [5,5,10]) == false);
assert(is_above_plane(plane, [-5,0,0]) == true);
assert(is_above_plane(plane, [5,0,0]) == false);
assert(is_above_plane(plane, [0,-5,0]) == true);
assert(is_above_plane(plane, [0,5,0]) == false);
assert(is_above_plane(plane, [0,0,5]) == true);
assert(is_above_plane(plane, [0,0,-5]) == false);
}
*test_above_plane();
*test_is_above_plane();
module test_is_path() {
@ -820,15 +819,6 @@ module test_polygon_shift() {
*test_polygon_shift();
module test_polygon_shift_to_closest_point() {
path = [[1,1],[-1,1],[-1,-1],[1,-1]];
assert(polygon_shift_to_closest_point(path,[1.1,1.1]) == [[1,1],[-1,1],[-1,-1],[1,-1]]);
assert(polygon_shift_to_closest_point(path,[-1.1,1.1]) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
assert(polygon_shift_to_closest_point(path,[-1.1,-1.1]) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
assert(polygon_shift_to_closest_point(path,[1.1,-1.1]) == [[1,-1],[1,1],[-1,1],[-1,-1]]);
}
*test_polygon_shift_to_closest_point();
module test_reindex_polygon() {
pent = subdivide_path([for(i=[0:4])[sin(72*i),cos(72*i)]],5);

View file

@ -1206,7 +1206,7 @@ function vnf_validate(vnf, show_warns=true, check_isects=false) =
faceverts = [for (k=face) varr[k]]
)
if (is_num(area) && abs(area) > EPSILON)
if (!coplanar(faceverts))
if (!is_coplanar(faceverts))
_vnf_validate_err("NONPLANAR", faceverts)
]),
issues = concat(issues, nonplanars)