Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorj.delarago <joeydelarago@gmail.com>2022-01-28 19:07:34 +0300
committerj.delarago <joeydelarago@gmail.com>2022-01-31 11:20:53 +0300
commit31e11c415d2ab3284e22e056d684addf8b28f01a (patch)
treef394efb5764ec7db254b6679f59aa694436e1441 /scripts
parenta20ff6f17057c7be4973aedfe0b1370763c01c0d (diff)
Add obj_trimmer.py script for trimming obj files used for printer base plates.
CURA-7541
Diffstat (limited to 'scripts')
-rw-r--r--scripts/obj_trimmer.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/scripts/obj_trimmer.py b/scripts/obj_trimmer.py
new file mode 100644
index 0000000000..5f1de29511
--- /dev/null
+++ b/scripts/obj_trimmer.py
@@ -0,0 +1,130 @@
+# Copyright (c) 2022 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+import argparse
+import os
+from typing import Optional, List
+
+"""
+ Used to reduce the size of obj files used for printer platform models.
+
+ Trims trailing 0 from coordinates
+ Removes duplicate vertex texture coordinates
+ Removes any rows that are not a face, vertex or vertex texture
+"""
+
+def process_obj(input_file, output_file):
+ with open(input_file, "r") as in_obj, open("temp", "w") as temp:
+ trim_lines(in_obj, temp)
+
+ with open("temp", "r") as temp, open(output_file, "w") as out_obj:
+ merge_duplicate_vt(temp, out_obj)
+
+ os.remove("temp")
+
+
+def trim_lines(in_obj, out_obj):
+ for line in in_obj:
+ line = trim_line(line)
+ if line:
+ out_obj.write(line + "\n")
+
+
+def trim_line(line: str) -> Optional[str]:
+ # Discards all rows that are not a vertex ("v"), face ("f") or vertex texture ("v")
+ values = line.split()
+
+ if values[0] == "vt":
+ return trim_vertex_texture(values)
+ elif values[0] == "f":
+ return trim_face(values)
+ elif values[0] == "v":
+ return trim_vertex(values)
+
+ return
+
+
+def trim_face(values: List[str]) -> str:
+ # Removes face normals (vn)
+ # f 15/15/17 15/15/17 14/14/17 -> f 15/15 15/15 14/14
+ for i, coordinates in enumerate(values[1:]):
+ v, vt = coordinates.split("/")[:2]
+ values[i + 1] = v + "/" + vt
+
+ return " ".join(values)
+
+
+def trim_vertex(values: List[str]) -> str:
+ # Removes trailing zeros from vertex coordinates
+ # v 0.044000 0.137000 0.123000 -> v 0.044 0.137 0.123
+ for i, coordinate in enumerate(values[1:]):
+ values[i + 1] = str(float(coordinate))
+ return " ".join(values)
+
+
+def trim_vertex_texture(values: List[str]) -> str:
+ # Removes trailing zeros from vertex texture coordinates
+ # vt 0.137000 0.123000 -> v 0.137 0.123
+ for i, coordinate in enumerate(values[1:]):
+ values[i + 1] = str(float(coordinate))
+ return " ".join(values)
+
+def merge_duplicate_vt(in_obj, out_obj):
+ # Removes duplicate vertex texture ("vt")
+ # Points references to all deleted copies in face ("f") to a single vertex texture
+
+ # Maps index of all copies of a vt line to the same index
+ vt_index_mapping = {}
+ # Maps vt line to index ("vt 0.043 0.137" -> 23)
+ vt_to_index = {}
+
+ # .obj file indexes start at 1
+ vt_index = 1
+ skipped_count = 0
+
+ # First write everything except faces
+ for line in in_obj.readlines():
+ if line[0] == "f":
+ continue
+
+ if line[:2] == "vt":
+ if line in vt_to_index.keys():
+ # vt with same value has already been written
+ # this points the current vt index to the one that has been written
+ vt_index_mapping[vt_index] = vt_to_index[line]
+ skipped_count += 1
+ else:
+ # vt has not been seen, point vt line to index
+ vt_to_index[line] = vt_index - skipped_count
+ vt_index_mapping[vt_index] = vt_index - skipped_count
+ out_obj.write(line)
+
+ vt_index += 1
+ else:
+ out_obj.write(line)
+
+ # Second pass remaps face vt index
+ in_obj.seek(0)
+ for line in in_obj.readlines():
+ if line[0] != "f":
+ continue
+
+ values = line.split()
+
+ for i, coordinates in enumerate(values[1:]):
+ v, vt = coordinates.split("/")[:2]
+ vt = int(vt)
+
+ if vt in vt_index_mapping.keys():
+ vt = vt_index_mapping[vt]
+
+ values[i + 1] = v + "/" + str(vt)
+
+ out_obj.write(" ".join(values) + "\n")
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Reduce the size of a .obj file")
+ parser.add_argument("input_file", type=str, help="Input .obj file name")
+ parser.add_argument("--output_file", default="output.obj", type=str, help="Output .obj file name")
+ args = parser.parse_args()
+ process_obj(args.input_file, args.output_file)