def make_arrow(cyl_mesh, head_mesh, start_vec, end_vec, width, head_width, head_length, color): start_vec = np.array(start_vec) end_vec = np.array(end_vec) v = end_vec - start_vec l = np.sqrt(v.dot(v)) v_norm = v / l cyl_height = l - head_length z_rot = np.arccos(v_norm.dot(np.array([0.0, 1.0, 0.0]))) y_rot = np.arctan2(v[2], v[0]) cyl_center = start_vec + cyl_height / 2 * v_norm head_center = start_vec + (cyl_height + head_length / 2) * v_norm cyl_geom = pjs.CylinderGeometry(radiusTop=width, radiusBottom=width, height=cyl_height) cyl_mesh.geometry = cyl_geom cyl_mesh.material = pjs.MeshLambertMaterial(color=color) cyl_mesh.position = cyl_center.tolist() cyl_mesh.setRotationFromMatrix( [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]) cyl_mesh.rotateY(-y_rot) cyl_mesh.rotateZ(-z_rot) head_geom = pjs.CylinderGeometry(radiusTop=0.0, radiusBottom=head_width, height=head_length) head_mesh.geometry = head_geom head_mesh.material = pjs.MeshLambertMaterial(color=color) head_mesh.position = head_center.tolist() head_mesh.setRotationFromMatrix( [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]) head_mesh.rotateY(-y_rot) head_mesh.rotateZ(-z_rot)
def ghostMaterial(self, origMaterial, solidColor): name = self._mangledNameForMaterial(True, origMaterial) if name not in self.materials: args = {'transparent': True, 'opacity': 0.25} args.update( self._colorTexArgs( *self._extractMaterialDescriptors(origMaterial), solidColor)) if (self.isLineMesh): self.materials[name] = pythreejs.LineBasicMaterial( **args, **self.commonArgs) elif (self.isPointCloud): self.materials[name] = pythreejs.PointsMaterial( **args, **self.commonArgs, size=5, sizeAttenuation=False) else: self.materials[name] = pythreejs.MeshLambertMaterial( **args, **self.commonArgs) else: # Update the existing ghost material's color (if a solid color is used) useVertexColors, textureMapDataTex = self._extractMaterialDescriptors( origMaterial) if (useVertexColors == False) and (textureMapDataTex is None): self.materials[name].color = solidColor return self.materials[name]
def __init__(self, structure, modeDoF = None, eigenvalues = None, width=512, height=512, numSteps=8, amplitude = 0.05, normalize = True, wireframe = False): super().__init__(structure, width, height, wireframe=wireframe) self.normalize = normalize self.amplitude = amplitude self.layout = ipywidgets.VBox() self.controls_layout = ipywidgets.HBox() self.action = None # Note: numSteps cannot be changed because this requires changing the number of morph attributes self.numSteps = numSteps self.morphMaterial = pythreejs.MeshLambertMaterial(color='lightgray', side='DoubleSide', morphTargets = True) self.modeMesh = None self.wireframeAction = None # Infer the methods for getting/setting the object's deformed # configuration. This involves, e.g., `setVars` for # microstructures/inflatables, `setDoFs` for elastic rods, and # `setVertices` FEMMeshes. self.meshMethods = dir(self.mesh) self.numVars, self.varGetter, self.varSetter = None, None, None if ("getVars" in self.meshMethods): self.numVars, self.varGetter, self.varSetter = self.mesh.numVars(), self.mesh.getVars, self.mesh.setVars elif ("getDoFs" in self.meshMethods): self.numVars, self.varGetter, self.varSetter = self.mesh.numDoF (), self.mesh.getDoFs, self.mesh.setDoFs elif ("setVertices" in self.meshMethods): # Mesh version self.numVars = self.mesh.numNodes() * self.mesh.embeddingDimension self.varGetter = lambda: self.mesh.nodes().ravel() # Note: setVertices will ignore the excess edge nodes in degree 2 case since # we do not implement isoparametric FEM. self.varSetter = lambda x: self.mesh.setVertices(x.reshape(-1, self.mesh.embeddingDimension)); else: raise Exception("Unable to infer object's variable accessor interface") if (modeDoF is not None): self.setModes(modeDoF, eigenvalues=eigenvalues)
def draw_mesh(mesh, color=None): vertices, faces = mesh.to_vertices_and_faces() hexcolor = rgb_to_hex(color[:3]) if color else '#cccccc' vertexcolors = [hexcolor] * len(vertices) faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces] geo = p3js.Geometry(vertices=vertices, faces=faces) geo.exec_three_obj_method('computeFaceNormals') return p3js.Mesh(geometry=geo, material=p3js.MeshLambertMaterial(vertexColors='VertexColors'), position=[0, 0, 0])
def __init__(self, bead, color, **kwargs): super().__init__(geometry=three.SphereGeometry(radius=3, widthSegments=10, heightSegments=10), material=three.MeshLambertMaterial(color=color), position=bead.position.tolist(), **kwargs) self.bead = bead
def ghostMaterial(self, origMaterial): name = self._mangledNameForMaterial(True, origMaterial) if name not in self.materials: args = {'transparent': True, 'opacity': 0.25} args.update(self._colorTexArgs(*self._extractMaterialDescriptors(origMaterial), 'red')) if (self.isLineMesh): self.materials[name] = pythreejs. LineBasicMaterial(**args, **self.commonArgs) else: self.materials[name] = pythreejs.MeshLambertMaterial(**args, **self.commonArgs) return self.materials[name]
def material(self, useVertexColors, textureMapDataTex = None): name = self._mangledMaterialName(False, useVertexColors, textureMapDataTex) if name not in self.materials: if (self.isLineMesh): args = self._colorTexArgs(useVertexColors, textureMapDataTex, 'black') self.materials[name] = pythreejs.LineBasicMaterial(**args, **self.commonArgs) else: args = self._colorTexArgs(useVertexColors, textureMapDataTex, 'lightgray') self.materials[name] = pythreejs.MeshLambertMaterial(**args, **self.commonArgs) return self.materials[name]
def draw_mesh(mesh, hexcolor): mesh_quads_to_triangles(mesh) vertices, faces = mesh.to_vertices_and_faces() vertexcolors = [hexcolor] * len(vertices) faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces] geo = p3js.Geometry(vertices=vertices, faces=faces) geo.exec_three_obj_method('computeFaceNormals') return p3js.Mesh( geometry=geo, material=p3js.MeshLambertMaterial(vertexColors='VertexColors'), position=[0, 0, 0])
def render_mesh(mesh, up_vector=(0, 1, 0)): geometry = build_geometry( mesh.triangles, mesh.positions, normals=getattr(mesh, "normals", None), colors=getattr(mesh, "colors", None), ) if hasattr(mesh, "colors"): material = three.MeshLambertMaterial(vertexColors="VertexColors") else: material = three.MeshLambertMaterial() obj = three.Mesh( geometry=geometry, material=material, position=[0, 0, 0], ) center = np.array(mesh.positions).reshape(-1, 3).mean(axis=0) offset = 8 * np.array(mesh.positions).reshape(-1, 3).std(axis=0) return render_scene(Scene(eye_pos=center + offset, obj_pos=center, obj=obj, up=up_vector))
def __init__(self): # TODO: arguments for width/height self._width = 600 self._height = 400 self._ball = _three.Mesh( geometry=_three.SphereGeometry( radius=1, widthSegments=30, heightSegments=20, ), material=_three.MeshLambertMaterial(color='lightgray'), ) self._axes = _three.AxesHelper(size=1.2) self._ambient_light = _three.AmbientLight( intensity=0.5, ) self._directional_light1 = _three.DirectionalLight( position=[0, 0, 1], intensity=0.6, ) self._directional_light2 = _three.DirectionalLight( position=[0, 0, -1], intensity=0.6, ) self._scene = _three.Scene( children=[ self._ball, self._axes, self._ambient_light, self._directional_light1, self._directional_light2, ], ) self._camera = _three.PerspectiveCamera( position=[0, 0, 2.4], up=[0, 0, 1], aspect=self._width/self._height, ) self._controls = _three.OrbitControls(controlling=self._camera) self._renderer = _three.Renderer( camera=self._camera, scene=self._scene, controls=[self._controls], width=self._width, height=self._height, #alpha=True, #clearOpacity=0.5, )
def __initialize_mesh(self): drawable_geometry = self.__get_drawable_from_boundary() material = three.MeshLambertMaterial( polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, flatShading=True, color="white", opacity=1., transparent=False, side='DoubleSide', wireframe=False, vertexColors='FaceColors', ) return three.Mesh(geometry=drawable_geometry, material=material, position=[0, 0, 0])
def mesh(self): import numpy as np import pythreejs as js wireframe = self.view_data.get('wireframe', False) def triangles(polygon): points = polygon.points return [(points[0], points[ix], points[ix + 1]) for ix in range(1, len(polygon.points) - 1)] def _ba(vs): points = np.array(vs, dtype=np.float32) return js.BufferAttribute(array=points, normalized=False) vertices = [ list(p.xyz) for polygon in self.polygons for t in triangles(polygon) for p in t ] normals = [ list(polygon.plane.normal.xyz) for polygon in self.polygons for t in triangles(polygon) for p in t ] geometry = js.BufferGeometry( attributes={ 'position': _ba(vertices), 'normal': _ba(normals) }, ) if not wireframe: color = self.view_data.get('color', 'white') material = material=js.MeshLambertMaterial(color=color) opacity = self.view_data.get('opacity') if opacity is not None: material.opacity = opacity material.transparent = True return js.Mesh(geometry, material) else: color = self.view_data.get('color', '#00ff00') material = js.MeshBasicMaterial(color=color, wireframe=True) return js.Mesh(geometry, material)
def __initialize_mesh(self): drawable_geometry = self.__get_drawable_from_boundary() #No color under textures or materials if len(self.geometry.material) != 0 or self.geometry.texture is not None: vertexEnum = 'NoColors' else: vertexEnum = 'FaceColors' materials = [] #LambertMaterial is a material for non-shiny surfaces, without specular highlights. if len(self.geometry.material) == 0: #No material or texture material_geometry = three.MeshLambertMaterial( map = self.getTexture(self.texture), polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, flatShading = True, opacity = 1., transparent = False, side = 'DoubleSide', wireframe=False, vertexColors = vertexEnum) materials = material_geometry else: for m in self.geometry.material: if self.geometry.smoothness: material_geometry = three.MeshLambertMaterial( map=self.getTexture(self.geometry.material[m]["map_kd"]), color=self.color(self.geometry.material[m]["kd"]), emissiveIntensity=self.geometry.material[m]["ke"], specular=self.color(self.geometry.material[m]["ks"]), shininess=self.geometry.material[m]["ns"], transparence=self.geometry.material[m]["transparence"], opacity=self.geometry.material[m]["opacity"], emissiveMap=self.getTexture(self.geometry.material[m]["map_ke"]), alphaMap=self.getTexture(self.geometry.material[m]["map_d"]), specularMap=self.getTexture(self.geometry.material[m]["map_ks"]), bumpMap=self.getTexture(self.geometry.material[m]["bump"]), normalMap=self.getTexture(self.geometry.material[m]["norm"]), refractionRatio=self.geometry.material[m]["ni"] ) else: material_geometry = three.MeshPhongMaterial( map = self.getTexture(self.geometry.material[m]["map_kd"]), color = self.color(self.geometry.material[m]["kd"]), emissiveIntensity = self.geometry.material[m]["ke"], specular = self.color(self.geometry.material[m]["ks"]), shininess =self.geometry.material[m]["ns"], transparence = self.geometry.material[m]["transparence"], opacity = self.geometry.material[m]["opacity"], emissiveMap = self.getTexture(self.geometry.material[m]["map_ke"]), alphaMap = self.getTexture(self.geometry.material[m]["map_d"]), specularMap = self.getTexture(self.geometry.material[m]["map_ks"]), bumpMap = self.getTexture(self.geometry.material[m]["bump"]), normalMap = self.getTexture(self.geometry.material[m]["norm"]), refractionRatio = self.geometry.material[m]["ni"] ) materials.append(material_geometry) mesh1 = three.Mesh( geometry=drawable_geometry, material=materials, position=[0, 0, 0] ) return mesh1
def visualise(mesh, geometric_field, number_of_dimensions, xi_interpolation, dependent_field=None, variable=None, mechanics_animation=False, colour_map_dependent_component_number=None, cmap='gist_rainbow', resolution=1, node_labels=False): if number_of_dimensions != 3: print( 'Warning: Only visualisation of 3D meshes is currently supported.') return if xi_interpolation != [1, 1, 1]: print( 'Warning: Only visualisation of 3D elements with linear Lagrange \ interpolation along all coordinate directions is currently \ supported.') return view_width = 600 view_height = 600 debug = False if debug: vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] faces = [[0, 1, 3], [0, 3, 2], [0, 2, 4], [2, 6, 4], [0, 4, 1], [1, 4, 5], [2, 3, 6], [3, 7, 6], [1, 5, 3], [3, 5, 7], [4, 6, 5], [5, 6, 7]] vertexcolors = [ '#000000', '#0000ff', '#00ff00', '#ff0000', '#00ffff', '#ff00ff', '#ffff00', '#ffffff' ] else: # Get mesh topology information. num_nodes = mesh_tools.num_nodes_get(mesh, mesh_component=1) node_nums = list(range(1, num_nodes + 1)) num_elements, element_nums = mesh_tools.num_element_get( mesh, mesh_component=1) # Convert geometric field to a morphic mesh and export to json mesh = mesh_tools.OpenCMISS_to_morphic(mesh, geometric_field, element_nums, node_nums, dimension=3, interpolation='linear') vertices, faces, _, xi_element_nums, xis = get_faces( mesh, res=resolution, exterior_only=True, include_xi=True) vertices = vertices.tolist() faces = faces.tolist() centroid = np.mean(vertices, axis=0) max_positions = np.max(vertices, axis=0) min_positions = np.min(vertices, axis=0) range_positions = max_positions - min_positions if (dependent_field is not None) and (colour_map_dependent_component_number is not None): solution = np.zeros(xis.shape[0]) for idx, (xi, xi_element_num) in enumerate(zip(xis, xi_element_nums)): solution[idx] = mesh_tools.interpolate_opencmiss_field_xi( dependent_field, xi, element_ids=[xi_element_num], dimension=3, deriv=1)[colour_map_dependent_component_number - 1] minima = min(solution) maxima = max(solution) import matplotlib norm = matplotlib.colors.Normalize(vmin=minima, vmax=maxima, clip=True) mapper = cm.ScalarMappable(norm=norm, cmap=cm.get_cmap(name=cmap)) vertex_colors = np.zeros((len(vertices), 3), dtype='float32') for idx, v in enumerate(solution): vertex_colors[idx, :] = mapper.to_rgba(v, alpha=None)[:3] # else: # raise ValueError('Visualisation not supported.') else: vertex_colors = np.tile(np.array([0.5, 0.5, 0.5], dtype='float32'), (len(vertices), 1)) geometry = pjs.BufferGeometry(attributes=dict( position=pjs.BufferAttribute(vertices, normalized=False), index=pjs.BufferAttribute( np.array(faces).astype(dtype='uint16').ravel(), normalized=False), color=pjs.BufferAttribute(vertex_colors), )) if mechanics_animation: deformed_vertices = np.zeros((xis.shape[0], 3), dtype='float32') for idx, (xi, xi_element_num) in enumerate(zip(xis, xi_element_nums)): deformed_vertices[idx, :] = \ mesh_tools.interpolate_opencmiss_field_xi( dependent_field, xi, element_ids=[xi_element_num], dimension=3, deriv=1)[0][:3] geometry.morphAttributes = { 'position': [ pjs.BufferAttribute(deformed_vertices), ] } geometry.exec_three_obj_method('computeFaceNormals') geometry.exec_three_obj_method('computeVertexNormals') surf1 = pjs.Mesh(geometry, pjs.MeshPhongMaterial(color='#ff3333', shininess=150, morphTargets=True, side='FrontSide'), name='A') surf2 = pjs.Mesh(geometry, pjs.MeshPhongMaterial(color='#ff3333', shininess=150, morphTargets=True, side='BackSide'), name='B') surf = pjs.Group(children=[surf1, surf2]) # camera = pjs.PerspectiveCamera( # fov=20, position=[range_positions[0] * 10, # range_positions[1] * 10, # range_positions[2] * 10], # width=view_width, # height=view_height, near=1, # far=max(range_positions) * 10) camera = pjs.PerspectiveCamera(position=[ range_positions[0] * 3, range_positions[1] * 3, range_positions[2] * 3 ], aspect=view_width / view_height) camera.up = [0, 0, 1] camera.lookAt(centroid.tolist()) scene3 = pjs.Scene(children=[ surf1, surf2, camera, pjs.DirectionalLight(position=[3, 5, 1], intensity=0.6), pjs.AmbientLight(intensity=0.5) ]) axes = pjs.AxesHelper(size=range_positions[0] * 2) scene3.add(axes) A_track = pjs.NumberKeyframeTrack( name='scene/A.morphTargetInfluences[0]', times=[0, 3], values=[0, 1]) B_track = pjs.NumberKeyframeTrack( name='scene/B.morphTargetInfluences[0]', times=[0, 3], values=[0, 1]) pill_clip = pjs.AnimationClip(tracks=[A_track, B_track]) pill_action = pjs.AnimationAction(pjs.AnimationMixer(scene3), pill_clip, scene3) renderer3 = pjs.Renderer( camera=camera, scene=scene3, controls=[pjs.OrbitControls(controlling=camera)], width=view_width, height=view_height) display(renderer3, pill_action) else: geometry.exec_three_obj_method('computeFaceNormals') geometry.exec_three_obj_method('computeVertexNormals') surf1 = pjs.Mesh(geometry=geometry, material=pjs.MeshLambertMaterial( vertexColors='VertexColors', side='FrontSide')) # Center the cube. surf2 = pjs.Mesh(geometry=geometry, material=pjs.MeshLambertMaterial( vertexColors='VertexColors', side='BackSide')) # Center the cube. surf = pjs.Group(children=[surf1, surf2]) camera = pjs.PerspectiveCamera(position=[ range_positions[0] * 3, range_positions[1] * 3, range_positions[2] * 3 ], aspect=view_width / view_height) camera.up = [0, 0, 1] camera.lookAt(centroid.tolist()) # if perspective: # camera.mode = 'perspective' # else: # camera.mode = 'orthographic' lights = [ pjs.DirectionalLight(position=[ range_positions[0] * 16, range_positions[1] * 12, range_positions[2] * 17 ], intensity=0.5), pjs.AmbientLight(intensity=0.8), ] orbit = pjs.OrbitControls(controlling=camera, screenSpacePanning=True, target=centroid.tolist()) scene = pjs.Scene() axes = pjs.AxesHelper(size=max(range_positions) * 2) scene.add(axes) scene.add(surf1) scene.add(surf2) scene.add(lights) if node_labels: # Add text labels for each mesh node. v, ids = mesh.get_node_ids(group='_default') for idx, v in enumerate(v): text = make_text(str(ids[idx]), position=(v[0], v[1], v[2])) scene.add(text) # Add text for axes labels. x_axis_label = make_text('x', position=(max(range_positions) * 2, 0, 0)) y_axis_label = make_text('y', position=(0, max(range_positions) * 2, 0)) z_axis_label = make_text('z', position=(0, 0, max(range_positions) * 2)) scene.add(x_axis_label) scene.add(y_axis_label) scene.add(z_axis_label) renderer = pjs.Renderer(scene=scene, camera=camera, controls=[orbit], width=view_width, height=view_height) camera.zoom = 1 display(renderer) return vertices, faces
def _render_obj(self, rendered_obj, **kw): obj_geometry = pjs.BufferGeometry(attributes=dict( position=pjs.BufferAttribute(rendered_obj.plot_verts), color=pjs.BufferAttribute(rendered_obj.base_cols), normal=pjs.BufferAttribute( rendered_obj.face_normals.astype('float32')))) vertices = rendered_obj.vertices # Create a mesh. Note that the material need to be told to use the vertex colors. my_object_mesh = pjs.Mesh( geometry=obj_geometry, material=pjs.MeshLambertMaterial(vertexColors='VertexColors'), position=[0, 0, 0], ) line_material = pjs.LineBasicMaterial(color='#ffffff', transparent=True, opacity=0.3, linewidth=1.0) my_object_wireframe_mesh = pjs.LineSegments( geometry=obj_geometry, material=line_material, position=[0, 0, 0], ) n_vert = vertices.shape[0] center = vertices.mean(axis=0) extents = self._get_extents(vertices) max_delta = np.max(extents[:, 1] - extents[:, 0]) camPos = [center[i] + 4 * max_delta for i in range(3)] light_pos = [center[i] + (i + 3) * max_delta for i in range(3)] # Set up a scene and render it: camera = pjs.PerspectiveCamera(position=camPos, fov=20, children=[ pjs.DirectionalLight( color='#ffffff', position=light_pos, intensity=0.5) ]) camera.up = (0, 0, 1) v = [0.0, 0.0, 0.0] if n_vert > 0: v = vertices[0].tolist() select_point_geom = pjs.SphereGeometry(radius=1.0) select_point_mesh = pjs.Mesh( select_point_geom, material=pjs.MeshBasicMaterial(color=SELECTED_VERTEX_COLOR), position=v, scale=(0.0, 0.0, 0.0)) #select_edge_mesh = pjs.ArrowHelper(dir=pjs.Vector3(1.0, 0.0, 0.0), origin=pjs.Vector3(0.0, 0.0, 0.0), length=1.0, # hex=SELECTED_EDGE_COLOR_INT, headLength=0.1, headWidth=0.05) arrow_cyl_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.01), material=pjs.MeshLambertMaterial()) arrow_head_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.001), material=pjs.MeshLambertMaterial()) scene_things = [ my_object_mesh, my_object_wireframe_mesh, select_point_mesh, arrow_cyl_mesh, arrow_head_mesh, camera, pjs.AmbientLight(color='#888888') ] if self.draw_grids: grids, space = self._get_grids(vertices) scene_things.append(grids) scene = pjs.Scene(children=scene_things, background=BACKGROUND_COLOR) click_picker = pjs.Picker(controlling=my_object_mesh, event='dblclick') out = Output() top_msg = HTML() def on_dblclick(change): if change['name'] == 'point': try: point = np.array(change['new']) face = click_picker.faceIndex face_points = rendered_obj.face_verts[face] face_vecs = face_points - np.roll(face_points, 1, axis=0) edge_lens = np.sqrt((face_vecs**2).sum(axis=1)) point_vecs = face_points - point[np.newaxis, :] point_dists = (point_vecs**2).sum(axis=1) min_point = np.argmin(point_dists) v1s = point_vecs.copy() v2s = np.roll(v1s, -1, axis=0) edge_mids = 0.5 * (v2s + v1s) edge_mid_dists = (edge_mids**2).sum(axis=1) min_edge_point = np.argmin(edge_mid_dists) edge_start = min_edge_point edge = face * 3 + edge_start close_vert = rendered_obj.face_verts[face, min_point] edge_start_vert = rendered_obj.face_verts[face, edge_start] edge_end_vert = rendered_obj.face_verts[face, (edge_start + 1) % 3] vertex = face * 3 + min_point radius = min( [edge_lens.max() * 0.02, 0.1 * edge_lens.min()]) edge_head_length = radius * 4 edge_head_width = radius * 2 select_point_mesh.scale = (radius, radius, radius) top_msg.value = '<font color="{}">selected face: {}</font>, <font color="{}">edge: {}</font>, <font color="{}"> vertex: {}</font>'.format( SELECTED_FACE_COLOR, face, SELECTED_EDGE_COLOR, edge, SELECTED_VERTEX_COLOR, vertex) newcols = rendered_obj.base_cols.copy() newcols[face * 3:(face + 1) * 3] = np.array( SELECTED_FACE_RGB, dtype='float32') select_point_mesh.position = close_vert.tolist() obj_geometry.attributes['color'].array = newcols with out: make_arrow(arrow_cyl_mesh, arrow_head_mesh, edge_start_vert, edge_end_vert, radius / 2, radius, radius * 3, SELECTED_EDGE_COLOR) except: with out: print(traceback.format_exc()) click_picker.observe(on_dblclick, names=['point']) renderer_obj = pjs.Renderer( camera=camera, background='#cccc88', background_opacity=0, scene=scene, controls=[pjs.OrbitControls(controlling=camera), click_picker], width=self.width, height=self.height) display_things = [top_msg, renderer_obj, out] if self.draw_grids: s = """ <svg width="{}" height="30"> <rect width="20" height="20" x="{}" y="0" style="fill:none;stroke-width:1;stroke:rgb(0,255,0)" /> <text x="{}" y="15">={:.1f}</text> Sorry, your browser does not support inline SVG. </svg>""".format(self.width, self.width // 2, self.width // 2 + 25, space) display_things.append(HTML(s)) display(VBox(display_things))
def hand_obj_children( obj_verts=None, obj_faces=None, gt_obj_verts=None, gt_obj_faces=None, hand_verts=None, mano_faces_left=None, display_wireframe=False, inside_face_colors=True, hand_opacity=1, obj_opacity=0.2, ): """Args: obj_verts(numpy.ndarray): vertices of object hand_verts(numpy.ndarray): vertices of handect *_faces(numpy.ndarray): faces """ scene_children = [] if obj_verts is not None: geo_obj = p3js.Geometry(vertices=obj_verts.tolist(), faces=obj_faces.tolist()) geo_obj.exec_three_obj_method("computeFaceNormals") mat = p3js.MeshLambertMaterial(color="red", side="FrontSide", transparent=True) mat.opacity = obj_opacity # obj_opacity surf_obj = p3js.Mesh(geometry=geo_obj, material=mat) if inside_face_colors: back_color = "#a91818" else: back_color = "red" mat_bak = p3js.MeshLambertMaterial(color=back_color, side="BackSide", transparent=True) mat_bak.opacity = obj_opacity surf_obj_back = p3js.Mesh(geometry=geo_obj, material=mat_bak) scene_children.append(surf_obj) scene_children.append(surf_obj_back) if display_wireframe: obj_edges = p3js.Mesh( geometry=geo_obj, material=p3js.MeshBasicMaterial(color="black", wireframe=True), ) scene_children.append(obj_edges) if gt_obj_verts is not None: geo_obj = p3js.Geometry(vertices=gt_obj_verts.tolist(), faces=gt_obj_faces.tolist()) geo_obj.exec_three_obj_method("computeFaceNormals") mat = p3js.MeshLambertMaterial(color="orange", side="FrontSide", transparent=True) mat.opacity = obj_opacity surf_obj = p3js.Mesh(geometry=geo_obj, material=mat) mat_back = p3js.MeshLambertMaterial(color="#a91818", side="BackSide", transparent=True) mat_back.opacity = obj_opacity surf_obj_back = p3js.Mesh(geometry=geo_obj, material=mat_bak) scene_children.append(surf_obj) scene_children.append(surf_obj_back) if display_wireframe: obj_edges = p3js.Mesh( geometry=geo_obj, material=p3js.MeshBasicMaterial(color="black", wireframe=True), ) scene_children.append(obj_edges) if hand_verts is not None: geo_hand = p3js.Geometry(vertices=hand_verts.tolist(), faces=mano_faces_left.tolist()) geo_hand.exec_three_obj_method("computeFaceNormals") mat = p3js.MeshLambertMaterial(color="blue", side="FrontSide", transparent=True) mat.opacity = hand_opacity surf_hand = p3js.Mesh(geometry=geo_hand, material=mat) bak_mat = p3js.MeshLambertMaterial(color="blue", side="BackSide", transparent=True) bak_mat.opacity = hand_opacity surf_hand_bak = p3js.Mesh(geometry=geo_hand, material=bak_mat) scene_children.append(surf_hand) scene_children.append(surf_hand_bak) if display_wireframe: hand_edges = p3js.Mesh( geometry=geo_hand, material=p3js.MeshBasicMaterial(color="black", wireframe=True), ) scene_children.append(hand_edges) return scene_children
def _render_stl(self, stl_file): vertices, faces = self._conv_stl(stl_file) # Map the vertex colors into the 'color' slot of the faces faces = [f + [None, [OBJ_COLOR for i in f], None] for f in faces] # Create the geometry: obj_geometry = pjs.Geometry(vertices=vertices, faces=faces, colors=[OBJ_COLOR] * len(vertices)) # Calculate normals per face, for nice crisp edges: obj_geometry.exec_three_obj_method('computeFaceNormals') # Create a mesh. Note that the material need to be told to use the vertex colors. my_object_mesh = pjs.Mesh( geometry=obj_geometry, material=pjs.MeshLambertMaterial(vertexColors='VertexColors'), position=[0, 0, 0], # Center the cube ) n_vert = len(vertices) center = [ sum([vertex[i] for vertex in vertices]) / float(n_vert) for i in range(3) ] extents = self._get_extents(vertices) max_delta = max([extent[1] - extent[0] for extent in extents]) camPos = [center[i] + 4 * max_delta for i in range(3)] light_pos = [center[i] + (i + 3) * max_delta for i in range(3)] # Set up a scene and render it: camera = pjs.PerspectiveCamera(position=camPos, fov=20, children=[ pjs.DirectionalLight( color='#ffffff', position=light_pos, intensity=0.5) ]) camera.up = (0, 0, 1) scene_things = [ my_object_mesh, camera, pjs.AmbientLight(color='#888888') ] if self.draw_grids: grids, space = self._get_grids(vertices) scene_things.append(grids) scene = pjs.Scene(children=scene_things, background=BACKGROUND_COLOR) renderer_obj = pjs.Renderer( camera=camera, background='#cccc88', background_opacity=0, scene=scene, controls=[pjs.OrbitControls(controlling=camera)], width=self.width, height=self.height) display_things = [renderer_obj] if self.draw_grids: s = """ <svg width="{}" height="30"> <rect width="20" height="20" x="{}" y="0" style="fill:none;stroke-width:1;stroke:rgb(0,255,0)" /> <text x="{}" y="15">={:.1f}</text> Sorry, your browser does not support inline SVG. </svg>""".format(self.width, self.width // 2, self.width // 2 + 25, space) display_things.append(HTML(s)) display(*display_things)
def material_from_color(color=None): if color: return p3js.MeshLambertMaterial(color=color) else: return p3js.MeshLambertMaterial(color='#cccccc')
def generate_3js_render( element_groups, canvas_size, zoom, camera_fov=30, background_color="white", background_opacity=1.0, reuse_objects=False, use_atom_arrays=False, use_label_arrays=False, ): """Create a pythreejs scene of the elements. Regarding initialisation performance, see: https://github.com/jupyter-widgets/pythreejs/issues/154 """ import pythreejs as pjs key_elements = {} group_elements = pjs.Group() key_elements["group_elements"] = group_elements unique_atom_sets = {} for el in element_groups["atoms"]: element_hash = ( ("radius", el.sradius), ("color", el.color), ("fill_opacity", el.fill_opacity), ("stroke_color", el.get("stroke_color", "black")), ("ghost", el.ghost), ) unique_atom_sets.setdefault(element_hash, []).append(el) group_atoms = pjs.Group() group_ghosts = pjs.Group() atom_geometries = {} atom_materials = {} outline_materials = {} for el_hash, els in unique_atom_sets.items(): el = els[0] data = dict(el_hash) if reuse_objects: atom_geometry = atom_geometries.setdefault( el.sradius, pjs.SphereBufferGeometry(radius=el.sradius, widthSegments=30, heightSegments=30), ) else: atom_geometry = pjs.SphereBufferGeometry(radius=el.sradius, widthSegments=30, heightSegments=30) if reuse_objects: atom_material = atom_materials.setdefault( (el.color, el.fill_opacity), pjs.MeshLambertMaterial(color=el.color, transparent=True, opacity=el.fill_opacity), ) else: atom_material = pjs.MeshLambertMaterial(color=el.color, transparent=True, opacity=el.fill_opacity) if use_atom_arrays: atom_mesh = pjs.Mesh(geometry=atom_geometry, material=atom_material) atom_array = pjs.CloneArray( original=atom_mesh, positions=[e.position.tolist() for e in els], merge=False, ) else: atom_array = [ pjs.Mesh( geometry=atom_geometry, material=atom_material, position=e.position.tolist(), name=e.info_string, ) for e in els ] data["geometry"] = atom_geometry data["material_body"] = atom_material if el.ghost: key_elements["group_ghosts"] = group_ghosts group_ghosts.add(atom_array) else: key_elements["group_atoms"] = group_atoms group_atoms.add(atom_array) if el.get("stroke_width", 1) > 0: if reuse_objects: outline_material = outline_materials.setdefault( el.get("stroke_color", "black"), pjs.MeshBasicMaterial( color=el.get("stroke_color", "black"), side="BackSide", transparent=True, opacity=el.get("stroke_opacity", 1.0), ), ) else: outline_material = pjs.MeshBasicMaterial( color=el.get("stroke_color", "black"), side="BackSide", transparent=True, opacity=el.get("stroke_opacity", 1.0), ) # TODO use stroke width to dictate scale if use_atom_arrays: outline_mesh = pjs.Mesh( geometry=atom_geometry, material=outline_material, scale=(1.05, 1.05, 1.05), ) outline_array = pjs.CloneArray( original=outline_mesh, positions=[e.position.tolist() for e in els], merge=False, ) else: outline_array = [ pjs.Mesh( geometry=atom_geometry, material=outline_material, position=e.position.tolist(), scale=(1.05, 1.05, 1.05), ) for e in els ] data["material_outline"] = outline_material if el.ghost: group_ghosts.add(outline_array) else: group_atoms.add(outline_array) key_elements.setdefault("atom_arrays", []).append(data) group_elements.add(group_atoms) group_elements.add(group_ghosts) group_labels = add_labels(element_groups, key_elements, use_label_arrays) group_elements.add(group_labels) if len(element_groups["cell_lines"]) > 0: cell_line_mat = pjs.LineMaterial( linewidth=1, color=element_groups["cell_lines"].group_properties["color"]) cell_line_geo = pjs.LineSegmentsGeometry(positions=[ el.position.tolist() for el in element_groups["cell_lines"] ]) cell_lines = pjs.LineSegments2(geometry=cell_line_geo, material=cell_line_mat) key_elements["cell_lines"] = cell_lines group_elements.add(cell_lines) if len(element_groups["bond_lines"]) > 0: bond_line_mat = pjs.LineMaterial( linewidth=element_groups["bond_lines"]. group_properties["stroke_width"], vertexColors="VertexColors", ) bond_line_geo = pjs.LineSegmentsGeometry( positions=[ el.position.tolist() for el in element_groups["bond_lines"] ], colors=[[Color(c).rgb for c in el.color] for el in element_groups["bond_lines"]], ) bond_lines = pjs.LineSegments2(geometry=bond_line_geo, material=bond_line_mat) key_elements["bond_lines"] = bond_lines group_elements.add(bond_lines) group_millers = pjs.Group() if len(element_groups["miller_lines"]) or len( element_groups["miller_planes"]): key_elements["group_millers"] = group_millers if len(element_groups["miller_lines"]) > 0: miller_line_mat = pjs.LineMaterial( linewidth=3, vertexColors="VertexColors" # TODO use stroke_width ) miller_line_geo = pjs.LineSegmentsGeometry( positions=[ el.position.tolist() for el in element_groups["miller_lines"] ], colors=[[Color(el.stroke_color).rgb] * 2 for el in element_groups["miller_lines"]], ) miller_lines = pjs.LineSegments2(geometry=miller_line_geo, material=miller_line_mat) group_millers.add(miller_lines) for el in element_groups["miller_planes"]: vertices = el.position.tolist() faces = [( 0, 1, 2, triangle_normal(vertices[0], vertices[1], vertices[2]), "black", 0, )] if len(vertices) == 4: faces.append(( 2, 3, 0, triangle_normal(vertices[2], vertices[3], vertices[0]), "black", 0, )) elif len(vertices) != 3: raise NotImplementedError("polygons with more than 4 points") plane_geom = pjs.Geometry(vertices=vertices, faces=faces) plane_mat = pjs.MeshBasicMaterial( color=el.fill_color, transparent=True, opacity=el.fill_opacity, side="DoubleSide", ) plane_mesh = pjs.Mesh(geometry=plane_geom, material=plane_mat) group_millers.add(plane_mesh) group_elements.add(group_millers) scene = pjs.Scene(background=None) scene.add([group_elements]) view_width, view_height = canvas_size minp, maxp = element_groups.get_position_range() # compute a minimum camera distance, that is guaranteed to encapsulate all elements camera_dist = maxp[2] + sqrt(maxp[0]**2 + maxp[1]**2) / tan( radians(camera_fov / 2)) camera = pjs.PerspectiveCamera( fov=camera_fov, position=[0, 0, camera_dist], aspect=view_width / view_height, zoom=zoom, ) scene.add([camera]) ambient_light = pjs.AmbientLight(color="lightgray") key_elements["ambient_light"] = ambient_light direct_light = pjs.DirectionalLight(position=(maxp * 2).tolist()) key_elements["direct_light"] = direct_light scene.add([camera, ambient_light, direct_light]) camera_control = pjs.OrbitControls(controlling=camera, screenSpacePanning=True) atom_picker = pjs.Picker(controlling=group_atoms, event="dblclick") key_elements["atom_picker"] = atom_picker material = pjs.SpriteMaterial( map=create_arrow_texture(right=False), transparent=True, depthWrite=False, depthTest=False, ) atom_pointer = pjs.Sprite(material=material, scale=(4, 3, 1), visible=False) scene.add(atom_pointer) key_elements["atom_pointer"] = atom_pointer renderer = pjs.Renderer( camera=camera, scene=scene, controls=[camera_control, atom_picker], width=view_width, height=view_height, alpha=True, clearOpacity=background_opacity, clearColor=background_color, ) return renderer, key_elements