mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-01-16 13:50:23 +01:00
Added polygon_shift_to_closest_point(), clockwise_polygon(), ccw_polygon()
This commit is contained in:
parent
be6575b5fd
commit
700acae000
105
geometry.scad
105
geometry.scad
@ -417,16 +417,6 @@ function plane3pt(p1, p2, p3) =
|
||||
) concat(normal, [normal*p1]);
|
||||
|
||||
|
||||
function plane_from_pointslist(points) =
|
||||
let(
|
||||
points = deduplicate(points),
|
||||
indices = find_noncollinear_points(points),
|
||||
p1 = points[indices[0]],
|
||||
p2 = points[indices[1]],
|
||||
p3 = points[indices[2]]
|
||||
) plane3pt(p1,p2,p3);
|
||||
|
||||
|
||||
// Function: plane3pt_indexed()
|
||||
// Usage:
|
||||
// plane3pt_indexed(points, i1, i2, i3);
|
||||
@ -448,6 +438,22 @@ function plane3pt_indexed(points, i1, i2, i3) =
|
||||
) plane3pt(p1,p2,p3);
|
||||
|
||||
|
||||
// Function: plane_from_pointslist()
|
||||
// Usage:
|
||||
// plane_from_pointslist(points);
|
||||
// Description:
|
||||
// Given a list of coplanar points, returns the cartesian equation of a plane.
|
||||
// Returns [A,B,C,D] where Ax+By+Cz+D=0 is the equation of the plane.
|
||||
function plane_from_pointslist(points) =
|
||||
let(
|
||||
points = deduplicate(points),
|
||||
indices = find_noncollinear_points(points),
|
||||
p1 = points[indices[0]],
|
||||
p2 = points[indices[1]],
|
||||
p3 = points[indices[2]]
|
||||
) plane3pt(p1,p2,p3);
|
||||
|
||||
|
||||
// Function: plane_normal()
|
||||
// Usage:
|
||||
// plane_normal(plane);
|
||||
@ -574,6 +580,21 @@ function polygon_area(vertices) =
|
||||
0.5*sum([for(i=[0:len(vertices)-1]) det2(select(vertices,i,i+1))]);
|
||||
|
||||
|
||||
// Function: polygon_shift_to_closest_point()
|
||||
// Usage:
|
||||
// polygon_shift_to_closest_point(path, pt);
|
||||
// Description:
|
||||
// Given a polygon `path`, rotates the point ordering so that the first point in the path is the one closest to the given point `pt`.
|
||||
function polygon_shift_to_closest_point(path, pt) =
|
||||
let(
|
||||
path = cleanup_path(path),
|
||||
closest = path_closest_point(path,pt),
|
||||
seg = select(path,closest[0],closest[0]+1),
|
||||
u = norm(closest[1]-seg[0]) / norm(seg[1]-seg[0]),
|
||||
segnum = closest[0] + (u>0.5? 1 : 0)
|
||||
) select(path,segnum,segnum+len(path)-1);
|
||||
|
||||
|
||||
// Function: first_noncollinear()
|
||||
// Usage:
|
||||
// first_noncollinear(i1, i2, points);
|
||||
@ -740,24 +761,6 @@ function point_in_polygon(point, path, eps=EPSILON) =
|
||||
sum([for(i=[0:1:len(path)-1]) let(seg=select(path,i,i+1)) if(!approx(seg[0],seg[1],eps=eps)) _point_above_below_segment(point, seg)]) != 0? 1 : -1;
|
||||
|
||||
|
||||
// Function: point_in_region()
|
||||
// Usage:
|
||||
// point_in_region(point, region);
|
||||
// Description:
|
||||
// Tests if a point is inside, outside, or on the border of a region.
|
||||
// Returns -1 if the point is outside the region.
|
||||
// Returns 0 if the point is on the boundary.
|
||||
// Returns 1 if the point lies inside the region.
|
||||
// Arguments:
|
||||
// point = The point to test.
|
||||
// region = The region to test against. Given as a list of polygon paths.
|
||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||
function point_in_region(point, region, eps=EPSILON, _i=0, _cnt=0) =
|
||||
(_i >= len(region))? ((_cnt%2==1)? 1 : -1) : let(
|
||||
pip = point_in_polygon(point, region[_i], eps=eps)
|
||||
) pip==0? 0 : point_in_region(point, region, eps=eps, _i=_i+1, _cnt = _cnt + (pip>0? 1 : 0));
|
||||
|
||||
|
||||
// Function: pointlist_bounds()
|
||||
// Usage:
|
||||
// pointlist_bounds(pts);
|
||||
@ -800,15 +803,15 @@ function furthest_point(pt, points) =
|
||||
) i;
|
||||
|
||||
|
||||
// Function: polygon_clockwise()
|
||||
// Function: polygon_is_clockwise()
|
||||
// Usage:
|
||||
// polygon_clockwise(path);
|
||||
// polygon_is_clockwise(path);
|
||||
// Description:
|
||||
// Return true if the given 2D simple polygon is in clockwise order, false otherwise.
|
||||
// Results for complex (self-intersecting) polygon are indeterminate.
|
||||
// Arguments:
|
||||
// path = The list of 2D path points for the perimeter of the polygon.
|
||||
function polygon_clockwise(path) =
|
||||
function polygon_is_clockwise(path) =
|
||||
let(
|
||||
minx = min(subindex(path,0)),
|
||||
lowind = search(minx, path, 0, 0),
|
||||
@ -819,6 +822,24 @@ function polygon_clockwise(path) =
|
||||
) det2([select(path,extreme+1)-path[extreme], select(path, extreme-1)-path[extreme]])<0;
|
||||
|
||||
|
||||
// Function: clockwise_polygon()
|
||||
// Usage:
|
||||
// clockwise_polygon(path);
|
||||
// Description:
|
||||
// Given a polygon path, returns the clockwise winding version of that path.
|
||||
function clockwise_polygon(path) =
|
||||
polygon_is_clockwise(path)? path : reverse(path);
|
||||
|
||||
|
||||
// Function: ccw_polygon()
|
||||
// Usage:
|
||||
// ccw_polygon(path);
|
||||
// Description:
|
||||
// Given a polygon path, returns the counter-clockwise winding version of that path.
|
||||
function ccw_polygon(path) =
|
||||
polygon_is_clockwise(path)? reverse(path) : path;
|
||||
|
||||
|
||||
|
||||
// Section: Regions and Boolean 2D Geometry
|
||||
|
||||
@ -872,6 +893,24 @@ function check_and_fix_path(path,valid_dim=undef,closed=false) =
|
||||
function cleanup_region(region, eps=EPSILON) = [for (path=region) cleanup_path(path, eps=eps)];
|
||||
|
||||
|
||||
// Function: point_in_region()
|
||||
// Usage:
|
||||
// point_in_region(point, region);
|
||||
// Description:
|
||||
// Tests if a point is inside, outside, or on the border of a region.
|
||||
// Returns -1 if the point is outside the region.
|
||||
// Returns 0 if the point is on the boundary.
|
||||
// Returns 1 if the point lies inside the region.
|
||||
// Arguments:
|
||||
// point = The point to test.
|
||||
// region = The region to test against. Given as a list of polygon paths.
|
||||
// eps = Acceptable variance. Default: `EPSILON` (1e-9)
|
||||
function point_in_region(point, region, eps=EPSILON, _i=0, _cnt=0) =
|
||||
(_i >= len(region))? ((_cnt%2==1)? 1 : -1) : let(
|
||||
pip = point_in_polygon(point, region[_i], eps=eps)
|
||||
) pip==0? 0 : point_in_region(point, region, eps=eps, _i=_i+1, _cnt = _cnt + (pip>0? 1 : 0));
|
||||
|
||||
|
||||
// Function: region_path_crossings()
|
||||
// Usage:
|
||||
// region_path_crossings(path, region);
|
||||
@ -1142,7 +1181,7 @@ function offset(
|
||||
is_region(path)? (
|
||||
assert(!return_faces, "return_faces not supported for regions.")
|
||||
let(
|
||||
path = [for (p=path) polygon_clockwise(p)? p : reverse(p)],
|
||||
path = [for (p=path) polygon_is_clockwise(p)? p : reverse(p)],
|
||||
rgn = exclusive_or([for (p = path) [p]]),
|
||||
pathlist = sort(idx=0,[
|
||||
for (i=[0:1:len(rgn)-1]) [
|
||||
@ -1164,7 +1203,7 @@ function offset(
|
||||
let(
|
||||
chamfer = is_def(r) ? false : chamfer,
|
||||
quality = max(0,round(quality)),
|
||||
flip_dir = closed && !polygon_clockwise(path) ? -1 : 1,
|
||||
flip_dir = closed && !polygon_is_clockwise(path) ? -1 : 1,
|
||||
d = flip_dir * (is_def(r) ? r : delta),
|
||||
shiftsegs = [for(i=[0:len(path)-1]) _shift_segment(select(path,i,i+1), d)],
|
||||
// good segments are ones where no point on the segment is less than distance d from any point on the path
|
||||
|
@ -636,7 +636,7 @@ module rounded_sweep(
|
||||
top = struct_set(argspec, top, grow=false);
|
||||
bottom = struct_set(argspec, bottom, grow=false);
|
||||
|
||||
clockwise = polygon_clockwise(path);
|
||||
clockwise = polygon_is_clockwise(path);
|
||||
|
||||
assert(height>=0, "Height must be nonnegative");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user