mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-01-16 13:50:23 +01:00
Merge pull request #344 from adrianVmariano/master
Added vnf_wireframe, tweaked reverse error message,
This commit is contained in:
commit
461bd21236
@ -290,7 +290,7 @@ function list_range(n=undef, s=0, e=undef, step=undef) =
|
||||
// Example:
|
||||
// reverse([3,4,5,6]); // Returns [6,5,4,3]
|
||||
function reverse(x) =
|
||||
assert(is_list(x)||is_string(x), "Input to reverse must be a list or string")
|
||||
assert(is_list(x)||is_string(x), str("Input to reverse must be a list or string. Got: ",x))
|
||||
let (elems = [ for (i = [len(x)-1 : -1 : 0]) x[i] ])
|
||||
is_string(x)? str_join(elems) : elems;
|
||||
|
||||
|
514
hull.scad
514
hull.scad
@ -1,257 +1,257 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: hull.scad
|
||||
// Functions to create 2D and 3D convex hulls.
|
||||
// To use, add the following line to the beginning of your file:
|
||||
// ```
|
||||
// include <BOSL2/std.scad>
|
||||
// include <BOSL2/hull.scad>
|
||||
// ```
|
||||
// Derived from Oskar Linde's Hull:
|
||||
// - https://github.com/openscad/scad-utils
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: Convex Hulls
|
||||
|
||||
|
||||
// Function: hull()
|
||||
// Usage:
|
||||
// hull(points);
|
||||
// Description:
|
||||
// Takes a list of 2D or 3D points (but not both in the same list) and returns either the list of
|
||||
// indexes into `points` that forms the 2D convex hull perimeter path, or the list of faces that
|
||||
// form the 3d convex hull surface. Each face is a list of indexes into `points`. If the input
|
||||
// points are co-linear, the result will be the indexes of the two extrema points. If the input
|
||||
// points are co-planar, the results will be a simple list of vertex indices that will form a planar
|
||||
// perimeter. Otherwise a list of faces will be returned, where each face is a simple list of
|
||||
// vertex indices for the perimeter of the face.
|
||||
// Arguments:
|
||||
// points = The set of 2D or 3D points to find the hull of.
|
||||
function hull(points) =
|
||||
assert(is_path(points),"Invalid input to hull")
|
||||
len(points[0]) == 2
|
||||
? hull2d_path(points)
|
||||
: hull3d_faces(points);
|
||||
|
||||
|
||||
// Module: hull_points()
|
||||
// Usage:
|
||||
// hull_points(points, [fast]);
|
||||
// Description:
|
||||
// If given a list of 2D points, creates a 2D convex hull polygon that encloses all those points.
|
||||
// If given a list of 3D points, creates a 3D polyhedron that encloses all the points. This should
|
||||
// handle about 4000 points in slow mode. If `fast` is set to true, this should be able to handle
|
||||
// far more.
|
||||
// Arguments:
|
||||
// points = The list of points to form a hull around.
|
||||
// fast = If true, uses a faster cheat that may handle more points, but also may emit warnings that can stop your script if you have "Halt on first warning" enabled. Default: false
|
||||
// Example(2D):
|
||||
// pts = [[-10,-10], [0,10], [10,10], [12,-10]];
|
||||
// hull_points(pts);
|
||||
// Example:
|
||||
// pts = [for (phi = [30:60:150], theta = [0:60:359]) spherical_to_xyz(10, theta, phi)];
|
||||
// hull_points(pts);
|
||||
module hull_points(points, fast=false) {
|
||||
if (points) {
|
||||
assert(is_list(points[0]));
|
||||
if (fast) {
|
||||
if (len(points[0]) == 2) {
|
||||
hull() polygon(points=points);
|
||||
} else {
|
||||
extra = len(points)%3;
|
||||
faces = concat(
|
||||
[[for(i=[0:1:extra+2])i]],
|
||||
[for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]
|
||||
);
|
||||
hull() polyhedron(points=points, faces=faces);
|
||||
}
|
||||
} else {
|
||||
perim = hull(points);
|
||||
if (is_num(perim[0])) {
|
||||
polygon(points=points, paths=[perim]);
|
||||
} else {
|
||||
polyhedron(points=points, faces=perim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function: hull2d_path()
|
||||
// Usage:
|
||||
// hull2d_path(points)
|
||||
// Description:
|
||||
// Takes a list of arbitrary 2D points, and finds the convex hull polygon to enclose them.
|
||||
// Returns a path as a list of indices into `points`. May return extra points, that are on edges of the hull.
|
||||
// Example(2D):
|
||||
// pts = [[-10,-10], [0,10], [10,10], [12,-10]];
|
||||
// path = hull2d_path(pts);
|
||||
// move_copies(pts) color("red") sphere(1);
|
||||
// polygon(points=pts, paths=[path]);
|
||||
function hull2d_path(points) =
|
||||
assert(is_path(points,2),"Invalid input to hull2d_path")
|
||||
len(points) < 2 ? []
|
||||
: len(points) == 2 ? [0,1]
|
||||
: let(tri=noncollinear_triple(points, error=false))
|
||||
tri == [] ? _hull_collinear(points)
|
||||
: let(
|
||||
remaining = [ for (i = [0:1:len(points)-1]) if (i != tri[0] && i!=tri[1] && i!=tri[2]) i ],
|
||||
ccw = triangle_area(points[tri[0]], points[tri[1]], points[tri[2]]) > 0,
|
||||
polygon = ccw ? [tri[0],tri[1],tri[2]] : [tri[0],tri[2],tri[1]]
|
||||
) _hull2d_iterative(points, polygon, remaining);
|
||||
|
||||
|
||||
|
||||
// Adds the remaining points one by one to the convex hull
|
||||
function _hull2d_iterative(points, polygon, remaining, _i=0) =
|
||||
(_i >= len(remaining))? polygon : let (
|
||||
// pick a point
|
||||
i = remaining[_i],
|
||||
// find the segments that are in conflict with the point (point not inside)
|
||||
conflicts = _find_conflicting_segments(points, polygon, points[i])
|
||||
// no conflicts, skip point and move on
|
||||
) (len(conflicts) == 0)? _hull2d_iterative(points, polygon, remaining, _i+1) : let(
|
||||
// find the first conflicting segment and the first not conflicting
|
||||
// conflict will be sorted, if not wrapping around, do it the easy way
|
||||
polygon = _remove_conflicts_and_insert_point(polygon, conflicts, i)
|
||||
) _hull2d_iterative(points, polygon, remaining, _i+1);
|
||||
|
||||
|
||||
function _hull_collinear(points) =
|
||||
let(
|
||||
a = points[0],
|
||||
n = points[1] - a,
|
||||
points1d = [ for(p = points) (p-a)*n ],
|
||||
min_i = min_index(points1d),
|
||||
max_i = max_index(points1d)
|
||||
) [min_i, max_i];
|
||||
|
||||
|
||||
function _find_conflicting_segments(points, polygon, point) = [
|
||||
for (i = [0:1:len(polygon)-1]) let(
|
||||
j = (i+1) % len(polygon),
|
||||
p1 = points[polygon[i]],
|
||||
p2 = points[polygon[j]],
|
||||
area = triangle_area(p1, p2, point)
|
||||
) if (area < 0) i
|
||||
];
|
||||
|
||||
|
||||
// remove the conflicting segments from the polygon
|
||||
function _remove_conflicts_and_insert_point(polygon, conflicts, point) =
|
||||
(conflicts[0] == 0)? let(
|
||||
nonconflicting = [ for(i = [0:1:len(polygon)-1]) if (!in_list(i, conflicts)) i ],
|
||||
new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
|
||||
polygon = concat([ for (i = new_indices) polygon[i] ], point)
|
||||
) polygon : let(
|
||||
before_conflicts = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
|
||||
after_conflicts = (max(conflicts) >= (len(polygon)-1))? [] : [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
|
||||
polygon = concat(before_conflicts, point, after_conflicts)
|
||||
) polygon;
|
||||
|
||||
|
||||
|
||||
// Function: hull3d_faces()
|
||||
// Usage:
|
||||
// hull3d_faces(points)
|
||||
// Description:
|
||||
// Takes a list of arbitrary 3D points, and finds the convex hull polyhedron to enclose
|
||||
// them. Returns a list of triangular faces, where each face is a list of indexes into the given `points`
|
||||
// list. The output will be valid for use with the polyhedron command, but may include vertices that are in the interior of a face of the hull, so it is not
|
||||
// necessarily the minimal representation of the hull.
|
||||
// If all points passed to it are coplanar, then the return is the list of indices of points
|
||||
// forming the convex hull polygon.
|
||||
// Example(3D):
|
||||
// pts = [[-20,-20,0], [20,-20,0], [0,20,5], [0,0,20]];
|
||||
// faces = hull3d_faces(pts);
|
||||
// move_copies(pts) color("red") sphere(1);
|
||||
// %polyhedron(points=pts, faces=faces);
|
||||
function hull3d_faces(points) =
|
||||
assert(is_path(points,3),"Invalid input to hull3d_faces")
|
||||
len(points) < 3 ? list_range(len(points))
|
||||
: let ( // start with a single non-collinear triangle
|
||||
tri = noncollinear_triple(points, error=false)
|
||||
)
|
||||
tri==[] ? _hull_collinear(points)
|
||||
: let(
|
||||
a = tri[0],
|
||||
b = tri[1],
|
||||
c = tri[2],
|
||||
plane = plane3pt_indexed(points, a, b, c),
|
||||
d = _find_first_noncoplanar(plane, points, 3)
|
||||
)
|
||||
d == len(points)
|
||||
? /* all coplanar*/
|
||||
let (
|
||||
pts2d = [ for (p = points) project_plane(p, points[a], points[b], points[c]) ],
|
||||
hull2d = hull2d_path(pts2d)
|
||||
) hull2d
|
||||
: let(
|
||||
remaining = [for (i = [0:1:len(points)-1]) if (i!=a && i!=b && i!=c && i!=d) i],
|
||||
// Build an initial tetrahedron.
|
||||
// Swap b, c if d is in front of triangle t.
|
||||
ifop = in_front_of_plane(plane, points[d]),
|
||||
bc = ifop? [c,b] : [b,c],
|
||||
b = bc[0],
|
||||
c = bc[1],
|
||||
triangles = [
|
||||
[a,b,c],
|
||||
[d,b,a],
|
||||
[c,d,a],
|
||||
[b,d,c]
|
||||
],
|
||||
// calculate the plane equations
|
||||
planes = [ for (t = triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
|
||||
) _hull3d_iterative(points, triangles, planes, remaining);
|
||||
|
||||
|
||||
// Adds the remaining points one by one to the convex hull
|
||||
function _hull3d_iterative(points, triangles, planes, remaining, _i=0) =
|
||||
_i >= len(remaining) ? triangles :
|
||||
let (
|
||||
// pick a point
|
||||
i = remaining[_i],
|
||||
// find the triangles that are in conflict with the point (point not inside)
|
||||
conflicts = _find_conflicts(points[i], planes),
|
||||
// for all triangles that are in conflict, collect their halfedges
|
||||
halfedges = [
|
||||
for(c = conflicts, i = [0:2]) let(
|
||||
j = (i+1)%3
|
||||
) [triangles[c][i], triangles[c][j]]
|
||||
],
|
||||
// find the outer perimeter of the set of conflicting triangles
|
||||
horizon = _remove_internal_edges(halfedges),
|
||||
// generate a new triangle for each horizon halfedge together with the picked point i
|
||||
new_triangles = [ for (h = horizon) concat(h,i) ],
|
||||
// calculate the corresponding plane equations
|
||||
new_planes = [ for (t = new_triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
|
||||
) _hull3d_iterative(
|
||||
points,
|
||||
// remove the conflicting triangles and add the new ones
|
||||
concat(list_remove(triangles, conflicts), new_triangles),
|
||||
concat(list_remove(planes, conflicts), new_planes),
|
||||
remaining,
|
||||
_i+1
|
||||
);
|
||||
|
||||
|
||||
function _remove_internal_edges(halfedges) = [
|
||||
for (h = halfedges)
|
||||
if (!in_list(reverse(h), halfedges))
|
||||
h
|
||||
];
|
||||
|
||||
|
||||
function _find_conflicts(point, planes) = [
|
||||
for (i = [0:1:len(planes)-1])
|
||||
if (in_front_of_plane(planes[i], point))
|
||||
i
|
||||
];
|
||||
|
||||
|
||||
function _find_first_noncoplanar(plane, points, i) =
|
||||
(i >= len(points) || !points_on_plane([points[i]],plane))? i :
|
||||
_find_first_noncoplanar(plane, points, i+1);
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: hull.scad
|
||||
// Functions to create 2D and 3D convex hulls.
|
||||
// To use, add the following line to the beginning of your file:
|
||||
// ```
|
||||
// include <BOSL2/std.scad>
|
||||
// include <BOSL2/hull.scad>
|
||||
// ```
|
||||
// Derived from Oskar Linde's Hull:
|
||||
// - https://github.com/openscad/scad-utils
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: Convex Hulls
|
||||
|
||||
|
||||
// Function: hull()
|
||||
// Usage:
|
||||
// hull(points);
|
||||
// Description:
|
||||
// Takes a list of 2D or 3D points (but not both in the same list) and returns either the list of
|
||||
// indexes into `points` that forms the 2D convex hull perimeter path, or the list of faces that
|
||||
// form the 3d convex hull surface. Each face is a list of indexes into `points`. If the input
|
||||
// points are co-linear, the result will be the indexes of the two extrema points. If the input
|
||||
// points are co-planar, the results will be a simple list of vertex indices that will form a planar
|
||||
// perimeter. Otherwise a list of faces will be returned, where each face is a simple list of
|
||||
// vertex indices for the perimeter of the face.
|
||||
// Arguments:
|
||||
// points = The set of 2D or 3D points to find the hull of.
|
||||
function hull(points) =
|
||||
assert(is_path(points),"Invalid input to hull")
|
||||
len(points[0]) == 2
|
||||
? hull2d_path(points)
|
||||
: hull3d_faces(points);
|
||||
|
||||
|
||||
// Module: hull_points()
|
||||
// Usage:
|
||||
// hull_points(points, [fast]);
|
||||
// Description:
|
||||
// If given a list of 2D points, creates a 2D convex hull polygon that encloses all those points.
|
||||
// If given a list of 3D points, creates a 3D polyhedron that encloses all the points. This should
|
||||
// handle about 4000 points in slow mode. If `fast` is set to true, this should be able to handle
|
||||
// far more.
|
||||
// Arguments:
|
||||
// points = The list of points to form a hull around.
|
||||
// fast = If true, uses a faster cheat that may handle more points, but also may emit warnings that can stop your script if you have "Halt on first warning" enabled. Default: false
|
||||
// Example(2D):
|
||||
// pts = [[-10,-10], [0,10], [10,10], [12,-10]];
|
||||
// hull_points(pts);
|
||||
// Example:
|
||||
// pts = [for (phi = [30:60:150], theta = [0:60:359]) spherical_to_xyz(10, theta, phi)];
|
||||
// hull_points(pts);
|
||||
module hull_points(points, fast=false) {
|
||||
if (points) {
|
||||
assert(is_list(points[0]));
|
||||
if (fast) {
|
||||
if (len(points[0]) == 2) {
|
||||
hull() polygon(points=points);
|
||||
} else {
|
||||
extra = len(points)%3;
|
||||
faces = concat(
|
||||
[[for(i=[0:1:extra+2])i]],
|
||||
[for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]
|
||||
);
|
||||
hull() polyhedron(points=points, faces=faces);
|
||||
}
|
||||
} else {
|
||||
perim = hull(points);
|
||||
if (is_num(perim[0])) {
|
||||
polygon(points=points, paths=[perim]);
|
||||
} else {
|
||||
polyhedron(points=points, faces=perim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function: hull2d_path()
|
||||
// Usage:
|
||||
// hull2d_path(points)
|
||||
// Description:
|
||||
// Takes a list of arbitrary 2D points, and finds the convex hull polygon to enclose them.
|
||||
// Returns a path as a list of indices into `points`. May return extra points, that are on edges of the hull.
|
||||
// Example(2D):
|
||||
// pts = [[-10,-10], [0,10], [10,10], [12,-10]];
|
||||
// path = hull2d_path(pts);
|
||||
// move_copies(pts) color("red") sphere(1);
|
||||
// polygon(points=pts, paths=[path]);
|
||||
function hull2d_path(points) =
|
||||
assert(is_path(points,2),"Invalid input to hull2d_path")
|
||||
len(points) < 2 ? []
|
||||
: len(points) == 2 ? [0,1]
|
||||
: let(tri=noncollinear_triple(points, error=false))
|
||||
tri == [] ? _hull_collinear(points)
|
||||
: let(
|
||||
remaining = [ for (i = [0:1:len(points)-1]) if (i != tri[0] && i!=tri[1] && i!=tri[2]) i ],
|
||||
ccw = triangle_area(points[tri[0]], points[tri[1]], points[tri[2]]) > 0,
|
||||
polygon = ccw ? [tri[0],tri[1],tri[2]] : [tri[0],tri[2],tri[1]]
|
||||
) _hull2d_iterative(points, polygon, remaining);
|
||||
|
||||
|
||||
|
||||
// Adds the remaining points one by one to the convex hull
|
||||
function _hull2d_iterative(points, polygon, remaining, _i=0) =
|
||||
(_i >= len(remaining))? polygon : let (
|
||||
// pick a point
|
||||
i = remaining[_i],
|
||||
// find the segments that are in conflict with the point (point not inside)
|
||||
conflicts = _find_conflicting_segments(points, polygon, points[i])
|
||||
// no conflicts, skip point and move on
|
||||
) (len(conflicts) == 0)? _hull2d_iterative(points, polygon, remaining, _i+1) : let(
|
||||
// find the first conflicting segment and the first not conflicting
|
||||
// conflict will be sorted, if not wrapping around, do it the easy way
|
||||
polygon = _remove_conflicts_and_insert_point(polygon, conflicts, i)
|
||||
) _hull2d_iterative(points, polygon, remaining, _i+1);
|
||||
|
||||
|
||||
function _hull_collinear(points) =
|
||||
let(
|
||||
a = points[0],
|
||||
n = points[1] - a,
|
||||
points1d = [ for(p = points) (p-a)*n ],
|
||||
min_i = min_index(points1d),
|
||||
max_i = max_index(points1d)
|
||||
) [min_i, max_i];
|
||||
|
||||
|
||||
function _find_conflicting_segments(points, polygon, point) = [
|
||||
for (i = [0:1:len(polygon)-1]) let(
|
||||
j = (i+1) % len(polygon),
|
||||
p1 = points[polygon[i]],
|
||||
p2 = points[polygon[j]],
|
||||
area = triangle_area(p1, p2, point)
|
||||
) if (area < 0) i
|
||||
];
|
||||
|
||||
|
||||
// remove the conflicting segments from the polygon
|
||||
function _remove_conflicts_and_insert_point(polygon, conflicts, point) =
|
||||
(conflicts[0] == 0)? let(
|
||||
nonconflicting = [ for(i = [0:1:len(polygon)-1]) if (!in_list(i, conflicts)) i ],
|
||||
new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
|
||||
polygon = concat([ for (i = new_indices) polygon[i] ], point)
|
||||
) polygon : let(
|
||||
before_conflicts = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
|
||||
after_conflicts = (max(conflicts) >= (len(polygon)-1))? [] : [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
|
||||
polygon = concat(before_conflicts, point, after_conflicts)
|
||||
) polygon;
|
||||
|
||||
|
||||
|
||||
// Function: hull3d_faces()
|
||||
// Usage:
|
||||
// hull3d_faces(points)
|
||||
// Description:
|
||||
// Takes a list of arbitrary 3D points, and finds the convex hull polyhedron to enclose
|
||||
// them. Returns a list of triangular faces, where each face is a list of indexes into the given `points`
|
||||
// list. The output will be valid for use with the polyhedron command, but may include vertices that are in the interior of a face of the hull, so it is not
|
||||
// necessarily the minimal representation of the hull.
|
||||
// If all points passed to it are coplanar, then the return is the list of indices of points
|
||||
// forming the convex hull polygon.
|
||||
// Example(3D):
|
||||
// pts = [[-20,-20,0], [20,-20,0], [0,20,5], [0,0,20]];
|
||||
// faces = hull3d_faces(pts);
|
||||
// move_copies(pts) color("red") sphere(1);
|
||||
// %polyhedron(points=pts, faces=faces);
|
||||
function hull3d_faces(points) =
|
||||
assert(is_path(points,3),"Invalid input to hull3d_faces")
|
||||
len(points) < 3 ? list_range(len(points))
|
||||
: let ( // start with a single non-collinear triangle
|
||||
tri = noncollinear_triple(points, error=false)
|
||||
)
|
||||
tri==[] ? _hull_collinear(points)
|
||||
: let(
|
||||
a = tri[0],
|
||||
b = tri[1],
|
||||
c = tri[2],
|
||||
plane = plane3pt_indexed(points, a, b, c),
|
||||
d = _find_first_noncoplanar(plane, points, 3)
|
||||
)
|
||||
d == len(points)
|
||||
? /* all coplanar*/
|
||||
let (
|
||||
pts2d = [ for (p = points) project_plane(p, points[a], points[b], points[c]) ],
|
||||
hull2d = hull2d_path(pts2d)
|
||||
) hull2d
|
||||
: let(
|
||||
remaining = [for (i = [0:1:len(points)-1]) if (i!=a && i!=b && i!=c && i!=d) i],
|
||||
// Build an initial tetrahedron.
|
||||
// Swap b, c if d is in front of triangle t.
|
||||
ifop = in_front_of_plane(plane, points[d]),
|
||||
bc = ifop? [c,b] : [b,c],
|
||||
b = bc[0],
|
||||
c = bc[1],
|
||||
triangles = [
|
||||
[a,b,c],
|
||||
[d,b,a],
|
||||
[c,d,a],
|
||||
[b,d,c]
|
||||
],
|
||||
// calculate the plane equations
|
||||
planes = [ for (t = triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
|
||||
) _hull3d_iterative(points, triangles, planes, remaining);
|
||||
|
||||
|
||||
// Adds the remaining points one by one to the convex hull
|
||||
function _hull3d_iterative(points, triangles, planes, remaining, _i=0) =
|
||||
_i >= len(remaining) ? triangles :
|
||||
let (
|
||||
// pick a point
|
||||
i = remaining[_i],
|
||||
// find the triangles that are in conflict with the point (point not inside)
|
||||
conflicts = _find_conflicts(points[i], planes),
|
||||
// for all triangles that are in conflict, collect their halfedges
|
||||
halfedges = [
|
||||
for(c = conflicts, i = [0:2]) let(
|
||||
j = (i+1)%3
|
||||
) [triangles[c][i], triangles[c][j]]
|
||||
],
|
||||
// find the outer perimeter of the set of conflicting triangles
|
||||
horizon = _remove_internal_edges(halfedges),
|
||||
// generate a new triangle for each horizon halfedge together with the picked point i
|
||||
new_triangles = [ for (h = horizon) concat(h,i) ],
|
||||
// calculate the corresponding plane equations
|
||||
new_planes = [ for (t = new_triangles) plane3pt_indexed(points, t[0], t[1], t[2]) ]
|
||||
) _hull3d_iterative(
|
||||
points,
|
||||
// remove the conflicting triangles and add the new ones
|
||||
concat(list_remove(triangles, conflicts), new_triangles),
|
||||
concat(list_remove(planes, conflicts), new_planes),
|
||||
remaining,
|
||||
_i+1
|
||||
);
|
||||
|
||||
|
||||
function _remove_internal_edges(halfedges) = [
|
||||
for (h = halfedges)
|
||||
if (!in_list(reverse(h), halfedges))
|
||||
h
|
||||
];
|
||||
|
||||
|
||||
function _find_conflicts(point, planes) = [
|
||||
for (i = [0:1:len(planes)-1])
|
||||
if (in_front_of_plane(planes[i], point))
|
||||
i
|
||||
];
|
||||
|
||||
|
||||
function _find_first_noncoplanar(plane, points, i) =
|
||||
(i >= len(points) || !points_on_plane([points[i]],plane))? i :
|
||||
_find_first_noncoplanar(plane, points, i+1);
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
32
vnf.scad
32
vnf.scad
@ -357,6 +357,38 @@ module vnf_polyhedron(vnf, convexity=2, extent=true, cp=[0,0,0], anchor="origin"
|
||||
|
||||
|
||||
|
||||
// Module: vnf_wireframe()
|
||||
// Usage:
|
||||
// vnf_wireframe(vnf, [r|d]);
|
||||
// Description:
|
||||
// Given a VNF, creates a wire frame ball-and-stick model of the polyhedron with a cylinder for each edge and a sphere at each vertex.
|
||||
// Arguments:
|
||||
// vnf = A vnf structure
|
||||
// r|d = radius or diameter of the cylinders forming the wire frame. Default: r=1
|
||||
// Example:
|
||||
// $fn=32;
|
||||
// ball = sphere(r=20, $fn=6);
|
||||
// vnf_wireframe(ball,d=1);
|
||||
// Example:
|
||||
// include<BOSL2/polyhedra.scad>
|
||||
// $fn=32;
|
||||
// cube_oct = regular_polyhedron_info("vnf", name="cuboctahedron", or=20);
|
||||
// vnf_wireframe(cube_oct);
|
||||
// Example: The spheres at the vertex are imperfect at aligning with the cylinders, so especially at low $fn things look prety ugly. This is normal.
|
||||
// include<BOSL2/polyhedra.scad>
|
||||
// $fn=8;
|
||||
// octahedron = regular_polyhedron_info("vnf", name="octahedron", or=20);
|
||||
// vnf_wireframe(octahedron,r=5);
|
||||
module vnf_wireframe(vnf, r, d)
|
||||
{
|
||||
r = get_radius(r=r,d=d,dflt=1);
|
||||
vertex = vnf[0];
|
||||
edges = unique([for (face=vnf[1], i=idx(face))
|
||||
sort([face[i], select(face,i+1)])
|
||||
]);
|
||||
for (e=edges) extrude_from_to(vertex[e[0]],vertex[e[1]]) circle(r=r);
|
||||
move_copies(vertex) sphere(r=r);
|
||||
}
|
||||
|
||||
|
||||
// Function: vnf_volume()
|
||||
|
Loading…
x
Reference in New Issue
Block a user