def test_export_to_x3d_IndexedFaceSet(self): """ 3rd test : export a sphere to an X3D IndexedFaceSet triangle mesh """ a_sphere = BRepPrimAPI_MakeBox(10., 10., 10.).Shape() ifs = Tesselator(a_sphere).ExportShapeToX3DIndexedFaceSet() self.assert_(ifs.startswith("<IndexedFaceSet")) self.assert_("0 10 0" in ifs) # a vertex self.assert_("0 0 1" in ifs) # a normal
def test_export_to_x3d(self): """ 3rd test : export a sphere to X3D file format """ a_sphere = BRepPrimAPI_MakeSphere(10.).Shape() tess = Tesselator(a_sphere) tess.Compute() tess.ExportShapeToX3D(os.path.join("test_io", "sphere.x3d")) self.assert_(os.path.exists(os.path.join("test_io", "sphere.x3d")))
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_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_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 import_as_one_shape(file): shp = read_step_file(file) tess = Tesselator(shp) tess.Compute() threejsString = tess.ExportShapeToThreejsJSONString('someid') # with open("outputs/threejs/shape.json", "w") as f: # f.write(threejsString) return threejsString
def test_export_to_3js_JSON(self): a_box = BRepPrimAPI_MakeBox(10, 20, 30).Shape() tess = Tesselator(a_box) tess.Compute() # get the JSON string JSON_str = tess.ExportShapeToThreejsJSONString("myshapeid") # check the python JSON parser can decode the string # i.e. the JSON string is well formed dico = json.loads(JSON_str) # after that, check that the number of vertices is ok assert len(dico["data"]["attributes"]["position"]["array"]) == 36 * 3
def _exportThreeJS(filePath, _shape): _tess = Tesselator(_shape) _tess.Compute(uv_coords=False, compute_edges=False, mesh_quality=50) json_shape = _tess.ExportShapeToThreejsJSONString(filePath) json_shape = json_shape.replace("data\\", "data/") json_shape = json_shape.replace("\\step_postprocessed\\", "/step_postprocessed/") return json_shape
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 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 create_files(self, shape): ''' generate .js and .html files ''' self._shape = shape print("Tesselate shape ...") t0 = time() tess = Tesselator(self._shape) t1 = time() print("done in %f s." % (t1-t0)) print("Exporting tesselation to JSON ...") t2 = time() tess.ExportShapeToThreejs(self._js_filename) t3 = time() print("done in %f s." % (t3-t2)) print("Generating HTML stream ...") self.GenerateHTMLFile() print("done.") return self._js_filename, self._html_filename
def DisplayShape(self, shape): self._shape = shape print("Tesselate shape ...") t0 = time() tess = Tesselator(self._shape) t1 = time() print("done in %f s." % (t1 - t0)) print("Exporting tesselation to X3D ...") t2 = time() tess.ExportShapeToX3D(self._x3d_filename) t3 = time() print("done in %f s." % (t3 - t2)) print("Generating HTML stream ...") self.GenerateHTMLFile() print("done.") print("Opening html output in the default webbrowser ...") # open the file in the browser _path = "file:///{0}".format( os.path.join(os.getcwd(), self._html_filename)) webbrowser.open_new_tab(_path)
def DisplayShape(self, shape): self._shape = shape print("Tesselate shape ...") t0 = time() tess = Tesselator(self._shape) t1 = time() print("done in %f s." % (t1 - t0)) print("Exporting tesselation to JSON ...") t2 = time() tess.ExportShapeToJSON(self._js_filename) t3 = time() print("done in %f s." % (t3 - t2)) print("Generating HTML stream ...") self.GenerateHTMLFile() print("done.") print("Opening html output in the default webbrowser ...") # previous version us a os.system call to the "open" command # but this is a platform (osx) specific solution _path = "file:///{0}".format( os.path.join(os.getcwd(), self._html_filename)) webbrowser.open_new_tab(_path)
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 compute(self): shape_tesselator = Tesselator(self._shape) shape_tesselator.Compute(compute_edges=self._export_edges, mesh_quality=self._mesh_quality) self._triangle_sets.append(shape_tesselator.ExportShapeToX3DIndexedFaceSet()) # then process edges if self._export_edges: # get number of edges nbr_edges = shape_tesselator.ObjGetEdgeCount() for i_edge in range(nbr_edges): edge_point_set = [] nbr_vertices = shape_tesselator.ObjEdgeGetVertexCount(i_edge) for i_vert in range(nbr_vertices): edge_point_set.append(shape_tesselator.GetEdgeVertex(i_edge, i_vert)) ils = ExportEdgeToILS(edge_point_set) self._line_sets.append(ils)
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 compute(self): # get faces explorer = TopExp_Explorer() explorer.Init(self._shape, TopAbs_FACE) if self._map_faces_to_mesh: # one mesh per face faces = [] while explorer.More(): current_face = explorer.Current() faces.append(current_face) explorer.Next() # loop over faces for face in faces: face_tesselator = Tesselator(face) self._indexed_face_sets.append(face_tesselator.ExportShapeToX3DIndexedFaceSet()) else: # only one mesh for the whole shape shape_tesselator = Tesselator(self._shape) self._indexed_face_sets.append(shape_tesselator.ExportShapeToX3DIndexedFaceSet())
def _write_threejs_json(html_dir, shape): tess = Tesselator(shape) tess.Compute(compute_edges=False, mesh_quality=1.) with open(os.path.join(html_dir, "table.json"), 'w') as f: f.write(tess.ExportShapeToThreejsJSONString('table'))
def test_export_to_x3d(self): """ 3rd test : export a sphere to X3D file format """ a_sphere = BRepPrimAPI_MakeSphere(10.).Shape() Tesselator(a_sphere).ExportShapeToX3D("sphere.x3d") self.assert_(os.path.exists("sphere.x3d"))
def stpTox3d(filename): shape = read_step_file('stp_uploads/%s.stp' % filename) tess = Tesselator(shape) tess.Compute() tess.ExportShapeToX3D('x3d_output/%s.x3d' % filename)
# TEST 1 : one big STEP file into one single compound # loads the step file # load twice, not a copy/paste typo. It's because meshes are stored # the second time, meshing time is much faster print("TEST 1 ===") shp = read_step_file( os.path.join('..', 'examples', 'models', 'RC_Buggy_2_front_suspension.stp')) shp2 = read_step_file( os.path.join('..', 'examples', 'models', 'RC_Buggy_2_front_suspension.stp')) # tesselate in single thread mode print("Tesselate in single thread mode") t_single = Tesselator(shp) t0 = time.monotonic() t_single.Compute(parallel=False, mesh_quality=0.5) t1 = time.monotonic() delta_single = t1 - t0 # tesselate in parallel thread mode print("Tesselate in parallelized mode") t_multi = Tesselator(shp2) t2 = time.monotonic() t_multi.Compute(parallel=True, mesh_quality=0.5) t3 = time.monotonic() delta_multi = t3 - t2 print("Test 1 Results:") print(" * single thread runtime: %.2fs" % delta_single)
##along with pythonOCC. If not, see <http://www.gnu.org/licenses/>. from OCC.Visualization import Tesselator from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeTorus try: 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)
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 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")
def tessellate(shape): tess = Tesselator(shape.wrapped) tess.Compute(compute_edges=True, mesh_quality=tolerance) return tess
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)