def __init__(self, bb_center, length=1, width=3): super().__init__(bb_center) self.axes = [] for vector, color in zip(([length, 0, 0], [0, length, 0], [0, 0, length]), ('red', 'green', 'blue')): self.axes.append( LineSegments2( LineSegmentsGeometry(positions=[[self.center, self._shift(self.center, vector)]]), LineMaterial(linewidth=width, color=color)))
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 _get_line_from_vec(v0, v1, scene_args): """ Draw the line given the two endpoints, some Three.js capabilities still don't work well in pythreejs (unable to update linewidth and such) LineSegments2 is the only one that has been tested successfully, but it cannot handle LineDashedMaterial :param v0: list, one endpoint of line :param v1: list, other endpoint of line :param scene_args: dict, properties of the line (line_width and color) :return: pythreejs object that displays the line segment """ obj_args = update_object_args(scene_args, "Lines", ["linewidth", "color"]) logger.debug(obj_args) line = LineSegments2( LineSegmentsGeometry(positions=[[v0, v1]]), LineMaterial(**obj_args), # Dashed lines do not work in pythreejs yet ) return line
def _get_line_from_vec(v0, v1, d_args): """Draw the line given the two endpoints, some threejs functionalities still don't work well in pythreejs (unable to update linewidth and such) LineSegments2 is the onlyone that has tested sucessfully but it cannot handle LineDashedMaterial Args: v0 (list): one endpoint of line v1 (list): other endpoint of line d_args (dict): properties of the line (line_width and color) Returns: LineSegments2: Pythreejs object that displays the line sement """ obj_args = update_object_args(d_args, "Lines", ['linewidth', 'color']) logger.debug(obj_args) line = LineSegments2( LineSegmentsGeometry(positions=[[v0, v1]]), LineMaterial(**obj_args), # Dashed lines do not work in pythreejs yet ) return line
def __init__(self, lines: Iterable[Edge], colors: Union[Iterable[Tuple[Coord3, ColorRGB]], Iterable[ColorRGB], ColorRGB, None] = None, width:int = 10, *args, **kwargs): """ Plots a series of line segments. Arguments: lines: Iterable of (u,v), where u,v are 3 tuples of float coordinates. Lines are drawn between each u and v. colors: Either * An iterable of (u,c), where u is a coordinate, and c is a color. * a list of c (3coord, RGB), the same length as lines * single 3 tuple (RGB) applied to all lines """ super().__init__(layer_name='lines',*args, **kwargs) if isinstance(colors, tuple): color = colors colors = None else: color = [0,0,0] colors = colors if (not colors is None) else [color for _ in lines] colors = np.array([c if len(c) == 2 else [c, c] for c in colors],dtype=np.float32) coords = [] for uv in lines: coords.extend(uv) self._coords = np.array(coords) geo = LineSegmentsGeometry( positions=np.array(lines,dtype=np.float32), colors=colors, ) mat = LineMaterial(linewidth=width, vertexColors="VertexColors") self._objects.append(LineSegments2(geo, mat))
def __init__(self, bb_center, length=1, width=3, display_labels=False): Helpers.__init__(self, bb_center) self.axes = [] for vector, color in zip( ([length, 0, 0], [0, length, 0], [0, 0, length]), ('red', 'green', 'blue')): self.axes.append( LineSegments2( LineSegmentsGeometry( positions=[[self.center, _shift(self.center, vector)]]), LineMaterial(linewidth=width, color=color))) if display_labels: # add x, y and z labels x_text = make_text("X", [length, 0, 0]) y_text = make_text("Y", [0, length, 0]) z_text = make_text("Z", [0, 0, length]) self.axes.append(x_text) self.axes.append(y_text) self.axes.append(z_text)
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 _get_line_from_vec(v0, v1): line = LineSegments2( LineSegmentsGeometry(positions=[[v0, v1]]), LineMaterial(linewidth=3, color="black"), ) return line
def _render_shape(self, shape_index, shape=None, edges=None, vertices=None, mesh_color=None, edge_color=None, vertex_color=None, render_edges=False, edge_width=1, vertex_width=5, deflection=0.05, transparent=False, opacity=1.0): edge_list = None edge_lines = None points = None shape_mesh = None if shape is not None: if mesh_color is None: mesh_color = self.default_mesh_color if edge_color is None: edge_color = self.default_edge_color if vertex_color is None: vertex_color = self.default_edge_color # same as edge_color # BEGIN copy # The next lines are copied with light modifications from # https://github.com/tpaviot/pythonocc-core/blob/master/src/Display/WebGl/jupyter_renderer.py # first, compute the tesselation tess = Tesselator(shape) tess.Compute(uv_coords=False, compute_edges=render_edges, mesh_quality=self.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') # compute normals np_normals = np.array(tess.GetNormalsAsTuple(), dtype='float32').reshape(-1, 3) if np_normals.shape != np_vertices.shape: raise AssertionError("Wrong number of normals/shapes") # build a BufferGeometry instance shape_geometry = BufferGeometry( attributes={ 'position': BufferAttribute(np_vertices), 'index': BufferAttribute(np_faces), 'normal': BufferAttribute(np_normals) }) shp_material = self._material(mesh_color, transparent=True, opacity=opacity) shape_mesh = Mesh(geometry=shape_geometry, material=shp_material, name="mesh_%d" % shape_index) if render_edges: edge_list = list( map( lambda i_edge: [ tess.GetEdgeVertex(i_edge, i_vert) for i_vert in range( tess.ObjEdgeGetVertexCount(i_edge)) ], range(tess.ObjGetEdgeCount()))) # END copy if vertices is not None: vertices_list = [] for vertex in vertices: p = BRep_Tool.Pnt(vertex) vertices_list.append((p.X(), p.Y(), p.Z())) vertices_list = np.array(vertices_list, dtype=np.float32) attributes = { "position": BufferAttribute(vertices_list, normalized=False) } mat = PointsMaterial(color=vertex_color, sizeAttenuation=False, size=vertex_width) geom = BufferGeometry(attributes=attributes) points = Points(geometry=geom, material=mat) if edges is not None: edge_list = [discretize_edge(edge, deflection) for edge in edges] if edge_list is not None: edge_list = _flatten(list(map(_explode, edge_list))) lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial(linewidth=edge_width, color=edge_color) edge_lines = LineSegments2(lines, mat, name="edges_%d" % shape_index) if shape_mesh is not None or edge_lines is not None or points is not None: index_mapping = {"mesh": None, "edges": None, "shape": shape_index} if shape_mesh is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(shape_mesh) index_mapping["mesh"] = ind if edge_lines is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(edge_lines) index_mapping["edges"] = ind if points is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(points) index_mapping["mesh"] = ind self.pick_mapping.append(index_mapping)
def _render_shape( self, shape=None, edges=None, vertices=None, mesh_color=None, edge_color=None, vertex_color=None, edge_width=1, vertex_width=5, transparent=False, opacity=1.0, ): edge_list = [] normals_list = [] edge_lines = [] normal_lines = [] points = None shape_mesh = None # edge_accuracy = None if shape is not None: # Compute the tesselation and build mesh with Timer(self.timeit, "", "build mesh:", 5): edge_list, normals_list = shape["edges"] shape_geometry = BufferGeometry( attributes={ "position": BufferAttribute(shape["vertices"]), "index": BufferAttribute(shape["triangles"]), "normal": BufferAttribute(shape["normals"]), } ) if mesh_color is None: mesh_color = self.default_mesh_color shp_material = material(mesh_color, transparent=transparent, opacity=opacity) shape_mesh = IndexedMesh(geometry=shape_geometry, material=shp_material) if vertices is not None: if vertex_color is None: vertex_color = self.default_edge_color # same as edge_color vertices_list = vertices attributes = {"position": BufferAttribute(vertices_list, normalized=False)} mat = PointsMaterial(color=vertex_color, sizeAttenuation=False, size=vertex_width) geom = BufferGeometry(attributes=attributes) points = IndexedPoints(geometry=geom, material=mat) if edges is not None: edge_list = edges if len(edge_list) > 0: if edge_color is None: edge_color = self.default_edge_color if isinstance(edge_color, (list, tuple)): if len(edge_list) != len(edge_color): print("warning: color list and edge list have different length, using first color for all edges") edge_color = edge_color[0] if isinstance(edge_color, (list, tuple)): lines = LineSegmentsGeometry( positions=edge_list, colors=[[Color(color).percentage] * 2 for color in edge_color], ) mat = LineMaterial(linewidth=edge_width, vertexColors="VertexColors") edge_lines = [IndexedLineSegments2(lines, mat)] else: lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial( linewidth=edge_width, color=edge_color.web_color if isinstance(edge_color, Color) else edge_color ) edge_lines = [IndexedLineSegments2(lines, mat)] if len(normals_list) > 0: lines = LineSegmentsGeometry(positions=normals_list) mat = LineMaterial(linewidth=2, color="#9400d3") normal_lines = [IndexedLineSegments2(lines, mat)] return shape_mesh, edge_lines, normal_lines, points
def render_shape( self, shape=None, edges=None, vertices=None, mesh_color=None, edge_color=None, vertex_color=None, render_edges=True, render_shapes=True, edge_width=1, vertex_width=5, transparent=False, opacity=1.0, ): edge_list = None edge_lines = None points = None shape_mesh = None render_timer = Timer(self.timeit, "| | shape render time") if shape is not None: if mesh_color is None: mesh_color = self.default_mesh_color if edge_color is None: edge_color = self.default_edge_color if vertex_color is None: vertex_color = self.default_edge_color # same as edge_color # Compute the tesselation and build mesh tesselation_timer = Timer(self.timeit, "| | | build mesh time") shape_geometry = RENDER_CACHE.tessellate(shape, self.quality, self.angular_tolerance, self.timeit) shp_material = material(mesh_color.web_color, transparent=transparent, opacity=opacity) # Do not cache building the mesh. Might lead to unpredictable results shape_mesh = IndexedMesh(geometry=shape_geometry, material=shp_material) tesselation_timer.stop() if render_edges: edges = get_edges(shape) # unset shape_mesh again if not render_shapes: shape_mesh = None if vertices is not None: vertices_list = [] for vertex in vertices: vertices_list.append(get_point(vertex)) vertices_list = np.array(vertices_list, dtype=np.float32) attributes = { "position": BufferAttribute(vertices_list, normalized=False) } mat = PointsMaterial(color=vertex_color.web_color, sizeAttenuation=False, size=vertex_width) geom = BufferGeometry(attributes=attributes) points = IndexedPoints(geometry=geom, material=mat) if edges is not None: discretize_timer = Timer(self.timeit, "| | | discretize time") edge_list = [ discretize_edge(edge, self.edge_accuracy) for edge in edges ] discretize_timer.stop() if edge_list is not None: discretize_timer = Timer(self.timeit, "| | | edge list") edge_list = flatten(list(map(explode, edge_list))) if isinstance(edge_color, (list, tuple)): if len(edge_list) != len(edge_color): print( "warning: color list and edge list have different length, using first color for all edges" ) edge_color = edge_color[0] if isinstance(edge_color, (list, tuple)): lines = LineSegmentsGeometry( positions=edge_list, colors=[[color.percentage] * 2 for color in edge_color], ) mat = LineMaterial(linewidth=edge_width, vertexColors="VertexColors") edge_lines = [IndexedLineSegments2(lines, mat)] else: lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial(linewidth=edge_width, color=edge_color.web_color) edge_lines = [IndexedLineSegments2(lines, mat)] discretize_timer.stop() render_timer.stop() return shape_mesh, edge_lines, points
def _render_shape( self, shape_index, shape=None, edges=None, vertices=None, mesh_color=None, edge_color=None, vertex_color=None, render_edges=False, edge_width=1, vertex_width=5, transparent=False, opacity=1.0, ): edge_list = None edge_lines = None points = None shape_mesh = None start_render_time = self._start_timer() if shape is not None: if mesh_color is None: mesh_color = self.default_mesh_color if edge_color is None: edge_color = self.default_edge_color if vertex_color is None: vertex_color = self.default_edge_color # same as edge_color # Compute the tesselation start_tesselation_time = self._start_timer() np_vertices, np_triangles, np_normals = tessellate( shape, self.quality, self.angular_tolerance ) if np_normals.shape != np_vertices.shape: raise AssertionError("Wrong number of normals/shapes") self._stop_timer("tesselation time", start_tesselation_time) # build a BufferGeometry instance shape_geometry = BufferGeometry( attributes={ "position": BufferAttribute(np_vertices), "index": BufferAttribute(np_triangles.ravel()), "normal": BufferAttribute(np_normals), } ) shp_material = self._material(mesh_color, transparent=True, opacity=opacity) shape_mesh = Mesh( geometry=shape_geometry, material=shp_material, name="mesh_%d" % shape_index ) if render_edges: edges = get_edges(shape) if vertices is not None: vertices_list = [] for vertex in vertices: vertices_list.append(get_point(vertex)) vertices_list = np.array(vertices_list, dtype=np.float32) attributes = {"position": BufferAttribute(vertices_list, normalized=False)} mat = PointsMaterial(color=vertex_color, sizeAttenuation=False, size=vertex_width) geom = BufferGeometry(attributes=attributes) points = Points(geometry=geom, material=mat) if edges is not None: start_discretize_time = self._start_timer() edge_list = [discretize_edge(edge, self.edge_accuracy) for edge in edges] self._stop_timer("discretize time", start_discretize_time) if edge_list is not None: edge_list = flatten(list(map(explode, edge_list))) lines = LineSegmentsGeometry(positions=edge_list) mat = LineMaterial(linewidth=edge_width, color=edge_color) edge_lines = LineSegments2(lines, mat, name="edges_%d" % shape_index) if shape_mesh is not None or edge_lines is not None or points is not None: index_mapping = {"mesh": None, "edges": None, "shape": shape_index} if shape_mesh is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(shape_mesh) index_mapping["mesh"] = ind if edge_lines is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(edge_lines) index_mapping["edges"] = ind if points is not None: ind = len(self.pickable_objects.children) self.pickable_objects.add(points) index_mapping["mesh"] = ind self.pick_mapping.append(index_mapping) self._stop_timer("shape render time", start_render_time)