From 410810f767d915c48f0771cc3629a57c1671789c Mon Sep 17 00:00:00 2001 From: Sebastian Sille <> Date: Thu, 11 Sep 2025 23:16:42 +0200 Subject: [PATCH 1/2] PyMVR Modification - add detailed xml declaration - make fixture attributes of BaseChildNode optional - make matrix of layer, groupobject, geometry3d and symbol optional. - (Usually only one object has a matrix, mostly scene object, truss, etc) - add Geometry3D to ChildList - add ChildList to Symdef --- pymvr/__init__.py | 59 ++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/pymvr/__init__.py b/pymvr/__init__.py index ecf28c9..3805bf3 100644 --- a/pymvr/__init__.py +++ b/pymvr/__init__.py @@ -98,11 +98,11 @@ def write_mvr(self, path: Optional[str] = None): if path is not None: if sys.version_info >= (3, 9): ElementTree.indent(self.xml_root, space=" ", level=0) - xmlstr = ElementTree.tostring( - self.xml_root, encoding="UTF-8", xml_declaration=True - ) + xmlstr = ElementTree.tostring(self.xml_root, encoding="unicode") + dec = '\n' + initxml = dec + xmlstr with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as z: - z.writestr("GeneralSceneDescription.xml", xmlstr) + z.writestr("GeneralSceneDescription.xml", initxml) for file_path, file_name in self.files_list: try: z.write(file_path, arcname=file_name) @@ -419,11 +419,11 @@ def __init__( matrix: Optional[Matrix] = None, classing: Optional[str] = None, fixture_id: Optional[str] = None, - fixture_id_numeric: int = 0, - unit_number: int = 0, - custom_id: int = 0, - custom_id_type: int = 0, - cast_shadow: bool = False, + fixture_id_numeric: Optional[int] = 0, + unit_number: Optional[int] = 0, + custom_id: Optional[int] = None, + custom_id_type: Optional[int] = None, + cast_shadow: Optional[bool] = False, addresses: Optional["Addresses"] = None, alignments: Optional["Alignments"] = None, custom_commands: Optional["CustomCommands"] = None, @@ -572,12 +572,16 @@ def populate_xml(self, element: Element): if self.connections: self.connections.to_xml(element) - ElementTree.SubElement(element, "FixtureID").text = str(self.fixture_id) or "0" - ElementTree.SubElement(element, "FixtureIDNumeric").text = str( - self.fixture_id_numeric + if self.fixture_id: + ElementTree.SubElement(element, "FixtureID").text = str(self.fixture_id) or "0" + + if self.fixture_id_numeric: + ElementTree.SubElement(element, "FixtureIDNumeric").text = str( + self.fixture_id_numeric ) - if self.unit_number is not None: + if self.unit_number: ElementTree.SubElement(element, "UnitNumber").text = str(self.unit_number) + if self.custom_id_type is not None: ElementTree.SubElement(element, "CustomIdType").text = str( self.custom_id_type @@ -882,7 +886,7 @@ def __init__( self.uuid = uuid self.classing = classing self.child_list = child_list - self.matrix = matrix if matrix is not None else Matrix(0) + self.matrix = matrix super().__init__(xml_node, *args, **kwargs) @@ -908,7 +912,8 @@ def to_xml(self): element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix: + Matrix(self.matrix.matrix).to_xml(parent=element) if self.classing: ElementTree.SubElement(element, "Classing").text = self.classing if self.child_list: @@ -927,6 +932,7 @@ def __init__( trusses: Optional[List["Truss"]] = None, video_screens: Optional[List["VideoScreen"]] = None, projectors: Optional[List["Projector"]] = None, + geometry3d: Optional[List["Geometry3D"]] = None, xml_node: Optional["Element"] = None, *args, **kwargs, @@ -939,6 +945,7 @@ def __init__( self.video_screens = video_screens if video_screens is not None else [] self.trusses = trusses if trusses is not None else [] self.projectors = projectors if projectors is not None else [] + self.geometry3d = geometry3d if geometry3d is not None else [] super().__init__(xml_node, *args, **kwargs) @@ -965,6 +972,7 @@ def _read_xml(self, xml_node: "Element"): ] self.projectors = [Projector(xml_node=i) for i in xml_node.findall("Projector")] + self.geometry3d = [Geometry3D(xml_node=i) for i in xml_node.findall("Geometry3D")] def to_xml(self, parent: Element): element = ElementTree.SubElement(parent, type(self).__name__) @@ -984,6 +992,8 @@ def to_xml(self, parent: Element): element.append(video_screen.to_xml()) for projector in self.projectors: element.append(projector.to_xml()) + for geometry3d in self.geometry3d: + element.append(geometry3d.to_xml()) return element @@ -1003,7 +1013,7 @@ def __init__( uuid = str(py_uuid.uuid4()) self.uuid = uuid self.child_list = child_list - self.matrix = matrix if matrix is not None else Matrix(0) + self.matrix = matrix super().__init__(xml_node, *args, **kwargs) @@ -1025,7 +1035,8 @@ def to_xml(self): element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix: + Matrix(self.matrix.matrix).to_xml(parent=element) if self.child_list: self.child_list.to_xml(parent=element) return element @@ -1141,6 +1152,7 @@ def __init__( self, uuid: Optional[str] = None, name: Optional[str] = None, + child_list: Optional["ChildList"] = None, geometry3d: Optional[List["Geometry3D"]] = None, symbol: Optional[List["Symbol"]] = None, xml_node: Optional["Element"] = None, @@ -1149,6 +1161,7 @@ def __init__( ): self.uuid = uuid self.name = name + self.child_list = child_list self.geometry3d = geometry3d if geometry3d is not None else [] self.symbol = symbol if symbol is not None else [] super().__init__(xml_node, *args, **kwargs) @@ -1174,6 +1187,8 @@ def to_xml(self): element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) + if self.child_list: + self.child_list.to_xml(element) for geo in self.geometry3d: element.append(geo.to_xml()) for sym in self.symbol: @@ -1191,7 +1206,7 @@ def __init__( **kwargs, ): self.file_name = file_name - self.matrix = matrix if matrix is not None else Matrix(0) + self.matrix = matrix super().__init__(xml_node, *args, **kwargs) def _read_xml(self, xml_node: "Element"): @@ -1219,7 +1234,8 @@ def __hash__(self): def to_xml(self): element = ElementTree.Element(type(self).__name__, fileName=self.file_name) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix: + Matrix(self.matrix.matrix).to_xml(parent=element) return element @@ -1235,7 +1251,7 @@ def __init__( ): self.uuid = uuid self.symdef = symdef - self.matrix = matrix if matrix is not None else Matrix(0) + self.matrix = matrix super().__init__(xml_node, *args, **kwargs) def _read_xml(self, xml_node: "Element"): @@ -1252,7 +1268,8 @@ def to_xml(self): element = ElementTree.Element( type(self).__name__, uuid=self.uuid, symdef=self.symdef ) - Matrix(self.matrix.matrix).to_xml(parent=element) + if self.matrix: + Matrix(self.matrix.matrix).to_xml(parent=element) return element From 801aa19a91b194f8cbbf194027f56fb054344131 Mon Sep 17 00:00:00 2001 From: Sebastian Sille <> Date: Fri, 12 Sep 2025 01:32:47 +0200 Subject: [PATCH 2/2] PyMVR modification - If matrix is identity it will not be added to xml. - Add better matrix check - Reformated with ruff --- pymvr/__init__.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/pymvr/__init__.py b/pymvr/__init__.py index 3805bf3..61163bd 100644 --- a/pymvr/__init__.py +++ b/pymvr/__init__.py @@ -573,12 +573,14 @@ def populate_xml(self, element: Element): self.connections.to_xml(element) if self.fixture_id: - ElementTree.SubElement(element, "FixtureID").text = str(self.fixture_id) or "0" + ElementTree.SubElement(element, "FixtureID").text = ( + str(self.fixture_id) or "0" + ) if self.fixture_id_numeric: ElementTree.SubElement(element, "FixtureIDNumeric").text = str( self.fixture_id_numeric - ) + ) if self.unit_number: ElementTree.SubElement(element, "UnitNumber").text = str(self.unit_number) @@ -886,7 +888,7 @@ def __init__( self.uuid = uuid self.classing = classing self.child_list = child_list - self.matrix = matrix + self.matrix = matrix if matrix is not None else Matrix(0) super().__init__(xml_node, *args, **kwargs) @@ -909,10 +911,13 @@ def __str__(self): return f"{self.name}" def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - if self.matrix: + if self.matrix and check_mtx: Matrix(self.matrix.matrix).to_xml(parent=element) if self.classing: ElementTree.SubElement(element, "Classing").text = self.classing @@ -972,7 +977,9 @@ def _read_xml(self, xml_node: "Element"): ] self.projectors = [Projector(xml_node=i) for i in xml_node.findall("Projector")] - self.geometry3d = [Geometry3D(xml_node=i) for i in xml_node.findall("Geometry3D")] + self.geometry3d = [ + Geometry3D(xml_node=i) for i in xml_node.findall("Geometry3D") + ] def to_xml(self, parent: Element): element = ElementTree.SubElement(parent, type(self).__name__) @@ -1013,7 +1020,7 @@ def __init__( uuid = str(py_uuid.uuid4()) self.uuid = uuid self.child_list = child_list - self.matrix = matrix + self.matrix = matrix if matrix is not None else Matrix(0) super().__init__(xml_node, *args, **kwargs) @@ -1032,10 +1039,13 @@ def _read_xml(self, xml_node: "Element"): self.matrix = Matrix(str_repr=matrix_node.text) def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, name=self.name, uuid=self.uuid ) - if self.matrix: + if self.matrix and check_mtx: Matrix(self.matrix.matrix).to_xml(parent=element) if self.child_list: self.child_list.to_xml(parent=element) @@ -1206,7 +1216,7 @@ def __init__( **kwargs, ): self.file_name = file_name - self.matrix = matrix + self.matrix = matrix if matrix is not None else Matrix(0) super().__init__(xml_node, *args, **kwargs) def _read_xml(self, xml_node: "Element"): @@ -1233,8 +1243,11 @@ def __hash__(self): return hash((self.file_name, str(self.matrix))) def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element(type(self).__name__, fileName=self.file_name) - if self.matrix: + if self.matrix and check_mtx: Matrix(self.matrix.matrix).to_xml(parent=element) return element @@ -1251,7 +1264,7 @@ def __init__( ): self.uuid = uuid self.symdef = symdef - self.matrix = matrix + self.matrix = matrix if matrix is not None else Matrix(0) super().__init__(xml_node, *args, **kwargs) def _read_xml(self, xml_node: "Element"): @@ -1265,10 +1278,13 @@ def __str__(self): return f"{self.uuid}" def to_xml(self): + check_mtx = any( + isinstance(i, float) for i in set().union(sum(self.matrix.matrix[:-1], [])) + ) element = ElementTree.Element( type(self).__name__, uuid=self.uuid, symdef=self.symdef ) - if self.matrix: + if self.matrix and check_mtx: Matrix(self.matrix.matrix).to_xml(parent=element) return element