summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Mastbaum <mastbaum@hep.upenn.edu>2012-05-02 16:46:22 -0400
committertlatorre <tlatorre@uchicago.edu>2021-05-09 08:42:39 -0700
commit6d515c3c8035c0899f7d27344c6ee545f3ce6f8a (patch)
tree7805440e911530b567e2ece72f9ac20bfad4b51a
parentef5645baef14b53ed8ca3d72941c364ef5586e50 (diff)
downloadchroma-6d515c3c8035c0899f7d27344c6ee545f3ce6f8a.tar.gz
chroma-6d515c3c8035c0899f7d27344c6ee545f3ce6f8a.tar.bz2
chroma-6d515c3c8035c0899f7d27344c6ee545f3ce6f8a.zip
add method to weld together solids at shared triangles
'weld' a solid onto another one at identical shared triangles. optionally apply a ``Surface`` or color to the shared surface. this isn't a boolean solid operation -- the triangles must be identical in the two meshes.
-rw-r--r--chroma/geometry.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/chroma/geometry.py b/chroma/geometry.py
index 601dcf7..be3e7eb 100644
--- a/chroma/geometry.py
+++ b/chroma/geometry.py
@@ -1,5 +1,6 @@
import sys
import os
+from itertools import chain
from hashlib import md5
import cPickle as pickle
import gzip
@@ -54,6 +55,16 @@ class Mesh(object):
# remap the triangles to the unique vertices
self.triangles = inverse[self.triangles]
+ def remove_null_triangles(self):
+ '''Remove any zero-area triangles from a mesh.
+
+ Returns the mask of retained triangles, which may be applied to the
+ material, surface, etc., arrays of an associated ``Solid``.
+ '''
+ mask = np.array([(len(set(x)) == 3) for x in self.triangles])
+ self.triangles = self.triangles[mask]
+ return mask
+
def assemble(self, key=slice(None), group=True):
"""
Return an assembled triangle mesh; i.e. return the vertex positions
@@ -127,6 +138,49 @@ class Solid(object):
def __add__(self, other):
return Solid(self.mesh + other.mesh, np.concatenate((self.material1, other.material1)), np.concatenate((self.material2, other.material2)), np.concatenate((self.surface, other.surface)), np.concatenate((self.color, other.color)))
+ def weld(self, other, shared_triangle_surface=None, shared_triangle_color=None):
+ '''Merge this solid with another at any identical triangles.
+
+ Triangles that are common to both solids will be reduced to one, with the
+ surface and color properties of this one unless otherwise specified with
+ ``shared_triangle_surface`` and/or ``shared_triangle_color``.
+
+ Note that this is NOT a boolean union!
+ '''
+ # create arrays of sets of (three-tuple) points
+ # use sets to take care of point order permutations, numpy element-wise-ness
+ points_self = np.array([set(map(tuple, [self.mesh.vertices[x] for x in y])) for y in self.mesh.triangles], dtype=set)
+ points_other = np.array([set(map(tuple, [other.mesh.vertices[x] for x in y])) for y in other.mesh.triangles], dtype=set)
+
+ # find any triangles in other that also exist in self
+ match = [np.where(points_other == x)[0] for x in points_self]
+ mask = np.array(map(lambda x: len(x)>0, match))
+ if mask.sum() == 0:
+ raise Exception('cannot weld solids with no shared triangles')
+
+ # get triangle ids of the duplicates
+ duplicates = sorted(list(chain(*[np.where(points_other == x)[0] for x in points_self])))
+
+ # create temporary second solid -- solid2 with duplicate triangles removed
+ mesh = Mesh(other.mesh.vertices, np.delete(other.mesh.triangles, duplicates, 0))
+ material1 = np.delete(other.material1, duplicates, 0)
+ material2 = np.delete(other.material2, duplicates, 0)
+ surface = np.delete(other.surface, duplicates, 0)
+ color = np.delete(other.color, duplicates, 0)
+
+ self.mesh = self.mesh + mesh
+ self.material1 = np.concatenate((self.material1, material1))
+ self.material2 = np.concatenate((self.material2, material2))
+ self.surface = np.concatenate((self.surface, surface))
+ self.color = np.concatenate((self.color, color))
+
+ # set properties at interface
+ self.material2[mask] = other.material1[0]
+ if shared_triangle_surface is not None:
+ self.surface[mask] = shared_triangle_surface
+ if shared_triangle_color is not None:
+ self.color[mask] = shared_triangle_color
+
@memoize_method_with_dictionary_arg
def material1_indices(self, material_lookup):
return np.fromiter(imap(material_lookup.get, self.material1), dtype=np.int32, count=len(self.material1))
@@ -295,3 +349,4 @@ class Geometry(object):
self.surface_index[self.surface_index == surface_lookup[None]] = -1
except KeyError:
pass
+