def occ_shape_to_threejs(self, shp: TopoDS_Shape, shape_color, edge_color, transparency, opacity): # first, compute the tesselation from .renderer_occ import occ_shape_to_faces from .threejs_utils import create_material np_vertices, np_faces, np_normals, edges = occ_shape_to_faces( shp, self.quality, self.render_edges, self.parallel) # set geometry properties buffer_geometry_properties = { "position": BufferAttribute(np_vertices), "index": BufferAttribute(np_faces), } if self.compute_normals_mode == NORMAL.SERVER_SIDE: if np_normals.shape != np_vertices.shape: raise AssertionError("Wrong number of normals/shapes") buffer_geometry_properties["normal"] = BufferAttribute(np_normals) # build a BufferGeometry instance shape_geometry = BufferGeometry(attributes=buffer_geometry_properties) # if the client has to render normals, add the related js instructions if self.compute_normals_mode == NORMAL.CLIENT_SIDE: shape_geometry.exec_three_obj_method("computeVertexNormals") # then a default material shp_material = create_material(shape_color, transparent=transparency, opacity=opacity) # and to the dict of shapes, to have a mapping between meshes and shapes mesh_id = "%s" % uuid.uuid4().hex self.mesh_id = mesh_id # finally create the mesh shape_mesh = Mesh(geometry=shape_geometry, material=shp_material, name=mesh_id) # edge rendering, if set to True if self.render_edges: edge_list = flatten(list(map(explode, edges))) lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial(linewidth=1, color=edge_color) edge_lines = LineSegments2(lines, mat, name=mesh_id) else: edge_lines = None return shape_mesh, edge_lines
def AddShapeToScene( self, shp, shape_color=None, # the default render_edges=False, edge_color=None, vertex_color=None, quality=1.0, transparency=False, opacity=1.0, ): # first, compute the tesselation tess = ShapeTesselator(shp) tess.Compute(compute_edges=render_edges, mesh_quality=quality, parallel=True) # get vertices and normals vertices_position = tess.GetVerticesPositionAsTuple() number_of_triangles = tess.ObjGetTriangleCount() number_of_vertices = len(vertices_position) # number of vertices should be a multiple of 3 if number_of_vertices % 3 != 0: raise AssertionError("Wrong number of vertices") if number_of_triangles * 9 != number_of_vertices: raise AssertionError("Wrong number of triangles") # then we build the vertex and faces collections as numpy ndarrays np_vertices = np.array(vertices_position, dtype="float32").reshape( int(number_of_vertices / 3), 3) # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used np_faces = np.arange(np_vertices.shape[0], dtype="uint32") # set geometry properties buffer_geometry_properties = { "position": BufferAttribute(np_vertices), "index": BufferAttribute(np_faces), } if self._compute_normals_mode == NORMAL.SERVER_SIDE: # get the normal list, converts to a numpy ndarray. This should not raise # any issue, since normals have been computed by the server, and are available # as a list of floats np_normals = np.array(tess.GetNormalsAsTuple(), dtype="float32").reshape(-1, 3) # quick check if np_normals.shape != np_vertices.shape: raise AssertionError("Wrong number of normals/shapes") buffer_geometry_properties["normal"] = BufferAttribute(np_normals) # build a BufferGeometry instance shape_geometry = BufferGeometry(attributes=buffer_geometry_properties) # if the client has to render normals, add the related js instructions if self._compute_normals_mode == NORMAL.CLIENT_SIDE: shape_geometry.exec_three_obj_method("computeVertexNormals") # then a default material shp_material = self._material(shape_color, transparent=transparency, opacity=opacity) # and to the dict of shapes, to have a mapping between meshes and shapes mesh_id = "%s" % uuid.uuid4().hex self._shapes[mesh_id] = shp # finally create the mesh shape_mesh = Mesh(geometry=shape_geometry, material=shp_material, name=mesh_id) # edge rendering, if set to True if render_edges: edges = list( map( lambda i_edge: [ tess.GetEdgeVertex(i_edge, i_vert) for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge)) ], range(tess.ObjGetEdgeCount()), )) edge_list = _flatten(list(map(_explode, edges))) lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial(linewidth=1, color=edge_color) edge_lines = LineSegments2(lines, mat, name=mesh_id) self._displayed_non_pickable_objects.add(edge_lines) return shape_mesh
def AddShapeToScene(self, shp, # the TopoDS_Shape to be displayed shape_color=default_shape_color, # the default render_edges=False, edge_color=default_edge_color, compute_uv_coords=False, quality=1.0, transparency=False, opacity=1.): # first, compute the tesselation tess = Tesselator(shp) tess.Compute(uv_coords=compute_uv_coords, compute_edges=render_edges, mesh_quality=quality, parallel=self._parallel) # get vertices and normals vertices_position = tess.GetVerticesPositionAsTuple() number_of_triangles = tess.ObjGetTriangleCount() number_of_vertices = len(vertices_position) # number of vertices should be a multiple of 3 if number_of_vertices % 3 != 0: raise AssertionError("Wrong number of vertices") if number_of_triangles * 9 != number_of_vertices: raise AssertionError("Wrong number of triangles") # then we build the vertex and faces collections as numpy ndarrays np_vertices = np.array(vertices_position, dtype='float32').reshape(int(number_of_vertices / 3), 3) # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used np_faces = np.arange(np_vertices.shape[0], dtype='uint32') # set geometry properties buffer_geometry_properties = {'position': BufferAttribute(np_vertices), 'index' : BufferAttribute(np_faces)} if self._compute_normals_mode == NORMAL.SERVER_SIDE: # get the normal list, converts to a numpy ndarray. This should not raise # any issue, since normals have been computed by the server, and are available # as a list of floats np_normals = np.array(tess.GetNormalsAsTuple(), dtype='float32').reshape(-1, 3) # quick check if np_normals.shape != np_vertices.shape: raise AssertionError("Wrong number of normals/shapes") buffer_geometry_properties['normal'] = BufferAttribute(np_normals) # build a BufferGeometry instance shape_geometry = BufferGeometry(attributes=buffer_geometry_properties) # if the client has to render normals, add the related js instructions if self._compute_normals_mode == NORMAL.CLIENT_SIDE: shape_geometry.exec_three_obj_method('computeVertexNormals') # then a default material shp_material = self._material(shape_color, transparent=transparency, opacity=opacity) # create a mesh unique id mesh_id = uuid.uuid4().hex # finally create the mash shape_mesh = Mesh(geometry=shape_geometry, material=shp_material, name=mesh_id) # and to the dict of shapes, to have a mapping between meshes and shapes self._shapes[mesh_id] = shp # edge rendering, if set to True edge_lines = None if render_edges: edges = list(map(lambda i_edge: [tess.GetEdgeVertex(i_edge, i_vert) for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge))], range(tess.ObjGetEdgeCount()))) edges = list(filter(lambda edge: len(edge) == 2, edges)) np_edge_vertices = np.array(edges, dtype=np.float32).reshape(-1, 3) np_edge_indices = np.arange(np_edge_vertices.shape[0], dtype=np.uint32) edge_geometry = BufferGeometry(attributes={ 'position': BufferAttribute(np_edge_vertices), 'index' : BufferAttribute(np_edge_indices) }) edge_material = LineBasicMaterial(color=edge_color, linewidth=1) edge_lines = LineSegments(geometry=edge_geometry, material=edge_material) # Add geometries to pickable or non pickable objects self._displayed_pickable_objects.add(shape_mesh) if render_edges: self._displayed_non_pickable_objects.add(edge_lines)
def DisplayMesh(self, mesh, color=default_mesh_color): """ Display a MEFISTO2 triangle mesh """ if not HAVE_SMESH: print("SMESH not installed, DisplayMesh method unavailable.") return if not isinstance(mesh, SMESH_Mesh): raise AssertionError("You mush provide an SMESH_Mesh instance") mesh_ds = mesh.GetMeshDS() # the mesh data source face_iter = mesh_ds.facesIterator() # vertices positions are stored to a liste vertices_position = [] for _ in range(mesh_ds.NbFaces()-1): face = face_iter.next() #print('Face %i, type %i' % (i, face.GetType())) #print(dir(face)) # if face.GetType == 3 : triangle mesh, then 3 nodes for j in range(3): node = face.GetNode(j) #print('Coordinates of node %i:(%f,%f,%f)'%(i, node.X(), node.Y(), node.Z())) vertices_position.append(node.X()) vertices_position.append(node.Y()) vertices_position.append(node.Z()) number_of_vertices = len(vertices_position) # then we build the vertex and faces collections as numpy ndarrays np_vertices = np.array(vertices_position, dtype='float32').reshape(int(number_of_vertices / 3), 3) # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used np_faces = np.arange(np_vertices.shape[0], dtype='uint32') # set geometry properties buffer_geometry_properties = {'position': BufferAttribute(np_vertices), 'index' : BufferAttribute(np_faces)} # build a BufferGeometry instance mesh_geometry = BufferGeometry(attributes=buffer_geometry_properties) mesh_geometry.exec_three_obj_method('computeVertexNormals') # then a default material mesh_material = MeshPhongMaterial(color=color, polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.5, wireframe=False, side='DoubleSide') edges_material = MeshPhongMaterial(color='black', polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.5, wireframe=True) # create a mesh unique id mesh_id = uuid.uuid4().hex # finally create the mash shape_mesh = Mesh(geometry=mesh_geometry, material=mesh_material, name=mesh_id) edges_mesh = Mesh(geometry=mesh_geometry, material=edges_material, name=mesh_id) # a special display for the mesh camera_target = [0., 0., 0.] # the point to look at camera_position = [0, 0., 100.] # the camera initial position camera = PerspectiveCamera(position=camera_position, lookAt=camera_target, up=[0, 0, 1], fov=50, children=[DirectionalLight(color='#ffffff', position=[50, 50, 50], intensity=0.9)]) scene_shp = Scene(children=[shape_mesh, edges_mesh, camera, AmbientLight(color='#101010')]) renderer = Renderer(camera=camera, background=self._background, background_opacity=self._background_opacity, scene=scene_shp, controls=[OrbitControls(controlling=camera, target=camera_target)], width=self._size[0], height=self._size[1], antialias=True) display(renderer)
def __init__(self, mesh: trimesh.Trimesh = None, obj: str = None, normalize: bool =False, color: Union[str,ColorRGB] ="#00bbee", alpha: float=1., transform: Union[Callable, None] = None, *args, **kwargs ): """ Add a mesh to the scene. Arguments: mesh: Mesh object, with attributes verticies, faces obj: object filename normalize : Normalize the coordinates of the vertices to be between -1 and 1 color: Color for the mesh alpha: transparency of the mesh transform: a function to transform the vertices """ if mesh is not None and obj is not None: raise ValueError('Received both mesh and obj') if isinstance(mesh, str): # perhaps this is a filename? try: mesh = trimesh.load(args[0]) except Exception as e: raise ValueError( "Did not understand arguments to method Figure#mesh" ) from e if isinstance(obj, np.ndarray): obj_data = obj elif isinstance(obj, list): obj_data = np.asarray(obj) # Do something with this obj_data? elif isinstance(obj, str): if "\n" in obj: # this is the file contents. raise NotImplementedError() else: try: # open the mesh file mesh = trimesh.load(obj) except Exception as e: raise ValueError("Could not read file as OBJ") from e assert hasattr(mesh, "vertices") and hasattr(mesh, "faces"), "Invalid mesh object" if mesh is None: raise ValueError("Could not understand how to parse mesh.") if transform is None: transform = lambda x: x verts = transform(mesh.vertices) faces = mesh.faces if normalize: # Normalize the vertex indices to be between -1,1 # Shifting these does change the coordinate system, # so visualizing multiple meshes won't work verts[:, 0] = _normalize_shift(verts[:, 0]) verts[:, 1] = _normalize_shift(verts[:, 1]) verts[:, 2] = _normalize_shift(verts[:, 2]) geo = BufferGeometry( attributes={ "position": BufferAttribute( array=verts.astype("float32"), normalized=False, # dtype=np.float64 ), "index": BufferAttribute( array=faces.astype("uint64").ravel(), normalized=False, # dtype=np.float64, ), } ) self._coords = verts transparent = alpha != 1. mat = MeshLambertMaterial(color=color, opacity=alpha, transparent=transparent) mesh = Mesh(geometry=geo, material=mat) geo.exec_three_obj_method("computeVertexNormals") super().__init__(*args, **kwargs) self._objects.append(mesh)