def shift(mesh, shift): #input shift as a vector vertices = mesh.vertices triangles = mesh.triangles n = np.shape(vertices)[0] newvertices = vertices + np.tile(shift, (n, 1)) return Mesh(newvertices, triangles, remove_duplicate_vertices=True)
def mesh_from_binary_stl(filename): "Return a mesh from a binary stl file." if filename.endswith('.bz2'): f = bz2.BZ2File(filename) else: f = open(filename) vertices = [] triangles = [] vertex_map = {} f.read(80) ntriangles = struct.unpack('<I', f.read(4))[0] for i in range(ntriangles): normal = tuple(struct.unpack('<fff', f.read(12))) triangle = [None] * 3 for j in range(3): vertex = tuple(struct.unpack('<fff', f.read(12))) if vertex not in vertex_map: vertices.append(vertex) vertex_map[vertex] = len(vertices) - 1 triangle[j] = vertex_map[vertex] triangles.append(triangle) f.read(2) f.close() return Mesh(np.array(vertices), np.array(triangles, dtype=np.uint32))
def rotate_extrude(x, y, nsteps=64): """ Return the solid mesh formed by extruding the profile defined by the x and y points `x` and `y` around the y axis. .. note:: The path traced by the points `x` and `y` should go counter-clockwise, otherwise the mesh will be inside out. Example: >>> # create a bipyramid >>> m = rotate_extrude([0,1,0], [-1,0,1], nsteps=4) """ if len(x) != len(y): raise Exception('`x` and `y` arrays must have the same length.') points = np.array([x, y, np.zeros(len(x))]).transpose() steps = np.linspace(0, 2 * np.pi, nsteps, endpoint=False) vertices = np.vstack( [rotate(points, angle, (0, -1, 0)) for angle in steps]) triangles = mesh_grid( np.arange(len(vertices)).reshape( (len(steps), len(points))).transpose()[::-1]) return Mesh(vertices, triangles, remove_duplicate_vertices=True)
def render_photon_track(self,geometry,photon_track,sz=1.0,color='wavelength'): origin = photon_track.pos[:-1] extent = photon_track.pos[1:]-photon_track.pos[:-1] perp1 = np.cross(origin,extent) perp1 = np.inner(sz/2.0/np.linalg.norm(perp1,axis=1),perp1.T).T perp2 = np.cross(perp1,extent) perp2 = np.inner(sz/2.0/np.linalg.norm(perp2,axis=1),perp2.T).T verts = [perp1+perp2,-perp1+perp2,perp1-perp2,-perp1-perp2] bot = [vert+origin for vert in verts] top = [vert+origin+extent for vert in verts] vertices = [origin,origin+extent,bot[0],top[0],bot[1],top[1],bot[2],top[2],bot[3],top[3]] vertices = np.transpose(np.asarray(vertices,np.float32),(1,0,2)) triangles = np.asarray([[1, 3, 5], [1, 5, 7], [1, 7, 9], [1, 9, 3], [3, 2, 4], [5, 4, 6], [7, 6, 8], [9, 8, 2], [2, 0, 0], [4, 0, 0], [6, 0, 0], [8, 0, 0], [1, 5, 1], [1, 7, 1], [1, 9, 1], [1, 3, 1], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 2, 3], [2, 0, 4], [4, 0, 6], [6, 0, 8], [8, 0, 2]], dtype=np.int32) if color == 'wavelength': r = np.asarray(np.interp(photon_track.wavelengths[:-1],[300,550,800],[0,0,255]),dtype=np.uint32) g = np.asarray(np.interp(photon_track.wavelengths[:-1],[300,550,800],[0,255,0]),dtype=np.uint32) b = np.asarray(np.interp(photon_track.wavelengths[:-1],[300,550,800],[255,0,0]),dtype=np.uint32) colors = np.bitwise_or(b,np.bitwise_or(np.left_shift(g,8),np.left_shift(r,16))) else: r,g,b = color colors = np.full_like(photon_track.wavelengths[:-1],((r<<16)|(g<<8)|b),dtype=np.uint32) markers = [Solid(Mesh(v,triangles), vacuum, vacuum, color=c) for v,c in zip(vertices,colors)] [geometry.add_solid(marker) for marker in markers]
def rotate(mesh, rotation_matrix): vertices = mesh.vertices triangles = mesh.triangles n = np.shape(vertices)[0] newvertices = np.empty((n, 3)) for i in range(n): newvertices[i] = np.dot(rotation_matrix, vertices[i]) return Mesh(newvertices, triangles, remove_duplicate_vertices=True)
def linear_extrude(x1, y1, height, x2=None, y2=None, center=None, endcaps=True): """ Return the solid mesh formed by linearly extruding the polygon formed by the x and y points `x1` and `y1` by a distance `height`. If `x2` and `y2` are given extrude by connecting the points `x1` and `y1` to `x2` and `y2`; this allows the creation of tapered solids. If `endcaps` is False, then the triangles on the endcaps will be left off, and the mesh will not be closed. .. note:: The path traced by the points `x` and `y` should go counter-clockwise, otherwise the mesh will be inside out. Example: >>> # create a hexagon prism >>> angles = np.linspace(0, 2*np.pi, 6, endpoint=False) >>> m = linear_extrude(np.cos(angles), np.sin(angles), 2.0) """ if len(x1) != len(y1): raise Exception('`x` and `y` arrays must have the same length.') if x2 is None: x2 = x1 if y2 is None: y2 = y1 if len(x2) != len(y2) or len(x2) != len(x1): raise Exception('`x` and `y` arrays must have the same length.') n = len(x1) vertex_iterators = [ izip(x1, y1, repeat(-height / 2.0, n)), izip(x2, y2, repeat(height / 2.0, n)) ] if endcaps: vertex_iterators = [izip(repeat(0,n),repeat(0,n),repeat(-height/2.0,n))] \ + vertex_iterators \ + [izip(repeat(0,n),repeat(0,n),repeat(height/2.0,n))] vertices = np.fromiter(flatten(roundrobin(*vertex_iterators)), float) vertices = vertices.reshape((len(vertices) // 3, 3)) if center is not None: vertices += center triangles = mesh_grid( np.arange(len(vertices)).reshape( (len(x1), len(vertices) // len(x1))).transpose()[::-1]) return Mesh(vertices, triangles, remove_duplicate_vertices=True)
def convex_polygon(x, y): """ Return a polygon mesh in the x-y plane. `x` and `y` are the x and y coordinates for the points in the polygon. The simple triangulation method used here requires that the polygon be convex and the points are specified in order. """ vertices = np.column_stack((x, y, np.zeros_like(x))) # Every triangle includes triangles = np.empty(shape=(len(vertices) - 2, 3), dtype=np.int32) triangles[:, 0] = 0 # Every triangle includes vertex zero triangles[:, 1] = np.arange(1, len(vertices) - 1) triangles[:, 2] = np.arange(2, len(vertices)) return Mesh(vertices=vertices, triangles=triangles)
def build_detector(self, detector=None, volume_classifier=_default_volume_classifier): ''' Add the meshes defined by this GDML to the detector. If detector is not specified, a new detector will be created. The volume_classifier should be a function that returns a classification of the volume ('pmt','solid','omit') and kwargs passed to the Solid constructor for that volume: material1, material2, color, surface The different classifications have different behaviors: 'pmt' should specify channel_type in the kwargs to identify the channel, calls add_pmt 'solid' will add a normal solid to the Chroma geometry, calls add_solid 'omit' will not add the Solid to the Chroma geometry ''' if detector is None: detector = Detector(vacuum) q = deque() q.append([self.world, np.zeros(3), np.identity(3), None]) while len(q): v, pos, rot, parent_material_ref = q.pop() for child, c_pos, c_rot in zip(v.children, v.child_pos, v.child_rot): c_pos = self.get_vals(c_pos) if c_pos is not None else np.zeros(3) c_rot = self.get_vals(c_rot) if c_rot is not None else np.identity(3) c_pos = np.matmul(c_pos,rot)+pos x_rot = make_rotation_matrix(c_rot[0], [1, 0, 0]) y_rot = make_rotation_matrix(c_rot[1], [0, 1, 0]) z_rot = make_rotation_matrix(c_rot[2], [0, 0, 1]) c_rot = np.matmul(rot, np.matmul(x_rot, np.matmul(y_rot, z_rot))) #FIXME verify this order q.append([child, c_pos, c_rot, v.material_ref]) m = self.get_mesh(v.solid_ref) mesh = Mesh(m.vertices, m.faces) # convert PyMesh mesh to Chroma mesh classification, kwargs = volume_classifier(v.name, v.material_ref, parent_material_ref) if classification == 'pmt': channel_type = kwargs.pop('channel_type',None) solid = Solid(mesh, **kwargs) detector.add_pmt(solid, displacement=pos, rotation=rot, channel_type=channel_type) elif classification == 'solid': solid = Solid(mesh, **kwargs) detector.add_solid(solid, displacement=pos, rotation=rot) elif classification == 'omit': pass else: raise Exception('Unknown volume classification: '+classification) return detector
def mesh_from_ascii_stl(filename): "Return a mesh from an ascii stl file." if filename.endswith('.bz2'): f = bz2.BZ2File(filename) else: f = open(filename) vertices = [] triangles = [] vertex_map = {} while True: line = f.readline() if line == '': break if not line.strip().startswith('vertex'): continue triangle = [None] * 3 for i in range(3): vertex = tuple([float(s) for s in line.strip().split()[1:]]) if vertex not in vertex_map: vertices.append(vertex) vertex_map[vertex] = len(vertices) - 1 triangle[i] = vertex_map[vertex] if i < 3: line = f.readline() triangles.append(triangle) f.close() return Mesh(np.array(vertices), np.array(triangles, dtype=np.uint32))
def visit(self, node, debug=False): """ :param node: DAENode instance DAENode instances and their pycollada underpinnings meet chroma here Chroma needs sensitive detectors to have an associated surface with detect property ... """ #assert node.__class__.__name__ == 'DAENode' self.vcount += 1 if self.vcount < 10: log.debug("visit : vcount %s node.index %s node.id %s " % (self.vcount, node.index, node.id)) bps = list(node.boundgeom.primitives()) bpl = bps[0] assert len(bps) == 1 and bpl.__class__.__name__ == 'BoundPolylist' tris = bpl.triangleset() vertices = tris._vertex triangles = tris._vertex_index mesh = Mesh(vertices, triangles, remove_duplicate_vertices=False) material2, material1 = self.find_outer_inner_materials(node) surface = self.find_surface( node) # lookup Chroma surface corresponding to the node if surface == None: surfacename = "NOT SPECIFIED" else: surfacename = surface.name if self.dump_node_info: print "[NODE %05d:%s]" % ( node.index, node.lv.id ), " NTriangles=%d OuterMat=%s InnerMat=%s Surface=%s" % (len( mesh.triangles), material2.name, material1.name, surfacename) color = 0x33ffffff solid = Solid(mesh, material1, material2, surface, color) solid.node = node # # hmm a PMT is comprised of several volumes all of which # have the same associated channel_id # channel_id = getattr(node, 'channel_id', None) if not channel_id is None and channel_id > 0: self.channel_count += 1 # nodes with associated non zero channel_id self.channel_ids.add(channel_id) self.chroma_geometry.add_pmt(solid, channel_id=channel_id) else: self.chroma_geometry.add_solid(solid) pass if debug and self.vcount % 1000 == 0: print node.id print self.vcount, bpl, tris, tris.material print mesh #print mesh.assemble() bounds = mesh.get_bounds() extent = bounds[1] - bounds[0] print extent
def build_checkerboard_scene(checkers_per_side=10, squares_per_checker=50): x = np.linspace(-5000.0, 5000.0, checkers_per_side * squares_per_checker + 1) y = np.linspace(-5000.0, 5000.0, checkers_per_side * squares_per_checker + 1) vertices = np.array(tuple(product(x, y, [0]))) triangles = [] for j in range(y.size - 1): for i in range(x.size - 1): triangles.append([ j * len(x) + i, (j + 1) * len(x) + i, (j + 1) * len(x) + i + 1 ]) triangles.append( [j * len(x) + i, j * len(x) + i + 1, (j + 1) * len(x) + i + 1]) checkerboard_mesh = Mesh(vertices, triangles, remove_duplicate_vertices=True) checkerboard_color_line1 = take( checkers_per_side * squares_per_checker * 2, cycle([0] * 2 * squares_per_checker + [0xffffff] * 2 * squares_per_checker)) * squares_per_checker checkerboard_color_line2 = take( checkers_per_side * squares_per_checker * 2, cycle([0xffffff] * 2 * squares_per_checker + [0] * 2 * squares_per_checker)) * squares_per_checker checkerboard_color = take( len(checkerboard_mesh.triangles), cycle(checkerboard_color_line1 + checkerboard_color_line2)) checkerboard_surface_line1 = take( checkers_per_side * squares_per_checker * 2, cycle([black_surface] * 2 * squares_per_checker + [lambertian_surface] * 2 * squares_per_checker)) * squares_per_checker checkerboard_surface_line2 = take( checkers_per_side * squares_per_checker * 2, cycle([lambertian_surface] * 2 * squares_per_checker + [black_surface] * 2 * squares_per_checker)) * squares_per_checker checkerboard_surface = take( len(checkerboard_mesh.triangles), cycle(checkerboard_surface_line1 + checkerboard_surface_line2)) checkerboard = Solid(checkerboard_mesh, vacuum, vacuum, surface=checkerboard_surface, color=checkerboard_color) sphere1 = Solid(sphere(1000.0, nsteps=512), water, vacuum) sphere2 = Solid(sphere(1000.0, nsteps=512), vacuum, vacuum, surface=shiny_surface) sphere3 = Solid(sphere(1000.0, nsteps=512), vacuum, vacuum, surface=lambertian_surface) checkerboard_scene = Geometry() checkerboard_scene.add_solid(checkerboard, displacement=(0, 0, -1500.0)) checkerboard_scene.add_solid(sphere1, displacement=(2000.0, -2000.0, 0)) checkerboard_scene.add_solid(sphere2, displacement=(-2000.0, -2000.0, 0)) checkerboard_scene.add_solid(sphere3, displacement=(0.0, 2000.0, 0)) return checkerboard_scene