123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- import os.path
- import zipfile
- from UM.Job import Job
- from UM.Logger import Logger
- from UM.Math.Matrix import Matrix
- from UM.Math.Vector import Vector
- from UM.Mesh.MeshBuilder import MeshBuilder
- from UM.Mesh.MeshReader import MeshReader
- from UM.Scene.GroupDecorator import GroupDecorator
- import UM.Application
- from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
- from UM.Application import Application
- from cura.Settings.ExtruderManager import ExtruderManager
- from cura.QualityManager import QualityManager
- from UM.Scene.SceneNode import SceneNode
- import Savitar
- import numpy
- try:
- import xml.etree.cElementTree as ET
- except ImportError:
- Logger.log("w", "Unable to load cElementTree, switching to slower version")
- import xml.etree.ElementTree as ET
- class ThreeMFReader(MeshReader):
- def __init__(self):
- super().__init__()
- self._supported_extensions = [".3mf"]
- self._root = None
- self._namespaces = {
- "3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02",
- "cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10"
- }
- self._base_name = ""
- self._unit = None
- 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 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))
-
- if xml_settings:
- node.addDecorator(SettingOverrideDecorator())
- global_container_stack = Application.getInstance().getGlobalContainerStack()
-
- if global_container_stack:
- multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
-
- 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)
-
- 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
-
- 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()
-
- 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
- def _createMatrixFromTransformationString(self, transformation):
- if transformation == "":
- return Matrix()
- splitted_transformation = transformation.split()
-
-
-
-
-
-
- temp_mat = Matrix()
-
- temp_mat._data[0, 0] = splitted_transformation[0]
- temp_mat._data[1, 0] = splitted_transformation[1]
- temp_mat._data[2, 0] = splitted_transformation[2]
- temp_mat._data[0, 1] = splitted_transformation[3]
- temp_mat._data[1, 1] = splitted_transformation[4]
- temp_mat._data[2, 1] = splitted_transformation[5]
- temp_mat._data[0, 2] = splitted_transformation[6]
- temp_mat._data[1, 2] = splitted_transformation[7]
- temp_mat._data[2, 2] = splitted_transformation[8]
-
- temp_mat._data[0, 3] = splitted_transformation[9]
- temp_mat._data[1, 3] = splitted_transformation[10]
- temp_mat._data[2, 3] = splitted_transformation[11]
- return temp_mat
- 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():
- um_node.addChild(self._convertSavitarNodeToUMNode(child))
- settings = savitar_node.getSettings()
-
- if settings:
- um_node.addDecorator(SettingOverrideDecorator())
- global_container_stack = Application.getInstance().getGlobalContainerStack()
-
- if global_container_stack:
- multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
-
- 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)
-
- 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]
-
- 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)
- return um_node
- def read(self, file_name):
- result = []
-
- 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)
-
- 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 = UM.Application.getInstance().getGlobalContainerStack()
-
-
- 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
-
-
- 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)
-
- scale_matrix = Matrix()
- scale_matrix.setByScaleVector(self._getScaleFromUnit(self._unit))
- transformation_matrix.multiply(scale_matrix)
-
- 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
-
-
-
-
-
-
-
-
- def _getScaleFromUnit(self, unit):
- if unit is None:
- unit = "millimeter"
- if unit == "micron":
- scale = 0.001
- elif unit == "millimeter":
- scale = 1
- elif unit == "centimeter":
- scale = 10
- elif unit == "inch":
- scale = 25.4
- elif unit == "foot":
- scale = 304.8
- elif unit == "meter":
- scale = 1000
- else:
- Logger.log("w", "Unrecognised unit %s used. Assuming mm instead", unit)
- scale = 1
- return Vector(scale, scale, scale)
|