Added vnf_bend_around_y_axis().

This commit is contained in:
Revar Desmera 2020-05-14 05:14:23 -07:00
parent a5fb810738
commit 32e0f26fd8
3 changed files with 223 additions and 1 deletions

View File

@ -1454,5 +1454,146 @@ function polygon_normal(poly) =
) unit(n);
function _split_polygon_at_x(poly, x) =
let(
xs = subindex(poly,0)
) (min(xs) >= x || max(xs) <= x)? [poly] :
let(
poly2 = [
for (p = pair_wrap(poly)) each [
p[0],
if(
(p[0].x < x && p[1].x > x) ||
(p[1].x < x && p[0].x > x)
) let(
u = (x - p[0].x) / (p[1].x - p[0].x)
) [
x, // Important for later exact match tests
u*(p[1].y-p[0].y)+p[0].y,
u*(p[1].z-p[0].z)+p[0].z,
]
]
],
out1 = [for (p = poly2) if(p.x <= x) p],
out2 = [for (p = poly2) if(p.x >= x) p],
out = [
if (len(out1)>=3) out1,
if (len(out2)>=3) out2,
]
) out;
function _split_polygon_at_y(poly, y) =
let(
ys = subindex(poly,1)
) (min(ys) >= y || max(ys) <= y)? [poly] :
let(
poly2 = [
for (p = pair_wrap(poly)) each [
p[0],
if(
(p[0].y < y && p[1].y > y) ||
(p[1].y < y && p[0].y > y)
) let(
u = (y - p[0].y) / (p[1].y - p[0].y)
) [
u*(p[1].x-p[0].x)+p[0].x,
y, // Important for later exact match tests
u*(p[1].z-p[0].z)+p[0].z,
]
]
],
out1 = [for (p = poly2) if(p.y <= y) p],
out2 = [for (p = poly2) if(p.y >= y) p],
out = [
if (len(out1)>=3) out1,
if (len(out2)>=3) out2,
]
) out;
function _split_polygon_at_z(poly, z) =
let(
zs = subindex(poly,1)
) (min(zs) >= z || max(zs) <= z)? [poly] :
let(
poly2 = [
for (p = pair_wrap(poly)) each [
p[0],
if(
(p[0].z < z && p[1].z > z) ||
(p[1].z < z && p[0].z > z)
) let(
u = (z - p[0].z) / (p[1].z - p[0].z)
) [
u*(p[1].x-p[0].x)+p[0].x,
u*(p[1].y-p[0].y)+p[0].y,
z, // Important for later exact match tests
]
]
],
out1 = [for (p = poly2) if(p.z <= z) p],
out2 = [for (p = poly2) if(p.z >= z) p],
out = [
if (len(out1)>=3) out1,
if (len(out2)>=3) out2,
]
) out;
// Function: split_polygons_at_each_x()
// Usage:
// splitpolys = split_polygons_at_each_x(polys, xs);
// Description:
// Given a list of 3D polygons, splits all of them wherever they cross any X value given in `xs`.
// Arguments:
// polys = A list of 3D polygons to split.
// xs = A list of scalar X values to split at.
function split_polygons_at_each_x(polys, xs, _i=0) =
_i>=len(xs)? polys :
split_polygons_at_each_x(
[
for (poly = polys)
each _split_polygon_at_x(poly, xs[_i])
], xs, _i=_i+1
);
// Function: split_polygons_at_each_y()
// Usage:
// splitpolys = split_polygons_at_each_y(polys, ys);
// Description:
// Given a list of 3D polygons, splits all of them wherever they cross any Y value given in `ys`.
// Arguments:
// polys = A list of 3D polygons to split.
// ys = A list of scalar Y values to split at.
function split_polygons_at_each_y(polys, ys, _i=0) =
_i>=len(ys)? polys :
split_polygons_at_each_y(
[
for (poly = polys)
each _split_polygon_at_y(poly, ys[_i])
], ys, _i=_i+1
);
// Function: split_polygons_at_each_z()
// Usage:
// splitpolys = split_polygons_at_each_z(polys, zs);
// Description:
// Given a list of 3D polygons, splits all of them wherever they cross any Z value given in `zs`.
// Arguments:
// polys = A list of 3D polygons to split.
// zs = A list of scalar Z values to split at.
function split_polygons_at_each_z(polys, zs, _i=0) =
_i>=len(zs)? polys :
split_polygons_at_each_z(
[
for (poly = polys)
each _split_polygon_at_z(poly, zs[_i])
], zs, _i=_i+1
);
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View File

@ -8,7 +8,7 @@
//////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,300];
BOSL_VERSION = [2,0,301];
// Section: BOSL Library Version Functions

View File

@ -397,6 +397,87 @@ function vnf_centroid(vnf) =
) val[1]/val[0]/8;
function _triangulate_planar_convex_polygons(polys) =
polys==[]? [] :
let(
tris = [for (poly=polys) if (len(poly)==3) poly],
bigs = [for (poly=polys) if (len(poly)>3) poly],
newtris = [for (poly=bigs) select(poly,-2,0)],
newbigs = [for (poly=bigs) select(poly,0,-2)],
newtris2 = _triangulate_planar_convex_polygons(newbigs),
outtris = concat(tris, newtris, newtris2)
) outtris;
// Function: vnf_bend_around_y_axis()
// Usage:
// bentvnf = vnf_bend_around_y_axis(vnf);
// Description:
// Given a VNF that is entirely above, or entirely below the Z=0 plane, bends the VNF around the
// Y axis, splitting up faces as necessary. Returns the bent VNF. Will error out if the VNF
// straddles the Z=0 plane, or if the bent VNF would wrap more than completely around. The 1:1
// radius is where the curved length of the bent VNF matches the length of the original VNF. If the
// `r` or `d` arguments are given, then they will specify the 1:1 radius or diameter. If they are
// not given, then the 1:1 radius will be defined by the distance of the furthest vertex in the
// original VNF from the Z=0 plane. You can adjust the granularity of the bend using the standard
// `$fa`, `$fs`, and `$fn` variables.
// Arguments:
// vnf = The original VNF to bend.
// r = If given, the radius where the size of the original shape is the same as in the original.
// d = If given, the diameter where the size of the original shape is the same as in the original.
// Example(3D):
// vnf0 = cube([100,40,10], center=true);
// vnf1 = up(35, p=vnf0);
// vnf2 = down(50, p=vnf0);
// bent1 = vnf_bend_around_y_axis(vnf1);
// bent2 = vnf_bend_around_y_axis(vnf2);
// vnf_polyhedron([bent1,bent2]);
// Example(3D):
// vnf0 = linear_sweep(star(n=5,step=2,d=100), height=10);
// vnf1 = up(35, p=vnf0);
// vnf2 = down(50, p=vnf0);
// bent1 = vnf_bend_around_y_axis(vnf1);
// bent2 = vnf_bend_around_y_axis(vnf2);
// vnf_polyhedron([bent1,bent2]);
// Example(3D):
// rgn = union(rect([100,20],center=true), rect([20,100],center=true));
// vnf0 = linear_sweep(zrot(45,p=rgn), height=10);
// vnf1 = up(35, p=vnf0);
// vnf2 = down(50, p=vnf0);
// bent1 = vnf_bend_around_y_axis(vnf1);
// bent2 = vnf_bend_around_y_axis(vnf2);
// vnf_polyhedron([bent1,bent2]);
function vnf_bend_around_y_axis(vnf,r,d) =
let(
vnf = vnf_triangulate(vnf),
verts = vnf[0],
bounds = pointlist_bounds(verts),
bmin = bounds[0],
bmax = bounds[1],
r = get_radius(r=r,d=d,dflt=max(abs(bmax.z), abs(bmin.z))),
width = bmax.x - bmin.x
)
assert(bmin.z > 0 || bmax.z < 0, "Entire shape MUST be completely above or below z=0.")
assert(width <= 2*PI*r, "Shape would wrap more than completely around the cylinder.")
let(
min_ang = 180 * bmin.x / (PI * r),
max_ang = 180 * bmax.x / (PI * r),
ang_span = max_ang-min_ang,
steps = ceil(segs(r) * ang_span/360),
step = width / steps,
bend_at = [for(i = [1:1:steps-1]) i*step+bmin.x],
facepolys = [for (face=vnf[1]) select(verts,face)],
splits = split_polygons_at_each_x(facepolys, bend_at),
newtris = _triangulate_planar_convex_polygons(splits),
bent_faces = [
for (tri = newtris) [
for (p = tri) let(
a = 180*p.x/(r*PI) * sign(bmax.z)
) [p.z*sin(a), p.y, p.z*cos(a)]
]
]
) vnf_add_faces(faces=bent_faces);
// Function&Module: vnf_validate()
// Usage: As Function