def buildMesh(self): super().buildMesh() mb = MeshBuilder() #SOLIDMESH mb.addDonut( inner_radius = LoadToolHandle.INNER_RADIUS, outer_radius = LoadToolHandle.OUTER_RADIUS, width = LoadToolHandle.LINE_WIDTH, axis = self.rotation_axis, color = self._y_axis_color ) self.setSolidMesh(mb.build()) mb = MeshBuilder() #SELECTIONMESH mb.addDonut( inner_radius = LoadToolHandle.ACTIVE_INNER_RADIUS, outer_radius = LoadToolHandle.ACTIVE_OUTER_RADIUS, width = LoadToolHandle.ACTIVE_LINE_WIDTH, axis = self.rotation_axis, color = ToolHandle.YAxisSelectionColor ) self.setSelectionMesh(mb.build())
def _read(self, file_name): """Decide if we need to use ascii or binary in order to read file""" mesh_builder = MeshBuilder() scene_node = SceneNode() self.load_file(file_name, mesh_builder, _use_numpystl = use_numpystl) mesh = mesh_builder.build() if use_numpystl: verts = mesh.getVertices() # In some cases numpy stl reads incorrectly and the result is that the Z values are all 0 # Add new error cases if you find them. if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]): # Something may have gone wrong in numpy stl, start over without numpy stl Logger.log("w", "All Z coordinates are the same using numpystl, trying again without numpy stl.") mesh_builder = MeshBuilder() self.load_file(file_name, mesh_builder, _use_numpystl = False) mesh = mesh_builder.build() verts = mesh.getVertices() if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]): Logger.log("e", "All Z coordinates are still the same without numpy stl... let's hope for the best") if mesh_builder.getVertexCount() == 0: Logger.log("d", "File did not contain valid data, unable to read.") return None # We didn't load anything. scene_node.setMeshData(mesh) Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount()) return scene_node
def buildMesh(self): #SOLIDMESH mb = MeshBuilder() mb.addDonut( inner_radius = self._inner_radius, outer_radius = self._outer_radius, width = self._line_width, color = self._z_axis_color ) mb.addDonut( inner_radius = self._inner_radius, outer_radius = self._outer_radius, width = self._line_width, axis = Vector.Unit_X, angle = math.pi / 2, color = self._y_axis_color ) mb.addDonut( inner_radius = self._inner_radius, outer_radius = self._outer_radius, width = self._line_width, axis = Vector.Unit_Y, angle = math.pi / 2, color = self._x_axis_color ) self.setSolidMesh(mb.build()) #SELECTIONMESH mb = MeshBuilder() mb.addDonut( inner_radius = self._active_inner_radius, outer_radius = self._active_outer_radius, width = self._active_line_width, color = ToolHandle.ZAxisSelectionColor ) mb.addDonut( inner_radius = self._active_inner_radius, outer_radius = self._active_outer_radius, width = self._active_line_width, axis = Vector.Unit_X, angle = math.pi / 2, color = ToolHandle.YAxisSelectionColor ) mb.addDonut( inner_radius = self._active_inner_radius, outer_radius = self._active_outer_radius, width = self._active_line_width, axis = Vector.Unit_Y, angle = math.pi / 2, color = ToolHandle.XAxisSelectionColor ) self.setSelectionMesh(mb.build())
def _subdivide(self, mesh, plane): start_time = time.time() plane_mesh_data = plane.getMeshData() plane_vertices = plane_mesh_data.getVertices() plane_face = [plane_vertices[0], plane_vertices[1], plane_vertices[2]] builders = [MeshBuilder(), MeshBuilder()] mesh_data = mesh.getMeshData() vertices = mesh_data.getVertices() indices = mesh_data.getIndices() faces = [] if indices: for index_array in indices: faces.append([ vertices[index_array[0]], vertices[index_array[1]], vertices[index_array[2]] ]) else: for i in range(0, len(vertices), 3): faces.append([vertices[i], vertices[i + 1], vertices[i + 2]]) for f in faces: intersection_type = self.check_intersection_with_triangle( plane_face, f) if intersection_type is None or ( intersection_type is not None and intersection_type[0] in [IntersectionType.Point, IntersectionType.Edge]): side = self.check_plane_side(plane_face, f) if side is not None: self.add_face_to_builder(builders[side], f) else: Logger.log("w", "Invalid face detected: " + str(f)) elif intersection_type[0] == IntersectionType.Face: self.add_face_to_builder(builders[0], f) self.add_face_to_builder(builders[1], f) elif intersection_type[0] == IntersectionType.Segment: new_faces = self.split_triangle(f, intersection_type[1]) for new_face in new_faces: self.add_face_to_builder( builders[self.check_plane_side(plane_face, new_face)], new_face) elif intersection_type[0] == IntersectionType.PointAndSegment: new_faces = self.split_triangle_in_one_segment( f, intersection_type[1]) for new_face in new_faces: self.add_face_to_builder( builders[self.check_plane_side(plane_face, new_face)], new_face) nodes = [SceneNode(), SceneNode()] for n in range(len(nodes)): builders[n].calculateNormals() nodes[n].setMeshData(builders[n].build()) nodes[n].setSelectable(True) nodes[n].setScale(mesh.getScale()) Logger.log( "w", i18n_catalog.i18n("Subdivision took %f seconds") % (time.time() - start_time)) return nodes[0], nodes[1]
def __init__(self, parent=None): super().__init__(parent) self._inner_radius = 40 self._outer_radius = 40.5 self._line_width = 0.5 self._active_inner_radius = 37 self._active_outer_radius = 44 self._active_line_width = 3 #SOLIDMESH mb = MeshBuilder() mb.addDonut(inner_radius=self._inner_radius, outer_radius=self._outer_radius, width=self._line_width, color=ToolHandle.ZAxisColor) mb.addDonut(inner_radius=self._inner_radius, outer_radius=self._outer_radius, width=self._line_width, axis=Vector.Unit_X, angle=math.pi / 2, color=ToolHandle.YAxisColor) mb.addDonut(inner_radius=self._inner_radius, outer_radius=self._outer_radius, width=self._line_width, axis=Vector.Unit_Y, angle=math.pi / 2, color=ToolHandle.XAxisColor) self.setSolidMesh(mb.build()) #SELECTIONMESH mb = MeshBuilder() mb.addDonut(inner_radius=self._active_inner_radius, outer_radius=self._active_outer_radius, width=self._active_line_width, color=ToolHandle.ZAxisColor) mb.addDonut(inner_radius=self._active_inner_radius, outer_radius=self._active_outer_radius, width=self._active_line_width, axis=Vector.Unit_X, angle=math.pi / 2, color=ToolHandle.YAxisColor) mb.addDonut(inner_radius=self._active_inner_radius, outer_radius=self._active_outer_radius, width=self._active_line_width, axis=Vector.Unit_Y, angle=math.pi / 2, color=ToolHandle.XAxisColor) self.setSelectionMesh(mb.build())
def test_render(): mocked_shader = MagicMock() with patch("UM.View.GL.OpenGL.OpenGL.getInstance"): render_batch = RenderBatch(mocked_shader) # Render without a camera shouldn't cause any effect. render_batch.render(None) assert mocked_shader.bind.call_count == 0 # Rendering with a camera should cause the shader to be bound and released (even if the batch is empty) mocked_camera = MagicMock() mocked_camera.getWorldTransformation = MagicMock(return_value=Matrix()) mocked_camera.getViewProjectionMatrix = MagicMock(return_value=Matrix()) with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"): render_batch.render(mocked_camera) assert mocked_shader.bind.call_count == 1 assert mocked_shader.release.call_count == 1 # Actualy render with an item in the batch mb = MeshBuilder() mb.addPyramid(10, 10, 10, color=Color(0.0, 1.0, 0.0, 1.0)) mb.calculateNormals() mesh_data = mb.build() render_batch.addItem(Matrix(), mesh_data, {}) with patch("UM.View.GL.OpenGL.OpenGL.getInstance"): with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"): render_batch.render(mocked_camera) assert mocked_shader.bind.call_count == 2 assert mocked_shader.release.call_count == 2
def read(self, file_name): mesh_builder = MeshBuilder() scene_node = SceneNode() if use_numpystl: self._loadWithNumpySTL(file_name, mesh_builder) else: f = open(file_name, "rb") if not self._loadBinary(mesh_builder, f): f.close() f = open(file_name, "rt") try: self._loadAscii(mesh_builder, f) except UnicodeDecodeError: return None f.close() Job.yieldThread() # Yield somewhat to ensure the GUI has time to update a bit. mesh_builder.calculateNormals(fast = True) mesh_builder.setFileName(file_name) mesh = mesh_builder.build() Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount()) scene_node.setMeshData(mesh) return scene_node
def test_reserveVertexCount(): builder = MeshBuilder() builder.addVertex(1, 2, 3) builder.reserveVertexCount(10) # Reserving face count should reset the verts assert builder.getVertexCount() == 0
def test_addFaceWithNormals(): builder = MeshBuilder() builder.addFaceWithNormals(0, 0, 0, 1, 0, 0, 10, 0, 0, 0, 1, 0, 10, 10, 0, 0, 0, 1) assert builder.getVertexCount() == 3 assert builder.getFaceCount() == 1 assert builder.hasNormals()
def test_addVertices(): builder = MeshBuilder() builder.addVertices(numpy.zeros(3)) assert builder.getVertexCount() == 3 builder.addVertices(numpy.zeros(3)) assert builder.getVertexCount() == 6
def test_setUVCoordinates(): builder = MeshBuilder() builder.setVertices(numpy.zeros((10 * 3, 3), dtype=numpy.float32)) builder.setVertexUVCoordinates(5, 20, 22) assert builder.hasUVCoordinates() assert builder.getUVCoordinates()[5, 0] == 20 assert builder.getUVCoordinates()[5, 1] == 22
def __init__(self, node, hull, thickness, parent=None): super().__init__(parent) self.setCalculateBoundingBox(False) self._original_parent = parent # Color of the drawn convex hull self._color = Color(*Application.getInstance().getTheme().getColor( "convex_hull").getRgb()) # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting. self._mesh_height = 0.1 self._thickness = thickness # The node this mesh is "watching" self._node = node self._convex_hull_head_mesh = None self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged) self._onNodeDecoratorsChanged(self._node) self._hull = hull if self._hull: hull_mesh_builder = MeshBuilder() if hull_mesh_builder.addConvexPolygonExtrusion( self._hull.getPoints()[::-1], # bottom layer is reversed self._mesh_height - thickness, self._mesh_height, color=self._color): hull_mesh = hull_mesh_builder.build() self.setMeshData(hull_mesh)
def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) Application.getInstance().getController().getScene().sceneChanged.emit(node)
def _read(self, file_name): try: self.defs = {} self.shapes = [] tree = ET.parse(file_name) xml_root = tree.getroot() if xml_root.tag != "X3D": return None scale = 1000 # Default X3D unit it one meter, while Cura's is one millimeters if xml_root[0].tag == "head": for head_node in xml_root[0]: if head_node.tag == "unit" and head_node.attrib.get( "category") == "length": scale *= float(head_node.attrib["conversionFactor"]) break xml_scene = xml_root[1] else: xml_scene = xml_root[0] if xml_scene.tag != "Scene": return None self.transform = Matrix() self.transform.setByScaleFactor(scale) self.index_base = 0 # Traverse the scene tree, populate the shapes list self.processChildNodes(xml_scene) if self.shapes: builder = MeshBuilder() builder.setVertices( numpy.concatenate([shape.verts for shape in self.shapes])) builder.setIndices( numpy.concatenate([shape.faces for shape in self.shapes])) builder.calculateNormals() builder.setFileName(file_name) mesh_data = builder.build() # Manually try and get the extents of the mesh_data. This should prevent nasty NaN issues from # leaving the reader. mesh_data.getExtents() node = SceneNode() node.setMeshData(mesh_data) node.setSelectable(True) node.setName(file_name) else: return None except Exception: Logger.logException("e", "Exception in X3D reader") return None return node
def test_addIndices(): builder = MeshBuilder() builder.addIndices(numpy.zeros(3)) assert builder.getFaceCount() == 3 assert builder.getIndices()[0] == 0 builder.addIndices(numpy.zeros(3)) assert builder.getFaceCount() == 6
def test_getSetType(): builder = MeshBuilder() builder.setType(MeshType.faces) assert builder.getType() == MeshType.faces # Should have no effect builder.setType("ZOMG") assert builder.getType() == MeshType.faces
def test_addLine(): builder = MeshBuilder() builder.addLine(Vector(0, 0, 0), Vector(10, 11, 12)) assert builder.getVertexCount() == 2 assert builder.getVertex(1)[0] == 10 assert builder.getVertex(1)[1] == 11 assert builder.getVertex(1)[2] == 12
def _onNodeDecoratorsChanged(self, node: SceneNode) -> None: convex_hull_head = self._node.callDecoration("getConvexHullHeadFull") if convex_hull_head: convex_hull_head_builder = MeshBuilder() convex_hull_head_builder.addConvexPolygon( convex_hull_head.getPoints(), self._mesh_height - self._thickness) self._convex_hull_head_mesh = convex_hull_head_builder.build()
def test_calculateNormals(): builder = MeshBuilder() # Builder shouldn't start off with normals assert not builder.hasNormals() # Ensure that if there are no vertices / faces that calling the calculate doesn't break anything. builder.calculateNormals() assert not builder.hasNormals() builder.addFaceByPoints(0, 0, 0, 10, 0, 0, 10, 10, 0) builder.calculateNormals() assert builder.hasNormals() assert numpy.array_equal(builder.getNormals(), numpy.array([[0., 0., 1.], [0., 0., 1.], [0., 0., 1.]])) builder2 = MeshBuilder() builder2.addFaceByPoints(0, 0, 0, 0, 10, 0, 0, 10, 10) builder2.calculateNormals(fast = True) assert numpy.array_equal(builder2.getNormals(), numpy.array([[1., 0., 0], [1., 0., 0.], [1., 0., 0.]]))
def _onGlobalContainerStackChanged(self): if self._global_container_stack: self.setMeshData(None) self._global_container_stack = Application.getInstance().getGlobalContainerStack() if self._global_container_stack: container = self._global_container_stack.findContainer({ "platform": "*" }) if container: mesh_file = container.getMetaDataEntry("platform") try: path = Resources.getPath(Resources.Meshes, mesh_file) except FileNotFoundError: Logger.log("w", "Unable to find the platform mesh %s", mesh_file) path = "" if self._load_platform_job: # This prevents a previous load job from triggering texture loads. self._load_platform_job.finished.disconnect(self._onPlatformLoaded) # Perform platform mesh loading in the background self._load_platform_job = _LoadPlatformJob(path) self._load_platform_job.finished.connect(self._onPlatformLoaded) self._load_platform_job.start() self._has_bed = True offset = container.getMetaDataEntry("platform_offset") if offset: if len(offset) == 3: self.setPosition(Vector(offset[0], offset[1], offset[2])) else: Logger.log("w", "Platform offset is invalid: %s", str(offset)) self.setPosition(Vector(0.0, 0.0, 0.0)) else: self.setPosition(Vector(0.0, 0.0, 0.0)) else: settings = Application.getInstance().getGlobalContainerStack() machine_width = settings.getProperty("machine_width", "value") machine_depth = settings.getProperty("machine_depth", "value") line_len = 25 line_wid = 1 handle_size = 3 mb = MeshBuilder() mb.addCube(line_wid, line_len, line_wid, Vector(-machine_width/2, line_len/2, machine_depth/2), ToolHandle.YAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(-machine_width/2, line_len, machine_depth/2), color=ToolHandle.YAxisSelectionColor) mb.addCube(line_len, line_wid, line_wid, Vector(line_len/2-machine_width/2, 0, machine_depth/2), ToolHandle.XAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(line_len-machine_width/2, 0, machine_depth/2), color=ToolHandle.XAxisSelectionColor, axis = Vector.Unit_Z, angle = 90) mb.addCube(line_wid, line_wid, line_len, Vector(-machine_width/2, 0, -line_len/2+machine_depth/2), ToolHandle.ZAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(-machine_width/2, 0, -line_len+machine_depth/2), color=ToolHandle.ZAxisSelectionColor, axis = Vector.Unit_X, angle = 90) self.setMeshData(mb.build()) self.setPosition(Vector(0.0, 0.0, 0.0)) self._has_bed = False
def __init__(self, parent=None): super().__init__(parent) self._handle_width = 8 self._handle_height = 14 self._handle_position = 20 mb = MeshBuilder() mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, self._handle_position, 0), color=ToolHandle.YAxisColor) mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, -self._handle_position, 0), color=ToolHandle.YAxisColor, axis=Vector.Unit_X, angle=180) mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(self._handle_position, 0, 0), color=ToolHandle.XAxisColor, axis=Vector.Unit_Z, angle=90) mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(-self._handle_position, 0, 0), color=ToolHandle.XAxisColor, axis=Vector.Unit_Z, angle=-90) mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, 0, -self._handle_position), color=ToolHandle.ZAxisColor, axis=Vector.Unit_X, angle=90) mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, 0, self._handle_position), color=ToolHandle.ZAxisColor, axis=Vector.Unit_X, angle=-90) self.setSolidMesh(mb.getData()) self.setSelectionMesh(mb.getData())
def test_addLineWithColor(): builder = MeshBuilder() builder.addLine(Vector(0, 0, 0), Vector(10, 11, 12), Color(1.0, 0.5, 0.25)) assert builder.getColors()[0][0] == 1.0 assert builder.getColors()[0][1] == 0.5 assert builder.getColors()[0][2] == 0.25 assert builder.getColors()[1][0] == 1.0 assert builder.getColors()[1][1] == 0.5 assert builder.getColors()[1][2] == 0.25
def __init__(self, node: SceneNode, hull: Optional[Polygon], thickness: float, parent: Optional[SceneNode] = None) -> None: """Convex hull node is a special type of scene node that is used to display an area, to indicate the location an object uses on the buildplate. This area (or area's in case of one at a time printing) is then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded to represent the raft as well. """ super().__init__(parent) self.setCalculateBoundingBox(False) self._original_parent = parent # Color of the drawn convex hull if not Application.getInstance().getIsHeadLess(): theme = QtApplication.getInstance().getTheme() if theme: self._color = Color(*theme.getColor("convex_hull").getRgb()) else: self._color = Color(0, 0, 0) else: self._color = Color(0, 0, 0) # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting. self._mesh_height = 0.1 self._thickness = thickness # The node this mesh is "watching" self._node = node # Area of the head + fans for display as a shadow on the buildplate self._convex_hull_head_mesh = None # type: Optional[MeshData] self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged) self._onNodeDecoratorsChanged(self._node) self._hull = hull if self._hull: hull_mesh_builder = MeshBuilder() if self._thickness == 0: if hull_mesh_builder.addConvexPolygon( self._hull.getPoints()[::], # bottom layer is reversed self._mesh_height, color = self._color): hull_mesh_builder.resetNormals() hull_mesh = hull_mesh_builder.build() self.setMeshData(hull_mesh) else: if hull_mesh_builder.addConvexPolygonExtrusion( self._hull.getPoints()[::-1], # bottom layer is reversed self._mesh_height - thickness, self._mesh_height, color = self._color): hull_mesh_builder.resetNormals() hull_mesh = hull_mesh_builder.build() self.setMeshData(hull_mesh)
def createMesh(self): builder = MeshBuilder() for polygon in self._polygons: poly_color = polygon.getColor() points = numpy.copy(polygon.data) if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType: points[:, 1] -= 0.01 # Calculate normals for the entire polygon using numpy. normals = numpy.copy(points) normals[:, 1] = 0.0 # We are only interested in 2D normals # Calculate the edges between points. # The call to numpy.roll shifts the entire array by one so that # we end up subtracting each next point from the current, wrapping # around. This gives us the edges from the next point to the current # point. normals[:] = normals[:] - numpy.roll(normals, -1, axis=0) # Calculate the length of each edge using standard Pythagoras lengths = numpy.sqrt(normals[:, 0]**2 + normals[:, 2]**2) # The normal of a 2D vector is equal to its x and y coordinates swapped # and then x inverted. This code does that. normals[:, [0, 2]] = normals[:, [2, 0]] normals[:, 0] *= -1 # Normalize the normals. normals[:, 0] /= lengths normals[:, 2] /= lengths # Scale all by the line width of the polygon so we can easily offset. normals *= (polygon.lineWidth / 2) #TODO: Use numpy magic to perform the vertex creation to speed up things. for i in range(len(points)): start = points[i - 1] end = points[i] normal = normals[i - 1] point1 = Vector(data=start - normal) point2 = Vector(data=start + normal) point3 = Vector(data=end + normal) point4 = Vector(data=end - normal) builder.addQuad(point1, point2, point3, point4, color=poly_color) return builder.getData()
def createMeshOrJumps(self, make_mesh): builder = MeshBuilder() line_count = 0 if make_mesh: for polygon in self._polygons: line_count += polygon.meshLineCount else: for polygon in self._polygons: line_count += polygon.jumpCount # Reserve the neccesary space for the data upfront builder.reserveFaceAndVertexCount(2 * line_count, 4 * line_count) for polygon in self._polygons: # Filter out the types of lines we are not interesed in depending on whether we are drawing the mesh or the jumps. index_mask = numpy.logical_not( polygon.jumpMask) if make_mesh else polygon.jumpMask # Create an array with rows [p p+1] and only keep those we whant to draw based on make_mesh points = numpy.concatenate((polygon.data[:-1], polygon.data[1:]), 1)[index_mask.ravel()] # Line types of the points we want to draw line_types = polygon.types[index_mask] # Shift the z-axis according to previous implementation. if make_mesh: points[polygon.isInfillOrSkinType(line_types), 1::3] -= 0.01 else: points[:, 1::3] += 0.01 # Create an array with normals and tile 2 copies to match size of points variable normals = numpy.tile(polygon.getNormals()[index_mask.ravel()], (1, 2)) # Scale all normals by the line width of the current line so we can easily offset. normals *= (polygon.lineWidths[index_mask.ravel()] / 2) # Create 4 points to draw each line segment, points +- normals results in 2 points each. # After this we reshape to one point per line. f_points = numpy.concatenate((points - normals, points + normals), 1).reshape((-1, 3)) # __index_pattern defines which points to use to draw the two faces for each lines egment, the following linesegment is offset by 4 f_indices = (self.__index_pattern + numpy.arange( 0, 4 * len(normals), 4, dtype=numpy.int32).reshape( (-1, 1))).reshape((-1, 3)) f_colors = numpy.repeat(polygon.mapLineTypeToColor(line_types), 4, 0) builder.addFacesWithColor(f_points, f_indices, f_colors) return builder.build()
def run(self) -> None: layer_data = None for node in DepthFirstIterator(self._scene.getRoot()): # type: ignore layer_data = node.callDecoration("getLayerData") if layer_data: break if self._cancel or not layer_data: return layer_mesh = MeshBuilder() for i in range(self._solid_layers): layer_number = self._layer_number - i if layer_number < 0: continue try: layer = layer_data.getLayer(layer_number).createMesh() except Exception: Logger.logException( "w", "An exception occurred while creating layer mesh.") return if not layer or layer.getVertices() is None: continue layer_mesh.addIndices(layer_mesh.getVertexCount() + layer.getIndices()) layer_mesh.addVertices(layer.getVertices()) # Scale layer color by a brightness factor based on the current layer number # This will result in a range of 0.5 - 1.0 to multiply colors by. brightness = numpy.ones( (1, 4), dtype=numpy.float32) * (2.0 - (i / self._solid_layers)) / 2.0 brightness[0, 3] = 1.0 layer_mesh.addColors(layer.getColors() * brightness) if self._cancel: return Job.yieldThread() if self._cancel: return Job.yieldThread() jump_mesh = layer_data.getLayer(self._layer_number).createJumps() if not jump_mesh or jump_mesh.getVertices() is None: jump_mesh = None self.setResult({"layers": layer_mesh.build(), "jumps": jump_mesh})
def __init__(self): super().__init__() self.scale_factor = 50 builder = MeshBuilder() builder.addQuad(Vector(-self.scale_factor, -self.scale_factor, 0), Vector(self.scale_factor, -self.scale_factor, 0), Vector(self.scale_factor, self.scale_factor, 0), Vector(-self.scale_factor, self.scale_factor, 0)) builder.addVertex(0, 0, 0.0001) mesh = builder.build() self.setMeshData(mesh) self.setSelectable(True) self.setName("Plane")
def _onNodeDecoratorsChanged(self, node): self._color = Color(35, 35, 35, 0.5) convex_hull_head = self._node.callDecoration("getConvexHullHead") if convex_hull_head: convex_hull_head_builder = MeshBuilder() convex_hull_head_builder.addConvexPolygon( convex_hull_head.getPoints(), self._mesh_height - self._thickness) self._convex_hull_head_mesh = convex_hull_head_builder.build() if not node: return
def test_getTransformedMeshdata(self): node = SceneNode() node.translate(Vector(10, 0, 0)) builder = MeshBuilder() builder.addVertex(10, 20, 20) node.setMeshData(builder.build()) transformed_mesh = node.getMeshDataTransformed() transformed_vertex = transformed_mesh.getVertices()[0] assert transformed_vertex[0] == 20 assert transformed_vertex[1] == 20 assert transformed_vertex[2] == 20
def test_getExtents(): # Create a cube mesh at position 0,0,0 builder = MeshBuilder() builder.addCube(20, 20, 20) mesh_data = builder.build() extents = mesh_data.getExtents() assert extents.width == 20 assert extents.height == 20 assert extents.depth == 20 assert extents.maximum == Vector(10, 10, 10) assert extents.minimum == Vector(-10, -10, -10)