mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-12 01:34:35 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -767,6 +767,7 @@ function _make_anchor_legal(anchor,geom) =
|
|||||||
// This module differs from {{position()}} and {{align()}} in that it rotates the children to
|
// This module differs from {{position()}} and {{align()}} in that it rotates the children to
|
||||||
// the anchor direction, which generally means it places the children on the surface of a parent.
|
// the anchor direction, which generally means it places the children on the surface of a parent.
|
||||||
// There are two modes of operation, parent anchor (single argument) and parent-child anchor (double argument).
|
// There are two modes of operation, parent anchor (single argument) and parent-child anchor (double argument).
|
||||||
|
// In most cases you should use the parent-child (double argument) version of `attach()`.
|
||||||
// .
|
// .
|
||||||
// The parent-child anchor (double argument) version is usually easier to use, and it is more powerful because it supports
|
// The parent-child anchor (double argument) version is usually easier to use, and it is more powerful because it supports
|
||||||
// alignment. You provide an anchor on the parent (`parent`) and an anchor on the child (`child`).
|
// alignment. You provide an anchor on the parent (`parent`) and an anchor on the child (`child`).
|
||||||
@@ -810,17 +811,6 @@ function _make_anchor_legal(anchor,geom) =
|
|||||||
// ignored** with the **double argument** version of `attach()`. As noted above, you can give `spin=` to the
|
// ignored** with the **double argument** version of `attach()`. As noted above, you can give `spin=` to the
|
||||||
// child but using the `spin=` parameter to `attach()` is more likely to be useful.
|
// child but using the `spin=` parameter to `attach()` is more likely to be useful.
|
||||||
// .
|
// .
|
||||||
// For the single parameter version of `attach()` you give only the `parent` anchor. The `align` direction
|
|
||||||
// is not permitted. In this case the child is placed at the specified parent anchor point
|
|
||||||
// and rotated to the anchor direction. For example, `attach(TOP) cuboid(2);` will place a small
|
|
||||||
// cube **with its center** located at the TOP anchor of the parent, so just half the cube will project
|
|
||||||
// from the parent. If you want the cube sitting on the parent you need to anchor the cube to its bottom:
|
|
||||||
// `attach(TOP) cuboid(2,anchor=BOT);`.
|
|
||||||
// .
|
|
||||||
// The **single argument** version of `attach()` **respects `anchor=` and `orient=` given to the child.**
|
|
||||||
// These options will probably be necessary, in fact, to get the child correctly positioned. Note that
|
|
||||||
// giving `spin=` to `attach()` in this case is the same as applying `zrot()` to the child.
|
|
||||||
// .
|
|
||||||
// You can overlap attached children into the parent by giving the `$overlap` value
|
// You can overlap attached children into the parent by giving the `$overlap` value
|
||||||
// which is 0 by default, or by the `overlap=` argument. This is to prevent OpenSCAD
|
// which is 0 by default, or by the `overlap=` argument. This is to prevent OpenSCAD
|
||||||
// from making non-manifold objects. You can define `$overlap=` as an argument in a parent
|
// from making non-manifold objects. You can define `$overlap=` as an argument in a parent
|
||||||
@@ -833,6 +823,17 @@ function _make_anchor_legal(anchor,geom) =
|
|||||||
// the parent. For an inside child this is equivalent to giving a positive overlap and negative inset value.
|
// the parent. For an inside child this is equivalent to giving a positive overlap and negative inset value.
|
||||||
// For a child with `inside=false` it is equivalent to a negative overlap and negative inset.
|
// For a child with `inside=false` it is equivalent to a negative overlap and negative inset.
|
||||||
// .
|
// .
|
||||||
|
// The single parameter version of `attach()` is rarely needed; to use it, you give only the `parent` anchor. The `align` direction
|
||||||
|
// is not permitted. In this case the child is placed at the specified parent anchor point
|
||||||
|
// and rotated to the anchor direction. For example, `attach(TOP) cuboid(2);` will place a small
|
||||||
|
// cube **with its center** located at the TOP anchor of the parent, so just half the cube will project
|
||||||
|
// from the parent. If you want the cube sitting on the parent you need to anchor the cube to its bottom:
|
||||||
|
// `attach(TOP) cuboid(2,anchor=BOT);`.
|
||||||
|
// .
|
||||||
|
// The **single argument** version of `attach()` **respects `anchor=` and `orient=` given to the child.**
|
||||||
|
// These options will probably be necessary, in fact, to get the child correctly positioned. Note that
|
||||||
|
// giving `spin=` to `attach()` in this case is the same as applying `zrot()` to the child.
|
||||||
|
// .
|
||||||
// For a step-by-step explanation of
|
// For a step-by-step explanation of
|
||||||
// attachments, see the [Attachments Tutorial](Tutorial-Attachments).
|
// attachments, see the [Attachments Tutorial](Tutorial-Attachments).
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
@@ -1267,7 +1267,6 @@ function bezier_vnf(patches=[], splinesteps=16, style="default") =
|
|||||||
: assert(false,"\nInvalid patch list.")
|
: assert(false,"\nInvalid patch list.")
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: bezier_vnf_degenerate_patch()
|
// Function: bezier_vnf_degenerate_patch()
|
||||||
@@ -1283,7 +1282,8 @@ function bezier_vnf(patches=[], splinesteps=16, style="default") =
|
|||||||
// equal. If the resulting patch has no faces then returns an empty VNF. Note that due to the degeneracy,
|
// equal. If the resulting patch has no faces then returns an empty VNF. Note that due to the degeneracy,
|
||||||
// the shape of the surface can be triangular even though the underlying patch is a rectangle.
|
// the shape of the surface can be triangular even though the underlying patch is a rectangle.
|
||||||
// If you specify return_edges then the return is a list whose first element is the VNF and whose second
|
// If you specify return_edges then the return is a list whose first element is the VNF and whose second
|
||||||
// element lists the edges in the order [left, right, top, bottom], where each list is a list of the actual
|
// element lists the edges in the order [left (index zero of rows), right (last index of rows), top (first row), bottom (last row)],
|
||||||
|
// where each list is a list of the actual
|
||||||
// point values, but possibly only a single point if that edge is degenerate.
|
// point values, but possibly only a single point if that edge is degenerate.
|
||||||
// The method checks for various types of degeneracy and uses a triangular or partly triangular array of sample points.
|
// The method checks for various types of degeneracy and uses a triangular or partly triangular array of sample points.
|
||||||
// See examples below for the types of degeneracy detected and how the patch is sampled for those cases.
|
// See examples below for the types of degeneracy detected and how the patch is sampled for those cases.
|
||||||
@@ -1292,7 +1292,7 @@ function bezier_vnf(patches=[], splinesteps=16, style="default") =
|
|||||||
// patch = Patch to process
|
// patch = Patch to process
|
||||||
// splinesteps = Number of segments to produce on each side. Default: 16
|
// splinesteps = Number of segments to produce on each side. Default: 16
|
||||||
// reverse = reverse direction of faces. Default: false
|
// reverse = reverse direction of faces. Default: false
|
||||||
// return_edges = if true return the points on the four edges: [left, right, top, bottom]. Default: false
|
// return_edges = if true return the points on the four edges of the array: [left (index zero of rows), right (last index of rows) , top (first row), bottom (last row)]. Default: false
|
||||||
// Example(3D,NoAxes): This quartic patch is degenerate at one corner, where a row of control points are equal. Processing this degenerate patch normally produces excess triangles near the degenerate point.
|
// Example(3D,NoAxes): This quartic patch is degenerate at one corner, where a row of control points are equal. Processing this degenerate patch normally produces excess triangles near the degenerate point.
|
||||||
// splinesteps=8;
|
// splinesteps=8;
|
||||||
// patch=[
|
// patch=[
|
||||||
|
@@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
// Section: Utility Functions
|
// Section: Utility Functions
|
||||||
// Definitions:
|
// Definitions:
|
||||||
// Point|Points = A numeric vector of length 2 or 3 that represents either a 2D or 3D vertex.
|
// Point|Points = A list of numbers, also called a vector. Usually has length 2 or 3 to represent points in the place on points in space.
|
||||||
// Pointlist|Pointlists|Point List|Point Lists = An unordered list of points.
|
// Pointlist|Pointlists|Point List|Point Lists = An unordered list of {{points}}.
|
||||||
// Path|Paths = A list of two or more 2D {{point}} coordinates that specify a route on the XY plane.
|
// Path|Paths = An ordered list of two or more {{points}} specifying a path through space. Usually points are 2D.
|
||||||
// Polygon|Polygons = A {{path}} where the first and last {{point}} coordinates are considered to be connected.
|
// Polygon|Polygons = A {{path}}, usually 2D, that describes a polygon by asuming that the first and last point are connected.
|
||||||
|
|
||||||
// Function: is_path()
|
// Function: is_path()
|
||||||
// Synopsis: Returns True if 'list' is a {{path}}.
|
// Synopsis: Returns True if 'list' is a {{path}}.
|
||||||
|
@@ -62,9 +62,9 @@
|
|||||||
// ];
|
// ];
|
||||||
// region(rgn);
|
// region(rgn);
|
||||||
//
|
//
|
||||||
// Definitions:
|
|
||||||
// Region|Regions = A list of zero or more non-intersecting {{polygons}}, representing possibly disjointed shape perimeters with enclosed holes.
|
|
||||||
|
|
||||||
|
// Definitions:
|
||||||
|
// Region|Regions = A list of one or more non-intersecting {{polygons}} representing a union of one or more disconnected polygons that may have internal holes.
|
||||||
|
|
||||||
// Function: is_region()
|
// Function: is_region()
|
||||||
// Synopsis: Returns true if the input appears to be a {{region}}.
|
// Synopsis: Returns true if the input appears to be a {{region}}.
|
||||||
|
@@ -7,11 +7,9 @@
|
|||||||
// two prisms together with a rounded fillet at the joint.
|
// two prisms together with a rounded fillet at the joint.
|
||||||
// Includes:
|
// Includes:
|
||||||
// include <BOSL2/std.scad>
|
// include <BOSL2/std.scad>
|
||||||
// include <BOSL2/rounding.scad>
|
|
||||||
// FileGroup: Advanced Modeling
|
// FileGroup: Advanced Modeling
|
||||||
// FileSummary: Round path corners, rounded prisms, rounded cutouts in tubes, filleted prism joints
|
// FileSummary: Round path corners, rounded prisms, rounded cutouts in tubes, filleted prism joints
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
include <structs.scad>
|
|
||||||
|
|
||||||
// Section: Types of Roundovers
|
// Section: Types of Roundovers
|
||||||
// The functions and modules in this file support two different types of roundovers and some different mechanisms for specifying
|
// The functions and modules in this file support two different types of roundovers and some different mechanisms for specifying
|
||||||
|
123
skin.scad
123
skin.scad
@@ -1731,7 +1731,15 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
|
|||||||
// You can also apply scaling to the profile along the path. You can give a list of scalar scale factors or a list of 2-vector scale.
|
// You can also apply scaling to the profile along the path. You can give a list of scalar scale factors or a list of 2-vector scale.
|
||||||
// In the latter scale the x and y scales of the profile are scaled separately before the profile is placed onto the path. For non-closed
|
// In the latter scale the x and y scales of the profile are scaled separately before the profile is placed onto the path. For non-closed
|
||||||
// paths you can also give a single scale value or a 2-vector, which is treated as the final scale. The intermediate sections
|
// paths you can also give a single scale value or a 2-vector, which is treated as the final scale. The intermediate sections
|
||||||
// are then scaled by linear interpolation either relative to length (if scale_by_length is true) or by point count otherwise.
|
// are then scaled by linear interpolation either relative to length (if scale_by_length is true) or by point count otherwise.
|
||||||
|
// .
|
||||||
|
// The `caps` parameter controls what happens at the ends of the polyhedron. If `closed=true` the shape links to itself and has no
|
||||||
|
// ends, but when `closed` is false, the two ends are, by default capped with flat faces. If you set `caps=false` then the ends
|
||||||
|
// receive no faces and the resulting non-manifold polyhedron has exposed edges. You can also set caps to a number, which adds a
|
||||||
|
// rounded cap with the specified radius, or you can set caps to an {{offset_sweep()}} end treatment, and the specified sweep will
|
||||||
|
// be attached as a cap. Note that you are **adding** a rounded cap, not rounding the specified shape as is common for many other
|
||||||
|
// library modules. The rounded cap is attached to the end face and may not blend neatly with the swept shape unless the sides of
|
||||||
|
// the swept shape are perpendicular to the end cap.
|
||||||
// .
|
// .
|
||||||
// You can use set `transforms` to true to return a list of transformation matrices instead of the swept shape. In this case, you can
|
// You can use set `transforms` to true to return a list of transformation matrices instead of the swept shape. In this case, you can
|
||||||
// often omit shape entirely. The exception is when `closed=true` and you are using the "incremental" method. In this case, `path_sweep`
|
// often omit shape entirely. The exception is when `closed=true` and you are using the "incremental" method. In this case, `path_sweep`
|
||||||
@@ -1764,7 +1772,7 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
|
|||||||
// uniform = if set to false then compute tangents using the uniform=false argument, which may give better results when your path is non-uniformly sampled. This argument is passed to {{path_tangents()}}. Default: true
|
// uniform = if set to false then compute tangents using the uniform=false argument, which may give better results when your path is non-uniformly sampled. This argument is passed to {{path_tangents()}}. Default: true
|
||||||
// tangent = a list of tangent vectors in case you need more accuracy (particularly at the end points of your curve)
|
// tangent = a list of tangent vectors in case you need more accuracy (particularly at the end points of your curve)
|
||||||
// relaxed = set to true with the "manual" method to relax the orthogonality requirement of cross sections to the path tangent. Default: false
|
// relaxed = set to true with the "manual" method to relax the orthogonality requirement of cross sections to the path tangent. Default: false
|
||||||
// caps = Can be a boolean or vector of two booleans. Set to false to disable caps at the two ends. Default: true
|
// caps = if closed is false, set caps to false to leave the ends open. Other values are true to create a flat cap, a number a rounded cap, or an {{offset_sweep()}} end treatment to create the specified offset sweep. Can be a single value or pair of values to control the caps independently at each end. Default: true
|
||||||
// style = vnf_vertex_array style. Default: "min_edge"
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// profiles = if true then display all the cross section profiles instead of the solid shape. Can help debug a sweep. (module only) Default: false
|
// profiles = if true then display all the cross section profiles instead of the solid shape. Can help debug a sweep. (module only) Default: false
|
||||||
// width = the width of lines used for profile display. (module only) Default: 1
|
// width = the width of lines used for profile display. (module only) Default: 1
|
||||||
@@ -2101,6 +2109,15 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
|
|||||||
// closed=true, twist=360*2/5,symmetry=5,
|
// closed=true, twist=360*2/5,symmetry=5,
|
||||||
// texture="bricks_vnf",tex_reps=[10,40],
|
// texture="bricks_vnf",tex_reps=[10,40],
|
||||||
// tex_depth=.1);
|
// tex_depth=.1);
|
||||||
|
// Example(NoScales): Applying rounded end caps to a sweep
|
||||||
|
// $fs=1;$fa=1;
|
||||||
|
// path_sweep(circle(r=5), arc(r=15, angle=[0,230]),caps=2.5);
|
||||||
|
// Example(NoScales): Using a small `$fn` creates a chamfer on the endcap
|
||||||
|
// $fs=1;$fa=1;
|
||||||
|
// path_sweep(circle(r=5), arc(r=15, angle=[0,230]),caps=1, $fn=4);
|
||||||
|
// Example(NoScales): One flat endcap and one rounding with a negative radius
|
||||||
|
// $fs=1;$fa=1;
|
||||||
|
// path_sweep(circle(r=5), arc(r=15, angle=[180,330]),caps=[true, -3]);
|
||||||
|
|
||||||
|
|
||||||
module path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true,
|
module path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true,
|
||||||
@@ -2113,9 +2130,6 @@ module path_sweep(shape, path, method="incremental", normal, closed, twist=0, tw
|
|||||||
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");
|
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");
|
||||||
trans_scale = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length,
|
trans_scale = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length,
|
||||||
symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true,_return_scales=true);
|
symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true,_return_scales=true);
|
||||||
caps = is_def(caps) ? caps :
|
|
||||||
closed ? false : true;
|
|
||||||
fullcaps = is_bool(caps) ? [caps,caps] : caps;
|
|
||||||
transforms = trans_scale[0];
|
transforms = trans_scale[0];
|
||||||
scales = trans_scale[1];
|
scales = trans_scale[1];
|
||||||
firstscale = is_num(scales[0]) ? 1/scales[0] : [1/scales[0].x, 1/scales[0].y];
|
firstscale = is_num(scales[0]) ? 1/scales[0] : [1/scales[0].x, 1/scales[0].y];
|
||||||
@@ -2125,7 +2139,7 @@ module path_sweep(shape, path, method="incremental", normal, closed, twist=0, tw
|
|||||||
shape_normals = -path3d(path_normals(clockwise_polygon(shape), closed=true))
|
shape_normals = -path3d(path_normals(clockwise_polygon(shape), closed=true))
|
||||||
)
|
)
|
||||||
[for(T=transforms) apply(_force_rot(T),shape_normals)];
|
[for(T=transforms) apply(_force_rot(T),shape_normals)];
|
||||||
vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, _closed_for_normals=closed, caps=fullcaps,style=style,
|
vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, _closed_for_normals=closed, caps=caps,style=style,
|
||||||
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples, normals=tex_normals,
|
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples, normals=tex_normals,
|
||||||
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip);
|
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip);
|
||||||
shapecent = point3d(centroid(shape));
|
shapecent = point3d(centroid(shape));
|
||||||
@@ -2181,10 +2195,6 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0,
|
|||||||
assert((is_region(shape) || is_path(shape,2)) || (transforms && !(closed && method=="incremental")),"shape must be a 2d path or region")
|
assert((is_region(shape) || is_path(shape,2)) || (transforms && !(closed && method=="incremental")),"shape must be a 2d path or region")
|
||||||
let(
|
let(
|
||||||
path = path3d(path),
|
path = path3d(path),
|
||||||
caps = is_def(caps) ? caps :
|
|
||||||
closed ? false : true,
|
|
||||||
capsOK = is_bool(caps) || is_bool_list(caps,2),
|
|
||||||
fullcaps = is_bool(caps) ? [caps,caps] : caps,
|
|
||||||
normalOK = is_undef(normal) || (method!="natural" && is_vector(normal,3))
|
normalOK = is_undef(normal) || (method!="natural" && is_vector(normal,3))
|
||||||
|| (method=="manual" && same_shape(normal,path)),
|
|| (method=="manual" && same_shape(normal,path)),
|
||||||
scaleOK = scale==1 || ((is_num(scale) || is_vector(scale,2)) && !closed) || is_vector(scale,len(path)) || is_matrix(scale,len(path),2)
|
scaleOK = scale==1 || ((is_num(scale) || is_vector(scale,2)) && !closed) || is_vector(scale,len(path)) || is_matrix(scale,len(path),2)
|
||||||
@@ -2193,8 +2203,6 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0,
|
|||||||
assert(normalOK, method=="natural" ? "Cannot specify normal with the \"natural\" method"
|
assert(normalOK, method=="natural" ? "Cannot specify normal with the \"natural\" method"
|
||||||
: method=="incremental" ? "Normal with \"incremental\" method must be a 3-vector"
|
: method=="incremental" ? "Normal with \"incremental\" method must be a 3-vector"
|
||||||
: str("Incompatible normal given. Must be a 3-vector or a list of ",len(path)," 3-vectors"))
|
: str("Incompatible normal given. Must be a 3-vector or a list of ",len(path)," 3-vectors"))
|
||||||
assert(capsOK, "caps must be boolean or a list of two booleans")
|
|
||||||
assert(!closed || !caps, "Cannot make closed shape with caps")
|
|
||||||
assert(is_undef(normal) || (is_vector(normal) && len(normal)==3) || (is_path(normal) && len(normal)==len(path) && len(normal[0])==3), "Invalid normal specified")
|
assert(is_undef(normal) || (is_vector(normal) && len(normal)==3) || (is_path(normal) && len(normal)==len(path) && len(normal[0])==3), "Invalid normal specified")
|
||||||
assert(is_undef(tangent) || (is_path(tangent) && len(tangent)==len(path) && len(tangent[0])==3), "Invalid tangent specified")
|
assert(is_undef(tangent) || (is_path(tangent) && len(tangent)==len(path) && len(tangent[0])==3), "Invalid tangent specified")
|
||||||
assert(scaleOK,str("Incompatible or invalid scale",closed?" for closed path":"",": must be ", closed?"":"a scalar, a 2-vector, ",
|
assert(scaleOK,str("Incompatible or invalid scale",closed?" for closed path":"",": must be ", closed?"":"a scalar, a 2-vector, ",
|
||||||
@@ -2330,7 +2338,7 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0,
|
|||||||
transforms && _return_scales
|
transforms && _return_scales
|
||||||
? [transform_list,scale]
|
? [transform_list,scale]
|
||||||
: transforms ? transform_list
|
: transforms ? transform_list
|
||||||
: sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps,style=style,
|
: sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=caps,style=style,
|
||||||
anchor=anchor,cp=cp,spin=spin,orient=orient,atype=atype,
|
anchor=anchor,cp=cp,spin=spin,orient=orient,atype=atype,
|
||||||
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples,
|
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples,
|
||||||
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip,
|
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip,
|
||||||
@@ -2485,9 +2493,16 @@ function _ofs_face_edge(face,firstlen,second=false) =
|
|||||||
// is a list of 4x4 transformation matrices. The sweep algorithm applies each transformation in sequence
|
// is a list of 4x4 transformation matrices. The sweep algorithm applies each transformation in sequence
|
||||||
// to the shape input and links the resulting polygons together to form a polyhedron.
|
// to the shape input and links the resulting polygons together to form a polyhedron.
|
||||||
// If `closed=true` then the first and last transformation are linked together.
|
// If `closed=true` then the first and last transformation are linked together.
|
||||||
// The `caps` parameter controls whether the ends of the shape are closed.
|
|
||||||
// As a function, returns the VNF for the polyhedron. As a module, computes the polyhedron.
|
// As a function, returns the VNF for the polyhedron. As a module, computes the polyhedron.
|
||||||
// .
|
// .
|
||||||
|
// The `caps` parameter controls what happens at the ends of the polyhedron. If `closed=true` the shape links to itself and has no
|
||||||
|
// ends, but when `closed` is false, the two ends are, by default capped with flat faces. If you set `caps=false` then the ends
|
||||||
|
// receive no faces and the resulting non-manifold polyhedron has exposed edges. You can also set caps to a number, which adds a
|
||||||
|
// rounded cap with the specified radius, or you can set caps to an {{offset_sweep()}} end treatment, and the specified sweep will
|
||||||
|
// be attached as a cap. Note that you are **adding** a rounded cap, not rounding the specified shape as is common for many other
|
||||||
|
// library modules. The rounded cap is attached to the end face and may not blend neatly with the swept shape unless the sides of
|
||||||
|
// the swept shape are perpendicular to the end cap.
|
||||||
|
// .
|
||||||
// This is a powerful, general framework for producing polyhedra. It is important
|
// This is a powerful, general framework for producing polyhedra. It is important
|
||||||
// to ensure that your resulting polyhedron does not include any self-intersections, or it will
|
// to ensure that your resulting polyhedron does not include any self-intersections, or it will
|
||||||
// be invalid and generate CGAL errors. If you get such errors, most likely you have an
|
// be invalid and generate CGAL errors. If you get such errors, most likely you have an
|
||||||
@@ -2500,11 +2515,13 @@ function _ofs_face_edge(face,firstlen,second=false) =
|
|||||||
// This works by passing through to {{vnf_vertex_array()}}, which also has more details on
|
// This works by passing through to {{vnf_vertex_array()}}, which also has more details on
|
||||||
// texturing. Note that textures work only when the shape is a path; you cannot apply a texture to a region.
|
// texturing. Note that textures work only when the shape is a path; you cannot apply a texture to a region.
|
||||||
// The texture tiles are oriented on the path sweep so that the Y axis of the tile is aligned with the sweep direction.
|
// The texture tiles are oriented on the path sweep so that the Y axis of the tile is aligned with the sweep direction.
|
||||||
|
// .
|
||||||
|
//
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// shape = 2d path or region, describing the shape to be swept.
|
// shape = 2d path or region, describing the shape to be swept.
|
||||||
// transforms = list of 4x4 matrices to apply
|
// transforms = list of 4x4 matrices to apply
|
||||||
// closed = set to true to form a closed (torus) model. Default: false
|
// closed = set to true to form a closed (torus) model. Default: false
|
||||||
// caps = true to create endcap faces when closed is false. Can be a singe boolean to specify endcaps at both ends, or a length 2 boolean array. Default is true if closed is false.
|
// caps = if closed is false, set caps to false to leave the ends open. Other values are true to create a flat cap, a number a rounded cap, or an {{offset_sweep()}} end treatment to create the specified offset sweep. Can be a single value or pair of values to control the caps independently at each end. Default: true
|
||||||
// style = vnf_vertex_array style. Default: "min_edge"
|
// style = vnf_vertex_array style. Default: "min_edge"
|
||||||
// ---
|
// ---
|
||||||
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
// convexity = convexity setting for use with polyhedron. (module only) Default: 10
|
||||||
@@ -2570,15 +2587,24 @@ function sweep(shape, transforms, closed=false, caps, style="min_edge",
|
|||||||
assert(is_consistent(transforms, ident(4)), "Input transforms must be a list of numeric 4x4 matrices in sweep")
|
assert(is_consistent(transforms, ident(4)), "Input transforms must be a list of numeric 4x4 matrices in sweep")
|
||||||
assert(is_path(shape,2) || is_region(shape), "Input shape must be a 2d path or a region.")
|
assert(is_path(shape,2) || is_region(shape), "Input shape must be a 2d path or a region.")
|
||||||
let(
|
let(
|
||||||
caps = is_def(caps) ? caps :
|
caps = is_list(caps) && select(caps,0,1)==["for","offset_sweep"] ? [caps,caps]
|
||||||
closed ? false : true,
|
: is_bool(caps) || is_num(caps) ? [caps,caps]
|
||||||
capsOK = is_bool(caps) || is_bool_list(caps,2),
|
: is_undef(caps) ? closed ? [false,false] : [true,true]
|
||||||
fullcaps = is_bool(caps) ? [caps,caps] : caps
|
: caps,
|
||||||
|
capsOK = is_list(caps) && len(caps)==2
|
||||||
|
&&
|
||||||
|
[] == [for(cap=caps)
|
||||||
|
if (!(is_bool(cap) || is_num(cap) || select(cap,0,1)==["for","offset_sweep"])) 1],
|
||||||
|
flatcaps = [for(cap=caps) is_bool(cap) ? cap : false],
|
||||||
|
fancycaps = [for(cap=caps) is_bool(cap) ? false
|
||||||
|
: is_num(cap) ? os_circle(r=cap,steps=ceil(segs(cap)/4))
|
||||||
|
: cap]
|
||||||
)
|
)
|
||||||
assert(len(transforms)>=2, "transformation must be length 2 or more")
|
assert(len(transforms)>=2, "transformation must be length 2 or more")
|
||||||
assert(capsOK, "caps must be boolean or a list of two booleans")
|
assert(capsOK, "caps must be boolean, number, an offset_sweep specification, or a list of two of those")
|
||||||
assert(!closed || !caps, "Cannot make closed shape with caps")
|
assert(!closed || caps==[false,false], "Cannot make closed shape with caps")
|
||||||
is_region(shape)?
|
is_region(shape)?
|
||||||
|
assert(fancycaps==[false,false], "rounded caps are not supported for regions")
|
||||||
assert(is_undef(texture), "textures are not supported for regions, only paths")
|
assert(is_undef(texture), "textures are not supported for regions, only paths")
|
||||||
let(
|
let(
|
||||||
regions = region_parts(shape),
|
regions = region_parts(shape),
|
||||||
@@ -2587,8 +2613,8 @@ function sweep(shape, transforms, closed=false, caps, style="min_edge",
|
|||||||
for (rgn=regions) each [
|
for (rgn=regions) each [
|
||||||
for (path=rgn)
|
for (path=rgn)
|
||||||
sweep(path, transforms, closed=closed, caps=false, style=style),
|
sweep(path, transforms, closed=closed, caps=false, style=style),
|
||||||
if (fullcaps[0]) vnf_from_region(rgn, transform=transforms[0], reverse=true),
|
if (flatcaps[0]) vnf_from_region(rgn, transform=transforms[0], reverse=true),
|
||||||
if (fullcaps[1]) vnf_from_region(rgn, transform=last(transforms)),
|
if (flatcaps[1]) vnf_from_region(rgn, transform=last(transforms)),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
vnf = vnf_join(vnfs)
|
vnf = vnf_join(vnfs)
|
||||||
@@ -2603,12 +2629,22 @@ function sweep(shape, transforms, closed=false, caps, style="min_edge",
|
|||||||
: let(
|
: let(
|
||||||
n = surface_normals(select(points,0,-2), col_wrap=true, row_wrap=true)
|
n = surface_normals(select(points,0,-2), col_wrap=true, row_wrap=true)
|
||||||
)
|
)
|
||||||
[each n, n[0]]
|
[each n, n[0]],
|
||||||
)
|
vva_result = vnf_vertex_array(points, normals=normals,
|
||||||
vnf_vertex_array(points, normals=normals,
|
cap1=flatcaps[0],cap2=flatcaps[1],col_wrap=true,style=style, return_edges=fancycaps!=[false,false],
|
||||||
cap1=fullcaps[0],cap2=fullcaps[1],col_wrap=true,style=style,
|
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples,
|
||||||
texture=texture, tex_reps=tex_reps, tex_size=tex_size, tex_samples=tex_samples,
|
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip),
|
||||||
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth, tex_extra=tex_extra, tex_skip=tex_skip);
|
vnf = fancycaps==[false,false] ? vva_result
|
||||||
|
: vnf_join(
|
||||||
|
[ vva_result[0],
|
||||||
|
for(ind=[0,1])
|
||||||
|
if (fancycaps[ind]) let(
|
||||||
|
polygon = vva_result[1][ind+2],
|
||||||
|
plane = plane_from_polygon(ind==0? reverse(polygon) : polygon)
|
||||||
|
)
|
||||||
|
apply(lift_plane(plane),offset_sweep(project_plane(plane, polygon), top=fancycaps[ind], caps=[false,true]))
|
||||||
|
])
|
||||||
|
) vnf;
|
||||||
|
|
||||||
|
|
||||||
module sweep(shape, transforms, closed=false, caps, style="min_edge", convexity=10,
|
module sweep(shape, transforms, closed=false, caps, style="min_edge", convexity=10,
|
||||||
@@ -4952,7 +4988,7 @@ module _textured_revolution(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function _textured_point_array(points, texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0, triangulate=false, tex_scaling="default",
|
function _textured_point_array(points, texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0, triangulate=false, tex_scaling="default",return_edges=false,
|
||||||
col_wrap=false, tex_depth=1, row_wrap=false, caps, cap1, cap2, reverse=false, style="min_edge", tex_extra, tex_skip, sidecaps,sidecap1,sidecap2,normals) =
|
col_wrap=false, tex_depth=1, row_wrap=false, caps, cap1, cap2, reverse=false, style="min_edge", tex_extra, tex_skip, sidecaps,sidecap1,sidecap2,normals) =
|
||||||
assert(tex_reps==undef || is_int(tex_reps) || (all_integer(tex_reps) && len(tex_reps)==2), "tex_reps must be an integer or list of two integers")
|
assert(tex_reps==undef || is_int(tex_reps) || (all_integer(tex_reps) && len(tex_reps)==2), "tex_reps must be an integer or list of two integers")
|
||||||
assert(tex_size==undef || is_num(tex_size) || is_vector(tex_size,2), "tex_size must be a scalar or 2-vector")
|
assert(tex_size==undef || is_num(tex_size) || is_vector(tex_size,2), "tex_size must be a scalar or 2-vector")
|
||||||
@@ -5016,7 +5052,8 @@ function _textured_point_array(points, texture, tex_reps, tex_size, tex_samples,
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
vnf_vertex_array(tex_surf, row_wrap=row_wrap, col_wrap=col_wrap, reverse=reverse,style=style, caps=caps, cap1=cap1, cap2=cap2, triangulate=triangulate)
|
vnf_vertex_array(tex_surf, row_wrap=row_wrap, col_wrap=col_wrap, reverse=reverse,style=style,
|
||||||
|
caps=caps, cap1=cap1, cap2=cap2, triangulate=triangulate, return_edges=return_edges)
|
||||||
: // VNF case
|
: // VNF case
|
||||||
let(
|
let(
|
||||||
local_scale = [for(y=[-1:1:ptsize.y])
|
local_scale = [for(y=[-1:1:ptsize.y])
|
||||||
@@ -5068,7 +5105,7 @@ function _textured_point_array(points, texture, tex_reps, tex_size, tex_samples,
|
|||||||
)
|
)
|
||||||
base + _tex_height(tex_depth,tex_inset,pt.z) * normal*(reverse?-1:1) * scale,
|
base + _tex_height(tex_depth,tex_inset,pt.z) * normal*(reverse?-1:1) * scale,
|
||||||
fullvnf = vnf_join([
|
fullvnf = vnf_join([
|
||||||
for(y=[0:1:tex_reps.y-1], x=[0:1:tex_reps.x-1])
|
for(y=[0:1:tex_reps.y-1], x=[0:1:tex_reps.x-1]) // Main body of the textured shape
|
||||||
[
|
[
|
||||||
[for(pt=vnf[0]) trans_pt(x,y,pt)],
|
[for(pt=vnf[0]) trans_pt(x,y,pt)],
|
||||||
vnf[1]
|
vnf[1]
|
||||||
@@ -5092,9 +5129,27 @@ function _textured_point_array(points, texture, tex_reps, tex_size, tex_samples,
|
|||||||
[for(pt = closed_path) trans_pt(x,y,[x?1:0,pt.y,pt.z])]]
|
[for(pt = closed_path) trans_pt(x,y,[x?1:0,pt.y,pt.z])]]
|
||||||
)
|
)
|
||||||
for(path=cap_paths) [path, [count(path,reverse=x!=0)]]
|
for(path=cap_paths) [path, [count(path,reverse=x!=0)]]
|
||||||
])
|
]),
|
||||||
|
edgepaths = !return_edges ? undef
|
||||||
|
: [
|
||||||
|
if (!col_wrap)
|
||||||
|
for(x=[0, tex_reps.x-1])
|
||||||
|
[for(y=[0:1:tex_reps.y-1],pt=xedge_paths[0][0])
|
||||||
|
trans_pt(x,y,[x?1:0,pt.y,pt.z])]
|
||||||
|
else each [[],[]],
|
||||||
|
|
||||||
|
if (!row_wrap && len(yedge_paths[0])>0)
|
||||||
|
for(ind=[0,1])
|
||||||
|
if ([cap1,cap2][ind]) []
|
||||||
|
else let(y=[0,tex_reps.y-1][ind])
|
||||||
|
[for(x=[0:1:tex_reps.x-1], pt=yedge_paths[0][0])
|
||||||
|
trans_pt(x,y,[pt.x,y?0:1,pt.z])]
|
||||||
|
else each [[],[]]
|
||||||
|
],
|
||||||
|
revvnf = reverse ? vnf_reverse_faces(fullvnf) : fullvnf
|
||||||
|
|
||||||
)
|
)
|
||||||
reverse ? vnf_reverse_faces(fullvnf) : fullvnf;
|
!return_edges ? revvnf : [revvnf, edgepaths];
|
||||||
|
|
||||||
|
|
||||||
// Resamples a point array to the specified size.
|
// Resamples a point array to the specified size.
|
||||||
|
3
std.scad
3
std.scad
@@ -35,10 +35,11 @@ include <geometry.scad>
|
|||||||
include <regions.scad>
|
include <regions.scad>
|
||||||
include <strings.scad>
|
include <strings.scad>
|
||||||
include <vnf.scad>
|
include <vnf.scad>
|
||||||
|
include <structs.scad>
|
||||||
|
include <rounding.scad>
|
||||||
include <skin.scad>
|
include <skin.scad>
|
||||||
include <utility.scad>
|
include <utility.scad>
|
||||||
include <partitions.scad>
|
include <partitions.scad>
|
||||||
include <structs.scad>
|
|
||||||
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
||||||
|
26
vnf.scad
26
vnf.scad
@@ -73,6 +73,12 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
|||||||
// For creating the texture, `vnf_vertex_array()` uses normals to the surface that it estimates from the surface data itself.
|
// For creating the texture, `vnf_vertex_array()` uses normals to the surface that it estimates from the surface data itself.
|
||||||
// If you have more accurate normals or need the normals to take particular values, you can pass an array of normals
|
// If you have more accurate normals or need the normals to take particular values, you can pass an array of normals
|
||||||
// using the `normals` parameter.
|
// using the `normals` parameter.
|
||||||
|
// .
|
||||||
|
// You can set `return_edges=true` to return the paths of the four edges of the output. In this case the return value
|
||||||
|
// is `[vnf,edgelist]` where edgelist is [left (column 0 of points), right (last column of points), top (points[0]), bottom (last(points)]. If a given
|
||||||
|
// edge does not exist then it will be the empty list in the output. An edge only exists it is not capped and not wrapped. The main
|
||||||
|
// need for this feature is when you have added a texture and need a way to interface the shape with something else. In this case you cannot
|
||||||
|
// easily determine the edges yourself from the input point list. edges are not easily
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// points = A list of vertices to divide into columns and rows.
|
// points = A list of vertices to divide into columns and rows.
|
||||||
// ---
|
// ---
|
||||||
@@ -99,6 +105,7 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
|||||||
// sidecap2 = set sidecap only for the `points[][max]` edge of the output
|
// sidecap2 = set sidecap only for the `points[][max]` edge of the output
|
||||||
// tex_scaling = set to "const" to disable grid size vertical scaling of the texture. Default: "default"
|
// tex_scaling = set to "const" to disable grid size vertical scaling of the texture. Default: "default"
|
||||||
// normals = array of normal vectors to each point in the point array for more accurate texture height calculation
|
// normals = array of normal vectors to each point in the point array for more accurate texture height calculation
|
||||||
|
// return_edges = if true return [vnf,edgelist] where edgelist is the paths of four edges, [left (column 0 of points), right (last column of points), top (points[0]), bottom (last(points)]. Default: false
|
||||||
// cp = (module) Centerpoint for determining intersection anchors or centering the shape. Determines the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
// cp = (module) Centerpoint for determining intersection anchors or centering the shape. Determines the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
||||||
// anchor = (module) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"origin"`
|
// anchor = (module) Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"origin"`
|
||||||
// spin = (module) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
// spin = (module) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||||
@@ -326,7 +333,7 @@ function vnf_vertex_array(
|
|||||||
row_wrap=false,
|
row_wrap=false,
|
||||||
reverse=false,
|
reverse=false,
|
||||||
style="default",
|
style="default",
|
||||||
triangulate = false,
|
triangulate = false, return_edges=false,
|
||||||
texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0, tex_scaling="default",
|
texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0, tex_scaling="default",
|
||||||
tex_depth=1, tex_extra, tex_skip, sidecaps,sidecap1,sidecap2, normals
|
tex_depth=1, tex_extra, tex_skip, sidecaps,sidecap1,sidecap2, normals
|
||||||
) =
|
) =
|
||||||
@@ -336,7 +343,7 @@ function vnf_vertex_array(
|
|||||||
assert(is_bool(triangulate))
|
assert(is_bool(triangulate))
|
||||||
is_def(texture) ?
|
is_def(texture) ?
|
||||||
_textured_point_array(points=points, texture=texture, tex_reps=tex_reps, tex_size=tex_size,
|
_textured_point_array(points=points, texture=texture, tex_reps=tex_reps, tex_size=tex_size,
|
||||||
tex_inset=tex_inset, tex_samples=tex_samples, tex_rot=tex_rot, tex_scaling=tex_scaling,
|
tex_inset=tex_inset, tex_samples=tex_samples, tex_rot=tex_rot, tex_scaling=tex_scaling, return_edges=return_edges,
|
||||||
col_wrap=col_wrap, row_wrap=row_wrap, tex_depth=tex_depth, caps=caps, cap1=cap1, cap2=cap2, reverse=reverse,
|
col_wrap=col_wrap, row_wrap=row_wrap, tex_depth=tex_depth, caps=caps, cap1=cap1, cap2=cap2, reverse=reverse,
|
||||||
style=style, tex_extra=tex_extra, tex_skip=tex_skip, sidecaps=sidecaps, sidecap1=sidecap1, sidecap2=sidecap2,normals=normals,triangulate=triangulate)
|
style=style, tex_extra=tex_extra, tex_skip=tex_skip, sidecaps=sidecaps, sidecap1=sidecap1, sidecap2=sidecap2,normals=normals,triangulate=triangulate)
|
||||||
:
|
:
|
||||||
@@ -431,10 +438,17 @@ function vnf_vertex_array(
|
|||||||
)
|
)
|
||||||
rfaces,
|
rfaces,
|
||||||
],
|
],
|
||||||
vnf = [verts, allfaces]
|
vnf = [verts, allfaces],
|
||||||
) triangulate? vnf_triangulate(vnf) : vnf;
|
tvnf = triangulate? vnf_triangulate(vnf) : vnf
|
||||||
|
)
|
||||||
|
!return_edges ? tvnf
|
||||||
|
: [tvnf, [
|
||||||
|
if (!col_wrap) deduplicate(column(points,0)) else [],
|
||||||
|
if (!col_wrap) deduplicate(column(points, len(points[0])-1)) else [],
|
||||||
|
if (!cap1 && !row_wrap) deduplicate(points[0]) else [],
|
||||||
|
if (!cap2 && !row_wrap) deduplicate(last(points)) else []
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
// Function&Module: vnf_tri_array()
|
// Function&Module: vnf_tri_array()
|
||||||
// Synopsis: Returns a VNF from an array of points. The array need not be rectangular.
|
// Synopsis: Returns a VNF from an array of points. The array need not be rectangular.
|
||||||
|
Reference in New Issue
Block a user