예제 #1
0
    def _checkHit(self, a: SceneNode, b: SceneNode) -> bool:
        """Checks if a can be printed before b

        :param a: node
        :param b: node
        :return: true if a can be printed before b
        """

        if a == b:
            return False

        a_hit_hull = a.callDecoration("getConvexHullBoundary")
        b_hit_hull = b.callDecoration("getConvexHullHeadFull")
        overlap = a_hit_hull.intersectsPolygon(b_hit_hull)

        if overlap:
            return True

        # Adhesion areas must never overlap, regardless of printing order
        # This would cause over-extrusion
        a_hit_hull = a.callDecoration("getAdhesionArea")
        b_hit_hull = b.callDecoration("getAdhesionArea")
        overlap = a_hit_hull.intersectsPolygon(b_hit_hull)

        if overlap:
            return True
        else:
            return False
예제 #2
0
 def _onSceneChangedDelayed(self, scene_node: SceneNode) -> None:
     # Ignore any changes that are not related to sliceable objects
     if not isinstance(scene_node, SceneNode) \
             or not scene_node.callDecoration("isSliceable") \
             or not scene_node.callDecoration("getBuildPlateNumber") == self._active_build_plate:
         return
     self._change_timer.start()
def test_SceneNodeDecorator():
    test_node = SceneNode()
    test_decorator = SceneNodeDecorator()
    amazing_decorator = TheAmazingTestDecorator()
    less_amazing_decorator = TheLessAmazingTestDecorator()
    not_amazing_decorator = TheNotSoAmazingTestDecorator()

    # Replace emit with mock object
    test_node.decoratorsChanged.emit = MagicMock()
    test_decorator.clear = MagicMock()

    # First actual change
    test_node.addDecorator(test_decorator)
    assert len(test_node.getDecorators()) == 1
    assert test_node.decoratorsChanged.emit.call_count == 1

    # Adding a decorator of the same type (SceneNodeDecorator) again should not do anything.
    test_node.addDecorator(test_decorator)
    assert len(test_node.getDecorators()) == 1
    assert test_node.decoratorsChanged.emit.call_count == 1
    assert test_node.getDecorator(type(test_decorator)) == test_decorator

    # Remove the decorator again!
    test_node.removeDecorator(SceneNodeDecorator)
    assert len(test_node.getDecorators()) == 0
    assert test_node.decoratorsChanged.emit.call_count == 2
    assert test_decorator.clear.call_count == 1  # Ensure that the clear of the test decorator is called.

    # Add a number of decorators!
    test_node.addDecorator(amazing_decorator)
    test_node.addDecorator(less_amazing_decorator)
    test_node.addDecorator(not_amazing_decorator)
    assert test_node.decoratorsChanged.emit.call_count == 5
    assert len(test_node.getDecorators()) == 3

    assert test_node.hasDecoration("zomg") == False
    assert test_node.hasDecoration("theOkayDecoration")
    assert test_node.hasDecoration("theAmazingDecoration")

    # Calling the decorations with args / kwargs
    assert test_node.callDecoration("theOkayDecoration", None) is None
    assert test_node.callDecoration("theEvenMoreAmazingDecoration",
                                    "beep") == ("beep", "Wow", "so wow")
    assert test_node.callDecoration("theEvenMoreAmazingDecoration",
                                    "beep",
                                    much_test="Wow") == ("beep", "Wow", "Wow")

    # Calling decoration that is "double"
    assert test_node.callDecoration("theAmazingDecoration") == "Amazing!"
    test_node.removeDecorator(TheAmazingTestDecorator)
    assert test_node.callDecoration("theAmazingDecoration") == "amazing"

    not_amazing_decorator.clear = MagicMock()
    test_node.removeDecorators()
    # Also assure that removing all decorators also triggers the clear
    assert not_amazing_decorator.clear.call_count == 1
    assert len(test_node.getDecorators()) == 0
    assert test_node.decoratorsChanged.emit.call_count == 7
    assert test_node.getDecorator(type(test_decorator)) is None
예제 #4
0
    def _onSceneChanged(self, scene_node: SceneNode) -> None:
        # Ignore any changes that are not related to sliceable objects
        if not isinstance(scene_node, SceneNode)\
                or not scene_node.callDecoration("isSliceable")\
                or not scene_node.callDecoration("getBuildPlateNumber") == self._active_build_plate:
            return

        self.setToZeroPrintInformation(self._active_build_plate)
예제 #5
0
 def _updateNodeListeners(self, node: SceneNode):
     per_mesh_stack = node.callDecoration("getStack")
     if per_mesh_stack:
         per_mesh_stack.propertyChanged.connect(self._onSettingPropertyChanged)
     active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
     if active_extruder_changed is not None:
         active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild)
         self._updateDisallowedAreasAndRebuild()
예제 #6
0
파일: BuildVolume.py 프로젝트: daid/Cura
 def _updateNodeListeners(self, node: SceneNode):
     per_mesh_stack = node.callDecoration("getStack")
     if per_mesh_stack:
         per_mesh_stack.propertyChanged.connect(self._onSettingPropertyChanged)
     active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
     if active_extruder_changed is not None:
         active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild)
         self._updateDisallowedAreasAndRebuild()
예제 #7
0
    def _onSceneChanged(self, source: SceneNode) -> None:
        if not isinstance(source, SceneNode):
            return

        # This case checks if the source node is a node that contains GCode. In this case the
        # current layer data is removed so the previous data is not rendered - CURA-4821
        if source.callDecoration("isBlockSlicing") and source.callDecoration(
                "getLayerData"):
            self._stored_optimized_layer_data = {}

        build_plate_changed = set()
        source_build_plate_number = source.callDecoration(
            "getBuildPlateNumber")
        if source == self._scene.getRoot():
            # we got the root node
            num_objects = self._numObjectsPerBuildPlate()
            for build_plate_number in list(
                    self._last_num_objects.keys()) + list(num_objects.keys()):
                if build_plate_number not in self._last_num_objects or num_objects[
                        build_plate_number] != self._last_num_objects[
                            build_plate_number]:
                    self._last_num_objects[build_plate_number] = num_objects[
                        build_plate_number]
                    build_plate_changed.add(build_plate_number)
        else:
            # we got a single scenenode
            if not source.callDecoration("isGroup"):
                if source.getMeshData() is None:
                    return
                if source.getMeshData().getVertices() is None:
                    return

            build_plate_changed.add(source_build_plate_number)

        build_plate_changed.discard(None)
        build_plate_changed.discard(-1)  # object not on build plate
        if not build_plate_changed:
            return

        if self._tool_active:
            # do it later, each source only has to be done once
            if source not in self._postponed_scene_change_sources:
                self._postponed_scene_change_sources.append(source)
            return

        self.stopSlicing()
        for build_plate_number in build_plate_changed:
            if build_plate_number not in self._build_plates_to_be_sliced:
                self._build_plates_to_be_sliced.append(build_plate_number)
            self.printDurationMessage.emit(source_build_plate_number, {}, [])
        self.processingProgress.emit(0.0)
        self.backendStateChange.emit(BackendState.NotStarted)
        # if not self._use_timer:
        # With manually having to slice, we want to clear the old invalid layer data.
        self._clearLayerData(build_plate_changed)

        self._invokeSlice()
예제 #8
0
def test_SceneNodeDecorator():
    test_node = SceneNode()
    test_decorator = SceneNodeDecorator()
    amazing_decorator = TheAmazingTestDecorator()
    less_amazing_decorator = TheLessAmazingTestDecorator()
    not_amazing_decorator = TheNotSoAmazingTestDecorator()

    # Replace emit with mock object
    test_node.decoratorsChanged.emit = MagicMock()
    test_decorator.clear = MagicMock()

    # First actual change
    test_node.addDecorator(test_decorator)
    assert len(test_node.getDecorators()) == 1
    assert test_node.decoratorsChanged.emit.call_count == 1

    # Adding a decorator of the same type (SceneNodeDecorator) again should not do anything.
    test_node.addDecorator(test_decorator)
    assert len(test_node.getDecorators()) == 1
    assert test_node.decoratorsChanged.emit.call_count == 1
    assert test_node.getDecorator(type(test_decorator)) == test_decorator

    # Remove the decorator again!
    test_node.removeDecorator(SceneNodeDecorator)
    assert len(test_node.getDecorators()) == 0
    assert test_node.decoratorsChanged.emit.call_count == 2
    assert test_decorator.clear.call_count == 1  # Ensure that the clear of the test decorator is called.

    # Add a number of decorators!
    test_node.addDecorator(amazing_decorator)
    test_node.addDecorator(less_amazing_decorator)
    test_node.addDecorator(not_amazing_decorator)
    assert test_node.decoratorsChanged.emit.call_count == 5
    assert len(test_node.getDecorators()) == 3

    assert test_node.hasDecoration("zomg") == False
    assert test_node.hasDecoration("theOkayDecoration")
    assert test_node.hasDecoration("theAmazingDecoration")

    # Calling the decorations with args / kwargs
    assert test_node.callDecoration("theOkayDecoration", None) is None
    assert test_node.callDecoration("theEvenMoreAmazingDecoration", "beep") == ("beep", "Wow", "so wow")
    assert test_node.callDecoration("theEvenMoreAmazingDecoration", "beep", much_test = "Wow") == ("beep", "Wow", "Wow")

    # Calling decoration that is "double"
    assert test_node.callDecoration("theAmazingDecoration") == "Amazing!"
    test_node.removeDecorator(TheAmazingTestDecorator)
    assert test_node.callDecoration("theAmazingDecoration") == "amazing"

    not_amazing_decorator.clear = MagicMock()
    test_node.removeDecorators()
    # Also assure that removing all decorators also triggers the clear
    assert not_amazing_decorator.clear.call_count == 1
    assert len(test_node.getDecorators()) == 0
    assert test_node.decoratorsChanged.emit.call_count == 7
    assert test_node.getDecorator(type(test_decorator)) is None
예제 #9
0
    def _onSceneChanged(self, source: SceneNode) -> None:
        """Listener for when the scene has changed.

        This should start a slice if the scene is now ready to slice.

        :param source: The scene node that was changed.
        """

        if not source.callDecoration("isSliceable") and source != self._scene.getRoot():
            return

        # This case checks if the source node is a node that contains GCode. In this case the
        # current layer data is removed so the previous data is not rendered - CURA-4821
        if source.callDecoration("isBlockSlicing") and source.callDecoration("getLayerData"):
            self._stored_optimized_layer_data = {}

        build_plate_changed = set()
        source_build_plate_number = source.callDecoration("getBuildPlateNumber")
        if source == self._scene.getRoot():
            # we got the root node
            num_objects = self._numObjectsPerBuildPlate()
            for build_plate_number in list(self._last_num_objects.keys()) + list(num_objects.keys()):
                if build_plate_number not in self._last_num_objects or num_objects[build_plate_number] != self._last_num_objects[build_plate_number]:
                    self._last_num_objects[build_plate_number] = num_objects[build_plate_number]
                    build_plate_changed.add(build_plate_number)
        else:
            # we got a single scenenode
            if not source.callDecoration("isGroup"):
                mesh_data = source.getMeshData()
                if mesh_data is None or mesh_data.getVertices() is None:
                    return

            # There are some SceneNodes that do not have any build plate associated, then do not add to the list.
            if source_build_plate_number is not None:
                build_plate_changed.add(source_build_plate_number)

        if not build_plate_changed:
            return

        if self._tool_active:
            # do it later, each source only has to be done once
            if source not in self._postponed_scene_change_sources:
                self._postponed_scene_change_sources.append(source)
            return

        self.stopSlicing()
        for build_plate_number in build_plate_changed:
            if build_plate_number not in self._build_plates_to_be_sliced:
                self._build_plates_to_be_sliced.append(build_plate_number)
            self.printDurationMessage.emit(source_build_plate_number, {}, [])
        self.processingProgress.emit(0.0)
        self._clearLayerData(build_plate_changed)

        self._invokeSlice()
예제 #10
0
    def _shouldNodeBeHandled(self, node: SceneNode) -> bool:
        is_group = bool(node.callDecoration("isGroup"))
        if not node.callDecoration("isSliceable") and not is_group:
            return False

        parent = node.getParent()
        if parent and parent.callDecoration("isGroup"):
            return False  # Grouped nodes don't need resetting as their parent (the group) is resetted)

        node_build_plate_number = node.callDecoration("getBuildPlateNumber")
        if Application.getInstance().getPreferences().getValue("view/filter_current_build_plate") and node_build_plate_number != self._build_plate_number:
            return False

        return True
예제 #11
0
    def _shouldNodeBeHandled(self, node: SceneNode) -> bool:
        is_group = bool(node.callDecoration("isGroup"))
        if not node.callDecoration("isSliceable") and not is_group:
            return False

        parent = node.getParent()
        if parent and parent.callDecoration("isGroup"):
            return False  # Grouped nodes don't need resetting as their parent (the group) is resetted)

        node_build_plate_number = node.callDecoration("getBuildPlateNumber")
        if Application.getInstance().getPreferences().getValue("view/filter_current_build_plate") and node_build_plate_number != self._build_plate_number:
            return False

        return True
예제 #12
0
    def _onSceneChanged(self, source: SceneNode) -> None:
        if not isinstance(source, SceneNode):
            return

        # This case checks if the source node is a node that contains GCode. In this case the
        # current layer data is removed so the previous data is not rendered - CURA-4821
        if source.callDecoration("isBlockSlicing") and source.callDecoration("getLayerData"):
            self._stored_optimized_layer_data = {}

        build_plate_changed = set()
        source_build_plate_number = source.callDecoration("getBuildPlateNumber")
        if source == self._scene.getRoot():
            # we got the root node
            num_objects = self._numObjectsPerBuildPlate()
            for build_plate_number in list(self._last_num_objects.keys()) + list(num_objects.keys()):
                if build_plate_number not in self._last_num_objects or num_objects[build_plate_number] != self._last_num_objects[build_plate_number]:
                    self._last_num_objects[build_plate_number] = num_objects[build_plate_number]
                    build_plate_changed.add(build_plate_number)
        else:
            # we got a single scenenode
            if not source.callDecoration("isGroup"):
                mesh_data = source.getMeshData()
                if mesh_data is None or mesh_data.getVertices() is None:
                    return

            # There are some SceneNodes that do not have any build plate associated, then do not add to the list.
            if source_build_plate_number is not None:
                build_plate_changed.add(source_build_plate_number)

        if not build_plate_changed:
            return

        if self._tool_active:
            # do it later, each source only has to be done once
            if source not in self._postponed_scene_change_sources:
                self._postponed_scene_change_sources.append(source)
            return

        self.stopSlicing()
        for build_plate_number in build_plate_changed:
            if build_plate_number not in self._build_plates_to_be_sliced:
                self._build_plates_to_be_sliced.append(build_plate_number)
            self.printDurationMessage.emit(source_build_plate_number, {}, [])
        self.processingProgress.emit(0.0)
        self.setState(BackendState.NotStarted)
        # if not self._use_timer:
            # With manually having to slice, we want to clear the old invalid layer data.
        self._clearLayerData(build_plate_changed)

        self._invokeSlice()
예제 #13
0
    def _onSceneChanged(self, source: SceneNode) -> None:
        if not isinstance(source, SceneNode):
            return
        if source.callDecoration("isBlockSlicing") and source.callDecoration(
                "getLayerData"):
            self._stored_optimized_layer_data = {}

        build_plate_changed = set()
        source_build_plate_number = source.callDecoration(
            "getBuildPlateNumber")
        if source == self._scene.getRoot():
            num_objects = self._numObjectsPerBuildPlate()
            for build_plate_number in list(
                    self._last_num_objects.keys()) + list(num_objects.keys()):
                if build_plate_number not in self._last_num_objects or num_objects[build_plate_number] != \
                        self._last_num_objects[build_plate_number]:
                    self._last_num_objects[build_plate_number] = num_objects[
                        build_plate_number]
                    build_plate_changed.add(build_plate_number)
        else:
            if not source.callDecoration("isGroup"):
                mesh_data = source.getMeshData()
                if mesh_data is None or mesh_data.getVertices() is None:
                    return

            if source_build_plate_number is not None:
                build_plate_changed.add(source_build_plate_number)

        if not build_plate_changed:
            return

        if self._tool_active:
            if source not in self._postponed_scene_change_sources:
                self._postponed_scene_change_sources.append(source)
            return

        self.stopSlicing()
        for build_plate_number in build_plate_changed:
            if build_plate_number not in self._build_plates_to_be_sliced:
                self._build_plates_to_be_sliced.append(build_plate_number)
            self.printDurationMessage.emit(source_build_plate_number, {}, [])
        self.processingProgress.emit(0.0)
        self.backendStateChange.emit(BackendState.NotStarted)
        # if not self._use_timer:
        # With manually having to slice, we want to clear the old invalid layer data.
        self._clearLayerData(build_plate_changed)

        self._invokeSlice()
예제 #14
0
def getNodeActiveExtruder(node: SceneNode) -> ExtruderStack:
    active_extruder_position = node.callDecoration("getActiveExtruderPosition")
    if active_extruder_position is None:
        active_extruder_position = 0
    else:
        active_extruder_position = int(active_extruder_position)

    # Only use the extruder that is active on our mesh_node
    # The back end only supports a single extruder, currently.
    # Ignore any extruder that is not the active extruder.
    machine_extruders = list(filter(
        lambda extruder: extruder.position == active_extruder_position,
        CuraApplication.getInstance().getMachineManager().activeMachine.extruderList
    ))

    if len(machine_extruders) > 0:
        return machine_extruders[0]

    return None
예제 #15
0
    def _convertSavitarNodeToUMNode(self, savitar_node):
        um_node = SceneNode()
        transformation = self._createMatrixFromTransformationString(
            savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(
            savitar_node.getMeshData().getFlatVerticesAsBytes(),
            dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            um_node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance(
            ).getGlobalContainerStack()

            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                default_stack = ExtruderManager.getInstance().getExtruderStack(
                    0)

                if default_stack:
                    um_node.callDecoration("setActiveExtruder",
                                           default_stack.getId())

                # Get the definition & set it
                definition = QualityManager.getInstance(
                ).getParentMachineDefinition(
                    global_container_stack.getBottom())
                um_node.callDecoration("getStack").getTop().setDefinition(
                    definition.getId())

            setting_container = um_node.callDecoration("getStack").getTop()

            for key in settings:
                setting_value = settings[key]

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder",
                                               extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                setting_container.setProperty(key, "value", setting_value)

        if len(um_node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
예제 #16
0
    def _createNodeFromObject(self, object, name=""):
        node = SceneNode()
        node.setName(name)
        mesh_builder = MeshBuilder()
        vertex_list = []

        components = object.find(".//3mf:components", self._namespaces)
        if components:
            for component in components:
                id = component.get("objectid")
                new_object = self._root.find(
                    "./3mf:resources/3mf:object[@id='{0}']".format(id),
                    self._namespaces)
                new_node = self._createNodeFromObject(
                    new_object, self._base_name + "_" + str(id))
                node.addChild(new_node)
                transform = component.get("transform")
                if transform is not None:
                    new_node.setTransformation(
                        self._createMatrixFromTransformationString(transform))

        # for vertex in entry.mesh.vertices.vertex:
        for vertex in object.findall(".//3mf:vertex", self._namespaces):
            vertex_list.append(
                [vertex.get("x"),
                 vertex.get("y"),
                 vertex.get("z")])
            Job.yieldThread()

        xml_settings = list(object.findall(".//cura:setting",
                                           self._namespaces))

        # Add the setting override decorator, so we can add settings to this node.
        if xml_settings:
            node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance(
            ).getGlobalContainerStack()
            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                multi_extrusion = global_container_stack.getProperty(
                    "machine_extruder_count", "value") > 1
                # Ensure that all extruder data is reset
                if not multi_extrusion:
                    default_stack_id = global_container_stack.getId()
                else:
                    default_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(0)
                    if default_stack:
                        default_stack_id = default_stack.getId()
                    else:
                        default_stack_id = global_container_stack.getId()
                node.callDecoration("setActiveExtruder", default_stack_id)

                # Get the definition & set it
                definition = QualityManager.getInstance(
                ).getParentMachineDefinition(
                    global_container_stack.getBottom())
                node.callDecoration("getStack").getTop().setDefinition(
                    definition)

            setting_container = node.callDecoration("getStack").getTop()
            for setting in xml_settings:
                setting_key = setting.get("key")
                setting_value = setting.text

                # Extruder_nr is a special case.
                if setting_key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        node.callDecoration("setActiveExtruder",
                                            extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                setting_container.setProperty(setting_key, "value",
                                              setting_value)

        if len(node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            node.addDecorator(group_decorator)

        triangles = object.findall(".//3mf:triangle", self._namespaces)
        mesh_builder.reserveFaceCount(len(triangles))

        for triangle in triangles:
            v1 = int(triangle.get("v1"))
            v2 = int(triangle.get("v2"))
            v3 = int(triangle.get("v3"))

            mesh_builder.addFaceByPoints(
                vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
                vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
                vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])

            Job.yieldThread()

        # TODO: We currently do not check for normals and simply recalculate them.
        mesh_builder.calculateNormals(fast=True)
        mesh_builder.setFileName(name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            node.setMeshData(mesh_data)

        node.setSelectable(True)
        return node
예제 #17
0
 def _onSceneChanged(self, changed_object: SceneNode):
     if changed_object.callDecoration(
             "getLayerData"):  # Any layer data has changed.
         self._switching_layers = True
         self._old_current_layer = 0
         self._old_current_path = 0
예제 #18
0
파일: ThreeMFReader.py 프로젝트: daid/Cura
    def _convertSavitarNodeToUMNode(self, savitar_node):
        um_node = SceneNode()
        transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(savitar_node.getMeshData().getFlatVerticesAsBytes(), dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            um_node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance().getGlobalContainerStack()
            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1

                # Ensure that all extruder data is reset
                if not multi_extrusion:
                    default_stack_id = global_container_stack.getId()
                else:
                    default_stack = ExtruderManager.getInstance().getExtruderStack(0)
                    if default_stack:
                        default_stack_id = default_stack.getId()
                    else:
                        default_stack_id = global_container_stack.getId()
                um_node.callDecoration("setActiveExtruder", default_stack_id)

                # Get the definition & set it
                definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
                um_node.callDecoration("getStack").getTop().setDefinition(definition)

            setting_container = um_node.callDecoration("getStack").getTop()

            for key in settings:
                setting_value = settings[key]

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder", extruder_stack.getId())
                    else:
                        Logger.log("w", "Unable to find extruder in position %s", setting_value)
                    continue
                setting_container.setProperty(key,"value", setting_value)

        if len(um_node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
예제 #19
0
파일: ThreeMFReader.py 프로젝트: mifga/Cura
    def _createNodeFromObject(self, object, name = ""):
        node = SceneNode()
        node.setName(name)
        mesh_builder = MeshBuilder()
        vertex_list = []

        components = object.find(".//3mf:components", self._namespaces)
        if components:
            for component in components:
                id = component.get("objectid")
                new_object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
                new_node = self._createNodeFromObject(new_object, self._base_name + "_" + str(id))
                node.addChild(new_node)
                transform = component.get("transform")
                if transform is not None:
                    new_node.setTransformation(self._createMatrixFromTransformationString(transform))

        # for vertex in entry.mesh.vertices.vertex:
        for vertex in object.findall(".//3mf:vertex", self._namespaces):
            vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
            Job.yieldThread()

        xml_settings = list(object.findall(".//cura:setting", self._namespaces))

        # Add the setting override decorator, so we can add settings to this node.
        if xml_settings:
            node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance().getGlobalContainerStack()
            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
                # Ensure that all extruder data is reset
                if not multi_extrusion:
                    default_stack_id = global_container_stack.getId()
                else:
                    default_stack = ExtruderManager.getInstance().getExtruderStack(0)
                    if default_stack:
                        default_stack_id = default_stack.getId()
                    else:
                        default_stack_id = global_container_stack.getId()
                node.callDecoration("setActiveExtruder", default_stack_id)

                # Get the definition & set it
                definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
                node.callDecoration("getStack").getTop().setDefinition(definition)

            setting_container = node.callDecoration("getStack").getTop()
            for setting in xml_settings:
                setting_key = setting.get("key")
                setting_value = setting.text

                # Extruder_nr is a special case.
                if setting_key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
                    if extruder_stack:
                        node.callDecoration("setActiveExtruder", extruder_stack.getId())
                    else:
                        Logger.log("w", "Unable to find extruder in position %s", setting_value)
                    continue
                setting_container.setProperty(setting_key,"value", setting_value)

        if len(node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            node.addDecorator(group_decorator)

        triangles = object.findall(".//3mf:triangle", self._namespaces)
        mesh_builder.reserveFaceCount(len(triangles))

        for triangle in triangles:
            v1 = int(triangle.get("v1"))
            v2 = int(triangle.get("v2"))
            v3 = int(triangle.get("v3"))

            mesh_builder.addFaceByPoints(vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
                                         vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
                                         vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])

            Job.yieldThread()

        # TODO: We currently do not check for normals and simply recalculate them.
        mesh_builder.calculateNormals()
        mesh_builder.setFileName(name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            node.setMeshData(mesh_data)

        node.setSelectable(True)
        return node