def test_tesselate_box(self): """ 1st test : tesselation of a box """ a_box = BRepPrimAPI_MakeBox(10, 20, 30).Shape() tess = Tesselator(a_box, atNormal, 1.0, 1, 0.01, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.) self.assert_(tess.ObjGetTriangleCount() == 12) self.assert_(tess.ObjGetNormalCount() == 24)
def test_tesselate_torus(self): """ 2st test : tesselation of a torus """ a_box = BRepPrimAPI_MakeTorus(10, 4).Shape() tess = Tesselator(a_box, atNormal, 1.0, 1, 0.01, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.) self.assert_(tess.ObjGetTriangleCount() > 100) self.assert_(tess.ObjGetNormalCount() > 100)
def test_tesselate_torus_with_edges(self): """ 2st test : tesselation of a torus """ a_torus = BRepPrimAPI_MakeTorus(10, 4).Shape() tess = Tesselator(a_torus, atNormal, 1.0, 1, 0.01, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.) tess.Compute(compute_edges=True) self.assert_(tess.ObjGetTriangleCount() > 100) self.assert_(tess.ObjGetNormalCount() > 100)
def DisplayShape(self, shape, vertex_shader=None, fragment_shader=None, map_faces_to_mesh=False, export_edges=False, color=(0.65, 0.65, 0.65), specular_color=(1, 1, 1), shininess=0.9, transparency=0., line_color=(0, 0., 0.), line_width=2., mesh_quality=1.): # create the shape hash shape_uuid = uuid.uuid4().hex shape_hash = "shp%s" % shape_uuid # tesselate tess = Tesselator(shape) tess.Compute(compute_edges=export_edges, mesh_quality=mesh_quality) # sys.stdout.write( "\r%s mesh shape, %i triangles" % (next(self.spinning_cursor), tess.ObjGetTriangleCount())) sys.stdout.flush() # export to 3JS shape_full_path = os.path.join(self._path, shape_hash + '.json') # add this shape to the shape dict, sotres everything related to it self._3js_shapes[shape_hash] = [ export_edges, color, specular_color, shininess, transparency, line_color, line_width ] # generate the mesh #tess.ExportShapeToThreejs(shape_hash, shape_full_path) # and also to JSON with open(shape_full_path, 'w') as json_file: json_file.write(tess.ExportShapeToThreejsJSONString(shape_uuid)) # draw edges if necessary edges = [] if export_edges: # export each edge to a single json # get number of edges nbr_edges = tess.ObjGetEdgeCount() for i_edge in range(nbr_edges): # after that, the file can be appended str_to_write = '' edge_point_set = [] nbr_vertices = tess.ObjEdgeGetVertexCount(i_edge) for i_vert in range(nbr_vertices): edge_point_set.append(tess.GetEdgeVertex(i_edge, i_vert)) # write to file edge_hash = "edg%s" % uuid.uuid4().hex str_to_write += ExportEdgeToJSON(edge_hash, edge_point_set) # create the file edge_full_path = os.path.join(self._path, edge_hash + '.json') with open(edge_full_path, "w") as edge_file: edge_file.write(str_to_write) # store this edge hash self._edges_hash.append(edge_hash)
def test_tesselate_torus_with_bad_quality(self): """ 2st test : tesselation of a torus """ a_torus = BRepPrimAPI_MakeTorus(10, 4).Shape() tess = Tesselator(a_torus, atNormal, 1.0, 1, 0.01, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.) tess.Compute(mesh_quality=40.) # since mesh quality is much lower, we should count less vertices and # triangles self.assert_(tess.ObjGetTriangleCount() > 10) self.assert_(tess.ObjGetTriangleCount() < 100) self.assert_(tess.ObjGetNormalCount() > 10) self.assert_(tess.ObjGetNormalCount() < 100)
def tessellate(self, tolerance): tess = Tesselator(self.wrapped) tess.Compute(compute_edges=True, mesh_quality=tolerance) vertices = [] indexes = [] # add vertices for i_vert in range(tess.ObjGetVertexCount()): xyz = tess.GetVertex(i_vert) vertices.append(Vector(*xyz)) # add triangles for i_tr in range(tess.ObjGetTriangleCount()): indexes.append(tess.GetTriangleIndex(i_tr)) return vertices, indexes
def draw_shape_mpl(shape): """ Draw a TopoDS_Shape with matplotlib """ tess = Tesselator(shape) triangles = [] edges = [] # get the triangles triangle_count = tess.ObjGetTriangleCount() for i_triangle in range(0, triangle_count): i1, i2, i3 = tess.GetTriangleIndex(i_triangle) triangles.append( [tess.GetVertex(i1), tess.GetVertex(i2), tess.GetVertex(i3)]) # get the edges edge_count = tess.ObjGetEdgeCount() for i_edge in range(0, edge_count): vertex_count = tess.ObjEdgeGetVertexCount(i_edge) edge = [] for i_vertex in range(0, vertex_count): vertex = tess.GetEdgeVertex(i_edge, i_vertex) edge.append(vertex) edges.append(edge) # plot it fig = plt.figure() ax = Axes3D(fig) ax.add_collection3d(Poly3DCollection(triangles, linewidths=0.2, alpha=0.5)) ax.add_collection3d(Line3DCollection(edges, colors='w', linewidths=1.0)) ax.get_xaxis().set_visible(True) ax.get_yaxis().set_visible(True) ax.set_autoscale_on(True) plt.show()
def DisplayShape(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, update=False): """ Displays a topods_shape in the renderer instance. shp: the TopoDS_Shape to render shape_color: the shape color, in html corm, eg '#abe000' render_edges: optional, False by default. If True, compute and dislay all edges as a linear interpolation of segments. edge_color: optional, black by default. The color used for edge rendering, in html form eg '#ff00ee' compute_uv_coords: optional, false by default. If True, compute texture coordinates (required if the shape has to be textured) quality: optional, 1.0 by default. If set to something lower than 1.0, mesh will be more precise. If set to something higher than 1.0, mesh will be less precise, i.e. lower numer of triangles. update: optional, False by default. If True, render all the shapes. """ # 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 assert number_of_vertices % 3 == 0 assert number_of_triangles * 9 == number_of_vertices # 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 assert np_normals.shape == np_vertices.shape 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 = MeshPhongMaterial(color=shape_color, polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.9) # 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) # adds this mesh to the list of meshes self._displayed_pickable_objects.add(shape_mesh) # 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) self._displayed_pickable_objects.add(edge_lines) if update: self.Display()
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 assert number_of_vertices % 3 == 0 assert number_of_triangles * 9 == number_of_vertices # 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 assert np_normals.shape == np_vertices.shape 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 = MeshPhongMaterial(color=shape_color, polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, shininess=0.9, transparent=transparency) # 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 generate_png(shape): """ Draw a TopoDS_Shape with matplotlib """ from OCC.Visualization import Tesselator from mpl_toolkits.mplot3d import Axes3D from matplotlib import pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection tess = Tesselator(shape) triangles = [] edges = [] # get the triangles triangle_count = tess.ObjGetTriangleCount() for i_triangle in range(0, triangle_count): i1, i2, i3 = tess.GetTriangleIndex(i_triangle) triangles.append([tess.GetVertex(i1), tess.GetVertex(i2), tess.GetVertex(i3)]) # get the edges edge_count = tess.ObjGetEdgeCount() for i_edge in range(0, edge_count): vertex_count = tess.ObjEdgeGetVertexCount(i_edge) edge = [] for i_vertex in range(0, vertex_count): vertex = tess.GetEdgeVertex(i_edge, i_vertex) edge.append(vertex) edges.append(edge) # plot it fig_side = plt.figure(figsize=(10, 4)) ax = Axes3D(fig_side) ax.add_collection3d(Poly3DCollection(triangles, linewidths=0.15, alpha=0.5)) ax.add_collection3d(Line3DCollection(edges, colors='w', linewidths=1.0)) ax.set_axis_off() ax.set_xlim(-1800, 1800) ax.set_ylim(-800, 800) ax.set_zlim(-800, 800) ax.view_init(elev=-1., azim=90) fig_side.savefig("views/side.png") fig_top = plt.figure(figsize=(5, 4)) ax_top = Axes3D(fig_top) ax_top.add_collection3d(Poly3DCollection(triangles, linewidths=0.15, alpha=0.5)) ax_top.add_collection3d(Line3DCollection(edges, colors='w', linewidths=1.0)) ax_top.set_axis_off() ax_top.set_xlim(-2500, 2500) ax_top.set_ylim(-50, 450) ax_top.set_zlim(-250, 250) ax_top.view_init(elev=-1., azim=-2) fig_top.savefig("views/back.png") ax_top.set_xlim(-2500, 2500) ax_top.set_ylim(-50, 450) ax_top.set_zlim(-200, 300) ax_top.view_init(elev=-1., azim=182) fig_top.savefig("views/front.png")
import numpy as np HAVE_NUMPY = True except: HAVE_NUMPY = False # create the shape box_s = BRepPrimAPI_MakeBox(10, 20, 30).Shape() # compute the tesselation tess = Tesselator(box_s) tess.Compute() # get vertices vertices_position = tess.GetVerticesPositionAsTuple() number_of_triangles = tess.ObjGetTriangleCount() number_of_vertices = len(vertices_position) # number of vertices should be a multiple of 3 assert number_of_vertices % 3 == 0 assert number_of_triangles * 9 == number_of_vertices # get normals normals = tess.GetNormalsAsTuple() number_of_normals = len(normals) assert number_of_normals == number_of_vertices # if HAVE_NUMPY, we try to reshape the tuple so that it is of # a ndarray such as [[x1, y1, z1], [x2, y2, z2], ...] # if HAVE_NUMPY: