mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-12 09:14:22 +02:00
Merge pull request #1622 from adrianVmariano/master
Add texture support to vnf_vertex_array texture cleanup and doc fixes
This commit is contained in:
@@ -198,9 +198,9 @@ module pco1810_cap(h, r, d, wall, texture="none", anchor=BOTTOM, spin=0, orient=
|
||||
difference() {
|
||||
union() {
|
||||
if (texture == "knurled") {
|
||||
cyl(d=w, h=hh, texture="diamonds", tex_size=[3,3], tex_style="concave", anchor=BOT);
|
||||
cyl(d=w, h=hh, texture="diamonds", tex_size=[3,3], style="concave", anchor=BOT);
|
||||
} else if (texture == "ribbed") {
|
||||
cyl(d=w, h=hh, texture="ribs", tex_size=[3,3], tex_style="min_edge", anchor=BOT);
|
||||
cyl(d=w, h=hh, texture="ribs", tex_size=[3,3], style="min_edge", anchor=BOT);
|
||||
} else {
|
||||
cyl(d=w, l=hh, anchor=BOTTOM);
|
||||
}
|
||||
@@ -387,9 +387,9 @@ module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
|
||||
difference() {
|
||||
union() {
|
||||
if (texture == "knurled") {
|
||||
cyl(d=w, h=11.2+wall, texture="diamonds", tex_size=[3,3], tex_style="concave", anchor=BOT);
|
||||
cyl(d=w, h=11.2+wall, texture="diamonds", tex_size=[3,3], style="concave", anchor=BOT);
|
||||
} else if (texture == "ribbed") {
|
||||
cyl(d=w, h=11.2+wall, texture="ribs", tex_size=[3,3], tex_style="min_edge", anchor=BOT);
|
||||
cyl(d=w, h=11.2+wall, texture="ribs", tex_size=[3,3], style="min_edge", anchor=BOT);
|
||||
} else {
|
||||
cyl(d=w, l=11.2+wall, anchor=BOTTOM);
|
||||
}
|
||||
@@ -610,9 +610,9 @@ module generic_bottle_cap(
|
||||
// thickness so the wall+texture are the specified wall thickness. That
|
||||
// seems wrong so this does specified thickness+texture
|
||||
if (texture == "knurled")
|
||||
cyl(d=w + 1.5*diamMagMult, l=h, texture="diamonds", tex_size=[3,3], tex_style="concave", anchor=BOT);
|
||||
cyl(d=w + 1.5*diamMagMult, l=h, texture="diamonds", tex_size=[3,3], style="concave", anchor=BOT);
|
||||
else if (texture == "ribbed")
|
||||
cyl(d=w + 1.5*diamMagMult, l=h, texture="ribs", tex_size=[3,3], tex_style="min_edge", anchor=BOT);
|
||||
cyl(d=w + 1.5*diamMagMult, l=h, texture="ribs", tex_size=[3,3], style="min_edge", anchor=BOT);
|
||||
else
|
||||
cyl(d = w, l = h, anchor = BOTTOM);
|
||||
}
|
||||
@@ -1314,9 +1314,9 @@ module sp_cap(diam,type,wall,style="L",top_adj=0, bot_adj=0, texture="none", anc
|
||||
difference(){
|
||||
up(wall){
|
||||
if (texture=="knurled")
|
||||
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,texture="trunc_pyramids", tex_size=[3,3], tex_style="convex");
|
||||
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,texture="trunc_pyramids", tex_size=[3,3], style="convex");
|
||||
else if (texture == "ribbed")
|
||||
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8,tex_taper=0,texture="trunc_ribs", tex_size=[3,3], tex_style="min_edge");
|
||||
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8,tex_taper=0,texture="trunc_ribs", tex_size=[3,3], style="min_edge");
|
||||
else
|
||||
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8);
|
||||
}
|
||||
|
@@ -1050,7 +1050,7 @@ function _normal_segment(p1,p2) =
|
||||
// "left" | [angle] | Same as "turn"
|
||||
// "right" | [angle] | Same as "turn", -angle
|
||||
// "angle" | angle | Set the default turn angle.
|
||||
// "setdir" | dir | Set turtle direction. The parameter `dir` can be an angle or a vector.
|
||||
// "setdir" | dir | Set turtle direction. The parameter `dir` can be an angle or a vector. (A 3d vector with zero Z component is allowed.)
|
||||
// "length" | length | Change the turtle move distance to `length`
|
||||
// "scale" | factor | Multiply turtle move distance by `factor`
|
||||
// "addlength" | length | Add `length` to the turtle move distance
|
||||
@@ -1184,12 +1184,12 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||
needeither = ["setdir"],
|
||||
chvec = !in_list(command,needvec) || is_vector(parm,2),
|
||||
chnum = !in_list(command,neednum) || is_num(parm),
|
||||
vec_or_num = !in_list(command,needeither) || (is_num(parm) || is_vector(parm,2)),
|
||||
vec_or_num = !in_list(command,needeither) || (is_num(parm) || is_vector(parm,2) || (is_vector(parm,3)&&parm.z==0)),
|
||||
lastpt = last(state[path])
|
||||
)
|
||||
assert(chvec,str("\"",command,"\" requires a vector parameter at index ",index))
|
||||
assert(chnum,str("\"",command,"\" requires a numeric parameter at index ",index))
|
||||
assert(vec_or_num,str("\"",command,"\" requires a vector or numeric parameter at index ",index))
|
||||
assert(vec_or_num,str("\"",command,"\" requires a 2-vector or numeric parameter at index ",index))
|
||||
|
||||
command=="move" ? list_set(state, path, concat(state[path],[default(parm,1)*state[step]+lastpt])) :
|
||||
command=="untilx" ? (
|
||||
@@ -1219,7 +1219,7 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||
command=="angle" ? list_set(state, angle, parm) :
|
||||
command=="setdir" ? (
|
||||
is_vector(parm) ?
|
||||
list_set(state, step, norm(state[step]) * unit(parm)) :
|
||||
list_set(state, step, norm(state[step]) * unit(point2d(parm))) :
|
||||
list_set(state, step, norm(state[step]) * [cos(parm),sin(parm)])
|
||||
) :
|
||||
command=="length" ? list_set(state, step, parm*unit(state[step])) :
|
||||
|
@@ -3475,6 +3475,35 @@ Access to the derivative smoothing parameter?
|
||||
// attach(RIGHT,"root")
|
||||
// join_prism(circle(r=8,$fn=32),
|
||||
// l=10, base="plane", fillet=4);
|
||||
// Example(3D,NoScales,VPR=[47.3,0,14.5],VPT=[-2.8467,-2.05938,-10.6999],VPD=220): Two join_prism objects are placed on the parent cylinder using anchors, and then their descriptions are used to contruct a curved handle with a bezier.
|
||||
// $fs=.5; $fa=4;
|
||||
// vspace=25;
|
||||
// bezlen=40;
|
||||
// cylr=20;
|
||||
// straightlen=10;
|
||||
// circ = circle(r=6);
|
||||
// cyl(r=cylr,h=50, rounding=3)
|
||||
// let(cyl=parent())
|
||||
// down(vspace/2)
|
||||
// attach(RIGHT+FWD, "root", spin=90)
|
||||
// join_prism(circ, base="cyl", base_r=20, height=straightlen, fillet=4)
|
||||
// let(base1=parent())
|
||||
// restore(cyl)
|
||||
// up(vspace/2)
|
||||
// attach(LEFT+FWD, "root", spin=90)
|
||||
// join_prism(circ, base="cyl", base_r=20, height=straightlen, fillet=4)
|
||||
// let(base2=parent())
|
||||
// let(
|
||||
// avg_dir = desc_dir(base1,anchor=TOP)+desc_dir(base2,anchor=TOP),
|
||||
// bez=[
|
||||
// desc_point(base1,anchor=TOP),
|
||||
// desc_point(base1,anchor=TOP)+bezlen*desc_dir(base1,anchor=TOP),
|
||||
// (cylr+straightlen+bezlen)*avg_dir,
|
||||
// desc_point(base2,anchor=TOP)+bezlen*desc_dir(base2,anchor=TOP),
|
||||
// desc_point(base2,anchor=TOP)]
|
||||
// )
|
||||
// path_sweep(circ,bezier_curve(bez,40));
|
||||
|
||||
module join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
||||
scale=1, prism_end_T=IDENT, short=false,
|
||||
length, l, height, h,
|
||||
@@ -4045,6 +4074,9 @@ function _prism_fillet_prism(name, basepoly, bot, top, d, k, N, overlap, uniform
|
||||
// n = number of facets to use for the fillets. Default: 15
|
||||
// n1 = number of facets at object1
|
||||
// n2 = number of facets at object2
|
||||
// fillet = fillet for both ends of the prism. Default: 0
|
||||
// fillet1 = fillet for the joint at object1
|
||||
// fillet2 = fillet for the joint at object2
|
||||
// k = fillet curvature parameter for both ends. Default: 0.7
|
||||
// k1 = fillet curvature parameter at object1
|
||||
// k2 = fillet curvature parameter at object2
|
||||
@@ -4513,8 +4545,8 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1=0, shift2
|
||||
smooth_normals, smooth_normals1, smooth_normals2,
|
||||
debug=false, debug_pos=false)
|
||||
{
|
||||
base_fillet = default(fillet1,fillet);
|
||||
aux_fillet = default(fillet2,fillet);
|
||||
base_fillet = first_defined([fillet1,fillet,0]);
|
||||
aux_fillet = first_defined([fillet2,fillet,0]);
|
||||
|
||||
base_overlap = first_defined([overlap1,overlap,1]);
|
||||
aux_overlap = first_defined([overlap2,overlap,1]);
|
||||
|
@@ -819,7 +819,8 @@ function prismoid(
|
||||
// You can specify the size of the ends using diameter or radius measured either inside or outside. Alternatively
|
||||
// you can give the length of the side of the polygon. You can specify chamfers and roundings for the ends, but not
|
||||
// the vertical edges. See {{rounded_prism()}} for prisms with rounded vertical edges. You can also specify texture for the side
|
||||
// faces, but note that texture is not compatible with any roundings or chamfers.
|
||||
// faces, but note that texture is not compatible with any roundings or chamfers.
|
||||
// See [Texturing](skin.scad#section-texturing) for more details on how textures work.
|
||||
// .
|
||||
// Anchors are based on the VNF of the prism. Especially for tapered or shifted prisms, this may give unexpected anchor positions, such as top side anchors
|
||||
// being located at the bottom of the shape, so confirm anchor positions before use.
|
||||
@@ -1155,10 +1156,12 @@ function regular_prism(n,
|
||||
// Topics: Shapes (3D), Attachable, VNF Generators
|
||||
// See Also: cuboid(), prismoid(), texture(), cyl(), rotate_sweep(), linear_sweep()
|
||||
// Usage:
|
||||
// textured_tile(texture, [size], [w1=], [w2=], [ang=], [shift=], [h=/height=/thickness=], [atype=], [diff=], [extra=], [skip=], ...) [ATTACHMENTS];
|
||||
// vnf = textured_tile(texture, [size], [w1=], [w2=], [ang=], [shift=], [h=/height=/thickness=], [atype=], [extra=], [skip=], ...);
|
||||
// textured_tile(texture, [size], [w1=], [w2=], [ang=], [shift=], [h=/height=/thickness=], [atype=], [diff=], [tex_extra=], [tex_skip=], ...) [ATTACHMENTS];
|
||||
// vnf = textured_tile(texture, [size], [w1=], [w2=], [ang=], [shift=], [h=/height=/thickness=], [atype=], [tex_extra=], [tex_skip=], ...);
|
||||
// Description:
|
||||
// Creates a cuboid or trapezoidal prism and places a texture on the top face. You can specify the size by giving a `size` scalar or vector as is
|
||||
// Creates a cuboid or trapezoidal prism and places a texture on the top face.
|
||||
// See [Texturing](skin.scad#section-texturing) for more details on how textures work.
|
||||
// You can specify the size of the object by giving a `size` scalar or vector as is
|
||||
// usual for a cube. If you give a scalar, however, it applies only to the X and Y dimensions: the default is to create a thin tile, not a cube.
|
||||
// The Z size specifies the size of the shape **not** including the applied texture (in the same way that other textured objects work).
|
||||
// If you omit the Z value then for regular textures, the default thickness will be 0.1 which provides a thin backing layer. A zero thickness
|
||||
@@ -1187,11 +1190,11 @@ function regular_prism(n,
|
||||
// has the exact same dimensions as the texture tile, you will have exactly aligned faces along the edges.
|
||||
// .
|
||||
// Most of the heightfield textures are designed to repeat in a way that requires one extra line of the texture to complete the pattern.
|
||||
// The `extra` parameter specifies the number of extra lines to repeat at the end of the texture and it defaults to 1 because most textures
|
||||
// do requires this extra line. If you need to disable this feature you can set the `extra` parameter to 0, or you can set it to a list of two
|
||||
// booleans to control the extra line of texture in the X and Y directions independently. The extra parameter
|
||||
// The `tex_extra` parameter specifies the number of extra lines to repeat at the end of the texture and it defaults to 1 because most textures
|
||||
// do requires this extra line. If you need to disable this feature you can set the `tex_extra` parameter to 0, or you can set it to a list of two
|
||||
// booleans to control the extra line of texture in the X and Y directions independently. The `tex_extra` parameter
|
||||
// is ignored for VNF textures. A heightfield texture may also have extra margin along a starting side that makes the texture unbalanced. You can
|
||||
// removed this using the `skip` parameter, which defaults to zero and similarly specifies the number of lines to skip in the X and Y directions at
|
||||
// removed this using the `tex_skip` parameter, which defaults to zero and similarly specifies the number of lines to skip in the X and Y directions at
|
||||
// the starting edges of the tile. You must have enough tile repetitions to accomodate the specified skip.
|
||||
// Anchor Types:
|
||||
// "tex" = Anchors around the texture, ignoring the base object. (default)
|
||||
@@ -1206,24 +1209,24 @@ function regular_prism(n,
|
||||
// ang = Specify the front angle(s) of the trapezoidal prism. Can give a scalar for an isosceles trapezoidal prism or a list of two angles, the left angle and right angle. You must omit one of `h`, `w1`, or `w2` to allow the freedom to control the angles.
|
||||
// shift = Scalar value to shift the back of the trapezoidal prism along the X axis by. Cannot be combined with ang. Default: 0
|
||||
// h / height / thickness = The thickness in the Z direction of the base that the texture sits on. Default: 0.1 or for inset textures 0.1 more than the inset depth
|
||||
// tex_size = An optional 2D target size for the textures. Actual texture sizes will be scaled somewhat to evenly fit the available surface. Default: `[1,1]`
|
||||
// tex_size = An optional 2D target size for the textures. Actual texture sizes will be scaled somewhat to evenly fit the available surface. Default: `[5,5]`
|
||||
// tex_reps = If given instead of tex_size, a 2-vector giving the number of texture tile repetitions in the horizontal and vertical directions.
|
||||
// tex_inset = If numeric, lowers the texture into the surface by the specified proportion, e.g. 0.5 would lower it half way into the surface. If `true`, insets by exactly its full depth. Default: `false`
|
||||
// tex_rot = Rotate texture by specified angle, which must be a multiple of 90 degrees. Default: 0
|
||||
// tex_depth = Specify texture depth; if negative, invert the texture. Default: 1.
|
||||
// diff = if set to true then "remove" and "keep" tags are set to cut out a space for the texture so that inset textures can be attached. Default: false
|
||||
// extra = number of extra lines of a hightfield texture to add at the end. Can be a scalar or 2-vector to give x and y values. Default: 1
|
||||
// skip = number of lines of a heightfield texture to skip when starting. Can be a scalar or two vector to give x and y values. Default: 0
|
||||
// tex_extra = number of extra lines of a hightfield texture to add at the end. Can be a scalar or 2-vector to give x and y values. Default: 1
|
||||
// tex_skip = number of lines of a heightfield texture to skip when starting. Can be a scalar or two vector to give x and y values. Default: 0
|
||||
// style = {{vnf_vertex_array()}} style used to triangulate heightfield textures. Default: "min_edge"
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// Example(3D,NoScale,VPT=[-0.257402,0.467403,-0.648606],VPR=[46.6,0,16.6],VPD=29.2405): Basic textured tile
|
||||
// Example(3D,NoScales,VPT=[-0.257402,0.467403,-0.648606],VPR=[46.6,0,16.6],VPD=29.2405): Basic textured tile
|
||||
// textured_tile("trunc_diamonds", 10, tex_reps=[5,5]);
|
||||
// Example(3D,NoScale,VPT=[-0.0852782,0.259593,0.139667],VPR=[58.5,0,345.1],VPD=36.0994): Attaching a tile to a cube
|
||||
// Example(3D,NoAxes,VPT=[-0.0852782,0.259593,0.139667],VPR=[58.5,0,345.1],VPD=36.0994): Attaching a tile to a cube
|
||||
// cuboid([12,12,4]) attach(TOP,BOT)
|
||||
// textured_tile("trunc_pyramids", 10, tex_reps=[5,5], style="convex");
|
||||
// Example(3D,NoScale,VPT = [-0.0788193, 0.10015, -0.0938629], VPR = [57.8, 0, 34.1], VPD = 29.2405): This inset texture doesn't look obviously different, but you can see that the object is below the XY plane.
|
||||
// Example(3D,NoScales,VPT = [-0.0788193, 0.10015, -0.0938629], VPR = [57.8, 0, 34.1], VPD = 29.2405): This inset texture doesn't look obviously different, but you can see that the object is below the XY plane.
|
||||
// textured_tile("trunc_pyramids_vnf", 10, tex_reps=[5,5], tex_inset=true);
|
||||
// Example(3D,NoAxes,VPT=[0.242444,0.170054,-0.0714754],VPR=[67.6,0,33.4],VPD=36.0994): Here we use the `diff` option combined with {{diff()}} to attach the inset texture to the front of a parent cuboid.
|
||||
// diff()
|
||||
@@ -1233,18 +1236,18 @@ function regular_prism(n,
|
||||
// Example(3D,NoAxes,VPT=[5.86588,-0.107082,-0.311155],VPR=[17.2,0,9.6],VPD=32.4895): Tile shaped like a rhombic prism
|
||||
// textured_tile("ribs", w1=10, w2=10, shift=4,ysize=7);
|
||||
// Example(3D,NoAxes,VPT=[-0.487417,-0.398897,-0.143258],VPR=[10.2,0,12.4],VPD=26.3165): A tile shaped like a trapezoidal prism. Note that trapezoidal tiles will always distort the texture, resulting in curves
|
||||
// textured_tile("diamonds", w1=10, w2=7, ysize=7) show_anchors(2);
|
||||
// textured_tile("diamonds", w1=10, w2=7, ysize=7);
|
||||
// Example(3D,NoAxes,VPT=[-0.0889877,-0.31974,0.554444],VPR=[22.1,0,22.2],VPD=32.4895): An inset trapezoidal tile placed into a cube
|
||||
// diff()cuboid([10,10,2])
|
||||
// attach(TOP,BOT)
|
||||
// textured_tile("trunc_diamonds", tex_reps=[5,5], tex_inset=true,
|
||||
// w1=8, w2=4, ysize=8, diff=true);
|
||||
// Example(3D,NoScales,VPT=[-0.0889877,-0.31974,0.554444],VPR=[58.5,0,21.5],VPD=32.4895): This example shows what happens if you set `extra` to zero for the "pyramids" texture. Note that the texture doesn't finish. The default of `extra=1` produces the correct result.
|
||||
// textured_tile("pyramids", 10, tex_reps=[5,5], extra=0);
|
||||
// Example(3D,NoScales,VPT=[-0.212176,-0.651766,0.124004],VPR=[58.5,0,21.5],VPD=29.2405): This texture has an asymmetry even with the default `extra=1`.
|
||||
// textured_tile("trunc_ribs", 10, tex_reps=[5,2]);
|
||||
// Example(3D,NoScales,VPT=[-0.212176,-0.651766,0.124004],VPR=[58.5,0,21.5],VPD=29.2405): It could be fixed by setting `extra=2`, which would place an extra flat strip on the right. But another option is to use the `skip` parameter to trim the flat part from the left. Note that we are also skipping in the y direction, but it doesn't make a difference for this texture, except that you need to have enough texture tiles to accommodate the skip. You can also set `skip` to a vector.
|
||||
// textured_tile("trunc_ribs", 10, tex_reps=[5,2], skip=1);
|
||||
// Example(3D,NoAxes,VPT=[-0.0889877,-0.31974,0.554444],VPR=[58.5,0,21.5],VPD=32.4895): This example shows what happens if you set `tex_extra` to zero for the "pyramids" texture. Note that the texture doesn't finish. The default of `tex_extra=1` produces the correct result.
|
||||
// textured_tile("pyramids", 10, tex_reps=[5,5], tex_extra=0);
|
||||
// Example(3D,NoAxes,VPT=[-0.212176,-0.651766,0.124004],VPR=[58.5,0,21.5],VPD=29.2405): This texture has an asymmetry even with the default `tex_extra=1`.
|
||||
// textured_tile("trunc_ribs", 10, tex_reps=[5,1]);
|
||||
// Example(3D,NoAxes,VPT=[-0.212176,-0.651766,0.124004],VPR=[58.5,0,21.5],VPD=29.2405): It could be fixed by setting `tex_extra=2`, which would place an extra flat strip on the right. But another option is to use the `tex_skip` parameter to trim the flat part from the left. Note that we are also skipping in the y direction, but it doesn't make a difference for this texture, except that you need to have enough texture tiles to accommodate the skip, so we increased the Y reps value to 2. You can also set `tex_skip` to a vector.
|
||||
// textured_tile("trunc_ribs", 10, tex_reps=[5,2], tex_skip=1);
|
||||
|
||||
|
||||
// This is like _tile_edge_path_list in that it finds the paths
|
||||
@@ -1287,8 +1290,8 @@ module textured_tile(
|
||||
tex_rot=0,
|
||||
tex_depth=1,
|
||||
diff=false,
|
||||
extra=1,
|
||||
skip=0,
|
||||
tex_extra=1,
|
||||
tex_skip=0,
|
||||
style="min_edge",
|
||||
atype="tex",
|
||||
anchor=CENTER, spin=0, orient=UP
|
||||
@@ -1297,8 +1300,8 @@ module textured_tile(
|
||||
|
||||
vnf_data = textured_tile(size=size,
|
||||
ysize=ysize, height=height, w1=w1, w2=w2, ang=ang, h=h, shift=shift,
|
||||
texture=texture, tex_size=tex_size, tex_reps=tex_reps,extra=extra,
|
||||
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth,skip=skip,
|
||||
texture=texture, tex_size=tex_size, tex_reps=tex_reps,tex_extra=tex_extra,
|
||||
tex_inset=tex_inset, tex_rot=tex_rot, tex_depth=tex_depth,tex_skip=tex_skip,
|
||||
style=style, atype="std",_return_anchor=true);
|
||||
h_w1_w2_shift = vnf_data[2];
|
||||
is_trap = is_def(h_w1_w2_shift);
|
||||
@@ -1333,15 +1336,15 @@ function textured_tile(
|
||||
texture,
|
||||
size,
|
||||
ysize, height, w1, w2, ang, h, shift, thickness,
|
||||
tex_size=[1,1],
|
||||
tex_size=[5,5],
|
||||
tex_reps,
|
||||
tex_inset=false,
|
||||
tex_rot=0,
|
||||
tex_depth=1,
|
||||
style="min_edge",
|
||||
atype="tex",
|
||||
extra=1,
|
||||
skip=0,
|
||||
tex_extra=1,
|
||||
tex_skip=0,
|
||||
anchor=CENTER, spin=0, orient=UP,
|
||||
_return_anchor=false
|
||||
) =
|
||||
@@ -1352,8 +1355,8 @@ function textured_tile(
|
||||
assert(is_undef(size) || num_defined([ysize,h, height, thickness, w1,w2,ang])==0, "Cannot combine size with any other dimensional specifications")
|
||||
|
||||
let(
|
||||
extra = is_list(extra) ? extra : [extra,extra],
|
||||
skip = is_list(skip) ? skip : [skip,skip],
|
||||
extra = is_list(tex_extra) ? tex_extra : [tex_extra,tex_extra],
|
||||
skip = is_list(tex_skip) ? tex_skip : [tex_skip,tex_skip],
|
||||
inset = is_num(tex_inset)? tex_inset : tex_inset? 1 : 0,
|
||||
default_thick = inset>0 ? 0.1+abs(tex_depth)*inset : 0.1,
|
||||
extra_ht = max(0,abs(tex_depth)*(1-inset)),
|
||||
@@ -1373,14 +1376,9 @@ function textured_tile(
|
||||
height = is_def(size) ? default(size.z,default_thick) : one_defined([h,height,thickness],"h,height,thickness",dflt=default_thick),
|
||||
size = is_def(size) ? is_num(size) ? [size,size,1] : point3d(size,1) // We only use the x and y components of size
|
||||
: [w1,ysize],
|
||||
|
||||
tex = is_string(texture)? texture(texture,$fn=_tex_fn_default()) : texture,
|
||||
texture = tex_rot==0? tex
|
||||
: is_vnf(tex)? zrot(tex_rot, cp=[1/2,1/2], p=tex)
|
||||
: tex_rot==180? reverse([for (row=tex) reverse(row)])
|
||||
: tex_rot==270? [for (row=transpose(tex)) reverse(row)]
|
||||
: reverse(transpose(tex)),
|
||||
check_tex = _validate_texture(texture),
|
||||
|
||||
texture = _get_texture(texture, tex_rot),
|
||||
|
||||
tex_reps = is_def(tex_reps) ? tex_reps
|
||||
: [round(size.x/tex_size.x), round(size.y/tex_size.y)],
|
||||
scale = [size.x/tex_reps.x, size.y/tex_reps.y],
|
||||
@@ -1989,8 +1987,10 @@ function cylinder(h, r1, r2, center, r, d, d1, d2, anchor, spin=0, orient=UP) =
|
||||
// the cylinder or cone's sloped side. The more specific parameters like chamfer1 or rounding2 override the more
|
||||
// general ones like chamfer or rounding, so if you specify `rounding=3, chamfer2=3` you will get a chamfer at the top and
|
||||
// rounding at the bottom. You can specify extra height at either end for use with difference(); the extra height is ignored by
|
||||
// anchoring.
|
||||
// anchoring.
|
||||
// .
|
||||
// You can apply a texture to the cylinder using the usual texture parameters.
|
||||
// See [Texturing](skin.scad#section-texturing) for more details on how textures work.
|
||||
// When creating a textured cylinder, the number of facets is determined by the sampling of the texture. Any `$fn`, `$fa` or `$fs` values in
|
||||
// effect are ignored. To create a textured prism with a specified number of flat facets use {{regular_prism()}}. Anchors for cylinders
|
||||
// appear on the ideal cylinder, not on actual discretized shape the module produces. For anchors on the shape surface, use {{regular_prism()}}.
|
||||
@@ -2293,8 +2293,8 @@ function cyl(
|
||||
extra, extra1, extra2,
|
||||
anchor, spin=0, orient=UP
|
||||
) =
|
||||
assert(num_defined([style,tex_style])<2, "In cyl() the 'tex_style' parameters has been replaced by 'style'. You cannot give both.")
|
||||
assert(num_defined([tex_reps,tex_counts])<2, "In cyl() the 'tex_counts' parameters has been replaced by 'tex_reps'. You cannot give both.")
|
||||
assert(num_defined([style,tex_style])<2, "In cyl() the 'tex_style' parameter has been replaced by 'style'. You cannot give both.")
|
||||
assert(num_defined([tex_reps,tex_counts])<2, "In cyl() the 'tex_counts' parameter has been replaced by 'tex_reps'. You cannot give both.")
|
||||
assert(num_defined([tex_scale,tex_depth])<2, "In cyl() the 'tex_scale' parameter has been replaced by 'tex_depth'. You cannot give both.")
|
||||
let(
|
||||
style = is_def(tex_style)? echo("In cyl() the 'tex_style' parameter is deprecated and has been replaced by 'style'")tex_style
|
||||
@@ -2393,7 +2393,7 @@ module cyl(
|
||||
assert(num_defined([style,tex_style])<2, "In cyl() the 'tex_style' parameters has been replaced by 'style'. You cannot give both.")
|
||||
assert(num_defined([tex_reps,tex_counts])<2, "In cyl() the 'tex_counts' parameters has been replaced by 'tex_reps'. You cannot give both.")
|
||||
assert(num_defined([tex_scale,tex_depth])<2, "In cyl() the 'tex_scale' parameter has been replaced by 'tex_depth'. You cannot give both.");
|
||||
style = is_def(tex_style)? echo("In cyl the 'tex_style()' parameters is deprecated and has been replaced by 'style'")tex_style
|
||||
style = is_def(tex_style)? echo("In cyl() the 'tex_style' parameter is deprecated and has been replaced by 'style'")tex_style
|
||||
: default(style,"min_edge");
|
||||
tex_reps = is_def(tex_counts)? echo("In cyl() the 'tex_counts' parameter is deprecated and has been replaced by 'tex_reps'")tex_counts
|
||||
: tex_reps;
|
||||
|
402
skin.scad
402
skin.scad
@@ -651,7 +651,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
||||
// linear_sweep(path, texture=tex, tex_size=[5,5], h=40);
|
||||
// Example: Textured with twist and scale.
|
||||
// linear_sweep(regular_ngon(n=3, d=50),
|
||||
// texture="rough", h=100, tex_depth=2,
|
||||
// texture="rough", h=100, tex_depth=.4,
|
||||
// tex_size=[20,20], style="min_edge",
|
||||
// convexity=10, scale=0.2, twist=120);
|
||||
// Example: As Function
|
||||
@@ -717,7 +717,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
||||
// [24, 25, 35, 33], [33, 35, 34], [24, 33, 6, 31], [34, 35, 11, 7],
|
||||
// [35, 25, 32, 11], [30, 32, 25, 23]]
|
||||
// ];
|
||||
// front_half(y=3){
|
||||
// front_half(y=33){
|
||||
// cyl(d=14.5,h=1,anchor=BOT,rounding=1/3,$fa=1,$fs=.5);
|
||||
// linear_sweep(circle(d=12), h=12, scale=1.3, texture=diag_weave_vnf,
|
||||
// tex_size=[5,5], convexity=12);
|
||||
@@ -1041,7 +1041,7 @@ function linear_sweep(
|
||||
// path = [for(y=[-30:30]) [ 20-3*(1-cos((y+30)/60*360)),y]];
|
||||
// rotate_sweep(path, closed=false, texture=tile, tex_rot=90,
|
||||
// tex_size=[12,8], tex_depth=9, angle=360);
|
||||
// Example(3D,Med,NoAxes: A basket weave texture, here only half way around the circle to avoid clutter.
|
||||
// Example(3D,Med,NoAxes,VPR=[78.1,0,199.3],VPT=[-4.55445,1.37814,-4.39897],VPD=192.044): A basket weave texture, here only half way around the circle to avoid clutter.
|
||||
// diag_weave_vnf = [
|
||||
// [[0.2, 0, 0], [0.8, 0, 0], [1, 0.2, 0.5], [1, 0.8, 0.5], [0.7, 0.5, 0.5],
|
||||
// [0.5, 0.3, 0], [0.2, 0, 0.5], [0.8, 0, 0.5], [1, 0.2, 1], [1, 0.8, 1],
|
||||
@@ -3150,7 +3150,7 @@ function associate_vertices(polygons, split, curpoly=0) =
|
||||
|
||||
|
||||
|
||||
// DefineHeader(Table;Headers=Texture Name|Type|Description): Texture Values
|
||||
|
||||
|
||||
// Section: Texturing
|
||||
// Some operations are able to add texture to the objects they create. A texture can be any regularly repeated variation in the height of the surface.
|
||||
@@ -4016,7 +4016,6 @@ function _validate_texture(texture) =
|
||||
min_xy = point2d(bounds[0]),
|
||||
max_xy = point2d(bounds[1])
|
||||
)
|
||||
//assert(min_xy==[0,0] && max_xy==[1,1],"VNF tiles must span exactly from [0,0] to [1,1] in the X and Y components."))
|
||||
assert(all_nonnegative(concat(min_xy,[1,1]-max_xy)), "VNF tile X and Y components must be between 0 and 1.")
|
||||
let(
|
||||
verts = texture[0],
|
||||
@@ -4037,6 +4036,29 @@ function _validate_texture(texture) =
|
||||
true;
|
||||
|
||||
|
||||
|
||||
function _tex_height(scale, inset, z) = scale<0 ? -(1-z - inset) * scale
|
||||
: (z - inset) * scale;
|
||||
|
||||
function _get_texture(texture, tex_rot) =
|
||||
let(
|
||||
tex_rot=!is_bool(tex_rot)? tex_rot
|
||||
: echo("boolean value for tex_rot is deprecated. Use a numerical angle divisible by 90.") tex_rot?90:0
|
||||
)
|
||||
assert(is_num(tex_rot) && posmod(tex_rot,90)==0, "tex_rot must be a multiple of 90 degrees")
|
||||
let(
|
||||
tex = is_string(texture)? texture(texture,$fn=_tex_fn_default()) : texture,
|
||||
check_tex = _validate_texture(tex),
|
||||
tex_rot = posmod(tex_rot,360)
|
||||
)
|
||||
tex_rot==0 ? tex
|
||||
: is_vnf(tex)? zrot(tex_rot, cp=[1/2,1/2], p=tex)
|
||||
: tex_rot==180? reverse([for (row=tex) reverse(row)])
|
||||
: tex_rot==270? [for (row=transpose(tex)) reverse(row)]
|
||||
: reverse(transpose(tex));
|
||||
|
||||
|
||||
|
||||
function _textured_linear_sweep(
|
||||
region, texture, tex_size=[5,5],
|
||||
h, counts, inset=false, rot=0,
|
||||
@@ -4059,21 +4081,15 @@ function _textured_linear_sweep(
|
||||
frac = pos-ind,
|
||||
texh = scale<0 ? -(1-tilez - inset) * scale
|
||||
: (tilez - inset) * scale,
|
||||
base = lerp(bases[ind], select(bases,ind+1), frac),
|
||||
norm = unit(lerp(norms[ind], select(norms,ind+1), frac))
|
||||
base = lerp(select(bases,ind), select(bases,ind+1), frac),
|
||||
norm = unit(lerp(select(norms,ind), select(norms,ind+1), frac))
|
||||
)
|
||||
base + norm * texh,
|
||||
|
||||
caps = is_bool(caps) ? [caps,caps] : caps,
|
||||
regions = is_path(region,2)? [[region]] : region_parts(region),
|
||||
tex = is_string(texture)? texture(texture,$fn=_tex_fn_default()) : texture,
|
||||
dummy = assert(is_undef(samples) || is_vnf(tex), "You gave the tex_samples argument with a heightfield texture, which is not permitted. Use the n= argument to texture() instead"),
|
||||
dummy2=is_bool(rot)?echo("boolean value for tex_rot is deprecated. Use a numerical angle, one of 0, 90, 180, or 270.")0:0,
|
||||
texture = !rot? tex :
|
||||
is_vnf(tex)? zrot(is_num(rot)?rot:90, cp=[1/2,1/2], p=tex) :
|
||||
rot==180? reverse([for (row=tex) reverse(row)]) :
|
||||
rot==270? [for (row=transpose(tex)) reverse(row)] :
|
||||
reverse(transpose(tex)),
|
||||
texture = _get_texture(texture, rot),
|
||||
dummy = assert(is_undef(samples) || is_vnf(texture), "You gave the tex_samples argument with a heightfield texture, which is not permitted. Use the n= argument to texture() instead"),
|
||||
h = first_defined([h, l, height, length, 1]),
|
||||
inset = is_num(inset)? inset : inset? 1 : 0,
|
||||
twist = default(twist, 0),
|
||||
@@ -4082,39 +4098,36 @@ function _textured_linear_sweep(
|
||||
is_num(scale)? [scale,scale,1] : scale,
|
||||
samples = !is_vnf(texture)? len(texture[0]) :
|
||||
is_num(samples)? samples : 8,
|
||||
check_tex = _validate_texture(texture),
|
||||
sorted_tile =
|
||||
!is_vnf(texture)? texture :
|
||||
vnf_tile =
|
||||
!is_vnf(texture) || samples==1 ? texture
|
||||
:
|
||||
let(
|
||||
s = 1 / max(1, samples),
|
||||
vnf = samples<=1? texture :
|
||||
let(
|
||||
slice_us = list([s:s:1-s/2]),
|
||||
vnft1 = vnf_slice(texture, "X", slice_us),
|
||||
vnft = twist? vnf_slice(vnft1, "Y", slice_us) : vnft1,
|
||||
zvnf = [
|
||||
[
|
||||
for (p=vnft[0]) [
|
||||
slice_us = list([s:s:1-s/2]),
|
||||
vnft1 = vnf_slice(texture, "X", slice_us),
|
||||
vnft = twist? vnf_slice(vnft1, "Y", slice_us) : vnft1,
|
||||
zvnf = [
|
||||
[
|
||||
for (p=vnft[0]) [
|
||||
approx(p.x,0)? 0 : approx(p.x,1)? 1 : p.x,
|
||||
approx(p.y,0)? 0 : approx(p.y,1)? 1 : p.y,
|
||||
p.z
|
||||
]
|
||||
],
|
||||
vnft[1]
|
||||
]
|
||||
) zvnf
|
||||
) _vnf_sort_vertices(vnf, idx=[1,0]),
|
||||
vertzs = !is_vnf(sorted_tile)? undef :
|
||||
group_sort(sorted_tile[0], idx=1),
|
||||
edge_paths = is_vnf(sorted_tile) ? _tile_edge_path_list(sorted_tile,1) : undef,
|
||||
],
|
||||
vnft[1]
|
||||
]
|
||||
) zvnf,
|
||||
edge_paths = is_vnf(texture) ? _tile_edge_path_list(vnf_tile,1) : undef,
|
||||
tpath = is_def(edge_paths)
|
||||
? len(edge_paths[0])==0 ? [] : hstack([column(edge_paths[0][0],0), column(edge_paths[0][0],2)])
|
||||
: let(
|
||||
row = sorted_tile[0],
|
||||
row = texture[0],
|
||||
rlen = len(row)
|
||||
) [for (i = [0:1:rlen]) [i/rlen, row[i%rlen]]],
|
||||
edge_closed_paths = is_def(edge_paths) ? edge_paths[1] : [],
|
||||
tmat = scale(scale) * zrot(twist) * up(h/2),
|
||||
texcnt = is_vnf(texture) ? undef
|
||||
: [len(texture[0]), len(texture)],
|
||||
pre_skew_vnf = vnf_join([
|
||||
for (rgn = regions) let(
|
||||
walls_vnf = vnf_join([
|
||||
@@ -4125,19 +4138,16 @@ function _textured_linear_sweep(
|
||||
is_vector(tex_size,2)
|
||||
? [round(plen/tex_size.x), max(1,round(h/tex_size.y)), ]
|
||||
: [ceil(6*plen/h), 6],
|
||||
obases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
onorms = path_normals(obases, closed=true),
|
||||
bases = list_wrap(obases),
|
||||
norms = list_wrap(onorms),
|
||||
bases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
norms = path_normals(bases, closed=true),
|
||||
vnf = is_vnf(texture)
|
||||
? vnf_join( // VNF tile texture
|
||||
let(
|
||||
row_vnf = vnf_join([
|
||||
for (i = [0:1:(scale==1?0:counts.y-1)], j = [0:1:counts.x-1]) [
|
||||
[
|
||||
for (group = vertzs)
|
||||
each [
|
||||
for (vert = group) let(
|
||||
for (vert=vnf_tile[0])
|
||||
let(
|
||||
xy = transform_pt(j,vert.x,vert.z,samples, inset, tex_scale, bases, norms),
|
||||
pt = point3d(xy,vert.y),
|
||||
v = vert.y / counts.y,
|
||||
@@ -4149,9 +4159,8 @@ function _textured_linear_sweep(
|
||||
zrot(twist*(v+vv)) *
|
||||
zscale(h/counts.y)
|
||||
) apply(mat, pt)
|
||||
]
|
||||
],
|
||||
sorted_tile[1]
|
||||
vnf_tile[1]
|
||||
]
|
||||
])
|
||||
) [
|
||||
@@ -4168,7 +4177,6 @@ function _textured_linear_sweep(
|
||||
]
|
||||
)
|
||||
: let( // Heightfield texture
|
||||
texcnt = [len(texture[0]), len(texture)],
|
||||
tile_rows = [
|
||||
for (ti = [0:1:texcnt.y-1])
|
||||
path3d([
|
||||
@@ -4204,10 +4212,8 @@ function _textured_linear_sweep(
|
||||
is_vector(tex_size,2)
|
||||
? [round(plen/tex_size.x), max(1,round(h/tex_size.y)), ]
|
||||
: [ceil(6*plen/h), 6],
|
||||
obases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
onorms = path_normals(obases, closed=true),
|
||||
bases = list_wrap(obases),
|
||||
norms = list_wrap(onorms),
|
||||
bases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
norms = path_normals(bases, closed=true),
|
||||
nupath = [
|
||||
for (j = [0:1:counts.x-1], vert = tpath)
|
||||
transform_pt(j,vert.x,vert.y,samples,inset,tex_scale,bases,norms)
|
||||
@@ -4224,10 +4230,8 @@ function _textured_linear_sweep(
|
||||
is_vector(tex_size,2)
|
||||
? [round(plen/tex_size.x), max(1,round(h/tex_size.y)), ]
|
||||
: [ceil(6*plen/h), 6],
|
||||
obases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
onorms = path_normals(obases, closed=true),
|
||||
bases = list_wrap(obases),
|
||||
norms = list_wrap(onorms),
|
||||
bases = resample_path(path, n=counts.x * samples, closed=true),
|
||||
norms = path_normals(bases, closed=true),
|
||||
modpaths = [for (j = [0:1:counts.x-1], cpath = edge_closed_paths)
|
||||
[for(vert = cpath)
|
||||
transform_pt(j,vert.x,vert.z,samples,inset,tex_scale,bases, norms)]
|
||||
@@ -4364,15 +4368,8 @@ function _textured_revolution(
|
||||
)
|
||||
assert(closed || is_path(shape,2))
|
||||
let(
|
||||
tex = is_string(texture)? texture(texture,$fn=_tex_fn_default()) : texture,
|
||||
dummy = assert(is_undef(samples) || is_vnf(tex), "You gave the tex_samples argument with a heightfield texture, which is not permitted. Use the n= argument to texture() instead"),
|
||||
dummy2=is_bool(rot)?echo("boolean value for tex_rot is deprecated. Use a numerical angle, one of 0, 90, 180, or 270.")0:0,
|
||||
texture = !rot? tex :
|
||||
is_vnf(tex)? zrot(is_num(rot)?rot:90, cp=[1/2,1/2], p=tex) :
|
||||
rot==180? reverse([for (row=tex) reverse(row)]) :
|
||||
rot==270? [for (row=transpose(tex)) reverse(row)] :
|
||||
reverse(transpose(tex)),
|
||||
check_tex = _validate_texture(texture),
|
||||
texture = _get_texture(texture, rot),
|
||||
dummy = assert(is_undef(samples) || is_vnf(texture), "You gave the tex_samples argument with a heightfield texture, which is not permitted. Use the n= argument to texture() instead"),
|
||||
inset = is_num(inset)? inset : inset? 1 : 0,
|
||||
samples = !is_vnf(texture)? len(texture) :
|
||||
is_num(samples)? samples : 8,
|
||||
@@ -4382,28 +4379,25 @@ function _textured_revolution(
|
||||
maxy = bounds[1].y,
|
||||
h = maxy - miny,
|
||||
circumf = 2 * PI * maxx,
|
||||
tile = !is_vnf(texture)? texture :
|
||||
texcnt = is_vnf(texture) ? undef : [len(texture[0]), len(texture)],
|
||||
tile = !is_vnf(texture) || samples==1 ? texture :
|
||||
let(
|
||||
utex = samples<=1? texture :
|
||||
let(
|
||||
s = 1 / samples,
|
||||
slices = list([s : s : 1-s/2]),
|
||||
vnfx = vnf_slice(texture, "X", slices),
|
||||
vnfy = inhibit_y_slicing? vnfx : vnf_slice(vnfx, "Y", slices),
|
||||
vnft = vnf_triangulate(vnfy),
|
||||
zvnf = [
|
||||
[
|
||||
for (p=vnft[0]) [
|
||||
approx(p.x,0)? 0 : approx(p.x,1)? 1 : p.x,
|
||||
approx(p.y,0)? 0 : approx(p.y,1)? 1 : p.y,
|
||||
p.z
|
||||
]
|
||||
],
|
||||
vnft[1]
|
||||
s = 1 / samples,
|
||||
slices = list([s : s : 1-s/2]),
|
||||
vnfx = vnf_slice(texture, "X", slices),
|
||||
vnfy = inhibit_y_slicing? vnfx : vnf_slice(vnfx, "Y", slices),
|
||||
vnft = vnf_triangulate(vnfy),
|
||||
zvnf = [
|
||||
[
|
||||
for (p=vnft[0]) [
|
||||
approx(p.x,0)? 0 : approx(p.x,1)? 1 : p.x,
|
||||
approx(p.y,0)? 0 : approx(p.y,1)? 1 : p.y,
|
||||
p.z
|
||||
]
|
||||
) zvnf
|
||||
) _vnf_sort_vertices(utex, idx=[0,1]),
|
||||
vertzs = is_vnf(texture)? group_sort(tile[0], idx=0) : undef,
|
||||
],
|
||||
vnft[1]
|
||||
]
|
||||
) zvnf,
|
||||
edge_paths = is_vnf(tile) ? _tile_edge_path_list(tile,1) : undef,
|
||||
bpath = is_def(edge_paths)
|
||||
? len(edge_paths[0])==0 ? [] : hstack([column(edge_paths[0][0],0), column(edge_paths[0][0],2)])
|
||||
@@ -4436,8 +4430,8 @@ function _textured_revolution(
|
||||
part = tileind * samples,
|
||||
ind = floor(part),
|
||||
frac = part - ind,
|
||||
base = lerp(bases[ind], select(bases,ind+1), frac),
|
||||
norm = unit(lerp(norms[ind], select(norms,ind+1), frac)),
|
||||
base = lerp(select(bases,ind), select(bases,ind+1), frac),
|
||||
norm = unit(lerp(select(norms,ind), select(norms,ind+1), frac)),
|
||||
scale = tex_scale * lookup(tileind/counts_y, taper_lup) * base.x/maxx,
|
||||
texh = scale<0 ? -(1-tilez - inset) * scale
|
||||
: (tilez - inset) * scale
|
||||
@@ -4452,26 +4446,21 @@ function _textured_revolution(
|
||||
is_vector(tex_size,2)? max(1,round(plen/tex_size.y)) : 6,
|
||||
obases = resample_path(path, n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
onorms = path_normals(obases, closed=closed),
|
||||
rbases = closed? list_wrap(obases) : obases,
|
||||
rnorms = closed? list_wrap(onorms) : onorms,
|
||||
bases = xrot(90, p=path3d(rbases)),
|
||||
norms = xrot(90, p=path3d(rnorms)),
|
||||
bases = xrot(90, p=path3d(obases)),
|
||||
norms = xrot(90, p=path3d(onorms)),
|
||||
vnf = is_vnf(texture)
|
||||
? vnf_join([ // VNF tile texture
|
||||
for (j = [0:1:counts_y-1])
|
||||
[
|
||||
[
|
||||
for (group = vertzs) each [
|
||||
for (vert = group)
|
||||
for (vert = tile[0])
|
||||
let(xyz = transform_point(j + (1-vert.y),vert.z,counts_y,bases, norms))
|
||||
zrot(vert.x*angle/counts_x, p=xyz)
|
||||
]
|
||||
],
|
||||
tile[1]
|
||||
]
|
||||
])
|
||||
: let( // Heightfield texture
|
||||
texcnt = [len(texture[0]), len(texture)],
|
||||
tiles = transpose([
|
||||
for (j = [0,1], tj = [0:1:texcnt.x-1])
|
||||
if (j == 0 || tj == 0)
|
||||
@@ -4502,23 +4491,18 @@ function _textured_revolution(
|
||||
plen = path_length(path, closed=closed),
|
||||
counts_y = is_vector(counts,2)? counts.y :
|
||||
is_vector(tex_size,2)? max(1,round(plen/tex_size.y)) : 6,
|
||||
obases = resample_path(path, n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
onorms = path_normals(obases, closed=closed),
|
||||
bases = closed? list_wrap(obases) : obases,
|
||||
norms = closed? list_wrap(onorms) : onorms,
|
||||
bases = resample_path(path, n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
norms = path_normals(bases, closed=closed),
|
||||
ppath = is_vnf(texture)
|
||||
? [ // VNF tile texture
|
||||
for (j = [0:1:counts_y-1])
|
||||
//for (group = vertzs, vert = reverse(group))
|
||||
for(vert=side_open_path)
|
||||
for (j = [0:1:counts_y-1], vert=side_open_path)
|
||||
transform_point(j + (1 - vert.y),vert.z,counts_y,bases, norms)
|
||||
]
|
||||
: let( // Heightfield texture
|
||||
texcnt = [len(texture[0]), len(texture)]
|
||||
) [
|
||||
:
|
||||
[ // Heightfield texture
|
||||
for (i = [0:1:counts_y-(closed?1:0)], ti = [0:1:texcnt.y-1])
|
||||
if (i != counts_y || ti == 0)
|
||||
transform_point(i + (ti/texcnt.y),texture[ti][0],counts_y,bases, norms)
|
||||
if (i != counts_y || ti == 0)
|
||||
transform_point(i + (ti/texcnt.y),texture[ti][0],counts_y,bases, norms)
|
||||
],
|
||||
path = closed? ppath : [
|
||||
[0, ppath[0].y],
|
||||
@@ -4534,10 +4518,8 @@ function _textured_revolution(
|
||||
plen = path_length(path, closed=closed),
|
||||
counts_y = is_vector(counts,2)? counts.y :
|
||||
is_vector(tex_size,2)? max(1,round(plen/tex_size.y)) : 6,
|
||||
obases = resample_path(path, n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
onorms = path_normals(obases, closed=closed),
|
||||
bases = closed? list_wrap(obases) : obases,
|
||||
norms = closed? list_wrap(onorms) : onorms,
|
||||
bases = resample_path(path, n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
norms = path_normals(bases, closed=closed),
|
||||
modpaths = [for (j = [0:1:counts_y-1], cpath=side_closed_paths)
|
||||
[for(vert=cpath)
|
||||
transform_point(j + (1 - vert.y),vert.z,counts_y,bases, norms)]
|
||||
@@ -4557,10 +4539,8 @@ function _textured_revolution(
|
||||
is_vector(tex_size,2)? max(1,round(plen/tex_size.y)) : 6,
|
||||
obases = resample_path(rgn[0], n=counts_y * samples + (closed?0:1), closed=closed),
|
||||
onorms = path_normals(obases, closed=closed),
|
||||
rbases = closed? list_wrap(obases) : obases,
|
||||
rnorms = closed? list_wrap(onorms) : onorms,
|
||||
bases = xrot(90, p=path3d(rbases)),
|
||||
norms = xrot(90, p=path3d(rnorms)),
|
||||
bases = xrot(90, p=path3d(obases)),
|
||||
norms = xrot(90, p=path3d(onorms)),
|
||||
caps_vnf = vnf_join([
|
||||
for (epath=edge_closed_paths, j = [-1,0])
|
||||
let(
|
||||
@@ -4649,5 +4629,203 @@ module _textured_revolution(
|
||||
}
|
||||
|
||||
|
||||
function _texture_point_array(points, texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0, triangulate=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) =
|
||||
assert(tex_reps==undef || is_vector(tex_reps,2))
|
||||
assert(tex_size==undef || is_num(tex_size) || is_vector(tex_size,2), "tex_size must be a scalar or 2-vector")
|
||||
assert(num_defined([tex_size, tex_reps])<2, "Cannot give both tex_size and tex_reps")
|
||||
assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge","min_area","flip1","flip2"]))
|
||||
assert(is_matrix(points[0], n=3),"Point array has the wrong shape or points are not 3d")
|
||||
assert(is_consistent(points), "Non-rectangular or invalid point array")
|
||||
let(
|
||||
cap1 = first_defined([cap1,caps,false]),
|
||||
cap2 = first_defined([cap2,caps,false]),
|
||||
sidecap1 = first_defined([sidecap1,sidecaps,false]),
|
||||
sidecap2 = first_defined([sidecap2,sidecaps,false]),
|
||||
tex_inset = is_num(tex_inset)? tex_inset : tex_inset? 1 : 0,
|
||||
texture = _get_texture(texture, tex_rot),
|
||||
dummy = assert(is_undef(tex_samples) || is_vnf(texture),
|
||||
"You gave the tex_samples argument with a heightfield texture, which is not permitted. Use the n= argument to texture() instead"),
|
||||
ptsize=[len(points[0]), len(points)],
|
||||
tex_reps = is_def(tex_reps) ? tex_reps
|
||||
: let(
|
||||
tex_size = is_undef(tex_sizes) ? [5,5] : force_list(tex_size,2),
|
||||
xsize = norm(points[0][0]-points[0][1])*(ptsize.x+(col_wrap?1:0)),
|
||||
ysize = norm(points[0][0]-points[1][0])*(ptsize.y+(row_wrap?1:0))
|
||||
)
|
||||
[round(xsize/tex_size.x), round(ysize/tex_size.y)],
|
||||
normals = surfnormals(points, col_wrap=col_wrap, row_wrap=row_wrap),
|
||||
getscale = function(x,y) (x+y)/2
|
||||
)
|
||||
!is_vnf(texture) ? // heightmap case
|
||||
let(
|
||||
extra = is_def(tex_extra) ? force_list(tex_extra,2)
|
||||
: [col_wrap?0:1, row_wrap?0:1],
|
||||
skip = is_def(tex_skip) ? force_list(tex_skip,2) : [0,0],
|
||||
texsize = [len(texture[0]), len(texture)],
|
||||
fullsize = [texsize.x*tex_reps.x+extra.x-skip.x, texsize.y*tex_reps.y+extra.y-skip.y],
|
||||
res_points = resample(points,fullsize, col_wrap=col_wrap, row_wrap=row_wrap),
|
||||
res_normals=resample(normals,fullsize, col_wrap=col_wrap, row_wrap=row_wrap),
|
||||
local_scale = [for(y=[0:1:fullsize.y-1])
|
||||
[for(x=[0:1:fullsize.x-1])
|
||||
let(
|
||||
xlen = [
|
||||
if(x>0 || col_wrap) norm(res_points[y][x] - select(res_points[y], x-1)),
|
||||
if(x<fullsize.x-1 || col_wrap) norm(res_points[y][x] - select(res_points[y], x+1))
|
||||
],
|
||||
ylen = [
|
||||
if(y>0 || row_wrap) norm(res_points[y][x] - select(res_points,y-1)[x]),
|
||||
if(y<fullsize.y-1 || row_wrap) norm(res_points[y][x] - select(res_points,y+1)[x])
|
||||
]
|
||||
)
|
||||
getscale(mean(xlen),mean(ylen))
|
||||
]
|
||||
],
|
||||
tex_surf =
|
||||
[for(y=[0:1:fullsize.y-1])
|
||||
[for(x=[0:1:fullsize.x-1])
|
||||
let(yind = (y+skip.y)%texsize.y,
|
||||
xind = (x+skip.x)%texsize.x
|
||||
)
|
||||
res_points[y][x] + _tex_height(tex_depth,tex_inset,texture[yind][xind]) * res_normals[y][x]*(reverse?-1:1)*local_scale[y][x]/local_scale[0][0]
|
||||
]
|
||||
]
|
||||
)
|
||||
vnf_vertex_array(tex_surf, row_wrap=row_wrap, col_wrap=col_wrap, reverse=reverse,style=style, caps=caps, triangulate=triangulate)
|
||||
: // VNF case
|
||||
let(
|
||||
local_scale = [for(y=[-1:1:ptsize.y-1])
|
||||
[for(x=[-1:1:ptsize.x-1])
|
||||
((!col_wrap && (x<0 || x==ptsize.x-1))
|
||||
|| (!row_wrap && (y<0 || y==ptsize.y-1))) ? undef
|
||||
: let(
|
||||
dx = [norm(select(select(points,y),x) - select(select(points,y),x+1)),
|
||||
norm(select(select(points,y+1),x) - select(select(points,y+1),x+1))],
|
||||
dy = [norm(select(select(points,y),x) - select(select(points,y+1),x)),
|
||||
norm(select(select(points,y),x+1) - select(select(points,y+1),x+1))]
|
||||
)
|
||||
getscale(mean(dx),mean(dy))]],
|
||||
samples = default(tex_samples,8),
|
||||
vnf = samples==1? texture :
|
||||
let(
|
||||
s = 1 / samples,
|
||||
slice_us = list([s:s:1-s/2]),
|
||||
vnft1 = vnf_slice(texture, "X", slice_us),
|
||||
vnft = vnf_slice(vnft1, "Y", slice_us),
|
||||
zvnf = [
|
||||
[
|
||||
for (p=vnft[0]) [
|
||||
approx(p.x,0)? 0 : approx(p.x,1)? 1 : p.x,
|
||||
approx(p.y,0)? 0 : approx(p.y,1)? 1 : p.y,
|
||||
p.z
|
||||
]
|
||||
],
|
||||
vnft[1]
|
||||
]
|
||||
)
|
||||
zvnf,
|
||||
yedge_paths = !row_wrap ? _tile_edge_path_list(vnf,1) : undef,
|
||||
xedge_paths = !col_wrap ? _tile_edge_path_list(vnf,0) : undef,
|
||||
trans_pt = function(x,y,pt)
|
||||
let(
|
||||
tileindx = x+pt.x,
|
||||
tileindy = y+(1-pt.y),
|
||||
refx = tileindx/tex_reps.x*(ptsize.x-(col_wrap?0:1)),
|
||||
refy = tileindy/tex_reps.y*(ptsize.y-(row_wrap?0:1)),
|
||||
xind = floor(refx),
|
||||
yind = floor(refy),
|
||||
xfrac = refx-xind,
|
||||
yfrac = refy-yind,
|
||||
corners = [points[yind%ptsize.y][xind%ptsize.x], points[(yind+1)%ptsize.y][xind%ptsize.x],
|
||||
points[yind%ptsize.y][(xind+1)%ptsize.x], points[(yind+1)%ptsize.y][(xind+1)%ptsize.x]],
|
||||
base = bilerp(corners,xfrac, yfrac),
|
||||
scale_list = xfrac==0 && yfrac==0 ? [local_scale[yind][xind], local_scale[yind][xind+1], local_scale[yind+1][xind], local_scale[yind+1][xind+1]]
|
||||
: xfrac==0 ? [local_scale[yind+1][xind], local_scale[yind+1][xind+1]]
|
||||
: yfrac==0 ? [local_scale[yind][xind+1], local_scale[yind+1][xind+1]]
|
||||
: [ local_scale[yind+1][xind+1]],
|
||||
scale = mean([for(s=scale_list) if (is_def(s)) s])/local_scale[1][1],
|
||||
normal = bilerp([normals[yind%ptsize.y][xind%ptsize.x], normals[(yind+1)%ptsize.y][xind%ptsize.x],
|
||||
normals[yind%ptsize.y][(xind+1)%ptsize.x], normals[(yind+1)%ptsize.y][(xind+1)%ptsize.x]],
|
||||
xfrac, yfrac)
|
||||
)
|
||||
base + _tex_height(tex_depth,tex_inset,pt.z) * normal*(reverse?-1:1) * scale,
|
||||
fullvnf = vnf_join([
|
||||
for(y=[0:1:tex_reps.y-1], x=[0:1:tex_reps.x-1])
|
||||
[
|
||||
[for(pt=vnf[0]) trans_pt(x,y,pt)],
|
||||
vnf[1]
|
||||
],
|
||||
for(y=[if (cap1) 0, if (cap2) tex_reps.y-1])
|
||||
let(
|
||||
cap_paths = [
|
||||
if (col_wrap && len(yedge_paths[0])>0)
|
||||
[for(x=[0:1:tex_reps.x-1], pt=yedge_paths[0][0])
|
||||
trans_pt(x,y,[pt.x,y?0:1,pt.z])],
|
||||
if (!row_wrap)
|
||||
for(closed_path=yedge_paths[1], x=[0:1:tex_reps.x-1])
|
||||
[for(pt = closed_path) trans_pt(x,y,[pt.x,y?0:1,pt.z])]
|
||||
]
|
||||
)
|
||||
for(path=cap_paths) [path, [count(path,reverse=y==0)]],
|
||||
if (!col_wrap)
|
||||
for(x=[if (sidecap1) 0, if (sidecap2) tex_reps.x-1])
|
||||
let(
|
||||
cap_paths = [for(closed_path=xedge_paths[1], y=[0:1:tex_reps.y-1])
|
||||
[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)]]
|
||||
])
|
||||
)
|
||||
reverse ? vnf_reverse_faces(fullvnf) : fullvnf;
|
||||
|
||||
///// These need to be either hidden or documented and placed somewhere.
|
||||
|
||||
|
||||
function bilerp(pts,x,y) =
|
||||
[1,x,y,x*y]*[[1, 0, 0, 0],[-1, 0, 1, 0],[-1,1,0,0],[1,-1,-1,1]]*pts;
|
||||
|
||||
|
||||
function resample(data, size, col_wrap=false, row_wrap=false) =
|
||||
let(
|
||||
xL=len(data[0]),
|
||||
yL=len(data),
|
||||
lastx=xL-(col_wrap?0:1),
|
||||
lasty=yL-(row_wrap?0:1),
|
||||
lastoutx = size.x - (col_wrap?0:1),
|
||||
lastouty = size.y - (row_wrap?0:1),
|
||||
xscale = lastx/lastoutx,
|
||||
yscale = lasty/lastouty
|
||||
)
|
||||
[
|
||||
for(y=[0:1:lastouty])
|
||||
[
|
||||
for(x=[0:1:lastoutx])
|
||||
let(
|
||||
sx = xscale*x,
|
||||
sy = yscale*y,
|
||||
xind=floor(sx),
|
||||
yind=floor(sy)
|
||||
)
|
||||
bilerp([data[yind%yL][xind%xL], data[(yind+1)%yL][xind%xL],
|
||||
data[yind%yL][(xind+1)%xL], data[(yind+1)%yL][(xind+1)%xL]],
|
||||
sx-xind, sy-yind)
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
function surfnormals(data, col_wrap=false, row_wrap=false) =
|
||||
let(
|
||||
rowderivs = [for(y=[0:1:len(data)-1]) path_tangents(data[y],closed=col_wrap)],
|
||||
colderivs = [for(x=[0:1:len(data[0])-1]) path_tangents(column(data,x), closed=row_wrap)]
|
||||
)
|
||||
[for(y=[0:1:len(data)-1])
|
||||
[for(x=[0:1:len(data[0])-1])
|
||||
cross(colderivs[x][y],rowderivs[y][x])]];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
95
vnf.scad
95
vnf.scad
@@ -27,13 +27,14 @@
|
||||
EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||
|
||||
|
||||
// Function: vnf_vertex_array()
|
||||
// Function&Module: vnf_vertex_array()
|
||||
// Synopsis: Returns a VNF structure from a rectangular vertex list.
|
||||
// SynTags: VNF
|
||||
// SynTags: VNF, Geom
|
||||
// Topics: VNF Generators, Lists
|
||||
// See Also: vnf_tri_array(), vnf_join(), vnf_from_polygons(), vnf_from_region()
|
||||
// Usage:
|
||||
// vnf = vnf_vertex_array(points, [caps=], [cap1=], [cap2=], [style=], [reverse=], [col_wrap=], [row_wrap=], [triangulate=]);
|
||||
// vnf_vertex_array(points, [caps=], [cap1=], [cap2=], [style=], [reverse=], [col_wrap=], [row_wrap=], [triangulate=],...) [ATTACHMENTS];
|
||||
// Description:
|
||||
// Creates a VNF structure from a rectangular vertex list, creating edges that connect the adjacent vertices in the vertex list
|
||||
// and creating the faces defined by those edges. You can optionally create the edges and faces to wrap the last column
|
||||
@@ -47,6 +48,23 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||
// adds a vertex in the center of each quadrilateral and creates four triangles, and the "convex" and "concave" styles
|
||||
// choose the locally convex/concave subdivision. The "min_area" option creates the triangulation with the minimal area. Degenerate faces
|
||||
// are not included in the output, but if this results in unused vertices they still appear in the output.
|
||||
// .
|
||||
// You can apply a texture to the vertex array VNF using the usual texture parameters.
|
||||
// See [Texturing](skin.scad#section-texturing) for more details on how textures work.
|
||||
// The top left corner of the texture tile will be aligned with `points[0][0]`, and the the X and Y directions correspond to `points[y][x]`.
|
||||
// In practice, it is probably easiest to observe the result and apply a suitable texture tile rotation by setting `tex_rot` if the result
|
||||
// is not what you wanted. The reference scale of your point data is also taken from the square at the [0][0] corner. This determines
|
||||
// the meaning of `tex_size` and it also affects the vertical texture scale. The size of the texture tiles will be proportional to the point
|
||||
// spacing of the location where they are placed, so if the points are closer together, you will get small texture elements. The `tex_depth` you
|
||||
// specify will be correct at the `points[0][0]` but will be different at places in the point array where the scale is different. Note that this
|
||||
// differs from {{rotate_sweep()}} which uses a uniform resampling of the curve you specify.
|
||||
// .
|
||||
// The point data for `vnf_vertex_array()` is resampled using bilinear interpolation to match the required point density of the tile count, but the
|
||||
// sampling is based on the grid, not on the distance between points. If you want to
|
||||
// avoid resampling, match the point data to the required point number for your tile count. For height field textures this means
|
||||
// the number of data points must equal the tile count times the number of entries in the tile minus `tex_skip` plus `tex_extra`.
|
||||
// Note that `tex_extra` defaults to 1 along dimensions that are not wrapped. For a VNF tile you need to have the the point
|
||||
// count equal to the tile count times tex_samples, plus one if wrapping is disabled.
|
||||
// Arguments:
|
||||
// points = A list of vertices to divide into columns and rows.
|
||||
// ---
|
||||
@@ -58,6 +76,29 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||
// reverse = If true, reverse all face normals.
|
||||
// style = The style of subdividing the quads into faces. Valid options are "default", "alt", "flip1", "flip2", "min_edge", "min_area", "quincunx", "convex" and "concave".
|
||||
// triangulate = If true, triangulates endcaps to resolve possible CGAL issues. This can be an expensive operation if the endcaps are complex. Default: false
|
||||
// convexity = (module) Max number of times a line could intersect a wall of the shape.
|
||||
// texture = A texture name string, or a rectangular array of scalar height values (0.0 to 1.0), or a VNF tile that defines the texture to apply to vertical surfaces. See {{texture()}} for what named textures are supported.
|
||||
// tex_size = An optional 2D target size for the textures at `points[0][0]`. Actual texture sizes will be scaled somewhat to evenly fit the available surface. Default: `[5,5]`
|
||||
// tex_reps = If given instead of tex_size, a 2-vector giving the number of texture tile repetitions in the horizontal and vertical directions.
|
||||
// tex_inset = If numeric, lowers the texture into the surface by the specified proportion, e.g. 0.5 would lower it half way into the surface. If `true`, insets by exactly its full depth. Default: `false`
|
||||
// tex_rot = Rotate texture by specified angle, which must be a multiple of 90 degrees. Default: 0
|
||||
// tex_depth = Specify texture depth; if negative, invert the texture. Default: 1.
|
||||
// tex_samples = Minimum number of "bend points" to have in VNF texture tiles. Default: 8
|
||||
// tex_extra = number of extra lines of a hightfield texture to add at the end. Can be a scalar or 2-vector to give x and y values. Default: 1
|
||||
// tex_skip = number of lines of a heightfield texture to skip when starting. Can be a scalar or two vector to give x and y values. Default: 0
|
||||
// sidecaps = if `col_wrap==false` this controls whether to cap any floating ends of a VNF tile on the texture. Does not affect the main texture surface. Ignored it doesn't apply. Default: false
|
||||
// sidecap1 = set sidecap only for the `points[][0]` edge of the output
|
||||
// sidecap2 = set sidecap only for the `points[][max]` edge of the output
|
||||
// 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"`
|
||||
// spin = (module) Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||
// orient = (module) Vector to rotate top toward, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||
// atype = (module) Select "hull" or "intersect" anchor type. Default: "hull"
|
||||
// Anchor Types:
|
||||
// "hull" = Anchors to the virtual convex hull of the shape.
|
||||
// "intersect" = Anchors to the surface of the shape.
|
||||
// Named Anchors:
|
||||
// "origin" = Anchor at the origin, oriented UP.
|
||||
// Example(3D):
|
||||
// vnf = vnf_vertex_array(
|
||||
// points=[
|
||||
@@ -160,6 +201,28 @@ EMPTY_VNF = [[],[]]; // The standard empty VNF with no vertices or faces.
|
||||
// apply(m, [ [rgroove[0].x,0,-z], each rgroove, [last(rgroove).x,0,-z] ])
|
||||
// ], caps=true, col_wrap=true, reverse=true);
|
||||
// vnf_polyhedron(vnf, convexity=8);
|
||||
|
||||
module vnf_vertex_array(
|
||||
points,
|
||||
caps, cap1, cap2,
|
||||
col_wrap=false,
|
||||
row_wrap=false,
|
||||
reverse=false,
|
||||
style="default",
|
||||
triangulate = false,
|
||||
texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0,
|
||||
tex_depth=1, tex_extra, tex_skip, sidecaps,sidecap1,sidecap2,
|
||||
convexity=2, cp="centroid", anchor="origin", spin=0, orient=UP, atype="hull")
|
||||
{
|
||||
vnf = vnf_vertex_array(points=points, caps=caps, cap1=cap2, cap2=cap2,
|
||||
col_wrap=col_wrap, row_wrap=row_wrap, reverse=reverse, style=style,triangulate=triangulate,
|
||||
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, sidecaps=sidecaps,sidecap1=sidecap1,sidecap2=sidecap2
|
||||
);
|
||||
vnf_polyhedron(vnf, convexity=2, cp="centroid", anchor="origin", spin=0, orient=UP, atype="hull") children();
|
||||
}
|
||||
|
||||
|
||||
function vnf_vertex_array(
|
||||
points,
|
||||
caps, cap1, cap2,
|
||||
@@ -167,14 +230,22 @@ function vnf_vertex_array(
|
||||
row_wrap=false,
|
||||
reverse=false,
|
||||
style="default",
|
||||
triangulate = false
|
||||
triangulate = false,
|
||||
texture, tex_reps, tex_size, tex_samples, tex_inset=false, tex_rot=0,
|
||||
tex_depth=1, tex_extra, tex_skip, sidecaps,sidecap1,sidecap2
|
||||
) =
|
||||
assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested")
|
||||
assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap")
|
||||
assert(in_list(style,["default","alt","quincunx", "convex","concave", "min_edge","min_area","flip1","flip2"]))
|
||||
assert(is_matrix(points[0], n=3),"Point array has the wrong shape or points are not 3d")
|
||||
assert(is_consistent(points), "Non-rectangular or invalid point array")
|
||||
assert(is_bool(triangulate))
|
||||
is_def(texture) ?
|
||||
_texture_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,
|
||||
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,triangulate=triangulate)
|
||||
:
|
||||
assert(!(any([caps,cap1,cap2]) && !col_wrap), "col_wrap must be true if caps are requested (without texture)")
|
||||
assert(!(any([caps,cap1,cap2]) && row_wrap), "Cannot combine caps with row_wrap (without texture)")
|
||||
let(
|
||||
pts = flatten(points),
|
||||
pcnt = len(pts),
|
||||
@@ -1013,20 +1084,6 @@ function _detri_combine_faces(edgelist,faces,normals,facelist,curface) =
|
||||
|
||||
|
||||
|
||||
function _vnf_sort_vertices(vnf, idx=[2,1,0]) =
|
||||
let(
|
||||
verts = vnf[0],
|
||||
faces = vnf[1],
|
||||
vidx = sortidx(verts, idx=idx),
|
||||
rvidx = sortidx(vidx),
|
||||
sorted_vnf = [
|
||||
[ for (i = vidx) verts[i] ],
|
||||
[ for (face = faces) [ for (i = face) rvidx[i] ] ],
|
||||
]
|
||||
) sorted_vnf;
|
||||
|
||||
|
||||
|
||||
|
||||
// Function: vnf_slice()
|
||||
// Synopsis: Slice the faces of a VNF along an axis.
|
||||
|
Reference in New Issue
Block a user