Пример #1
0
def test_addVertices():
    builder = MeshBuilder()
    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 3

    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 6
Пример #2
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})
Пример #3
0
    def run(self):
        layer_data = None
        for node in DepthFirstIterator(self._scene.getRoot()):
            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})
Пример #4
0
    def run(self):
        layer_data = None
        for node in DepthFirstIterator(self._scene.getRoot()):
            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 as e:
                print(e)
                return

            if not layer or layer.getVertices() is None:
                continue

            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 = (2.0 - (i / self._solid_layers)) / 2.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})
Пример #5
0
    def _constructSupport(self, buffer: QImage) -> None:
        depth_pass = PickingPass(
            buffer.width(), buffer.height()
        )  #Instead of using the picking pass to pick for us, we need to bulk-pick digits so do this in Numpy.
        depth_pass.render()
        depth_image = depth_pass.getOutput()
        camera = CuraApplication.getInstance().getController().getScene(
        ).getActiveCamera()

        #to_support = qimage2ndarray.raw_view(buffer)
        #to_support= _qimageview(_qt.QImage(buffer))
        to_support = self._raw_view(buffer)

        #depth = qimage2ndarray.recarray_view(depth_image)
        depth = self._recarray_view(depth_image)

        depth.a = 0  #Discard alpha channel.
        depth = depth.view(dtype=_np.int32).astype(
            _np.float32
        ) / 1000  #Conflate the R, G and B channels to one 24-bit (cast to 32) float. Divide by 1000 to get mm.
        support_positions_2d = _np.array(
            _np.where(_np.bitwise_and(to_support == 255, depth < 16777))
        )  #All the 2D coordinates on the screen where we want support. The 16777 is for points that don't land on a model.
        support_depths = _np.take(
            depth, support_positions_2d[0, :] * depth.shape[1] +
            support_positions_2d[1, :])  #The depth at those pixels.
        support_positions_2d = support_positions_2d.transpose(
        )  #We want rows with pixels, not columns with pixels.
        if len(support_positions_2d) == 0:
            Logger.log(
                "i",
                "Support was not drawn on the surface of any objects. Not creating support."
            )
            return
        support_positions_2d[:, [0, 1]] = support_positions_2d[:, [
            1, 0
        ]]  #Swap columns to get OpenGL's coordinate system.
        camera_viewport = _np.array(
            [camera.getViewportWidth(),
             camera.getViewportHeight()])
        support_positions_2d = support_positions_2d * 2.0 / camera_viewport - 1.0  #Scale to view coordinates (range -1 to 1).
        inverted_projection = _np.linalg.inv(
            camera.getProjectionMatrix().getData())
        transformation = camera.getWorldTransformation().getData()
        transformation[:,
                       1] = -transformation[:,
                                            1]  #Invert Z to get OpenGL's coordinate system.

        #For each pixel, get the near and far plane.
        near = _np.ndarray((support_positions_2d.shape[0], 4))
        near.fill(1)
        near[0:support_positions_2d.shape[0],
             0:support_positions_2d.shape[1]] = support_positions_2d
        near[:, 2].fill(-1)
        near = _np.dot(inverted_projection, near.transpose())
        near = _np.dot(transformation, near)
        near = near[0:3] / near[3]
        far = _np.ndarray((support_positions_2d.shape[0], 4))
        far.fill(1)
        far[0:support_positions_2d.shape[0],
            0:support_positions_2d.shape[1]] = support_positions_2d
        far = _np.dot(inverted_projection, far.transpose())
        far = _np.dot(transformation, far)
        far = far[0:3] / far[3]

        #Direction is from near plane pixel to far plane pixel, normalised.
        direction = near - far
        direction /= _np.linalg.norm(direction, axis=0)

        #Final position is in the direction of the pixel, moving with <depth> mm away from the camera position.
        support_positions_3d = (
            support_depths - 1
        ) * direction  #We want the support to appear just before the surface, not behind the surface, so - 1.
        support_positions_3d = support_positions_3d.transpose()
        camera_position_data = camera.getPosition().getData()
        support_positions_3d = support_positions_3d + camera_position_data

        #Create the vertices for the 3D mesh.
        #This mesh consists of a diamond-shape for each position that we traced.
        n = support_positions_3d.shape[0]
        Logger.log(
            "i",
            "Adding support in {num_pixels} locations.".format(num_pixels=n))
        vertices = support_positions_3d.copy().astype(_np.float32)
        vertices = _np.resize(vertices,
                              (n * 6, support_positions_3d.shape[1]
                               ))  #Resize will repeat all coordinates 6 times.
        #For each position, create a diamond shape around the position with 6 vertices.
        vertices[
            n * 0:n * 1,
            0] -= support_depths * 0.001 * self.globule_size  #First corner (-x, +y).
        vertices[n * 0:n * 1, 2] += support_depths * 0.001 * self.globule_size
        vertices[
            n * 1:n * 2,
            0] += support_depths * 0.001 * self.globule_size  #Second corner (+x, +y).
        vertices[n * 1:n * 2, 2] += support_depths * 0.001 * self.globule_size
        vertices[
            n * 2:n * 3,
            0] -= support_depths * 0.001 * self.globule_size  #Third corner (-x, -y).
        vertices[n * 2:n * 3, 2] -= support_depths * 0.001 * self.globule_size
        vertices[
            n * 3:n * 4,
            0] += support_depths * 0.001 * self.globule_size  #Fourth corner (+x, -y)
        vertices[n * 3:n * 4, 2] -= support_depths * 0.001 * self.globule_size
        vertices[n * 4:n * 5,
                 1] += support_depths * 0.001 * self.globule_size  #Top side.
        vertices[
            n * 5:n * 6,
            1] -= support_depths * 0.001 * self.globule_size  #Bottom side.

        #Create the faces of the diamond.
        indices = _np.arange(n, dtype=_np.int32)
        indices = _np.kron(indices, _np.ones(
            (3, 1))).astype(_np.int32).transpose()
        indices = _np.resize(
            indices, (n * 8, 3)
        )  #Creates 8 triangles using 3 times the same vertex, for each position: [[0, 0, 0], [1, 1, 1], ... , [0, 0, 0], [1, 1, 1], ... ]

        #indices[n * 0: n * 1, 0] += n * 0 #First corner.
        indices[n * 0:n * 1, 1] += n * 1  #Second corner.
        indices[n * 0:n * 1, 2] += n * 4  #Top side.

        indices[n * 1:n * 2, 0] += n * 1  #Second corner.
        indices[n * 1:n * 2, 1] += n * 3  #Fourth corner.
        indices[n * 1:n * 2, 2] += n * 4  #Top side.

        indices[n * 2:n * 3, 0] += n * 3  #Fourth corner.
        indices[n * 2:n * 3, 1] += n * 2  #Third corner.
        indices[n * 2:n * 3, 2] += n * 4  #Top side.

        indices[n * 3:n * 4, 0] += n * 2  #Third corner.
        #indices[n * 3: n * 4, 1] += n * 0 #First corner.
        indices[n * 3:n * 4, 2] += n * 4  #Top side.

        indices[n * 4:n * 5, 0] += n * 1  #Second corner.
        #indices[n * 4: n * 5, 1] += n * 0 #First corner.
        indices[n * 4:n * 5, 2] += n * 5  #Bottom side.

        indices[n * 5:n * 6, 0] += n * 3  #Fourth corner.
        indices[n * 5:n * 6, 1] += n * 1  #Second corner.
        indices[n * 5:n * 6, 2] += n * 5  #Bottom side.

        indices[n * 6:n * 7, 0] += n * 2  #Third corner.
        indices[n * 6:n * 7, 1] += n * 3  #Fourth corner.
        indices[n * 6:n * 7, 2] += n * 5  #Bottom side.

        #indices[n * 7: n * 8, 0] += n * 0 #First corner.
        indices[n * 7:n * 8, 1] += n * 2  #Third corner.
        indices[n * 7:n * 8, 2] += n * 5  #Bottom side.

        builder = MeshBuilder()
        builder.addVertices(vertices)
        builder.addIndices(indices)

        #Create the scene node.
        scene = CuraApplication.getInstance().getController().getScene()
        new_node = CuraSceneNode(parent=scene.getRoot(), name="BrushSupport")
        new_node.setSelectable(False)
        new_node.setMeshData(builder.build())
        new_node.addDecorator(
            BuildPlateDecorator(CuraApplication.getInstance().
                                getMultiBuildPlateModel().activeBuildPlate))
        new_node.addDecorator(SliceableObjectDecorator())
        operation = GroupedOperation()

        #Figure out which mesh this piece of support belongs to.
        #TODO: You can draw support in one stroke over multiple meshes. The support would belong to an arbitrary one of these.
        selection_pass = CuraApplication.getInstance().getRenderer(
        ).getRenderPass("selection")
        parent_id = selection_pass.getIdAtPosition(
            support_positions_2d[0][0], support_positions_2d[0]
            [1])  #Find the selection under the first support pixel.
        parent_node = scene.getRoot()
        if not parent_id:
            Logger.log("d", "Can't link custom support to any scene node.")
        else:
            for node in BreadthFirstIterator(scene.getRoot()):
                if id(node) == parent_id:
                    parent_node = node
                    break

        #Add the appropriate per-object settings.
        stack = new_node.callDecoration(
            "getStack"
        )  #Created by SettingOverrideDecorator that is automatically added to CuraSceneNode.
        settings = stack.getTop()
        support_mesh_instance = SettingInstance(
            stack.getSettingDefinition("support_mesh"), settings)
        support_mesh_instance.setProperty("value", True)
        support_mesh_instance.resetState()
        settings.addInstance(support_mesh_instance)
        drop_down_instance = SettingInstance(
            stack.getSettingDefinition("support_mesh_drop_down"), settings)
        drop_down_instance.setProperty("value", True)
        drop_down_instance.resetState()
        settings.addInstance(drop_down_instance)

        #Add the scene node to the scene (and allow for undo).
        operation.addOperation(
            AddSceneNodeOperation(new_node, scene.getRoot())
        )  #Set the parent to root initially, then change the parent, so that we don't have to alter the transformation.
        operation.addOperation(SetParentOperation(new_node, parent_node))
        operation.push()

        scene.sceneChanged.emit(new_node)