示例#1
0
    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())
示例#2
0
    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
示例#3
0
    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())
示例#4
0
 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]
示例#5
0
    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())
示例#6
0
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
示例#7
0
    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
示例#9
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()
示例#10
0
def test_addVertices():
    builder = MeshBuilder()
    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 3

    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 6
示例#11
0
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
示例#12
0
    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)
示例#13
0
    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)
示例#14
0
    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
示例#15
0
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
示例#16
0
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
示例#17
0
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
示例#18
0
 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()
示例#19
0
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.]]))
示例#20
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
示例#21
0
    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())
示例#22
0
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
示例#23
0
    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)
示例#24
0
    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()
示例#25
0
    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()
示例#26
0
    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})
示例#27
0
 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")
示例#28
0
    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
示例#29
0
    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
示例#30
0
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)