mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-01-16 13:50:23 +01:00
Quadrupled bezier patch speed.
This commit is contained in:
parent
b8239d2dde
commit
d0595fb132
99
beziers.scad
99
beziers.scad
@ -241,9 +241,9 @@ function bezier_triangle_point(patch, u, v) =
|
||||
len(patch) == 1 ? patch[0][0] :
|
||||
let(
|
||||
n = len(patch)-1,
|
||||
Pu = [for(i=[0:n-1]) select(patch[i],1,-1)],
|
||||
Pv = [for(i=[0:n-1]) select(patch[i],0,-2)],
|
||||
Pw = select(patch,1,-1)
|
||||
Pu = [for(i=[0:n-1]) [for (j=[1:len(patch[i])-1]) patch[i][j]]],
|
||||
Pv = [for(i=[0:n-1]) [for (j=[0:len(patch[i])-2]) patch[i][j]]],
|
||||
Pw = [for(i=[1:len(patch)-1]) patch[i]]
|
||||
)
|
||||
bezier_triangle_point(u*Pu + v*Pv + (1-u-v)*Pw, u, v);
|
||||
|
||||
@ -254,9 +254,9 @@ function _vertex_list_merge(v1, v2) = concat(v1, [for (v=v2) if (!in_list(v,v1))
|
||||
function _vertex_list_face(v, face) = [for (pt = face) search([pt], v, num_returns_per_match=1)[0]];
|
||||
|
||||
|
||||
// Function: bezier_patch_vertices_and_faces()
|
||||
// Function: bezier_patch()
|
||||
// Usage:
|
||||
// bezier_patch_vertices_and_faces(patch, [splinesteps], [vertices], [faces]);
|
||||
// bezier_patch(patch, [splinesteps], [vertices], [faces]);
|
||||
// Description:
|
||||
// Calculate vertices and faces for forming a partial polyhedron
|
||||
// from the given bezier rectangular patch. Returns a list containing
|
||||
@ -270,30 +270,33 @@ function _vertex_list_face(v, face) = [for (pt = face) search([pt], v, num_retur
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// vertices = Vertex list to add new points to. Default: []
|
||||
// faces = Face list to add new faces to. Default: []
|
||||
function bezier_patch_vertices_and_faces(patch, splinesteps=16, vertices=[], faces=[]) =
|
||||
function bezier_patch(patch, splinesteps=16, vertices=[], faces=[]) =
|
||||
let(
|
||||
base = len(vertices),
|
||||
pts = [for (v=[0:splinesteps], u=[0:splinesteps]) bezier_patch_point(patch, u/splinesteps, v/splinesteps)],
|
||||
new_vertices = _vertex_list_merge(vertices, pts),
|
||||
new_vertices = concat(vertices, pts),
|
||||
new_faces = [
|
||||
for (
|
||||
v=[0:splinesteps-1],
|
||||
u=[0:splinesteps-1],
|
||||
i=[0,1]
|
||||
) let (
|
||||
v1 = u+v*(splinesteps+1),
|
||||
v1 = u+v*(splinesteps+1) + base,
|
||||
v2 = v1 + 1,
|
||||
v3 = v1 + splinesteps + 1,
|
||||
v4 = v3 + 1,
|
||||
face = i? [v1,v3,v2] : [v2,v3,v4],
|
||||
facepts = [for (idx = face) pts[idx]]
|
||||
) _vertex_list_face(new_vertices, facepts)
|
||||
face = i? [v1,v3,v2] : [v2,v3,v4]
|
||||
) face
|
||||
]
|
||||
) [new_vertices, concat(faces, new_faces)];
|
||||
|
||||
|
||||
// Function: bezier_triangle_vertices_and_faces()
|
||||
function _tri_count(n) = (n*(1+n))/2;
|
||||
|
||||
|
||||
// Function: bezier_triangle()
|
||||
// Usage:
|
||||
// bezier_triangle_vertices_and_faces(patch, [splinesteps], [vertices], [faces]);
|
||||
// bezier_triangle(patch, [splinesteps], [vertices], [faces]);
|
||||
// Description:
|
||||
// Calculate vertices and faces for forming a partial polyhedron
|
||||
// from the given bezier triangular patch. Returns a list containing
|
||||
@ -307,24 +310,40 @@ function bezier_patch_vertices_and_faces(patch, splinesteps=16, vertices=[], fac
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// vertices = Vertex list to add new points to. Default: []
|
||||
// faces = Face list to add new faces to. Default: []
|
||||
function bezier_triangle_vertices_and_faces(patch, splinesteps=16, vertices=[], faces=[]) =
|
||||
// Example(3D):
|
||||
// tri = [
|
||||
// [[-50,-33,0], [-25,16,-50], [0,66,0]],
|
||||
// [[0,-33,-50], [25,16,-50]],
|
||||
// [[50,-33,0]]
|
||||
// ];
|
||||
// vnf = bezier_triangle(tri, splinesteps=16);
|
||||
// polyhedron(points=vnf[0], faces=vnf[1]);
|
||||
function bezier_triangle(patch, splinesteps=16, vertices=[], faces=[]) =
|
||||
let(
|
||||
pts = [for (u=[0:splinesteps], v=[0:splinesteps-u]) bezier_triangle_point(patch, u/splinesteps, v/splinesteps)],
|
||||
new_vertices = _vertex_list_merge(vertices, pts),
|
||||
base = len(vertices),
|
||||
pts = [
|
||||
for (
|
||||
u=[0:splinesteps],
|
||||
v=[0:splinesteps-u]
|
||||
) bezier_triangle_point(patch, u/splinesteps, v/splinesteps)
|
||||
],
|
||||
new_vertices = concat(vertices, pts),
|
||||
patchlen = len(patch),
|
||||
tricnt = _tri_count(splinesteps+1),
|
||||
new_faces = [
|
||||
for (
|
||||
u=[0:splinesteps-1],
|
||||
v=[0:splinesteps-u-1]
|
||||
) let (
|
||||
v1 = bezier_triangle_point(patch, u/splinesteps, v/splinesteps),
|
||||
v2 = bezier_triangle_point(patch, (u+1)/splinesteps, v/splinesteps),
|
||||
v3 = bezier_triangle_point(patch, u/splinesteps, (v+1)/splinesteps),
|
||||
v4 = bezier_triangle_point(patch, (u+1)/splinesteps, (v+1)/splinesteps),
|
||||
v1 = v + (tricnt - _tri_count(splinesteps+1-u)) + base,
|
||||
v2 = v1 + 1,
|
||||
v3 = v + (tricnt - _tri_count(splinesteps-u)) + base,
|
||||
v4 = v3 + 1,
|
||||
allfaces = concat(
|
||||
[[v1,v2,v3]],
|
||||
((u<splinesteps-1 && v<splinesteps-u-1)? [[v2,v4,v3]] : [])
|
||||
)
|
||||
) for (facepts=allfaces) _vertex_list_face(new_vertices, facepts)
|
||||
) for (face=allfaces) face
|
||||
]
|
||||
) [new_vertices, concat(faces, new_faces)];
|
||||
|
||||
@ -436,7 +455,7 @@ function patches_rotate(patches, a=undef, v=undef, cp=[0,0,0]) = [for (patch=pat
|
||||
// polyhedron.
|
||||
// Arguments:
|
||||
// patches = A list of rectangular bezier patches.
|
||||
// tripatches = A list of triangular bezier patches.
|
||||
// tris = A list of triangular bezier patches.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
// vertices = Vertex list to add new points to. Default: []
|
||||
// faces = Face list to add new faces to. Default: []
|
||||
@ -455,14 +474,14 @@ function patches_rotate(patches, a=undef, v=undef, cp=[0,0,0]) = [for (patch=pat
|
||||
// ];
|
||||
// vnf = bezier_surface_vertices_and_faces(patches=[patch1, patch2], splinesteps=16);
|
||||
// polyhedron(points=vnf[0], faces=vnf[1]);
|
||||
function bezier_surface_vertices_and_faces(patches=[], tripatches=[], splinesteps=16, i=0, vertices=[], faces=[]) =
|
||||
function bezier_surface_vertices_and_faces(patches=[], tris=[], splinesteps=16, i=0, vertices=[], faces=[]) =
|
||||
let(
|
||||
vnf = (i >= len(patches))? [vertices, faces] :
|
||||
bezier_patch_vertices_and_faces(patches[i], splinesteps=splinesteps, vertices=vertices, faces=faces),
|
||||
vnf2 = (i >= len(tripatches))? vnf :
|
||||
bezier_triangle_vertices_and_faces(tripatches[i], splinesteps=splinesteps, vertices=vnf[0], faces=vnf[1])
|
||||
) (i >= len(patches) && i >= len(tripatches))? vnf2 :
|
||||
bezier_surface_vertices_and_faces(patches=patches, tripatches=tripatches, splinesteps=splinesteps, i=i+1, vertices=vnf2[0], faces=vnf2[1]);
|
||||
bezier_patch(patches[i], splinesteps=splinesteps, vertices=vertices, faces=faces),
|
||||
vnf2 = (i >= len(tris))? vnf :
|
||||
bezier_triangle(tris[i], splinesteps=splinesteps, vertices=vnf[0], faces=vnf[1])
|
||||
) (i >= len(patches) && i >= len(tris))? vnf2 :
|
||||
bezier_surface_vertices_and_faces(patches=patches, tris=tris, splinesteps=splinesteps, i=i+1, vertices=vnf2[0], faces=vnf2[1]);
|
||||
|
||||
|
||||
|
||||
@ -926,7 +945,7 @@ module trace_bezier(bez, N=3, size=1) {
|
||||
// Takes a list of two or more bezier patches and attempts to make a complete polyhedron from them.
|
||||
// Arguments:
|
||||
// patches = A list of rectangular bezier patches.
|
||||
// tripatches = A list of triangular bezier patches.
|
||||
// tris = A list of triangular bezier patches.
|
||||
// vertices = Vertex list for additional non-bezier faces. Default: []
|
||||
// faces = Additional non-bezier faces. Default: []
|
||||
// splinesteps = Number of steps to divide each bezier segment into. Default: 16
|
||||
@ -944,9 +963,9 @@ module trace_bezier(bez, N=3, size=1) {
|
||||
// [[18,82,0], [33,100, 0], [ 67,100, 0], [ 82, 82,0]],
|
||||
// ];
|
||||
// bezier_polyhedron([patch1, patch2], splinesteps=8);
|
||||
module bezier_polyhedron(patches=[], tripatches=[], splinesteps=16, vertices=[], faces=[])
|
||||
module bezier_polyhedron(patches=[], tris=[], splinesteps=16, vertices=[], faces=[])
|
||||
{
|
||||
sfc = bezier_surface_vertices_and_faces(patches=patches, tripatches=tripatches, splinesteps=splinesteps, vertices=vertices, faces=faces);
|
||||
sfc = bezier_surface_vertices_and_faces(patches=patches, tris=tris, splinesteps=splinesteps, vertices=vertices, faces=faces);
|
||||
polyhedron(points=sfc[0], faces=sfc[1]);
|
||||
}
|
||||
|
||||
@ -955,13 +974,13 @@ module bezier_polyhedron(patches=[], tripatches=[], splinesteps=16, vertices=[],
|
||||
// Module: trace_bezier_patches()
|
||||
// Usage:
|
||||
// trace_bezier_patches(patches, [size], [showcps], [splinesteps]);
|
||||
// trace_bezier_patches(tripatches, [size], [showcps], [splinesteps]);
|
||||
// trace_bezier_patches(patches, tripatches, [size], [showcps], [splinesteps]);
|
||||
// trace_bezier_patches(tris, [size], [showcps], [splinesteps]);
|
||||
// trace_bezier_patches(patches, tris, [size], [showcps], [splinesteps]);
|
||||
// Description:
|
||||
// Shows the surface, and optionally, control points of a list of bezier patches.
|
||||
// Arguments:
|
||||
// patches = A list of rectangular bezier patches.
|
||||
// tripatches = A list of triangular bezier patches.
|
||||
// tris = A list of triangular bezier patches.
|
||||
// splinesteps = Number of steps to divide each bezier segment into. default=16
|
||||
// showcps = If true, show the controlpoints as well as the surface.
|
||||
// size = Size to show control points and lines.
|
||||
@ -979,7 +998,7 @@ module bezier_polyhedron(patches=[], tripatches=[], splinesteps=16, vertices=[],
|
||||
// [[15,85,0], [33,100, 0], [ 67,100, 0], [ 85, 85,0]],
|
||||
// ];
|
||||
// trace_bezier_patches(patches=[patch1, patch2], splinesteps=8, showcps=true);
|
||||
module trace_bezier_patches(patches=[], tripatches=[], size=1, showcps=false, splinesteps=16)
|
||||
module trace_bezier_patches(patches=[], tris=[], size=1, showcps=false, splinesteps=16)
|
||||
{
|
||||
if (showcps) {
|
||||
for (patch = patches) {
|
||||
@ -989,9 +1008,10 @@ module trace_bezier_patches(patches=[], tripatches=[], size=1, showcps=false, sp
|
||||
if (i<len(patch)-1) extrude_from_to(patch[i][j], patch[i+1][j]) circle(d=size);
|
||||
if (j<len(patch[i])-1) extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
|
||||
}
|
||||
vnf = bezier_patch_vertices_and_faces(patch, splinesteps=splinesteps);
|
||||
vnf = bezier_patch(patch, splinesteps=splinesteps);
|
||||
color("blue") place_copies(vnf[0]) sphere(d=size);
|
||||
}
|
||||
for (patch = tripatches) {
|
||||
for (patch = tris) {
|
||||
place_copies(flatten(patch)) color("red") sphere(d=size*2);
|
||||
color("cyan")
|
||||
for (i=[0:len(patch)-2], j=[0:len(patch[i])-2]) {
|
||||
@ -999,10 +1019,11 @@ module trace_bezier_patches(patches=[], tripatches=[], size=1, showcps=false, sp
|
||||
extrude_from_to(patch[i][j], patch[i][j+1]) circle(d=size);
|
||||
extrude_from_to(patch[i+1][j], patch[i][j+1]) circle(d=size);
|
||||
}
|
||||
vnf = bezier_triangle_vertices_and_faces(patch, splinesteps=splinesteps);
|
||||
vnf = bezier_triangle(patch, splinesteps=splinesteps);
|
||||
color("blue") place_copies(vnf[0]) sphere(d=size);
|
||||
}
|
||||
}
|
||||
bezier_polyhedron(patches=patches, tripatches=tripatches, splinesteps=splinesteps);
|
||||
bezier_polyhedron(patches=patches, tris=tris, splinesteps=splinesteps);
|
||||
}
|
||||
|
||||
|
||||
|
117
examples/bezier_patches.scad
Normal file
117
examples/bezier_patches.scad
Normal file
@ -0,0 +1,117 @@
|
||||
include <BOSL/constants.scad>
|
||||
use <BOSL/transforms.scad>
|
||||
use <BOSL/beziers.scad>
|
||||
use <BOSL/math.scad>
|
||||
|
||||
|
||||
function CR_corner(size, orient=[0,0,0], trans=[0,0,0]) =
|
||||
let (
|
||||
r = 0.4,
|
||||
k = r/2,
|
||||
// I know this patch is not yet correct for continuous
|
||||
// rounding, but it's a first approximation proof of concept.
|
||||
// Currently this is a degree 4 triangular patch.
|
||||
patch = [
|
||||
[[1,1,0], [1,r,0], [1,0,0], [1,0,r], [1,0,1]],
|
||||
[[r,1,0], [k,k,0], [k,0,k], [r,0,1]],
|
||||
[[0,1,0], [0,k,k], [0,0,1]],
|
||||
[[0,1,r], [0,r,1]],
|
||||
[[0,1,1]]
|
||||
]
|
||||
) [for (row=patch)
|
||||
translate_points(v=trans,
|
||||
rotate_points3d(v=orient,
|
||||
scale_points(v=size, row)
|
||||
)
|
||||
)
|
||||
];
|
||||
|
||||
|
||||
function CR_edge(size, orient=[0,0,0], trans=[0,0,0]) =
|
||||
let (
|
||||
r = 0.4,
|
||||
a = -1/2,
|
||||
b = -1/4,
|
||||
c = 1/4,
|
||||
d = 1/2,
|
||||
// I know this patch is not yet correct for continuous
|
||||
// rounding, but it's a first approximation proof of concept.
|
||||
// Currently this is a degree 4 rectangular patch.
|
||||
patch = [
|
||||
[[1,0,a], [1,0,b], [1,0,0], [1,0,c], [1,0,d]],
|
||||
[[r,0,a], [r,0,b], [r,0,0], [r,0,c], [r,0,d]],
|
||||
[[0,0,a], [0,0,b], [0,0,0], [0,0,c], [0,0,d]],
|
||||
[[0,r,a], [0,r,b], [0,r,0], [0,r,c], [0,r,d]],
|
||||
[[0,1,a], [0,1,b], [0,1,0], [0,1,c], [0,1,d]]
|
||||
]
|
||||
) [for (row=patch)
|
||||
translate_points(v=trans,
|
||||
rotate_points3d(v=orient,
|
||||
scale_points(v=size, row)
|
||||
)
|
||||
)
|
||||
];
|
||||
|
||||
|
||||
module CR_cube(size=[100,100,100], r=10, splinesteps=8, cheat=false)
|
||||
{
|
||||
s = size-2*[r,r,r];
|
||||
h = size/2;
|
||||
corners = [
|
||||
CR_corner([r,r,r], orient=ORIENT_Z, trans=[-size.x/2, -size.y/2, -size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_Z_90, trans=[ size.x/2, -size.y/2, -size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_Z_180, trans=[ size.x/2, size.y/2, -size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_Z_270, trans=[-size.x/2, size.y/2, -size.z/2]),
|
||||
|
||||
CR_corner([r,r,r], orient=ORIENT_ZNEG, trans=[ size.x/2, -size.y/2, size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_ZNEG_90, trans=[-size.x/2, -size.y/2, size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_ZNEG_180, trans=[-size.x/2, size.y/2, size.z/2]),
|
||||
CR_corner([r,r,r], orient=ORIENT_ZNEG_270, trans=[ size.x/2, size.y/2, size.z/2])
|
||||
];
|
||||
edges = [
|
||||
CR_edge([r, r, s.x], orient=ORIENT_X, trans=[ 0, -h.y, -h.z]),
|
||||
CR_edge([r, r, s.x], orient=ORIENT_X_90, trans=[ 0, h.y, -h.z]),
|
||||
CR_edge([r, r, s.x], orient=ORIENT_X_180, trans=[ 0, h.y, h.z]),
|
||||
CR_edge([r, r, s.x], orient=ORIENT_X_270, trans=[ 0, -h.y, h.z]),
|
||||
|
||||
CR_edge([r, r, s.y], orient=ORIENT_Y, trans=[ h.x, 0, -h.z]),
|
||||
CR_edge([r, r, s.y], orient=ORIENT_Y_90, trans=[-h.x, 0, -h.z]),
|
||||
CR_edge([r, r, s.y], orient=ORIENT_Y_180, trans=[-h.x, 0, h.z]),
|
||||
CR_edge([r, r, s.y], orient=ORIENT_Y_270, trans=[ h.x, 0, h.z]),
|
||||
|
||||
CR_edge([r, r, s.z], orient=ORIENT_Z, trans=[-h.x, -h.y, 0]),
|
||||
CR_edge([r, r, s.z], orient=ORIENT_Z_90, trans=[ h.x, -h.y, 0]),
|
||||
CR_edge([r, r, s.z], orient=ORIENT_Z_180, trans=[ h.x, h.y, 0]),
|
||||
CR_edge([r, r, s.z], orient=ORIENT_Z_270, trans=[-h.x, h.y, 0])
|
||||
];
|
||||
faces = [
|
||||
// Yes, these are degree 1 bezier patches. That means just the four corner points.
|
||||
// Since these are flat, it doesn't matter what degree they are, and this will reduce calculation overhead.
|
||||
bezier_patch_flat([s.y, s.z], N=1, orient=ORIENT_X, trans=[ h.x, 0, 0]),
|
||||
bezier_patch_flat([s.y, s.z], N=1, orient=ORIENT_XNEG, trans=[-h.x, 0, 0]),
|
||||
|
||||
bezier_patch_flat([s.x, s.z], N=1, orient=ORIENT_Y, trans=[ 0, h.y, 0]),
|
||||
bezier_patch_flat([s.x, s.z], N=1, orient=ORIENT_YNEG, trans=[ 0, -h.y, 0]),
|
||||
|
||||
bezier_patch_flat([s.x, s.y], N=1, orient=ORIENT_Z, trans=[ 0, 0, h.z]),
|
||||
bezier_patch_flat([s.x, s.y], N=1, orient=ORIENT_ZNEG, trans=[ 0, 0, -h.z])
|
||||
];
|
||||
// Generating all the patches above took about 0.05 secs.
|
||||
|
||||
if (cheat) {
|
||||
// Generating the points for the corners takes 5 seconds on my weak-sauce laptop.
|
||||
// Hulling it takes less than a second.
|
||||
hull() bezier_polyhedron(tris=corners, splinesteps=splinesteps);
|
||||
} else {
|
||||
// Generating the polyhedron fully from bezier patches takes 12 seconds on my laptop.
|
||||
bezier_polyhedron(patches=concat(edges, faces), tris=corners, splinesteps=splinesteps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CR_cube(size=[100,100,100], r=20, splinesteps=16, cheat=false);
|
||||
cube(1);
|
||||
|
||||
|
||||
|
||||
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
Loading…
x
Reference in New Issue
Block a user