diff --git a/README.md b/README.md index cfaf1a3..b2cae41 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ - https://en.wikipedia.org/wiki/Polygon_triangulation - do this to fix my wave example! - http://www.polygontriangulation.com/2018/07/triangulation-algorithm.html +- Clean up examples.ram_horn_branch(). The way I clean it up might + help inform some cleaner designs. - I really need to standardize some of the behavior of fundamental operations (with regard to things like sizes they generate). This is behavior that, if it changes, will change a lot of things that I'm @@ -58,6 +60,7 @@ identical except that it is higher-resolution? - Use mixins to extend 3D transformations to things (matrices, cages, meshes, existing transformations) +- I can transform a Cage. Why not a CageGen? ## ???? - Embed this in Blender? @@ -75,3 +78,7 @@ - Current system is very "generative". Could I do basically L-system if I have rules for how a much is *refined*? What about IFS? - Do this in Rust once I understand WTF I am doing + +## Other thoughts + +- Why do I never use the term "extruding" to describe what I'm doing? \ No newline at end of file diff --git a/cage.py b/cage.py index 34fae33..0eb8517 100644 --- a/cage.py +++ b/cage.py @@ -67,6 +67,20 @@ class Cage(object): trans_verts[2*i+1] = m trans_edges = [[7, 0, 1], [1, 2, 3], [3, 4, 5], [5, 6, 7]] return cages, trans_verts, trans_edges + def subdivide_x_deprecated(self): + mids = (self.verts + numpy.roll(self.verts, -1, axis=0)) / 2 + centroid = numpy.mean(self.verts, axis=0) + arrs = [ + [self.verts[0,:], mids[0,:], mids[2,:], self.verts[3,:]], + [mids[0,:], self.verts[1,:], self.verts[2,:], mids[2,:]], + ] + cages = [Cage(numpy.array(a), self.splits) for a in arrs] + trans_verts = numpy.zeros((2*len(self.verts),3), dtype=self.verts.dtype) + for i,(v,m) in enumerate(zip(self.verts, mids)): + trans_verts[2*i] = v + trans_verts[2*i+1] = m + trans_edges = [[7, 0, 1], [1, 2, 3], [3, 4, 5], [5, 6, 7]] + return cages, trans_verts, trans_edges def is_fork(self): return False def transform(self, xform): diff --git a/examples.py b/examples.py index f3af75b..8699681 100755 --- a/examples.py +++ b/examples.py @@ -2,6 +2,7 @@ import itertools +import math import numpy import stl.mesh import trimesh @@ -148,22 +149,13 @@ def ram_horn_branch(): for i in range(count): if i > 0: c = cage1.transform(xf) - #print("DEBUG: recur, i={}, yield {}".format(i, c.verts)) yield c xf0 = xf xf = incr.compose(xf) - # .compose(opening_boundary(i)) def xf_sub(i): - # yes, I can do this in a one-liner - # yes, it should be normalized, but I reused from something else - if i == 0: - dx, dy = 1, 1 - elif i == 1: - dx, dy = -1, 1 - elif i == 2: - dx, dy = -1, -1 - elif i == 3: - dx, dy = 1, -1 + # (dx,dy) should be normalized, but I reused from something else + dx = 1 if i == 0 or i == 1 else -1 + dy = 1 if i == 0 or i == 3 else -1 return meshutil.Transform().translate(0, 0, 0.5).rotate([-dy,dx,0], -numpy.pi/6) subdiv, trans_vs, trans_es = cage1.subdivide_deprecated() gens = [cage.CageGen(itertools.chain( @@ -172,12 +164,6 @@ def ram_horn_branch(): for i,cage_sub in enumerate(subdiv)] yield cage.CageFork(gens, xf.apply_to(trans_vs), trans_es) - # TODO: The starting cage needs to be one iteration *earlier*, and the - # subdivided cage is fine, but the generators likewise need to start - # one iteration earlier. Look closely in Blender at the mesh, - # specifically just prior to the fork. - # - # xf0.apply_to(trans_vs) is identical to last cage yielded? cg = cage.CageGen(itertools.chain( [cage0], recur(meshutil.Transform(), cage0, 8), @@ -186,6 +172,43 @@ def ram_horn_branch(): mesh = cg.to_mesh(count=32, close_first=True, close_last=True) return mesh +def dream_pendant(): + center = meshutil.Transform().translate(-0.5, -0.5, 0) + cage0 = cage.Cage.from_arrays([ + [0, 0, 0], + [1, 0, 0], + [1, 1, 0], + [0, 1, 0], + ]).transform(center) + incr = meshutil.Transform() \ + .scale(0.95, 1.0, 0.95) \ + .rotate([0,1,0], 0.2) \ + .translate(0,0,0.9) + def recur(xf, cage1, count): + for i in range(count): + if i > 0: + c = cage1.transform(xf) + yield c + xf0 = xf + xf = incr.compose(xf) + def xf_rot(a): + return meshutil.Transform().rotate([0,1,0], a) + subdiv, trans_vs, trans_es = cage1.subdivide_x_deprecated() + gens = [cage.CageGen(itertools.chain( + [cage_sub.transform(xf)], + recur(xf_rot(ang).compose(xf), cage_sub, 5))) + for cage_sub,ang in + zip(subdiv, [-0.2, 0.7])] + yield cage.CageFork(gens, xf.apply_to(trans_vs), trans_es) + cg = cage.CageGen(itertools.chain( + [cage0], + recur(meshutil.Transform(), cage0, 3), + )) + # TODO: if this is just a list it seems silly to require itertools + mesh1 = cg.to_mesh(count=32, close_first=False, close_last=True) + mesh2 = mesh1.transform(meshutil.Transform().rotate([0,1,0], math.pi)) + return meshutil.FaceVertexMesh.concat_many([mesh1, mesh2]) + def branch_test(): b0 = numpy.array([ [0, 0, 0], @@ -356,6 +379,7 @@ def main(): # TODO: Fix #ram_horn3: "ramhorn3.stl", ram_horn_branch: "ramhorn_branch.stl", + dream_pendant: "dream_pendant.stl", twist: "twist.stl", twist_nonlinear: "twist_nonlinear.stl", twist_from_gen: "twist_from_gen.stl",