mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
remove polygon_shift, hide noncollinear_triple
modify glued circle to not produce duplicate points
This commit is contained in:
parent
ec87be11ec
commit
477dd55781
11 changed files with 61 additions and 89 deletions
|
@ -1952,8 +1952,6 @@ module anchor_arrow2d(s=15, color=[0.333,0.333,1], $tags="anchor-arrow") {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
// Module: expose_anchors()
|
||||
// Usage:
|
||||
// expose_anchors(opacity) {child1() show_anchors(); child2() show_anchors(); ...}
|
||||
|
|
|
@ -153,7 +153,7 @@ function is_collinear(a, b, c, eps=EPSILON) =
|
|||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
let( points = is_def(c) ? [a,b,c]: a )
|
||||
len(points)<3 ? true :
|
||||
noncollinear_triple(points,error=false,eps=eps) == [];
|
||||
_noncollinear_triple(points,error=false,eps=eps) == [];
|
||||
|
||||
|
||||
// Function: point_line_distance()
|
||||
|
@ -429,7 +429,7 @@ 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
|
||||
: let( ip = noncollinear_triple(points,error=false,eps=eps) )
|
||||
: let( ip = _noncollinear_triple(points,error=false,eps=eps) )
|
||||
ip == [] ? false :
|
||||
let( plane = plane3pt(points[ip[0]],points[ip[1]],points[ip[2]]) )
|
||||
_pointlist_greatest_distance(points,plane) < eps;
|
||||
|
@ -850,7 +850,7 @@ function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps
|
|||
)
|
||||
(len(inside)==0 ? undef : _merge_segments(inside, [inside[0]], eps))
|
||||
: // 3d case
|
||||
let(indices = noncollinear_triple(poly))
|
||||
let(indices = _noncollinear_triple(poly))
|
||||
indices==[] ? undef : // Polygon is collinear
|
||||
let(
|
||||
plane = plane3pt(poly[indices[0]], poly[indices[1]], poly[indices[2]]),
|
||||
|
@ -1384,25 +1384,22 @@ function circle_circle_tangents(c1,r1,c2,r2,d1,d2) =
|
|||
|
||||
|
||||
|
||||
// Section: Pointlists
|
||||
|
||||
|
||||
// Function: noncollinear_triple()
|
||||
// Usage:
|
||||
// test = noncollinear_triple(points);
|
||||
// Topics: Geometry, Noncollinearity
|
||||
// Description:
|
||||
// Finds the indices of three non-collinear points from the pointlist `points`.
|
||||
// It selects two well separated points to define a line and chooses the third point
|
||||
// to be the point farthest off the line. The points do not necessarily having the
|
||||
// same winding direction as the polygon so they cannot be used to determine the
|
||||
// winding direction or the direction of the normal.
|
||||
// If all points are collinear returns [] when `error=true` or an error otherwise .
|
||||
// Arguments:
|
||||
// points = List of input points.
|
||||
// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`.
|
||||
// eps = Tolerance for collinearity test. Default: EPSILON.
|
||||
function noncollinear_triple(points,error=true,eps=EPSILON) =
|
||||
/// Internal Function: _noncollinear_triple()
|
||||
/// Usage:
|
||||
/// test = _noncollinear_triple(points);
|
||||
/// Topics: Geometry, Noncollinearity
|
||||
/// Description:
|
||||
/// Finds the indices of three non-collinear points from the pointlist `points`.
|
||||
/// It selects two well separated points to define a line and chooses the third point
|
||||
/// to be the point farthest off the line. The points do not necessarily having the
|
||||
/// same winding direction as the polygon so they cannot be used to determine the
|
||||
/// winding direction or the direction of the normal.
|
||||
/// If all points are collinear returns [] when `error=true` or an error otherwise .
|
||||
/// Arguments:
|
||||
/// points = List of input points.
|
||||
/// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`.
|
||||
/// eps = Tolerance for collinearity test. Default: EPSILON.
|
||||
function _noncollinear_triple(points,error=true,eps=EPSILON) =
|
||||
assert( is_path(points), "Invalid input points." )
|
||||
assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
|
||||
len(points)<3 ? [] :
|
||||
|
@ -1953,26 +1950,6 @@ function reverse_polygon(poly) =
|
|||
[ poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ];
|
||||
|
||||
|
||||
|
||||
// Function: polygon_shift()
|
||||
// Usage:
|
||||
// newpoly = polygon_shift(poly, i);
|
||||
// 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.
|
||||
// Example:
|
||||
// polygon_shift([[3,4], [8,2], [0,2], [-4,0]], 2); // Returns [[0,2], [-4,0], [3,4], [8,2]]
|
||||
function polygon_shift(poly, i) =
|
||||
let(poly=force_path(poly,"poly"))
|
||||
assert(is_path(poly), "Invalid polygon." )
|
||||
list_rotate(cleanup_path(poly), i);
|
||||
|
||||
|
||||
|
||||
// Function: reindex_polygon()
|
||||
// Usage:
|
||||
// newpoly = reindex_polygon(reference, poly);
|
||||
|
@ -2021,7 +1998,7 @@ function reindex_polygon(reference, poly, return_error=false) =
|
|||
[for(i=[0:N-1])
|
||||
norm(reference[i]-fixpoly[(i+k)%N]) ] ]*I,
|
||||
min_ind = min_index(val),
|
||||
optimal_poly = polygon_shift(fixpoly, min_ind)
|
||||
optimal_poly = list_rotate(fixpoly, min_ind)
|
||||
)
|
||||
return_error? [optimal_poly, val[min_ind]] :
|
||||
optimal_poly;
|
||||
|
@ -2175,7 +2152,7 @@ function is_polygon_convex(poly,eps=EPSILON) =
|
|||
? let( size = max([for(p=poly) norm(p-p0)]), tol=pow(size,2)*eps )
|
||||
assert( size>eps, "The polygon is self-crossing or its points are collinear" )
|
||||
min(crosses) >=-tol || max(crosses)<=tol
|
||||
: let( ip = noncollinear_triple(poly,error=false,eps=eps) )
|
||||
: let( ip = _noncollinear_triple(poly,error=false,eps=eps) )
|
||||
assert( ip!=[], "The points are collinear")
|
||||
let(
|
||||
crx = cross(poly[ip[1]]-poly[ip[0]],poly[ip[2]]-poly[ip[1]]),
|
||||
|
|
|
@ -166,7 +166,7 @@ function hull3d_faces(points) =
|
|||
assert(is_path(points,3),"Invalid input to hull3d_faces")
|
||||
len(points) < 3 ? count(len(points))
|
||||
: let ( // start with a single non-collinear triangle
|
||||
tri = noncollinear_triple(points, error=false)
|
||||
tri = _noncollinear_triple(points, error=false)
|
||||
)
|
||||
tri==[] ? _hull_collinear(points)
|
||||
: let(
|
||||
|
|
|
@ -497,7 +497,7 @@ function reverse(x) =
|
|||
// Topics: List Handling
|
||||
// See Also: select(), reverse()
|
||||
// Description:
|
||||
// Rotates the contents of a list by `n` positions left.
|
||||
// Rotates the contents of a list by `n` positions left, so that list[n] becomes the first entry of the list.
|
||||
// If `n` is negative, then the rotation is `abs(n)` positions to the right.
|
||||
// If `list` is a string, then a string is returned with the characters rotates within the string.
|
||||
// Arguments:
|
||||
|
|
|
@ -1132,7 +1132,7 @@ function os_mask(mask, out=false, extra,check_valid, quality, offset) =
|
|||
)
|
||||
assert(len(origin_index)==1,"Cannot find origin in the mask")
|
||||
let(
|
||||
points = ([for(pt=polygon_shift(mask,origin_index[0])) [xfactor*max(pt.x,0),-max(pt.y,0)]])
|
||||
points = ([for(pt=list_rotate(mask,origin_index[0])) [xfactor*max(pt.x,0),-max(pt.y,0)]])
|
||||
)
|
||||
os_profile(deduplicate(move(-points[1],p=list_tail(points))), extra,check_valid,quality,offset);
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
|
|||
each arc(N=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n)
|
||||
],
|
||||
maxx_idx = max_index(column(path2,0)),
|
||||
path3 = polygon_shift(path2,maxx_idx)
|
||||
path3 = list_rotate(path2,maxx_idx)
|
||||
) path3
|
||||
),
|
||||
path = apply(mat, path4),
|
||||
|
@ -1009,7 +1009,7 @@ function teardrop2d(r, ang=45, cap_h, d, anchor=CENTER, spin=0) =
|
|||
], closed=true
|
||||
),
|
||||
maxx_idx = max_index(column(path,0)),
|
||||
path2 = polygon_shift(path,maxx_idx)
|
||||
path2 = list_rotate(path,maxx_idx)
|
||||
) reorient(anchor,spin, two_d=true, path=path2, p=path2);
|
||||
|
||||
|
||||
|
@ -1051,20 +1051,23 @@ function glued_circles(r, spread=10, tangent=30, d, anchor=CENTER, spin=0) =
|
|||
ea1 = 270+tangent,
|
||||
lobearc = ea1-sa1,
|
||||
lobesegs = ceil(segs(r)*lobearc/360),
|
||||
lobestep = lobearc / lobesegs,
|
||||
sa2 = 270-tangent,
|
||||
ea2 = 270+tangent,
|
||||
subarc = ea2-sa2,
|
||||
arcsegs = ceil(segs(r2)*abs(subarc)/360),
|
||||
arcstep = subarc / arcsegs,
|
||||
path = concat(
|
||||
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep) r * [cos(a),sin(a)] - cp1],
|
||||
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep+180) r2 * [cos(a),sin(a)] - cp2],
|
||||
[for (i=[0:1:lobesegs]) let(a=sa1+i*lobestep+180) r * [cos(a),sin(a)] + cp1],
|
||||
tangent==0? [] : [for (i=[0:1:arcsegs]) let(a=ea2-i*arcstep) r2 * [cos(a),sin(a)] + cp2]
|
||||
),
|
||||
// In the tangent zero case the inner curves are missing so we need to complete the two
|
||||
// outer curves. In the other case the inner curves are present and endpoint=false
|
||||
// prevents point duplication.
|
||||
path = tangent==0 ?
|
||||
concat(arc(N=lobesegs+1, r=r, cp=-cp1, angle=[sa1,ea1]),
|
||||
arc(N=lobesegs+1, r=r, cp=cp1, angle=[sa1+180,ea1+180]))
|
||||
:
|
||||
concat(arc(N=lobesegs, r=r, cp=-cp1, angle=[sa1,ea1], endpoint=false),
|
||||
[for(theta=lerpn(ea2+180,ea2-subarc+180,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] - cp2],
|
||||
arc(N=lobesegs, r=r, cp=cp1, angle=[sa1+180,ea1+180], endpoint=false),
|
||||
[for(theta=lerpn(ea2,ea2-subarc,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] + cp2]),
|
||||
maxx_idx = max_index(column(path,0)),
|
||||
path2 = reverse_polygon(polygon_shift(path,maxx_idx))
|
||||
path2 = reverse_polygon(list_rotate(path,maxx_idx))
|
||||
) reorient(anchor,spin, two_d=true, path=path2, extent=true, p=path2);
|
||||
|
||||
|
||||
|
|
14
skin.scad
14
skin.scad
|
@ -344,7 +344,7 @@
|
|||
// hex = path3d(hexagon(side=flare*sidelen, align_side=RIGHT, anchor="side0"),height);
|
||||
// pentmate = path3d(pentagon(side=flare*sidelen,align_side=LEFT,anchor="side0"),height);
|
||||
// // Native index would require mapping first and last vertices together, which is not allowed, so shift
|
||||
// hexmate = polygon_shift(
|
||||
// hexmate = list_rotate(
|
||||
// path3d(apply(move(pushvec)*rot(angle),hexagon(side=sidelen,align_side=LEFT,anchor="side0"))),
|
||||
// -1);
|
||||
// join_vertex = lerp(
|
||||
|
@ -1540,7 +1540,7 @@ function _skin_distance_match(poly1,poly2) =
|
|||
;
|
||||
i<=len(big)
|
||||
;
|
||||
shifted = polygon_shift(big,i),
|
||||
shifted = list_rotate(big,i),
|
||||
result =_dp_distance_array(small, shifted, abort_thresh = bestcost),
|
||||
bestmap = result[0]<bestcost ? result[1] : bestmap,
|
||||
bestpoly = result[0]<bestcost ? shifted : bestpoly,
|
||||
|
@ -1555,8 +1555,8 @@ function _skin_distance_match(poly1,poly2) =
|
|||
// These shifts are needed to handle the case when points from both ends of one curve map to a single point on the other
|
||||
bigshift = len(bigmap) - max(max_index(bigmap,all=true))-1,
|
||||
smallshift = len(smallmap) - max(max_index(smallmap,all=true))-1,
|
||||
newsmall = polygon_shift(repeat_entries(small,unique_count(smallmap)[1]),smallshift),
|
||||
newbig = polygon_shift(repeat_entries(map_poly[1],unique_count(bigmap)[1]),bigshift)
|
||||
newsmall = list_rotate(repeat_entries(small,unique_count(smallmap)[1]),smallshift),
|
||||
newbig = list_rotate(repeat_entries(map_poly[1],unique_count(bigmap)[1]),bigshift)
|
||||
)
|
||||
swap ? [newbig, newsmall] : [newsmall,newbig];
|
||||
|
||||
|
@ -1571,8 +1571,8 @@ function _skin_aligned_distance_match(poly1, poly2) =
|
|||
map = _dp_extract_map(result[1]),
|
||||
shift0 = len(map[0]) - max(max_index(map[0],all=true))-1,
|
||||
shift1 = len(map[1]) - max(max_index(map[1],all=true))-1,
|
||||
new0 = polygon_shift(repeat_entries(poly1,unique_count(map[0])[1]),shift0),
|
||||
new1 = polygon_shift(repeat_entries(poly2,unique_count(map[1])[1]),shift1)
|
||||
new0 = list_rotate(repeat_entries(poly1,unique_count(map[0])[1]),shift0),
|
||||
new1 = list_rotate(repeat_entries(poly2,unique_count(map[1])[1]),shift1)
|
||||
)
|
||||
[new0,new1];
|
||||
|
||||
|
@ -1598,7 +1598,7 @@ function _skin_tangent_match(poly1, poly2) =
|
|||
curve_offset = centroid(small)-centroid(big),
|
||||
cutpts = [for(i=[0:len(small)-1]) _find_one_tangent(big, select(small,i,i+1),curve_offset=curve_offset)],
|
||||
shift = last(cutpts)+1,
|
||||
newbig = polygon_shift(big, shift),
|
||||
newbig = list_rotate(big, shift),
|
||||
repeat_counts = [for(i=[0:len(small)-1]) posmod(cutpts[i]-select(cutpts,i-1),len(big))],
|
||||
newsmall = repeat_entries(small,repeat_counts)
|
||||
)
|
||||
|
|
|
@ -40,10 +40,9 @@ test_circle_2tangents();
|
|||
test_circle_3points();
|
||||
test_circle_point_tangents();
|
||||
|
||||
test_noncollinear_triple();
|
||||
test__noncollinear_triple();
|
||||
test_polygon_area();
|
||||
test_is_polygon_convex();
|
||||
test_polygon_shift();
|
||||
test_reindex_polygon();
|
||||
test_align_polygon();
|
||||
test_centroid();
|
||||
|
@ -787,15 +786,6 @@ module test_is_polygon_convex() {
|
|||
*test_is_polygon_convex();
|
||||
|
||||
|
||||
module test_polygon_shift() {
|
||||
path = [[1,1],[-1,1],[-1,-1],[1,-1]];
|
||||
assert(polygon_shift(path,1) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
|
||||
assert(polygon_shift(path,2) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
|
||||
}
|
||||
*test_polygon_shift();
|
||||
|
||||
|
||||
|
||||
module test_reindex_polygon() {
|
||||
pent = subdivide_path([for(i=[0:4])[sin(72*i),cos(72*i)]],5);
|
||||
circ = circle($fn=5,r=2.2);
|
||||
|
@ -827,13 +817,13 @@ module test_align_polygon() {
|
|||
*test_align_polygon();
|
||||
|
||||
|
||||
module test_noncollinear_triple() {
|
||||
assert(noncollinear_triple([[1,1],[2,2],[3,3],[4,4],[4,5],[5,6]]) == [0,5,3]);
|
||||
assert(noncollinear_triple([[1,1],[2,2],[8,3],[4,4],[4,5],[5,6]]) == [0,2,5]);
|
||||
module test__noncollinear_triple() {
|
||||
assert(_noncollinear_triple([[1,1],[2,2],[3,3],[4,4],[4,5],[5,6]]) == [0,5,3]);
|
||||
assert(_noncollinear_triple([[1,1],[2,2],[8,3],[4,4],[4,5],[5,6]]) == [0,2,5]);
|
||||
u = unit([5,3]);
|
||||
assert_equal(noncollinear_triple([for(i = [2,3,4,5,7,12,15]) i * u], error=false),[]);
|
||||
assert_equal(_noncollinear_triple([for(i = [2,3,4,5,7,12,15]) i * u], error=false),[]);
|
||||
}
|
||||
*test_noncollinear_triple();
|
||||
*test__noncollinear_triple();
|
||||
|
||||
|
||||
module test_centroid() {
|
||||
|
|
|
@ -133,6 +133,9 @@ module test_list_rotate() {
|
|||
assert(list_rotate([1,2,3,4,5],5) == [1,2,3,4,5]);
|
||||
assert(list_rotate([1,2,3,4,5],6) == [2,3,4,5,1]);
|
||||
assert(list_rotate([],3) == []);
|
||||
path = [[1,1],[-1,1],[-1,-1],[1,-1]];
|
||||
assert(list_rotate(path,1) == [[-1,1],[-1,-1],[1,-1],[1,1]]);
|
||||
assert(list_rotate(path,2) == [[-1,-1],[1,-1],[1,1],[-1,1]]);
|
||||
}
|
||||
test_list_rotate();
|
||||
|
||||
|
|
|
@ -100,10 +100,11 @@ test_teardrop2d();
|
|||
|
||||
module test_glued_circles() {
|
||||
$fn=24;
|
||||
assert_approx(glued_circles(r=15, spread=40, tangent=30), [[35,0],[34.4888873943,-3.88228567654],[32.9903810568,-7.5],[30.6066017178,-10.6066017178],[27.5,-12.9903810568],[23.8822856765,-14.4888873943],[20,-15],[16.1177143235,-14.4888873943],[12.5,-12.9903810568],[12.5,-12.9903810568],[6.47047612756,-10.4928704942],[0,-9.64101615138],[-6.47047612756,-10.4928704942],[-12.5,-12.9903810568],[-12.5,-12.9903810568],[-16.1177143235,-14.4888873943],[-20,-15],[-23.8822856765,-14.4888873943],[-27.5,-12.9903810568],[-30.6066017178,-10.6066017178],[-32.9903810568,-7.5],[-34.4888873943,-3.88228567654],[-35,0],[-34.4888873943,3.88228567654],[-32.9903810568,7.5],[-30.6066017178,10.6066017178],[-27.5,12.9903810568],[-23.8822856765,14.4888873943],[-20,15],[-16.1177143235,14.4888873943],[-12.5,12.9903810568],[-6.47047612756,10.4928704942],[0,9.64101615138],[6.47047612756,10.4928704942],[12.5,12.9903810568],[12.5,12.9903810568],[16.1177143235,14.4888873943],[20,15],[23.8822856765,14.4888873943],[27.5,12.9903810568],[30.6066017178,10.6066017178],[32.9903810568,7.5],[34.4888873943,3.88228567654]]);
|
||||
assert_approx(glued_circles(d=30, spread=40, tangent=30), [[35,0],[34.4888873943,-3.88228567654],[32.9903810568,-7.5],[30.6066017178,-10.6066017178],[27.5,-12.9903810568],[23.8822856765,-14.4888873943],[20,-15],[16.1177143235,-14.4888873943],[12.5,-12.9903810568],[12.5,-12.9903810568],[6.47047612756,-10.4928704942],[0,-9.64101615138],[-6.47047612756,-10.4928704942],[-12.5,-12.9903810568],[-12.5,-12.9903810568],[-16.1177143235,-14.4888873943],[-20,-15],[-23.8822856765,-14.4888873943],[-27.5,-12.9903810568],[-30.6066017178,-10.6066017178],[-32.9903810568,-7.5],[-34.4888873943,-3.88228567654],[-35,0],[-34.4888873943,3.88228567654],[-32.9903810568,7.5],[-30.6066017178,10.6066017178],[-27.5,12.9903810568],[-23.8822856765,14.4888873943],[-20,15],[-16.1177143235,14.4888873943],[-12.5,12.9903810568],[-6.47047612756,10.4928704942],[0,9.64101615138],[6.47047612756,10.4928704942],[12.5,12.9903810568],[12.5,12.9903810568],[16.1177143235,14.4888873943],[20,15],[23.8822856765,14.4888873943],[27.5,12.9903810568],[30.6066017178,10.6066017178],[32.9903810568,7.5],[34.4888873943,3.88228567654]]);
|
||||
assert_approx(glued_circles(d=30, spread=30, tangent=45), [[30,0],[29.4888873943,-3.88228567654],[27.9903810568,-7.5],[25.6066017178,-10.6066017178],[22.5,-12.9903810568],[18.8822856765,-14.4888873943],[15,-15],[11.1177143235,-14.4888873943],[7.5,-12.9903810568],[4.3933982822,-10.6066017178],[4.3933982822,-10.6066017178],[3.1066017178,-9.61920798589],[1.60809538023,-8.99850633757],[0,-8.7867965644],[-1.60809538023,-8.99850633757],[-3.1066017178,-9.61920798589],[-4.3933982822,-10.6066017178],[-4.3933982822,-10.6066017178],[-7.5,-12.9903810568],[-11.1177143235,-14.4888873943],[-15,-15],[-18.8822856765,-14.4888873943],[-22.5,-12.9903810568],[-25.6066017178,-10.6066017178],[-27.9903810568,-7.5],[-29.4888873943,-3.88228567654],[-30,0],[-29.4888873943,3.88228567654],[-27.9903810568,7.5],[-25.6066017178,10.6066017178],[-22.5,12.9903810568],[-18.8822856765,14.4888873943],[-15,15],[-11.1177143235,14.4888873943],[-7.5,12.9903810568],[-4.3933982822,10.6066017178],[-3.1066017178,9.61920798589],[-1.60809538023,8.99850633757],[0,8.7867965644],[1.60809538023,8.99850633757],[3.1066017178,9.61920798589],[4.3933982822,10.6066017178],[4.3933982822,10.6066017178],[7.5,12.9903810568],[11.1177143235,14.4888873943],[15,15],[18.8822856765,14.4888873943],[22.5,12.9903810568],[25.6066017178,10.6066017178],[27.9903810568,7.5],[29.4888873943,3.88228567654]]);
|
||||
assert_approx(glued_circles(d=30, spread=30, tangent=-30), [[30,0],[29.4888873943,-3.88228567654],[27.9903810568,-7.5],[25.6066017178,-10.6066017178],[22.5,-12.9903810568],[22.5,-12.9903810568],[11.6468570296,-17.4859000695],[0,-19.0192378865],[-11.6468570296,-17.4859000695],[-22.5,-12.9903810568],[-22.5,-12.9903810568],[-25.6066017178,-10.6066017178],[-27.9903810568,-7.5],[-29.4888873943,-3.88228567654],[-30,0],[-29.4888873943,3.88228567654],[-27.9903810568,7.5],[-25.6066017178,10.6066017178],[-22.5,12.9903810568],[-11.6468570296,17.4859000695],[0,19.0192378865],[11.6468570296,17.4859000695],[22.5,12.9903810568],[22.5,12.9903810568],[25.6066017178,10.6066017178],[27.9903810568,7.5],[29.4888873943,3.88228567654]]);
|
||||
assert_approx(glued_circles(r=15, spread=40, tangent=30), deduplicate([[35,0],[34.4888873943,-3.88228567654],[32.9903810568,-7.5],[30.6066017178,-10.6066017178],[27.5,-12.9903810568],[23.8822856765,-14.4888873943],[20,-15],[16.1177143235,-14.4888873943],[12.5,-12.9903810568],[12.5,-12.9903810568],[6.47047612756,-10.4928704942],[0,-9.64101615138],[-6.47047612756,-10.4928704942],[-12.5,-12.9903810568],[-12.5,-12.9903810568],[-16.1177143235,-14.4888873943],[-20,-15],[-23.8822856765,-14.4888873943],[-27.5,-12.9903810568],[-30.6066017178,-10.6066017178],[-32.9903810568,-7.5],[-34.4888873943,-3.88228567654],[-35,0],[-34.4888873943,3.88228567654],[-32.9903810568,7.5],[-30.6066017178,10.6066017178],[-27.5,12.9903810568],[-23.8822856765,14.4888873943],[-20,15],[-16.1177143235,14.4888873943],[-12.5,12.9903810568],[-6.47047612756,10.4928704942],[0,9.64101615138],[6.47047612756,10.4928704942],[12.5,12.9903810568],[12.5,12.9903810568],[16.1177143235,14.4888873943],[20,15],[23.8822856765,14.4888873943],[27.5,12.9903810568],[30.6066017178,10.6066017178],[32.9903810568,7.5],[34.4888873943,3.88228567654]]));
|
||||
assert_approx(glued_circles(d=30, spread=40, tangent=30),deduplicate( [[35,0],[34.4888873943,-3.88228567654],[32.9903810568,-7.5],[30.6066017178,-10.6066017178],[27.5,-12.9903810568],[23.8822856765,-14.4888873943],[20,-15],[16.1177143235,-14.4888873943],[12.5,-12.9903810568],[12.5,-12.9903810568],[6.47047612756,-10.4928704942],[0,-9.64101615138],[-6.47047612756,-10.4928704942],[-12.5,-12.9903810568],[-12.5,-12.9903810568],[-16.1177143235,-14.4888873943],[-20,-15],[-23.8822856765,-14.4888873943],[-27.5,-12.9903810568],[-30.6066017178,-10.6066017178],[-32.9903810568,-7.5],[-34.4888873943,-3.88228567654],[-35,0],[-34.4888873943,3.88228567654],[-32.9903810568,7.5],[-30.6066017178,10.6066017178],[-27.5,12.9903810568],[-23.8822856765,14.4888873943],[-20,15],[-16.1177143235,14.4888873943],[-12.5,12.9903810568],[-6.47047612756,10.4928704942],[0,9.64101615138],[6.47047612756,10.4928704942],[12.5,12.9903810568],[12.5,12.9903810568],[16.1177143235,14.4888873943],[20,15],[23.8822856765,14.4888873943],[27.5,12.9903810568],[30.6066017178,10.6066017178],[32.9903810568,7.5],[34.4888873943,3.88228567654]]));
|
||||
assert_approx(glued_circles(d=30, spread=30, tangent=45),deduplicate( [[30,0],[29.4888873943,-3.88228567654],[27.9903810568,-7.5],[25.6066017178,-10.6066017178],[22.5,-12.9903810568],[18.8822856765,-14.4888873943],[15,-15],[11.1177143235,-14.4888873943],[7.5,-12.9903810568],[4.3933982822,-10.6066017178],[4.3933982822,-10.6066017178],[3.1066017178,-9.61920798589],[1.60809538023,-8.99850633757],[0,-8.7867965644],[-1.60809538023,-8.99850633757],[-3.1066017178,-9.61920798589],[-4.3933982822,-10.6066017178],[-4.3933982822,-10.6066017178],[-7.5,-12.9903810568],[-11.1177143235,-14.4888873943],[-15,-15],[-18.8822856765,-14.4888873943],[-22.5,-12.9903810568],[-25.6066017178,-10.6066017178],[-27.9903810568,-7.5],[-29.4888873943,-3.88228567654],[-30,0],[-29.4888873943,3.88228567654],[-27.9903810568,7.5],[-25.6066017178,10.6066017178],[-22.5,12.9903810568],[-18.8822856765,14.4888873943],[-15,15],[-11.1177143235,14.4888873943],[-7.5,12.9903810568],[-4.3933982822,10.6066017178],[-3.1066017178,9.61920798589],[-1.60809538023,8.99850633757],[0,8.7867965644],[1.60809538023,8.99850633757],[3.1066017178,9.61920798589],[4.3933982822,10.6066017178],[4.3933982822,10.6066017178],[7.5,12.9903810568],[11.1177143235,14.4888873943],[15,15],[18.8822856765,14.4888873943],[22.5,12.9903810568],[25.6066017178,10.6066017178],[27.9903810568,7.5],[29.4888873943,3.88228567654]]));
|
||||
assert_approx(glued_circles(d=30, spread=30, tangent=-30), deduplicate([[30,0],[29.4888873943,-3.88228567654],[27.9903810568,-7.5],[25.6066017178,-10.6066017178],[22.5,-12.9903810568],[22.5,-12.9903810568],[11.6468570296,-17.4859000695],[0,-19.0192378865],[-11.6468570296,-17.4859000695],[-22.5,-12.9903810568],[-22.5,-12.9903810568],[-25.6066017178,-10.6066017178],[-27.9903810568,-7.5],[-29.4888873943,-3.88228567654],[-30,0],[-29.4888873943,3.88228567654],[-27.9903810568,7.5],[-25.6066017178,10.6066017178],[-22.5,12.9903810568],[-11.6468570296,17.4859000695],[0,19.0192378865],[11.6468570296,17.4859000695],[22.5,12.9903810568],[22.5,12.9903810568],[25.6066017178,10.6066017178],[27.9903810568,7.5],[29.4888873943,3.88228567654]]));
|
||||
assert_approx(glued_circles(d=30, spread=50, tangent=0),[[40, 0], [39.4888873943, -3.88228567654], [37.9903810568, -7.5], [35.6066017178, -10.6066017178], [32.5, -12.9903810568], [28.8822856765, -14.4888873943], [25, -15], [-25, -15], [-28.8822856765, -14.4888873943], [-32.5, -12.9903810568], [-35.6066017178, -10.6066017178], [-37.9903810568, -7.5], [-39.4888873943, -3.88228567654], [-40, 0], [-39.4888873943, 3.88228567654], [-37.9903810568, 7.5], [-35.6066017178, 10.6066017178], [-32.5, 12.9903810568], [-28.8822856765, 14.4888873943], [-25, 15], [25, 15], [28.8822856765, 14.4888873943], [32.5, 12.9903810568], [35.6066017178, 10.6066017178], [37.9903810568, 7.5], [39.4888873943, 3.88228567654]]);
|
||||
}
|
||||
test_glued_circles();
|
||||
|
||||
|
|
4
vnf.scad
4
vnf.scad
|
@ -351,8 +351,8 @@ function _path_path_closest_vertices(path1,path2) =
|
|||
function _join_paths_at_vertices(path1,path2,v1,v2) =
|
||||
let(
|
||||
repeat_start = !approx(path1[v1],path2[v2]),
|
||||
path1 = clockwise_polygon(polygon_shift(path1,v1)),
|
||||
path2 = ccw_polygon(polygon_shift(path2,v2))
|
||||
path1 = clockwise_polygon(list_rotate(path1,v1)),
|
||||
path2 = ccw_polygon(list_rotate(path2,v2))
|
||||
)
|
||||
[
|
||||
each path1,
|
||||
|
|
Loading…
Reference in a new issue