mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
Update geometry.scad
Removed all double definitions
This commit is contained in:
parent
26ff57491e
commit
29672105ed
1 changed files with 1 additions and 160 deletions
161
geometry.scad
161
geometry.scad
|
@ -20,16 +20,6 @@
|
||||||
// point = The point to test.
|
// point = The point to test.
|
||||||
// edge = Array of two points forming the line segment to test against.
|
// edge = Array of two points forming the line segment to test against.
|
||||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||||
function point_on_segment2d(point, edge, eps=EPSILON) =
|
|
||||||
assert( is_vector(point,2), "Invalid point." )
|
|
||||||
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
|
||||||
assert( _valid_line(edge,eps=eps), "Invalid segment." )
|
|
||||||
approx(point,edge[0],eps=eps)
|
|
||||||
|| approx(point,edge[1],eps=eps) // 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
|
|
||||||
&& approx(point_left_of_line2d(point, edge),0,eps=eps) ); // and on the line defined by edge
|
|
||||||
|
|
||||||
function point_on_segment2d(point, edge, eps=EPSILON) =
|
function point_on_segment2d(point, edge, eps=EPSILON) =
|
||||||
assert( is_vector(point,2), "Invalid point." )
|
assert( is_vector(point,2), "Invalid point." )
|
||||||
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
||||||
|
@ -98,10 +88,6 @@ function collinear(a, b, c, eps=EPSILON) =
|
||||||
: noncollinear_triple(points,error=false,eps=eps)==[];
|
: noncollinear_triple(points,error=false,eps=eps)==[];
|
||||||
|
|
||||||
|
|
||||||
//*** valid for any dimension
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: distance_from_line()
|
// Function: distance_from_line()
|
||||||
// Usage:
|
// Usage:
|
||||||
// distance_from_line(line, pt);
|
// distance_from_line(line, pt);
|
||||||
|
@ -330,17 +316,6 @@ function segment_intersection(s1,s2,eps=EPSILON) =
|
||||||
// stroke(line, endcaps="arrow2");
|
// stroke(line, endcaps="arrow2");
|
||||||
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
// color("blue") translate(pt) sphere(r=1,$fn=12);
|
||||||
// color("red") translate(p2) sphere(r=1,$fn=12);
|
// color("red") translate(p2) sphere(r=1,$fn=12);
|
||||||
function line_closest_point(line,pt) =
|
|
||||||
assert(is_path(line)&&len(line)==2)
|
|
||||||
assert(same_shape(pt,line[0]))
|
|
||||||
assert(!approx(line[0],line[1]))
|
|
||||||
let(
|
|
||||||
seglen = norm(line[1]-line[0]),
|
|
||||||
segvec = (line[1]-line[0])/seglen,
|
|
||||||
projection = (pt-line[0]) * segvec
|
|
||||||
)
|
|
||||||
line[0] + projection*segvec;
|
|
||||||
|
|
||||||
function line_closest_point(line,pt) =
|
function line_closest_point(line,pt) =
|
||||||
assert(_valid_line(line), "Invalid line." )
|
assert(_valid_line(line), "Invalid line." )
|
||||||
assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." )
|
assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." )
|
||||||
|
@ -1042,23 +1017,6 @@ function closest_point_on_plane(plane, point) =
|
||||||
// Returns [POINT, U] if line intersects plane at one point.
|
// Returns [POINT, U] if line intersects plane at one point.
|
||||||
// Returns [LINE, undef] if the line is on the plane.
|
// Returns [LINE, undef] if the line is on the plane.
|
||||||
// Returns undef if line is parallel to, but not on the given plane.
|
// Returns undef if line is parallel to, but not on the given plane.
|
||||||
function _general_plane_line_intersection(plane, line, eps=EPSILON) =
|
|
||||||
let(
|
|
||||||
p0 = line[0],
|
|
||||||
p1 = line[1],
|
|
||||||
n = plane_normal(plane),
|
|
||||||
u = p1 - p0,
|
|
||||||
d = n * u
|
|
||||||
) abs(d)<eps? (
|
|
||||||
points_on_plane(p0,plane,eps)? [line,undef] : // Line on plane
|
|
||||||
undef // Line parallel to plane
|
|
||||||
) : let(
|
|
||||||
v0 = closest_point_on_plane(plane, [0,0,0]),
|
|
||||||
w = p0 - v0,
|
|
||||||
s1 = (-n * w) / d,
|
|
||||||
pt = s1 * u + p0
|
|
||||||
) [pt, s1];
|
|
||||||
|
|
||||||
function _general_plane_line_intersection(plane, line, eps=EPSILON) =
|
function _general_plane_line_intersection(plane, line, eps=EPSILON) =
|
||||||
let( a = plane*[each line[0],-1],
|
let( a = plane*[each line[0],-1],
|
||||||
b = plane*[each(line[1]-line[0]),-1] )
|
b = plane*[each(line[1]-line[0]),-1] )
|
||||||
|
@ -1345,40 +1303,6 @@ function find_circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
|
||||||
// translate(circ[0]) color("green") stroke(circle(r=circ[1]),closed=true,$fn=72);
|
// translate(circ[0]) color("green") stroke(circle(r=circ[1]),closed=true,$fn=72);
|
||||||
// translate(circ[0]) color("red") circle(d=3, $fn=12);
|
// translate(circ[0]) color("red") circle(d=3, $fn=12);
|
||||||
// move_copies(pts) color("blue") circle(d=3, $fn=12);
|
// move_copies(pts) color("blue") circle(d=3, $fn=12);
|
||||||
function find_circle_3points(pt1, pt2, pt3) =
|
|
||||||
(is_undef(pt2) && is_undef(pt3) && is_list(pt1))
|
|
||||||
? find_circle_3points(pt1[0], pt1[1], pt1[2])
|
|
||||||
: 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] :
|
|
||||||
let(
|
|
||||||
v1 = pt1-pt2,
|
|
||||||
v2 = pt3-pt2,
|
|
||||||
n = vector_axis(v1,v2),
|
|
||||||
n2 = n.z<0? -n : n
|
|
||||||
) len(pt1)+len(pt2)+len(pt3)>6? (
|
|
||||||
let(
|
|
||||||
a = project_plane(pt1, pt1, pt2, pt3),
|
|
||||||
b = project_plane(pt2, pt1, pt2, pt3),
|
|
||||||
c = project_plane(pt3, pt1, pt2, pt3),
|
|
||||||
res = find_circle_3points(a, b, c)
|
|
||||||
) res[0]==undef? [undef,undef,undef] : let(
|
|
||||||
cp = lift_plane(res[0], pt1, pt2, pt3),
|
|
||||||
r = norm(pt2-cp)
|
|
||||||
) [cp, r, n2]
|
|
||||||
) : let(
|
|
||||||
mp1 = pt2 + v1/2,
|
|
||||||
mp2 = pt2 + v2/2,
|
|
||||||
mpv1 = rot(90, v=n, p=v1),
|
|
||||||
mpv2 = rot(90, v=n, p=v2),
|
|
||||||
l1 = [mp1, mp1+mpv1],
|
|
||||||
l2 = [mp2, mp2+mpv2],
|
|
||||||
isect = line_intersection(l1,l2)
|
|
||||||
) is_undef(isect)? [undef,undef,undef] : let(
|
|
||||||
r = norm(pt2-isect)
|
|
||||||
) [isect, r, n2];
|
|
||||||
|
|
||||||
function find_circle_3points(pt1, pt2, pt3) =
|
function find_circle_3points(pt1, pt2, pt3) =
|
||||||
(is_undef(pt2) && is_undef(pt3) && is_list(pt1))
|
(is_undef(pt2) && is_undef(pt3) && is_list(pt1))
|
||||||
? find_circle_3points(pt1[0], pt1[1], pt1[2])
|
? find_circle_3points(pt1[0], pt1[1], pt1[2])
|
||||||
|
@ -1405,9 +1329,6 @@ function find_circle_3points(pt1, pt2, pt3) =
|
||||||
[ cp, r, n ];
|
[ cp, r, n ];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: circle_point_tangents()
|
// Function: circle_point_tangents()
|
||||||
// Usage:
|
// Usage:
|
||||||
// tangents = circle_point_tangents(r|d, cp, pt);
|
// tangents = circle_point_tangents(r|d, cp, pt);
|
||||||
|
@ -1607,19 +1528,6 @@ function furthest_point(pt, points) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// poly = polygon to compute the area of.
|
// poly = polygon to compute the area of.
|
||||||
// signed = if true, a signed area is returned (default: false)
|
// signed = if true, a signed area is returned (default: false)
|
||||||
function polygon_area(poly) =
|
|
||||||
assert(is_path(poly), "Invalid polygon." )
|
|
||||||
len(poly)<3? 0 :
|
|
||||||
len(poly[0])==2? 0.5*sum([for(i=[0:1:len(poly)-1]) det2(select(poly,i,i+1))]) :
|
|
||||||
let(
|
|
||||||
plane = plane_from_points(poly)
|
|
||||||
) plane==undef? undef :
|
|
||||||
let(
|
|
||||||
n = unit(plane_normal(plane)),
|
|
||||||
total = sum([for (i=[0:1:len(poly)-1]) cross(poly[i], select(poly,i+1))]),
|
|
||||||
res = abs(total * n) / 2
|
|
||||||
) res;
|
|
||||||
|
|
||||||
function polygon_area(poly, signed=false) =
|
function polygon_area(poly, signed=false) =
|
||||||
assert(is_path(poly), "Invalid polygon." )
|
assert(is_path(poly), "Invalid polygon." )
|
||||||
len(poly)<3 ? 0 :
|
len(poly)<3 ? 0 :
|
||||||
|
@ -1644,15 +1552,6 @@ function polygon_area(poly, signed=false) =
|
||||||
// Example:
|
// Example:
|
||||||
// spiral = [for (i=[0:36]) let(a=-i*10) (10+i)*[cos(a),sin(a)]];
|
// spiral = [for (i=[0:36]) let(a=-i*10) (10+i)*[cos(a),sin(a)]];
|
||||||
// is_convex_polygon(spiral); // Returns: false
|
// is_convex_polygon(spiral); // Returns: false
|
||||||
function is_convex_polygon(poly) =
|
|
||||||
assert(is_path(poly,dim=2), "The input should be a 2D polygon." )
|
|
||||||
let(
|
|
||||||
l = len(poly),
|
|
||||||
c = [for (i=idx(poly)) cross(poly[(i+1)%l]-poly[i],poly[(i+2)%l]-poly[(i+1)%l])]
|
|
||||||
)
|
|
||||||
len([for (x=c) if(x>0) 1])==0 ||
|
|
||||||
len([for (x=c) if(x<0) 1])==0;
|
|
||||||
|
|
||||||
function is_convex_polygon(poly) =
|
function is_convex_polygon(poly) =
|
||||||
assert(is_path(poly,dim=2), "The input should be a 2D polygon." )
|
assert(is_path(poly,dim=2), "The input should be a 2D polygon." )
|
||||||
let( l = len(poly) )
|
let( l = len(poly) )
|
||||||
|
@ -1726,33 +1625,6 @@ function polygon_shift_to_closest_point(path, pt) =
|
||||||
// move_copies(concat(circ,pent)) circle(r=.1,$fn=32);
|
// move_copies(concat(circ,pent)) circle(r=.1,$fn=32);
|
||||||
// color("red") move_copies([pent[0],circ[0]]) circle(r=.1,$fn=32);
|
// color("red") move_copies([pent[0],circ[0]]) circle(r=.1,$fn=32);
|
||||||
// color("blue") translate(reindexed[0])circle(r=.1,$fn=32);
|
// color("blue") translate(reindexed[0])circle(r=.1,$fn=32);
|
||||||
function reindex_polygon(reference, poly, return_error=false) =
|
|
||||||
assert(is_path(reference) && is_path(poly,dim=len(reference[0])),
|
|
||||||
"Invalid polygon(s) or incompatible dimensions. " )
|
|
||||||
assert(len(reference)==len(poly), "The polygons must have the same length.")
|
|
||||||
let(
|
|
||||||
dim = len(reference[0]),
|
|
||||||
N = len(reference),
|
|
||||||
fixpoly = dim != 2? poly :
|
|
||||||
polygon_is_clockwise(reference)? clockwise_polygon(poly) :
|
|
||||||
ccw_polygon(poly),
|
|
||||||
dist = [
|
|
||||||
// Matrix of all pairwise distances
|
|
||||||
for (p1=reference) [
|
|
||||||
for (p2=fixpoly) norm(p1-p2)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
// Compute the sum of all distance pairs for a each shift
|
|
||||||
sums = [
|
|
||||||
for(shift=[0:1:N-1]) sum([
|
|
||||||
for(i=[0:1:N-1]) dist[i][(i+shift)%N]
|
|
||||||
])
|
|
||||||
],
|
|
||||||
optimal_poly = polygon_shift(fixpoly,min_index(sums))
|
|
||||||
)
|
|
||||||
return_error? [optimal_poly, min(sums)] :
|
|
||||||
optimal_poly;
|
|
||||||
|
|
||||||
function reindex_polygon(reference, poly, return_error=false) =
|
function reindex_polygon(reference, poly, return_error=false) =
|
||||||
assert(is_path(reference) && is_path(poly,dim=len(reference[0])),
|
assert(is_path(reference) && is_path(poly,dim=len(reference[0])),
|
||||||
"Invalid polygon(s) or incompatible dimensions. " )
|
"Invalid polygon(s) or incompatible dimensions. " )
|
||||||
|
@ -1774,7 +1646,6 @@ function reindex_polygon(reference, poly, return_error=false) =
|
||||||
optimal_poly;
|
optimal_poly;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: align_polygon()
|
// Function: align_polygon()
|
||||||
// Usage:
|
// Usage:
|
||||||
// newpoly = align_polygon(reference, poly, angles, [cp]);
|
// newpoly = align_polygon(reference, poly, angles, [cp]);
|
||||||
|
@ -1819,26 +1690,6 @@ function align_polygon(reference, poly, angles, cp) =
|
||||||
// Given a simple 2D polygon, returns the 2D coordinates of the polygon's centroid.
|
// Given a simple 2D polygon, returns the 2D coordinates of the polygon's centroid.
|
||||||
// Given a simple 3D planar polygon, returns the 3D coordinates of the polygon's centroid.
|
// Given a simple 3D planar polygon, returns the 3D coordinates of the polygon's centroid.
|
||||||
// If the polygon is self-intersecting, the results are undefined.
|
// If the polygon is self-intersecting, the results are undefined.
|
||||||
function centroid(poly) =
|
|
||||||
assert( is_path(poly), "The input must be a 2D or 3D polygon." )
|
|
||||||
len(poly[0])==2
|
|
||||||
? sum([
|
|
||||||
for(i=[0:len(poly)-1])
|
|
||||||
let(segment=select(poly,i,i+1))
|
|
||||||
det2(segment)*sum(segment)
|
|
||||||
]) / 6 / polygon_area(poly)
|
|
||||||
: let( plane = plane_from_points(poly, fast=true) )
|
|
||||||
assert( !is_undef(plane), "The polygon must be planar." )
|
|
||||||
let(
|
|
||||||
n = plane_normal(plane),
|
|
||||||
p1 = vector_angle(n,UP)>15? vector_axis(n,UP) : vector_axis(n,RIGHT),
|
|
||||||
p2 = vector_axis(n,p1),
|
|
||||||
cp = mean(poly),
|
|
||||||
proj = project_plane(poly,cp,cp+p1,cp+p2),
|
|
||||||
cxy = centroid(proj)
|
|
||||||
)
|
|
||||||
lift_plane(cxy,cp,cp+p1,cp+p2);
|
|
||||||
|
|
||||||
function centroid(poly) =
|
function centroid(poly) =
|
||||||
assert( is_path(poly,dim=[2,3]), "The input must be a 2D or 3D polygon." )
|
assert( is_path(poly,dim=[2,3]), "The input must be a 2D or 3D polygon." )
|
||||||
len(poly[0])==2
|
len(poly[0])==2
|
||||||
|
@ -1915,21 +1766,11 @@ function point_in_polygon(point, path, eps=EPSILON) =
|
||||||
// Results for complex (self-intersecting) polygon are indeterminate.
|
// Results for complex (self-intersecting) polygon are indeterminate.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// path = The list of 2D path points for the perimeter of the polygon.
|
// path = The list of 2D path points for the perimeter of the polygon.
|
||||||
function polygon_is_clockwise(path) =
|
|
||||||
assert(is_path(path,dim=2), "Input should be a 2d polygon")
|
|
||||||
let(
|
|
||||||
minx = min(subindex(path,0)),
|
|
||||||
lowind = search(minx, path, 0, 0),
|
|
||||||
lowpts = select(path, lowind),
|
|
||||||
miny = min(subindex(lowpts, 1)),
|
|
||||||
extreme_sub = search(miny, lowpts, 1, 1)[0],
|
|
||||||
extreme = select(lowind,extreme_sub)
|
|
||||||
) det2([select(path,extreme+1)-path[extreme], select(path, extreme-1)-path[extreme]])<0;
|
|
||||||
|
|
||||||
function polygon_is_clockwise(path) =
|
function polygon_is_clockwise(path) =
|
||||||
assert(is_path(path,dim=2), "Input should be a 2d path")
|
assert(is_path(path,dim=2), "Input should be a 2d path")
|
||||||
polygon_area(path, signed=true)<0;
|
polygon_area(path, signed=true)<0;
|
||||||
|
|
||||||
|
|
||||||
// Function: clockwise_polygon()
|
// Function: clockwise_polygon()
|
||||||
// Usage:
|
// Usage:
|
||||||
// clockwise_polygon(path);
|
// clockwise_polygon(path);
|
||||||
|
|
Loading…
Reference in a new issue