예제 #1
0
 def processTransform(self, node):
     rot = readRotation(node, "rotation", (0, 0, 1, 0)) # (angle, axisVactor) tuple
     trans = readVector(node, "translation", (0, 0, 0)) # Vector
     scale = readVector(node, "scale", (1, 1, 1)) # Vector
     center = readVector(node, "center", (0, 0, 0)) # Vector
     scale_orient = readRotation(node, "scaleOrientation", (0, 0, 1, 0)) # (angle, axisVactor) tuple
     
     # Store the previous transform; in Cura, the default matrix multiplication is in place        
     prev = Matrix(self.transform.getData()) # It's deep copy, I've checked
     
     # The rest of transform manipulation will be applied in place
     got_center = (center.x != 0 or center.y != 0 or center.z != 0)
     
     T = self.transform
     if trans.x != 0 or trans.y != 0 or trans.z !=0:
         T.translate(trans)
     if got_center:
         T.translate(center)
     if rot[0] != 0:
         T.rotateByAxis(*rot)
     if scale.x != 1 or scale.y != 1 or scale.z != 1:
         got_scale_orient = scale_orient[0] != 0
         if got_scale_orient:
             T.rotateByAxis(*scale_orient)
         # No scale by vector in place operation in UM
         S = Matrix()
         S.setByScaleVector(scale)
         T.multiply(S)
         if got_scale_orient:
             T.rotateByAxis(-scale_orient[0], scale_orient[1])
     if got_center:
         T.translate(-center)
         
     self.processChildNodes(node)
     self.transform = prev
예제 #2
0
    def scale(self,
              scale: Vector,
              transform_space: int = TransformSpace.Local) -> None:
        """Scale the scene object (and thus its children) by given amount

        :param scale: :type{Vector} A Vector with three scale values
        :param transform_space: The space relative to which to scale. Can be any one of the constants in SceneNode::TransformSpace.
        """

        if not self._enabled:
            return

        scale_matrix = Matrix()
        scale_matrix.setByScaleVector(scale)
        if transform_space == SceneNode.TransformSpace.Local:
            self._transformation.multiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.Parent:
            self._transformation.preMultiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.World:
            self._transformation.multiply(
                self._world_transformation.getInverse())
            self._transformation.multiply(scale_matrix)
            self._transformation.multiply(self._world_transformation)

        self._transformChanged()
예제 #3
0
    def read(self, file_name):
        result = []
        # The base object of 3mf is a zipped archive.
        try:
            archive = zipfile.ZipFile(file_name, "r")
            self._base_name = os.path.basename(file_name)
            parser = Savitar.ThreeMFParser()
            scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
            self._unit = scene_3mf.getUnit()
            for node in scene_3mf.getSceneNodes():
                um_node = self._convertSavitarNodeToUMNode(node)
                if um_node is None:
                    continue
                # compensate for original center position, if object(s) is/are not around its zero position

                transform_matrix = Matrix()
                mesh_data = um_node.getMeshData()
                if mesh_data is not None:
                    extents = mesh_data.getExtents()
                    center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
                    transform_matrix.setByTranslation(center_vector)
                transform_matrix.multiply(um_node.getLocalTransformation())
                um_node.setTransformation(transform_matrix)

                global_container_stack = Application.getInstance().getGlobalContainerStack()

                # Create a transformation Matrix to convert from 3mf worldspace into ours.
                # First step: flip the y and z axis.
                transformation_matrix = Matrix()
                transformation_matrix._data[1, 1] = 0
                transformation_matrix._data[1, 2] = 1
                transformation_matrix._data[2, 1] = -1
                transformation_matrix._data[2, 2] = 0

                # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
                # build volume.
                if global_container_stack:
                    translation_vector = Vector(x=-global_container_stack.getProperty("machine_width", "value") / 2,
                                                y=-global_container_stack.getProperty("machine_depth", "value") / 2,
                                                z=0)
                    translation_matrix = Matrix()
                    translation_matrix.setByTranslation(translation_vector)
                    transformation_matrix.multiply(translation_matrix)

                # Third step: 3MF also defines a unit, wheras Cura always assumes mm.
                scale_matrix = Matrix()
                scale_matrix.setByScaleVector(self._getScaleFromUnit(self._unit))
                transformation_matrix.multiply(scale_matrix)

                # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
                um_node.setTransformation(um_node.getLocalTransformation().preMultiply(transformation_matrix))

                result.append(um_node)

        except Exception:
            Logger.logException("e", "An exception occurred in 3mf reader.")
            return []

        return result
예제 #4
0
    def scale(self, scale: Vector, transform_space: int = TransformSpace.Local) -> None:
        if not self._enabled:
            return

        scale_matrix = Matrix()
        scale_matrix.setByScaleVector(scale)
        if transform_space == SceneNode.TransformSpace.Local:
            self._transformation.multiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.Parent:
            self._transformation.preMultiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.World:
            self._transformation.multiply(self._world_transformation.getInverse())
            self._transformation.multiply(scale_matrix)
            self._transformation.multiply(self._world_transformation)

        self._transformChanged()
예제 #5
0
    def scale(self, scale: Vector, transform_space: int = TransformSpace.Local):
        if not self._enabled:
            return

        scale_matrix = Matrix()
        scale_matrix.setByScaleVector(scale)
        if transform_space == SceneNode.TransformSpace.Local:
            self._transformation.multiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.Parent:
            self._transformation.preMultiply(scale_matrix)
        elif transform_space == SceneNode.TransformSpace.World:
            self._transformation.multiply(self._world_transformation.getInverse())
            self._transformation.multiply(scale_matrix)
            self._transformation.multiply(self._world_transformation)

        self._transformChanged()
예제 #6
0
    def _read(self, file_name: str) -> Union[SceneNode, List[SceneNode]]:
        self._empty_project = False
        result = []
        # The base object of 3mf is a zipped archive.
        try:
            archive = zipfile.ZipFile(file_name, "r")
            self._base_name = os.path.basename(file_name)
            parser = Savitar.ThreeMFParser()
            scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
            self._unit = scene_3mf.getUnit()

            for key, value in scene_3mf.getMetadata().items():
                CuraApplication.getInstance().getController().getScene(
                ).setMetaDataEntry(key, value)

            for node in scene_3mf.getSceneNodes():
                um_node = self._convertSavitarNodeToUMNode(node, file_name)
                if um_node is None:
                    continue

                # compensate for original center position, if object(s) is/are not around its zero position
                transform_matrix = Matrix()
                mesh_data = um_node.getMeshData()
                if mesh_data is not None:
                    extents = mesh_data.getExtents()
                    if extents is not None:
                        center_vector = Vector(extents.center.x,
                                               extents.center.y,
                                               extents.center.z)
                        transform_matrix.setByTranslation(center_vector)
                transform_matrix.multiply(um_node.getLocalTransformation())
                um_node.setTransformation(transform_matrix)

                global_container_stack = CuraApplication.getInstance(
                ).getGlobalContainerStack()

                # Create a transformation Matrix to convert from 3mf worldspace into ours.
                # First step: flip the y and z axis.
                transformation_matrix = Matrix()
                transformation_matrix._data[1, 1] = 0
                transformation_matrix._data[1, 2] = 1
                transformation_matrix._data[2, 1] = -1
                transformation_matrix._data[2, 2] = 0

                # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
                # build volume.
                if global_container_stack:
                    translation_vector = Vector(
                        x=-global_container_stack.getProperty(
                            "machine_width", "value") / 2,
                        y=-global_container_stack.getProperty(
                            "machine_depth", "value") / 2,
                        z=0)
                    translation_matrix = Matrix()
                    translation_matrix.setByTranslation(translation_vector)
                    transformation_matrix.multiply(translation_matrix)

                # Third step: 3MF also defines a unit, whereas Cura always assumes mm.
                scale_matrix = Matrix()
                scale_matrix.setByScaleVector(
                    self._getScaleFromUnit(self._unit))
                transformation_matrix.multiply(scale_matrix)

                # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
                um_node.setTransformation(
                    um_node.getLocalTransformation().preMultiply(
                        transformation_matrix))

                # Check if the model is positioned below the build plate and honor that when loading project files.
                node_meshdata = um_node.getMeshData()
                if node_meshdata is not None:
                    aabb = node_meshdata.getExtents(
                        um_node.getWorldTransformation())
                    if aabb is not None:
                        minimum_z_value = aabb.minimum.y  # y is z in transformation coordinates
                        if minimum_z_value < 0:
                            um_node.addDecorator(ZOffsetDecorator())
                            um_node.callDecoration("setZOffset",
                                                   minimum_z_value)

                result.append(um_node)

            if len(result) == 0:
                self._empty_project = True

        except Exception:
            Logger.logException("e", "An exception occurred in 3mf reader.")
            return []

        return result
예제 #7
0
    def read(self, file_name):
        result = []
        # The base object of 3mf is a zipped archive.
        archive = zipfile.ZipFile(file_name, "r")
        self._base_name = os.path.basename(file_name)
        try:
            self._root = ET.parse(archive.open("3D/3dmodel.model"))
            self._unit = self._root.getroot().get("unit")

            build_items = self._root.findall("./3mf:build/3mf:item",
                                             self._namespaces)

            for build_item in build_items:
                id = build_item.get("objectid")
                object = self._root.find(
                    "./3mf:resources/3mf:object[@id='{0}']".format(id),
                    self._namespaces)
                if "type" in object.attrib:
                    if object.attrib["type"] == "support" or object.attrib[
                            "type"] == "other":
                        # Ignore support objects, as cura does not support these.
                        # We can't guarantee that they wont be made solid.
                        # We also ignore "other", as I have no idea what to do with them.
                        Logger.log(
                            "w",
                            "3MF file contained an object of type %s which is not supported by Cura",
                            object.attrib["type"])
                        continue
                    elif object.attrib[
                            "type"] == "solidsupport" or object.attrib[
                                "type"] == "model":
                        pass  # Load these as normal
                    else:
                        # We should technically fail at this point because it's an invalid 3MF, but try to continue anyway.
                        Logger.log(
                            "e",
                            "3MF file contained an object of type %s which is not supported by the 3mf spec",
                            object.attrib["type"])
                        continue

                build_item_node = self._createNodeFromObject(
                    object, self._base_name + "_" + str(id))

                # compensate for original center position, if object(s) is/are not around its zero position
                transform_matrix = Matrix()
                mesh_data = build_item_node.getMeshData()
                if mesh_data is not None:
                    extents = mesh_data.getExtents()
                    center_vector = Vector(extents.center.x, extents.center.y,
                                           extents.center.z)
                    transform_matrix.setByTranslation(center_vector)

                # offset with transform from 3mf
                transform = build_item.get("transform")
                if transform is not None:
                    transform_matrix.multiply(
                        self._createMatrixFromTransformationString(transform))

                build_item_node.setTransformation(transform_matrix)

                global_container_stack = UM.Application.getInstance(
                ).getGlobalContainerStack()

                # Create a transformation Matrix to convert from 3mf worldspace into ours.
                # First step: flip the y and z axis.
                transformation_matrix = Matrix()
                transformation_matrix._data[1, 1] = 0
                transformation_matrix._data[1, 2] = 1
                transformation_matrix._data[2, 1] = -1
                transformation_matrix._data[2, 2] = 0

                # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
                # build volume.
                if global_container_stack:
                    translation_vector = Vector(
                        x=-global_container_stack.getProperty(
                            "machine_width", "value") / 2,
                        y=-global_container_stack.getProperty(
                            "machine_depth", "value") / 2,
                        z=0)
                    translation_matrix = Matrix()
                    translation_matrix.setByTranslation(translation_vector)
                    transformation_matrix.multiply(translation_matrix)

                # Third step: 3MF also defines a unit, wheras Cura always assumes mm.
                scale_matrix = Matrix()
                scale_matrix.setByScaleVector(
                    self._getScaleFromUnit(self._unit))
                transformation_matrix.multiply(scale_matrix)

                # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
                build_item_node.setTransformation(
                    build_item_node.getLocalTransformation().preMultiply(
                        transformation_matrix))

                result.append(build_item_node)

        except Exception as e:
            Logger.log("e", "An exception occurred in 3mf reader: %s", e)

        return result
예제 #8
0
파일: ThreeMFReader.py 프로젝트: mifga/Cura
    def read(self, file_name):
        result = []
        # The base object of 3mf is a zipped archive.
        archive = zipfile.ZipFile(file_name, "r")
        self._base_name = os.path.basename(file_name)
        try:
            self._root = ET.parse(archive.open("3D/3dmodel.model"))
            self._unit = self._root.getroot().get("unit")

            build_items = self._root.findall("./3mf:build/3mf:item", self._namespaces)

            for build_item in build_items:
                id = build_item.get("objectid")
                object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
                if "type" in object.attrib:
                    if object.attrib["type"] == "support" or object.attrib["type"] == "other":
                        # Ignore support objects, as cura does not support these.
                        # We can't guarantee that they wont be made solid.
                        # We also ignore "other", as I have no idea what to do with them.
                        Logger.log("w", "3MF file contained an object of type %s which is not supported by Cura", object.attrib["type"])
                        continue
                    elif object.attrib["type"] == "solidsupport" or object.attrib["type"] == "model":
                        pass  # Load these as normal
                    else:
                        # We should technically fail at this point because it's an invalid 3MF, but try to continue anyway.
                        Logger.log("e", "3MF file contained an object of type %s which is not supported by the 3mf spec",
                                   object.attrib["type"])
                        continue

                build_item_node = self._createNodeFromObject(object, self._base_name + "_" + str(id))

                # compensate for original center position, if object(s) is/are not around its zero position
                transform_matrix = Matrix()
                mesh_data = build_item_node.getMeshData()
                if mesh_data is not None:
                    extents = mesh_data.getExtents()
                    center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
                    transform_matrix.setByTranslation(center_vector)

                # offset with transform from 3mf
                transform = build_item.get("transform")
                if transform is not None:
                    transform_matrix.multiply(self._createMatrixFromTransformationString(transform))

                build_item_node.setTransformation(transform_matrix)

                global_container_stack = UM.Application.getInstance().getGlobalContainerStack()

                # Create a transformation Matrix to convert from 3mf worldspace into ours.
                # First step: flip the y and z axis.
                transformation_matrix = Matrix()
                transformation_matrix._data[1, 1] = 0
                transformation_matrix._data[1, 2] = 1
                transformation_matrix._data[2, 1] = -1
                transformation_matrix._data[2, 2] = 0

                # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
                # build volume.
                if global_container_stack:
                    translation_vector = Vector(x = -global_container_stack.getProperty("machine_width", "value") / 2,
                                                y = -global_container_stack.getProperty("machine_depth", "value") / 2,
                                                z = 0)
                    translation_matrix = Matrix()
                    translation_matrix.setByTranslation(translation_vector)
                    transformation_matrix.multiply(translation_matrix)

                # Third step: 3MF also defines a unit, wheras Cura always assumes mm.
                scale_matrix = Matrix()
                scale_matrix.setByScaleVector(self._getScaleFromUnit(self._unit))
                transformation_matrix.multiply(scale_matrix)

                # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
                build_item_node.setTransformation(build_item_node.getLocalTransformation().preMultiply(transformation_matrix))

                result.append(build_item_node)

        except Exception as e:
            Logger.log("e", "An exception occurred in 3mf reader: %s", e)

        return result
예제 #9
0
    def _read(self, file_name: str) -> Union[SceneNode, List[SceneNode]]:
        result = []
        self._object_count = 0  # Used to name objects as there is no node name yet.
        # The base object of 3mf is a zipped archive.
        try:
            archive = zipfile.ZipFile(file_name, "r")
            self._base_name = os.path.basename(file_name)
            parser = Savitar.ThreeMFParser()
            scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
            self._unit = scene_3mf.getUnit()
            for node in scene_3mf.getSceneNodes():
                um_node = self._convertSavitarNodeToUMNode(node)
                if um_node is None:
                    continue
                # compensate for original center position, if object(s) is/are not around its zero position

                transform_matrix = Matrix()
                mesh_data = um_node.getMeshData()
                if mesh_data is not None:
                    extents = mesh_data.getExtents()
                    if extents is not None:
                        center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
                        transform_matrix.setByTranslation(center_vector)
                transform_matrix.multiply(um_node.getLocalTransformation())
                um_node.setTransformation(transform_matrix)

                global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()

                # Create a transformation Matrix to convert from 3mf worldspace into ours.
                # First step: flip the y and z axis.
                transformation_matrix = Matrix()
                transformation_matrix._data[1, 1] = 0
                transformation_matrix._data[1, 2] = 1
                transformation_matrix._data[2, 1] = -1
                transformation_matrix._data[2, 2] = 0

                # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
                # build volume.
                if global_container_stack:
                    translation_vector = Vector(x = -global_container_stack.getProperty("machine_width", "value") / 2,
                                                y = -global_container_stack.getProperty("machine_depth", "value") / 2,
                                                z = 0)
                    translation_matrix = Matrix()
                    translation_matrix.setByTranslation(translation_vector)
                    transformation_matrix.multiply(translation_matrix)

                # Third step: 3MF also defines a unit, whereas Cura always assumes mm.
                scale_matrix = Matrix()
                scale_matrix.setByScaleVector(self._getScaleFromUnit(self._unit))
                transformation_matrix.multiply(scale_matrix)

                # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
                um_node.setTransformation(um_node.getLocalTransformation().preMultiply(transformation_matrix))

                # Check if the model is positioned below the build plate and honor that when loading project files.
                node_meshdata = um_node.getMeshData()
                if node_meshdata is not None:
                    aabb = node_meshdata.getExtents(um_node.getWorldTransformation())
                    if aabb is not None:
                        minimum_z_value = aabb.minimum.y  # y is z in transformation coordinates
                        if minimum_z_value < 0:
                            um_node.addDecorator(ZOffsetDecorator())
                            um_node.callDecoration("setZOffset", minimum_z_value)

                result.append(um_node)

        except Exception:
            Logger.logException("e", "An exception occurred in 3mf reader.")
            return []

        return result