Some performance improvements
This commit is contained in:
parent
a8c78287f1
commit
43e5a282e6
276
Scratch.ipynb
276
Scratch.ipynb
File diff suppressed because one or more lines are too long
65
examples.py
65
examples.py
@ -19,8 +19,9 @@ def ram_horn():
|
|||||||
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
||||||
xf0_to_1 = meshutil.Transform().translate(0,0,1)
|
xf0_to_1 = meshutil.Transform().translate(0,0,1)
|
||||||
b1 = xf0_to_1.apply_to(b0)
|
b1 = xf0_to_1.apply_to(b0)
|
||||||
mesh = meshutil.join_boundary_simple(b0, b1)
|
meshes = []
|
||||||
mesh = mesh.concat(meshutil.close_boundary_simple(b0))
|
meshes.append(meshutil.join_boundary_simple(b0, b1))
|
||||||
|
meshes.append(meshutil.close_boundary_simple(b0))
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
# Opening boundary:
|
# Opening boundary:
|
||||||
b = b1
|
b = b1
|
||||||
@ -37,10 +38,10 @@ def ram_horn():
|
|||||||
.translate(0,0,0.8)
|
.translate(0,0,0.8)
|
||||||
b_sub1 = incr.compose(xf).apply_to(b)
|
b_sub1 = incr.compose(xf).apply_to(b)
|
||||||
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
||||||
mesh = mesh.concat(m)
|
meshes.append(m)
|
||||||
xf = incr.compose(xf)
|
xf = incr.compose(xf)
|
||||||
# Close final boundary:
|
# Close final boundary:
|
||||||
mesh = mesh.concat(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
meshes.append(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
||||||
# ::-1 is to reverse the boundary's order to fix winding order.
|
# ::-1 is to reverse the boundary's order to fix winding order.
|
||||||
# Not sure of the "right" way to fix winding order here.
|
# Not sure of the "right" way to fix winding order here.
|
||||||
# The boundary vertices go in an identical order... it's just
|
# The boundary vertices go in an identical order... it's just
|
||||||
@ -51,6 +52,7 @@ def ram_horn():
|
|||||||
|
|
||||||
# I don't need to subdivide *geometry*.
|
# I don't need to subdivide *geometry*.
|
||||||
# I need to subdivide *space* and then put geometry in it.
|
# I need to subdivide *space* and then put geometry in it.
|
||||||
|
mesh = meshutil.FaceVertexMesh.concat_many(meshes)
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
# Interlocking twists.
|
# Interlocking twists.
|
||||||
@ -63,17 +65,13 @@ def twist(ang=0.1, dz=0.2, dx0=2, count=4, scale=0.98):
|
|||||||
[1, 1, 0],
|
[1, 1, 0],
|
||||||
[0, 1, 0],
|
[0, 1, 0],
|
||||||
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
||||||
mesh = None
|
meshes = []
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
xf = meshutil.Transform() \
|
xf = meshutil.Transform() \
|
||||||
.translate(dx0, 0, 0) \
|
.translate(dx0, 0, 0) \
|
||||||
.rotate([0,0,1], numpy.pi * 2 * i / count)
|
.rotate([0,0,1], numpy.pi * 2 * i / count)
|
||||||
b0 = xf.apply_to(b)
|
b0 = xf.apply_to(b)
|
||||||
m = meshutil.close_boundary_simple(b0)
|
meshes.append(meshutil.close_boundary_simple(b0))
|
||||||
if mesh is None:
|
|
||||||
mesh = m
|
|
||||||
else:
|
|
||||||
mesh = mesh.concat(m)
|
|
||||||
for layer in range(256):
|
for layer in range(256):
|
||||||
b_sub0 = xf.apply_to(b)
|
b_sub0 = xf.apply_to(b)
|
||||||
incr = meshutil.Transform() \
|
incr = meshutil.Transform() \
|
||||||
@ -82,10 +80,11 @@ def twist(ang=0.1, dz=0.2, dx0=2, count=4, scale=0.98):
|
|||||||
.scale(scale)
|
.scale(scale)
|
||||||
b_sub1 = xf.compose(incr).apply_to(b)
|
b_sub1 = xf.compose(incr).apply_to(b)
|
||||||
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
||||||
mesh = mesh.concat(m)
|
meshes.append(m)
|
||||||
xf = xf.compose(incr)
|
xf = xf.compose(incr)
|
||||||
# Close final boundary:
|
# Close final boundary:
|
||||||
mesh = mesh.concat(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
meshes.append(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
||||||
|
mesh = meshutil.FaceVertexMesh.concat_many(meshes)
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
def twist_nonlinear(dx0 = 2, dz=0.2, count=3, scale=0.99, layers=100):
|
def twist_nonlinear(dx0 = 2, dz=0.2, count=3, scale=0.99, layers=100):
|
||||||
@ -100,17 +99,13 @@ def twist_nonlinear(dx0 = 2, dz=0.2, count=3, scale=0.99, layers=100):
|
|||||||
[1, 1, 0],
|
[1, 1, 0],
|
||||||
[0, 1, 0],
|
[0, 1, 0],
|
||||||
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
], dtype=numpy.float64) - [0.5, 0.5, 0]
|
||||||
mesh = None
|
meshes = []
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
xf = meshutil.Transform() \
|
xf = meshutil.Transform() \
|
||||||
.translate(dx0, 0, 0) \
|
.translate(dx0, 0, 0) \
|
||||||
.rotate([0,0,1], numpy.pi * 2 * i / count)
|
.rotate([0,0,1], numpy.pi * 2 * i / count)
|
||||||
b0 = xf.apply_to(b)
|
b0 = xf.apply_to(b)
|
||||||
m = meshutil.close_boundary_simple(b0)
|
meshes.append(meshutil.close_boundary_simple(b0))
|
||||||
if mesh is None:
|
|
||||||
mesh = m
|
|
||||||
else:
|
|
||||||
mesh = mesh.concat(m)
|
|
||||||
for layer in range(layers):
|
for layer in range(layers):
|
||||||
b_sub0 = xf.apply_to(b)
|
b_sub0 = xf.apply_to(b)
|
||||||
ang = ang_fn(layer)
|
ang = ang_fn(layer)
|
||||||
@ -120,10 +115,11 @@ def twist_nonlinear(dx0 = 2, dz=0.2, count=3, scale=0.99, layers=100):
|
|||||||
.scale(scale)
|
.scale(scale)
|
||||||
b_sub1 = xf.compose(incr).apply_to(b)
|
b_sub1 = xf.compose(incr).apply_to(b)
|
||||||
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
m = meshutil.join_boundary_simple(b_sub0, b_sub1)
|
||||||
mesh = mesh.concat(m)
|
meshes.append(m)
|
||||||
xf = xf.compose(incr)
|
xf = xf.compose(incr)
|
||||||
# Close final boundary:
|
# Close final boundary:
|
||||||
mesh = mesh.concat(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
meshes.append(meshutil.close_boundary_simple(b_sub1[::-1,:]))
|
||||||
|
mesh = meshutil.FaceVertexMesh.concat_many(meshes)
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
# Generate a frame with 'count' boundaries in the XZ plane.
|
# Generate a frame with 'count' boundaries in the XZ plane.
|
||||||
@ -138,6 +134,7 @@ def gen_twisted_boundary(count=4, dx0=2, dz=0.2, ang=0.1):
|
|||||||
], dtype=numpy.float64) - [0.5, 0, 0.5]
|
], dtype=numpy.float64) - [0.5, 0, 0.5]
|
||||||
b = meshutil.subdivide_boundary(b)
|
b = meshutil.subdivide_boundary(b)
|
||||||
b = meshutil.subdivide_boundary(b)
|
b = meshutil.subdivide_boundary(b)
|
||||||
|
b = meshutil.subdivide_boundary(b)
|
||||||
# Generate 'seed' transformations:
|
# Generate 'seed' transformations:
|
||||||
xfs = [meshutil.Transform().translate(dx0, 0, 0).rotate([0,1,0], numpy.pi * 2 * i / count)
|
xfs = [meshutil.Transform().translate(dx0, 0, 0).rotate([0,1,0], numpy.pi * 2 * i / count)
|
||||||
for i in range(count)]
|
for i in range(count)]
|
||||||
@ -183,29 +180,30 @@ def gen_torus_xy(gen, rad=2, frames=100):
|
|||||||
|
|
||||||
# String together boundaries from a generator.
|
# String together boundaries from a generator.
|
||||||
# If count is nonzero, run only this many iterations.
|
# If count is nonzero, run only this many iterations.
|
||||||
def gen2mesh(gen, count=0, flip_order=False, loop=False):
|
def gen2mesh(gen, count=0, flip_order=False, loop=False, join_fn=meshutil.join_boundary_optim):
|
||||||
# Get first list of boundaries:
|
# Get first list of boundaries:
|
||||||
bs_first = next(gen)
|
bs_first = next(gen)
|
||||||
bs_last = bs_first
|
bs_last = bs_first
|
||||||
# TODO: Begin and end with close_boundary_simple
|
# TODO: Begin and end with close_boundary_simple
|
||||||
mesh = meshutil.FaceVertexMesh.Empty()
|
meshes = []
|
||||||
for i,bs_cur in enumerate(gen):
|
for i,bs_cur in enumerate(gen):
|
||||||
if count > 0 and i >= count:
|
if count > 0 and i >= count:
|
||||||
break
|
break
|
||||||
for j,b in enumerate(bs_cur):
|
for j,b in enumerate(bs_cur):
|
||||||
if flip_order:
|
if flip_order:
|
||||||
m = meshutil.join_boundary_simple(b, bs_last[j])
|
m = join_fn(b, bs_last[j])
|
||||||
else:
|
else:
|
||||||
m = meshutil.join_boundary_simple(bs_last[j], b)
|
m = join_fn(bs_last[j], b)
|
||||||
mesh = mesh.concat(m)
|
meshes.append(m)
|
||||||
bs_last = bs_cur
|
bs_last = bs_cur
|
||||||
if loop:
|
if loop:
|
||||||
for b0,b1 in zip(bs_last, bs_first):
|
for b0,b1 in zip(bs_last, bs_first):
|
||||||
if flip_order:
|
if flip_order:
|
||||||
m = meshutil.join_boundary_simple(b1, b0)
|
m = join_fn(b1, b0)
|
||||||
else:
|
else:
|
||||||
m = meshutil.join_boundary_simple(b0, b1)
|
m = join_fn(b0, b1)
|
||||||
mesh = mesh.concat(m)
|
meshes.append(m)
|
||||||
|
mesh = meshutil.FaceVertexMesh.concat_many(meshes)
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
def twist_from_gen():
|
def twist_from_gen():
|
||||||
@ -216,12 +214,21 @@ def twist_from_gen():
|
|||||||
# frames = How many step to build this from:
|
# frames = How many step to build this from:
|
||||||
# turn = How many full turns to make in inner twist
|
# turn = How many full turns to make in inner twist
|
||||||
# count = How many inner twists to have
|
# count = How many inner twists to have
|
||||||
def twisty_torus(frames = 200, turns = 4, count = 4, rad = 4):
|
def twisty_torus(frames = 5000, turns = 4, count = 4, rad = 4):
|
||||||
# In order to make this line up properly:
|
# In order to make this line up properly:
|
||||||
angle = numpy.pi * 2 * turns / frames
|
angle = numpy.pi * 2 * turns / frames
|
||||||
gen = gen_torus_xy(gen_twisted_boundary(count=count, ang=angle), rad=rad, frames=frames)
|
gen = gen_torus_xy(gen_twisted_boundary(count=count, ang=angle), rad=rad, frames=frames)
|
||||||
return gen2mesh(gen, 0, flip_order=True, loop=True)
|
return gen2mesh(gen, 0, flip_order=True, loop=True)
|
||||||
|
|
||||||
|
# frames = How many step to build this from:
|
||||||
|
# turn = How many full turns to make in inner twist
|
||||||
|
# count = How many inner twists to have
|
||||||
|
def twisty_torus_opt(frames = 200, turns = 4, count = 4, rad = 4):
|
||||||
|
# In order to make this line up properly:
|
||||||
|
angle = numpy.pi * 2 * turns / frames
|
||||||
|
gen = gen_torus_xy(gen_twisted_boundary(count=count, ang=angle), rad=rad, frames=frames)
|
||||||
|
return gen2mesh(gen, 0, flip_order=True, loop=True, join_fn=meshutil.join_boundary_optim)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
fns = {
|
fns = {
|
||||||
ram_horn: "ramhorn.stl",
|
ram_horn: "ramhorn.stl",
|
||||||
|
|||||||
31
meshutil.py
31
meshutil.py
@ -38,8 +38,27 @@ class FaceVertexMesh(object):
|
|||||||
v[i] = [self.v[iv0], self.v[iv1], self.v[iv2]]
|
v[i] = [self.v[iv0], self.v[iv1], self.v[iv2]]
|
||||||
return stl.mesh.Mesh(data)
|
return stl.mesh.Mesh(data)
|
||||||
@classmethod
|
@classmethod
|
||||||
def Empty(self):
|
def Empty(cls):
|
||||||
return FaceVertexMesh(numpy.zeros((0,3)), numpy.zeros((0,3), dtype=int))
|
return FaceVertexMesh(numpy.zeros((0,3)), numpy.zeros((0,3), dtype=int))
|
||||||
|
@classmethod
|
||||||
|
def concat_many(cls, meshes):
|
||||||
|
nv = 0
|
||||||
|
nf = 0
|
||||||
|
for m in meshes:
|
||||||
|
nv += m.v.shape[0]
|
||||||
|
nf += m.f.shape[0]
|
||||||
|
v = numpy.zeros((nv,3), dtype=numpy.float64)
|
||||||
|
f = numpy.zeros((nf,3), dtype=int)
|
||||||
|
vi = 0
|
||||||
|
fi = 0
|
||||||
|
for m in meshes:
|
||||||
|
vj = vi + m.v.shape[0]
|
||||||
|
fj = fi + m.f.shape[0]
|
||||||
|
v[vi:vj,:] = m.v
|
||||||
|
f[fi:fj,:] = m.f + vi
|
||||||
|
vi = vj
|
||||||
|
fi = fj
|
||||||
|
return FaceVertexMesh(v, f)
|
||||||
|
|
||||||
class Transform(object):
|
class Transform(object):
|
||||||
def __init__(self, mtx=None):
|
def __init__(self, mtx=None):
|
||||||
@ -207,6 +226,16 @@ def join_boundary_simple(bound1, bound2):
|
|||||||
fs[2*i + 1] = [v1, n + v0, v0]
|
fs[2*i + 1] = [v1, n + v0, v0]
|
||||||
return FaceVertexMesh(vs, fs)
|
return FaceVertexMesh(vs, fs)
|
||||||
|
|
||||||
|
def join_boundary_optim(bound1, bound2):
|
||||||
|
# bound1 and bound2 must stay in order, but we can rotate
|
||||||
|
# the starting point to whatever we want. Use distance as
|
||||||
|
# a metric:
|
||||||
|
errs = [numpy.linalg.norm(bound1 - numpy.roll(bound2, i, axis=0))
|
||||||
|
for i,_ in enumerate(bound1)]
|
||||||
|
# What shift gives the lowest distance?
|
||||||
|
i = numpy.argmin(errs)
|
||||||
|
return join_boundary_simple(bound1, numpy.roll(bound2, i, axis=0))
|
||||||
|
|
||||||
def close_boundary_simple(bound):
|
def close_boundary_simple(bound):
|
||||||
# This will fail for any non-convex boundary!
|
# This will fail for any non-convex boundary!
|
||||||
centroid = numpy.mean(bound, axis=0)
|
centroid = numpy.mean(bound, axis=0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user