Some checks failed
Build / build (18.x, macos-latest) (push) Has been cancelled
Build / build (18.x, ubuntu-latest) (push) Has been cancelled
Build / build (18.x, windows-latest) (push) Has been cancelled
Build / build (20.x, macos-latest) (push) Has been cancelled
Build / build (20.x, ubuntu-latest) (push) Has been cancelled
Build / build (20.x, windows-latest) (push) Has been cancelled
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
import json
|
|
import sys
|
|
|
|
|
|
def get_script_arguments(argv):
|
|
if "--pass" in argv:
|
|
pass_index = argv.index("--pass")
|
|
script_args = argv[pass_index + 1 :]
|
|
else:
|
|
script_args = argv[2:]
|
|
|
|
if len(script_args) < 3:
|
|
raise ValueError("Expected input path, deleted paths manifest, and output path.")
|
|
|
|
return script_args[0], script_args[1], script_args[2]
|
|
|
|
|
|
def should_include_in_tree(document_object):
|
|
type_id = getattr(document_object, "TypeId", "")
|
|
return type_id not in {"App::Origin", "App::Line", "App::Plane", "Part::Feature"}
|
|
|
|
|
|
def get_tree_children(objects):
|
|
filtered_objects = [document_object for document_object in objects if should_include_in_tree(document_object)]
|
|
|
|
def sort_key(document_object):
|
|
child_count = len(get_tree_children(list(getattr(document_object, "OutList", []))))
|
|
is_leaf_part = child_count == 0
|
|
return (1 if is_leaf_part else 0)
|
|
|
|
filtered_objects.sort(key=sort_key)
|
|
return filtered_objects
|
|
|
|
|
|
def enumerate_objects(objects, parent_path=""):
|
|
filtered_objects = get_tree_children(objects)
|
|
for index, document_object in enumerate(filtered_objects):
|
|
object_path = str(index) if parent_path == "" else parent_path + "/" + str(index)
|
|
yield object_path, document_object
|
|
child_objects = list(getattr(document_object, "OutList", []))
|
|
yield from enumerate_objects(child_objects, object_path)
|
|
|
|
|
|
def collect_all_subtree_objects(objects):
|
|
collected_objects = []
|
|
for document_object in objects:
|
|
collected_objects.append(document_object)
|
|
child_objects = list(getattr(document_object, "OutList", []))
|
|
collected_objects.extend(collect_all_subtree_objects(child_objects))
|
|
return collected_objects
|
|
|
|
|
|
def collect_subtree_objects(objects, target_path, parent_path=""):
|
|
collected_objects = []
|
|
filtered_objects = get_tree_children(objects)
|
|
for index, document_object in enumerate(filtered_objects):
|
|
object_path = str(index) if parent_path == "" else parent_path + "/" + str(index)
|
|
child_objects = list(getattr(document_object, "OutList", []))
|
|
if target_path is None:
|
|
collected_objects.append(document_object)
|
|
collected_objects.extend(collect_all_subtree_objects(child_objects))
|
|
elif object_path == target_path:
|
|
collected_objects.append(document_object)
|
|
collected_objects.extend(collect_all_subtree_objects(child_objects))
|
|
elif target_path.startswith(object_path + "/"):
|
|
collected_objects.extend(collect_subtree_objects(child_objects, target_path, object_path))
|
|
return collected_objects
|
|
|
|
|
|
def build_removal_names(objects_to_delete):
|
|
removal_candidates = []
|
|
seen_names = set()
|
|
for document_object in objects_to_delete:
|
|
object_name = getattr(document_object, "Name", None)
|
|
if object_name is None or object_name in seen_names:
|
|
continue
|
|
seen_names.add(object_name)
|
|
subtree_depth = len(list(getattr(document_object, "OutListRecursive", [])))
|
|
removal_candidates.append((object_name, subtree_depth))
|
|
|
|
removal_candidates.sort(key=lambda candidate: candidate[1], reverse=True)
|
|
return [object_name for object_name, _depth in removal_candidates]
|
|
|
|
|
|
def main():
|
|
input_path, deleted_paths_path, output_path = get_script_arguments(sys.argv)
|
|
|
|
with open(deleted_paths_path, "r", encoding="utf-8") as deleted_file:
|
|
deleted_paths = set(json.load(deleted_file))
|
|
|
|
import FreeCAD
|
|
import Import
|
|
|
|
document = FreeCAD.newDocument("TrimmedStep")
|
|
Import.insert(input_path, document.Name)
|
|
|
|
objects_to_delete = []
|
|
root_objects = list(document.RootObjects)
|
|
for deleted_path in deleted_paths:
|
|
objects_to_delete.extend(collect_subtree_objects(root_objects, deleted_path))
|
|
|
|
for object_name in build_removal_names(objects_to_delete):
|
|
if document.getObject(object_name) is None:
|
|
continue
|
|
document.removeObject(object_name)
|
|
|
|
Import.export(list(document.RootObjects), output_path)
|
|
FreeCAD.closeDocument(document.Name)
|
|
|
|
|
|
if __name__ in ("__main__", "freecad_trim_step"):
|
|
main()
|