mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Renamed some geometry.scad functions. Added geometry.scad tests.
This commit is contained in:
parent
b3c87922aa
commit
aa3af91889
2 changed files with 224 additions and 28 deletions
|
@ -39,25 +39,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// Section: Lines and Triangles
|
||||
|
||||
// Function: point_on_segment()
|
||||
// Function: point_on_segment2d()
|
||||
// Usage:
|
||||
// point_on_segment(point, edge);
|
||||
// point_on_segment2d(point, edge);
|
||||
// Description:
|
||||
// Determine if the point is on the line segment between two points.
|
||||
// Returns true if yes, and false if not.
|
||||
// Arguments:
|
||||
// point = The point to test.
|
||||
// edge = Array of two points forming the line segment to test against.
|
||||
function point_on_segment(point, edge) =
|
||||
function point_on_segment2d(point, edge) =
|
||||
point==edge[0] || point==edge[1] || // The point is an endpoint
|
||||
sign(edge[0].x-point.x)==sign(point.x-edge[1].x) // point is in between the
|
||||
&& sign(edge[0].y-point.y)==sign(point.y-edge[1].y) // edge endpoints
|
||||
&& point_left_of_segment(point, edge)==0; // and on the line defined by edge
|
||||
&& point_left_of_segment2d(point, edge)==0; // and on the line defined by edge
|
||||
|
||||
|
||||
// Function: point_left_of_segment()
|
||||
// Function: point_left_of_segment2d()
|
||||
// Usage:
|
||||
// point_left_of_segment(point, edge);
|
||||
// point_left_of_segment2d(point, edge);
|
||||
// Description:
|
||||
// Return >0 if point is left of the line defined by edge.
|
||||
// Return =0 if point is on the line.
|
||||
|
@ -65,16 +65,16 @@ function point_on_segment(point, edge) =
|
|||
// Arguments:
|
||||
// point = The point to check position of.
|
||||
// edge = Array of two points forming the line segment to test against.
|
||||
function point_left_of_segment(point, edge) =
|
||||
function point_left_of_segment2d(point, edge) =
|
||||
(edge[1].x-edge[0].x) * (point.y-edge[0].y) - (point.x-edge[0].x) * (edge[1].y-edge[0].y);
|
||||
|
||||
|
||||
// Internal non-exposed function.
|
||||
function _point_above_below_segment(point, edge) =
|
||||
edge[0].y <= point.y? (
|
||||
(edge[1].y > point.y && point_left_of_segment(point, edge) > 0)? 1 : 0
|
||||
(edge[1].y > point.y && point_left_of_segment2d(point, edge) > 0)? 1 : 0
|
||||
) : (
|
||||
(edge[1].y <= point.y && point_left_of_segment(point, edge) < 0)? -1 : 0
|
||||
(edge[1].y <= point.y && point_left_of_segment2d(point, edge) < 0)? -1 : 0
|
||||
);
|
||||
|
||||
|
||||
|
@ -82,7 +82,7 @@ function _point_above_below_segment(point, edge) =
|
|||
// Usage:
|
||||
// right_of_line2d(line, pt)
|
||||
// Description:
|
||||
// Returns true if the given point is to the left of the given line.
|
||||
// Returns true if the given point is to the left of the extended line defined by two points on it.
|
||||
// Arguments:
|
||||
// line = A list of two points.
|
||||
// pt = The point to test.
|
||||
|
@ -255,15 +255,12 @@ function in_front_of_plane(plane, point) =
|
|||
// simplify_path(path, [eps])
|
||||
// Arguments:
|
||||
// path = A list of 2D path points.
|
||||
// eps = Largest angle variance allowed. Default: EPSILON (1-e9) degrees.
|
||||
function simplify_path(path, eps=EPSILON, _a=0, _b=2, _acc=[]) =
|
||||
(_b >= len(path))? concat([path[0]], _acc, [path[len(path)-1]]) :
|
||||
simplify_path(
|
||||
path, eps,
|
||||
(collinear_indexed(path, _a, _b-1, _b, eps=eps)? _a : _b-1),
|
||||
_b+1,
|
||||
(collinear_indexed(path, _a, _b-1, _b, eps=eps)? _acc : concat(_acc, [path[_b-1]]))
|
||||
);
|
||||
// eps = Largest positional variance allowed. Default: `EPSILON` (1-e9)
|
||||
function simplify_path(path, eps=EPSILON) =
|
||||
len(path)<=2? path : let(
|
||||
indices = concat([0], [for (i=[1:len(path)-2]) if (!collinear_indexed(path, i-1, i, i+1, eps=eps)) i], [len(path)-1])
|
||||
) [for (i = indices) path[i]];
|
||||
|
||||
|
||||
|
||||
// Function: simplify_path_indexed()
|
||||
|
@ -276,14 +273,11 @@ function simplify_path(path, eps=EPSILON, _a=0, _b=2, _acc=[]) =
|
|||
// points = A list of points.
|
||||
// path = A list of indexes into `points` that forms a path.
|
||||
// eps = Largest angle variance allowed. Default: EPSILON (1-e9) degrees.
|
||||
function simplify_path_indexed(points, path, eps=EPSILON, _a=0, _b=2, _acc=[]) =
|
||||
(_b >= len(path))? concat([path[0]], _acc, [path[len(path)-1]]) :
|
||||
simplify_path_indexed(
|
||||
points, path, eps,
|
||||
(collinear_indexed(points, path[_a], path[_b-1], path[_b], eps=eps)? _a : _b-1),
|
||||
_b+1,
|
||||
(collinear_indexed(points, path[_a], path[_b-1], path[_b], eps=eps)? _acc : concat(_acc, [path[_b-1]]))
|
||||
);
|
||||
function simplify_path_indexed(points, path, eps=EPSILON) =
|
||||
len(path)<=2? path : let(
|
||||
indices = concat([0], [for (i=[1:len(path)-2]) if (!collinear_indexed(points, path[i-1], path[i], path[i+1], eps=eps)) i], [len(path)-1])
|
||||
) [for (i = indices) path[i]];
|
||||
|
||||
|
||||
|
||||
// Function: point_in_polygon()
|
||||
|
@ -304,7 +298,7 @@ function simplify_path_indexed(points, path, eps=EPSILON, _a=0, _b=2, _acc=[]) =
|
|||
// path = The list of 2D path points forming the perimeter of the polygon.
|
||||
function point_in_polygon(point, path) =
|
||||
// Does the point lie on any edges? If so return 0.
|
||||
sum([for(i=[0:len(path)-1]) point_on_segment(point, select(path, i, i+1))?1:0])>0 ? 0 :
|
||||
sum([for(i=[0:len(path)-1]) point_on_segment2d(point, select(path, i, i+1))?1:0])>0 ? 0 :
|
||||
// Otherwise compute winding number and return 1 for interior, -1 for exterior
|
||||
sum([for(i=[0:len(path)-1]) _point_above_below_segment(point, select(path, i, i+1))]) != 0 ? 1 : -1;
|
||||
|
||||
|
|
202
tests/test_geometry.scad
Normal file
202
tests/test_geometry.scad
Normal file
|
@ -0,0 +1,202 @@
|
|||
include <BOSL2/std.scad>
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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_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);
|
||||
}
|
||||
test_point_on_segment2d();
|
||||
|
||||
|
||||
module test_point_left_of_segment() {
|
||||
assert(point_left_of_segment2d([ -3, 0], [[-10,-10], [10,10]]) > 0);
|
||||
assert(point_left_of_segment2d([ 0, 0], [[-10,-10], [10,10]]) == 0);
|
||||
assert(point_left_of_segment2d([ 3, 0], [[-10,-10], [10,10]]) < 0);
|
||||
}
|
||||
test_point_left_of_segment();
|
||||
|
||||
|
||||
module test_right_of_line2d() {
|
||||
assert(right_of_line2d([[-10,-10], [10,10]], [ -3, 0]) == false);
|
||||
assert(right_of_line2d([[-10,-10], [10,10]], [ 0, 0]) == false);
|
||||
assert(right_of_line2d([[-10,-10], [10,10]], [ 3, 0]) == true);
|
||||
}
|
||||
test_right_of_line2d();
|
||||
|
||||
|
||||
module test_collinear() {
|
||||
assert(collinear([-10,-10], [-15, -16], [10,10]) == false);
|
||||
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);
|
||||
}
|
||||
test_collinear();
|
||||
|
||||
|
||||
module test_collinear_indexed() {
|
||||
pts = [
|
||||
[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]
|
||||
];
|
||||
assert(collinear_indexed(pts, 0,1,2) == false);
|
||||
assert(collinear_indexed(pts, 1,2,3) == true);
|
||||
assert(collinear_indexed(pts, 2,3,4) == true);
|
||||
assert(collinear_indexed(pts, 3,4,5) == false);
|
||||
assert(collinear_indexed(pts, 4,5,6) == false);
|
||||
assert(collinear_indexed(pts, 4,3,2) == true);
|
||||
assert(collinear_indexed(pts, 0,5,6) == false);
|
||||
}
|
||||
test_collinear_indexed();
|
||||
|
||||
|
||||
module test_distance_from_line() {
|
||||
assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,1,1])) < EPSILON);
|
||||
assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [-1,-1,-1])) < EPSILON);
|
||||
assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [1,-1,0]) - sqrt(2)) < EPSILON);
|
||||
assert(abs(distance_from_line([[-10,-10,-10], [10,10,10]], [8,-8,0]) - 8*sqrt(2)) < EPSILON);
|
||||
}
|
||||
test_distance_from_line();
|
||||
|
||||
|
||||
module test_triangle_area2d() {
|
||||
assert(abs(triangle_area2d([0,0], [0,10], [10,0]) + 50) < EPSILON);
|
||||
assert(abs(triangle_area2d([0,0], [0,10], [0,15])) < EPSILON);
|
||||
assert(abs(triangle_area2d([0,0], [10,0], [0,10]) - 50) < EPSILON);
|
||||
}
|
||||
test_triangle_area2d();
|
||||
|
||||
|
||||
module test_plane3pt() {
|
||||
assert(plane3pt([0,0,20], [0,10,10], [0,0,0]) == [1,0,0,0]);
|
||||
assert(plane3pt([2,0,20], [2,10,10], [2,0,0]) == [1,0,0,2]);
|
||||
assert(plane3pt([0,0,0], [10,0,10], [0,0,20]) == [0,1,0,0]);
|
||||
assert(plane3pt([0,2,0], [10,2,10], [0,2,20]) == [0,1,0,2]);
|
||||
assert(plane3pt([0,0,0], [10,10,0], [20,0,0]) == [0,0,1,0]);
|
||||
assert(plane3pt([0,0,2], [10,10,2], [20,0,2]) == [0,0,1,2]);
|
||||
}
|
||||
test_plane3pt();
|
||||
|
||||
|
||||
module test_plane3pt_indexed() {
|
||||
pts = [
|
||||
[0,0,0], [10,0,0], [0,10,0], [0,0,10]
|
||||
];
|
||||
s13 = sqrt(1/3);
|
||||
assert(plane3pt_indexed(pts, 0,3,2) == [1,0,0,0]);
|
||||
assert(plane3pt_indexed(pts, 0,2,3) == [-1,0,0,0]);
|
||||
assert(plane3pt_indexed(pts, 0,1,3) == [0,1,0,0]);
|
||||
assert(plane3pt_indexed(pts, 0,3,1) == [0,-1,0,0]);
|
||||
assert(plane3pt_indexed(pts, 0,2,1) == [0,0,1,0]);
|
||||
assert(plane3pt_indexed(pts, 0,1,2) == [0,0,-1,0]);
|
||||
assert(plane3pt_indexed(pts, 3,2,1) == [s13,s13,s13,10*s13]);
|
||||
assert(plane3pt_indexed(pts, 1,2,3) == [-s13,-s13,-s13,-10*s13]);
|
||||
}
|
||||
test_plane3pt_indexed();
|
||||
|
||||
|
||||
module test_distance_from_plane() {
|
||||
plane1 = plane3pt([-10,0,0], [0,10,0], [10,0,0]);
|
||||
assert(distance_from_plane(plane1, [0,0,5]) == 5);
|
||||
assert(distance_from_plane(plane1, [5,5,8]) == 8);
|
||||
}
|
||||
test_distance_from_plane();
|
||||
|
||||
|
||||
module test_coplanar() {
|
||||
plane = plane3pt([0,0,0], [0,10,10], [10,0,10]);
|
||||
assert(coplanar(plane, [5,5,10]) == true);
|
||||
assert(coplanar(plane, [10/3,10/3,20/3]) == true);
|
||||
assert(coplanar(plane, [0,0,0]) == true);
|
||||
assert(coplanar(plane, [1,1,0]) == false);
|
||||
assert(coplanar(plane, [-1,1,0]) == true);
|
||||
assert(coplanar(plane, [1,-1,0]) == true);
|
||||
assert(coplanar(plane, [5,5,5]) == false);
|
||||
}
|
||||
test_coplanar();
|
||||
|
||||
|
||||
module test_in_front_of_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);
|
||||
}
|
||||
test_in_front_of_plane();
|
||||
|
||||
|
||||
module test_simplify_path() {
|
||||
path = [[-20,-20], [-10,-20], [0,-10], [10,0], [20,10], [20,20], [15,30]];
|
||||
assert(simplify_path(path) == [[-20,-20], [-10,-20], [20,10], [20,20], [15,30]]);
|
||||
}
|
||||
test_simplify_path();
|
||||
|
||||
|
||||
module test_simplify_path_indexed() {
|
||||
pts = [[10,0], [0,-10], [20,20], [20,10], [-20,-20], [15,30], [-10,-20]];
|
||||
path = [4,6,1,0,3,2,5];
|
||||
assert(simplify_path_indexed(pts, path) == [4,6,3,2,5]);
|
||||
}
|
||||
test_simplify_path_indexed();
|
||||
|
||||
|
||||
module test_point_in_polygon() {
|
||||
poly = [for (a=[0:30:359]) 10*[cos(a),sin(a)]];
|
||||
assert(point_in_polygon([0,0], poly) == 1);
|
||||
assert(point_in_polygon([20,0], poly) == -1);
|
||||
assert(point_in_polygon([5,5], poly) == 1);
|
||||
assert(point_in_polygon([-5,5], poly) == 1);
|
||||
assert(point_in_polygon([-5,-5], poly) == 1);
|
||||
assert(point_in_polygon([5,-5], poly) == 1);
|
||||
assert(point_in_polygon([-10,-10], poly) == -1);
|
||||
assert(point_in_polygon([10,0], poly) == 0);
|
||||
assert(point_in_polygon([0,10], poly) == 0);
|
||||
assert(point_in_polygon([0,-10], poly) == 0);
|
||||
}
|
||||
test_point_in_polygon();
|
||||
|
||||
|
||||
module test_pointlist_bounds() {
|
||||
pts = [
|
||||
[-53,27,12],
|
||||
[-63,97,36],
|
||||
[84,-32,-5],
|
||||
[63,-24,42],
|
||||
[23,57,-42]
|
||||
];
|
||||
assert(pointlist_bounds(pts) == [[-63,-32,-42], [84,97,42]]);
|
||||
}
|
||||
test_pointlist_bounds();
|
||||
|
||||
|
||||
|
||||
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
Loading…
Reference in a new issue