naming
This commit is contained in:
parent
3793c45f54
commit
29f7b71be1
5 changed files with 124 additions and 4 deletions
|
|
@ -232,7 +232,7 @@ class SLICENODE_SeparateMeshByRange(SliceNode):
|
||||||
# Attribute values might be floats or ints, we check for equality
|
# Attribute values might be floats or ints, we check for equality
|
||||||
mask = vals == target_val
|
mask = vals == target_val
|
||||||
|
|
||||||
num_digits = max(2, self.end_val)
|
num_digits = max(2, len(str(self.end_val)))
|
||||||
|
|
||||||
if np.all(mask):
|
if np.all(mask):
|
||||||
res.objects.append(so)
|
res.objects.append(so)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@ class SLICENODE_GetPaths(SliceNode):
|
||||||
sp = SlicePaths(so, extrusion_rate=e_rates, feedrate=f_rates, extra_attributes=extra_attrs_data)
|
sp = SlicePaths(so, extrusion_rate=e_rates, feedrate=f_rates, extra_attributes=extra_attrs_data)
|
||||||
if hasattr(obj, "transforms"):
|
if hasattr(obj, "transforms"):
|
||||||
sp.transforms = list(getattr(obj, "transforms", []))
|
sp.transforms = list(getattr(obj, "transforms", []))
|
||||||
|
if hasattr(obj, "name") and getattr(obj, "name"):
|
||||||
|
name_val = str(getattr(obj, "name"))
|
||||||
|
sp.name = name_val
|
||||||
|
sp.objects_info = {"objects": [{"name": name_val, "polygon": []}]}
|
||||||
return sp
|
return sp
|
||||||
|
|
||||||
@register_class
|
@register_class
|
||||||
|
|
@ -109,6 +113,22 @@ class SLICENODE_SliceShells(SliceNode):
|
||||||
slices.first_layer_height = fl_height
|
slices.first_layer_height = fl_height
|
||||||
slices.transforms = list(getattr(coll, "transforms", [])) or list(getattr(merged_object, "transforms", []))
|
slices.transforms = list(getattr(coll, "transforms", [])) or list(getattr(merged_object, "transforms", []))
|
||||||
|
|
||||||
|
names = []
|
||||||
|
if objects:
|
||||||
|
for o in objects:
|
||||||
|
n = getattr(o, "name", "")
|
||||||
|
if n:
|
||||||
|
if n.endswith("_merged"):
|
||||||
|
n = n[:-7]
|
||||||
|
if n and n not in names:
|
||||||
|
names.append(n)
|
||||||
|
if not names and hasattr(coll, "name") and getattr(coll, "name"):
|
||||||
|
names.append(str(getattr(coll, "name")))
|
||||||
|
|
||||||
|
if names:
|
||||||
|
slices.name = "-".join(names)
|
||||||
|
slices.objects_info = {"objects": [{"name": n, "polygon": []} for n in names]}
|
||||||
|
|
||||||
if len(z_values) > 0 and fl_height is not None and layer_height > 0:
|
if len(z_values) > 0 and fl_height is not None and layer_height > 0:
|
||||||
mult = fl_height / layer_height
|
mult = fl_height / layer_height
|
||||||
z_first = z_values[0]
|
z_first = z_values[0]
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from numpy import float64
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyclipper
|
import pyclipper
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
import copy
|
||||||
from shapely.geometry.base import BaseGeometry
|
from shapely.geometry.base import BaseGeometry
|
||||||
|
|
||||||
from ..infra.blender.blender_mesh_capture import PdfProperties
|
from ..infra.blender.blender_mesh_capture import PdfProperties
|
||||||
|
|
@ -164,8 +165,10 @@ class SlicePaths(list[np.ndarray]):
|
||||||
transforms: list[dict]
|
transforms: list[dict]
|
||||||
object_properties: list[tuple[str, str]]
|
object_properties: list[tuple[str, str]]
|
||||||
pdf_properties: PdfProperties
|
pdf_properties: PdfProperties
|
||||||
|
name: str
|
||||||
|
objects_info: dict | None
|
||||||
|
|
||||||
def __init__(self, paths: list[np.ndarray] = [], groups: list[int] = [], extrusion_rate: list[np.ndarray] | None = None, feedrate: list[np.ndarray] | None = None, extra_attributes: dict[str, list[np.ndarray]] | None = None, layer_height: float = 0.2, first_layer_height: float | None = None, transforms: list[dict] | None = None):
|
def __init__(self, paths: list[np.ndarray] = [], groups: list[int] = [], extrusion_rate: list[np.ndarray] | None = None, feedrate: list[np.ndarray] | None = None, extra_attributes: dict[str, list[np.ndarray]] | None = None, layer_height: float = 0.2, first_layer_height: float | None = None, transforms: list[dict] | None = None, name: str = "", objects_info: dict | None = None):
|
||||||
super().__init__(paths)
|
super().__init__(paths)
|
||||||
|
|
||||||
self.groups = []
|
self.groups = []
|
||||||
|
|
@ -188,6 +191,8 @@ class SlicePaths(list[np.ndarray]):
|
||||||
self.layer_height = layer_height
|
self.layer_height = layer_height
|
||||||
self.first_layer_height = first_layer_height
|
self.first_layer_height = first_layer_height
|
||||||
self.transforms = list(transforms) if transforms is not None else []
|
self.transforms = list(transforms) if transforms is not None else []
|
||||||
|
self.name = name
|
||||||
|
self.objects_info = copy.deepcopy(objects_info) if objects_info is not None else None
|
||||||
|
|
||||||
def copy_with(self, paths: list[np.ndarray], groups: list[int] | None = None, extrusion_rate: list[np.ndarray] | None = None, feedrate: list[np.ndarray] | None = None, extra_attributes: dict[str, list[np.ndarray]] | None = None) -> SlicePaths:
|
def copy_with(self, paths: list[np.ndarray], groups: list[int] | None = None, extrusion_rate: list[np.ndarray] | None = None, feedrate: list[np.ndarray] | None = None, extra_attributes: dict[str, list[np.ndarray]] | None = None) -> SlicePaths:
|
||||||
"""Returns a new SlicePaths object with new paths/groups, preserving all metadata and instance attributes."""
|
"""Returns a new SlicePaths object with new paths/groups, preserving all metadata and instance attributes."""
|
||||||
|
|
@ -349,11 +354,30 @@ class SlicePaths(list[np.ndarray]):
|
||||||
merged.append_with_group(path, group=g, extrusion_rate=ext, feedrate=feed, extra_attributes=extra)
|
merged.append_with_group(path, group=g, extrusion_rate=ext, feedrate=feed, extra_attributes=extra)
|
||||||
|
|
||||||
merged_transforms = []
|
merged_transforms = []
|
||||||
|
merged_names = []
|
||||||
|
merged_objs = []
|
||||||
for sp in paths_list:
|
for sp in paths_list:
|
||||||
|
if hasattr(sp, "objects_info") and getattr(sp, "objects_info"):
|
||||||
|
for obj_entry in sp.objects_info.get("objects", []):
|
||||||
|
if obj_entry not in merged_objs:
|
||||||
|
merged_objs.append(dict(obj_entry))
|
||||||
|
n_str = obj_entry.get("name", "")
|
||||||
|
if n_str and n_str not in merged_names:
|
||||||
|
merged_names.append(n_str)
|
||||||
|
elif hasattr(sp, "name") and getattr(sp, "name"):
|
||||||
|
n_str = str(getattr(sp, "name"))
|
||||||
|
if n_str and n_str not in merged_names:
|
||||||
|
merged_names.append(n_str)
|
||||||
|
merged_objs.append({"name": n_str, "polygon": []})
|
||||||
|
|
||||||
for t in getattr(sp, "transforms", []):
|
for t in getattr(sp, "transforms", []):
|
||||||
if t not in merged_transforms:
|
if t not in merged_transforms:
|
||||||
merged_transforms.append(t)
|
merged_transforms.append(t)
|
||||||
|
|
||||||
merged.transforms = merged_transforms
|
merged.transforms = merged_transforms
|
||||||
|
if merged_objs:
|
||||||
|
merged.objects_info = {"objects": merged_objs}
|
||||||
|
merged.name = "-".join(merged_names)
|
||||||
|
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
|
|
@ -1583,6 +1607,8 @@ class Pather(object):
|
||||||
self.retraction_feedrate: float = 0.0
|
self.retraction_feedrate: float = 0.0
|
||||||
self.lift: float = 0.0
|
self.lift: float = 0.0
|
||||||
self.transforms: list[dict] = list(getattr(paths, "transforms", []))
|
self.transforms: list[dict] = list(getattr(paths, "transforms", []))
|
||||||
|
self.objects_info: dict | None = getattr(paths, "objects_info", None)
|
||||||
|
self.name: str = str(getattr(paths, "name", ""))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def layer_width(self) -> float:
|
def layer_width(self) -> float:
|
||||||
|
|
@ -1653,6 +1679,13 @@ class Pather(object):
|
||||||
f";OFFSET_Y={offset_y:.6f}",
|
f";OFFSET_Y={offset_y:.6f}",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if self.objects_info:
|
||||||
|
import json
|
||||||
|
header.append(f"; objects_info = {json.dumps(self.objects_info)}")
|
||||||
|
elif self.name:
|
||||||
|
import json
|
||||||
|
header.append(f'; objects_info = {json.dumps({"objects": [{"name": self.name, "polygon": []}]})}')
|
||||||
|
|
||||||
if hasattr(self, "transforms") and self.transforms:
|
if hasattr(self, "transforms") and self.transforms:
|
||||||
import json
|
import json
|
||||||
header.append(f";PREPARATION_TRANSFORMS={json.dumps(self.transforms)}")
|
header.append(f";PREPARATION_TRANSFORMS={json.dumps(self.transforms)}")
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ def parse_gcode_metadata(gcode: str) -> dict[str, Any]:
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def get_gcode_name_from_metadata(gcode: str, default: str = "output") -> str:
|
def get_gcode_name_from_metadata(gcode: str, default: str = "output") -> str:
|
||||||
"""Generates a descriptive name for the G-code based on its objects_info metadata."""
|
"""Generates a descriptive name for the G-code based on its objects_info metadata or object comments."""
|
||||||
parts_match = re.search(r"; objects_info = (.*)", gcode)
|
parts_match = re.search(r"; objects_info = (.*)", gcode)
|
||||||
|
|
||||||
filament_match = re.search(r"; filament_type = (.*)", gcode)
|
filament_match = re.search(r"; filament_type = (.*)", gcode)
|
||||||
|
|
@ -54,8 +54,19 @@ def get_gcode_name_from_metadata(gcode: str, default: str = "output") -> str:
|
||||||
object_names = "-".join(f"{c}x{n}" if c > 1 else n for n, c in counts.items())
|
object_names = "-".join(f"{c}x{n}" if c > 1 else n for n, c in counts.items())
|
||||||
parts = [object_names, filament, printer]
|
parts = [object_names, filament, printer]
|
||||||
return "-".join([str(p) for p in parts if p])
|
return "-".join([str(p) for p in parts if p])
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Fallback search for object name comments (e.g. ; OBJECT_NAME = ..., ; object_name = ..., ; OBJECT: ...)
|
||||||
|
obj_matches = re.findall(r";\s*(?:OBJECT_NAME|object_name|OBJECT|object)\s*[:=]\s*(.+)", gcode)
|
||||||
|
if obj_matches:
|
||||||
|
names = [m.strip().split(" id:")[0] for m in obj_matches if m.strip()]
|
||||||
|
if names:
|
||||||
|
counts = Counter(names)
|
||||||
|
object_names = "-".join(f"{c}x{n}" if c > 1 else n for n, c in counts.items())
|
||||||
|
parts = [object_names, filament, printer]
|
||||||
|
return "-".join([str(p) for p in parts if p])
|
||||||
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -706,5 +706,61 @@ class TestSlice(unittest.TestCase):
|
||||||
res_intr = node.evaluate_output("SLICESOCK_Intrinsics")
|
res_intr = node.evaluate_output("SLICESOCK_Intrinsics")
|
||||||
self.assertEqual(res_intr.retraction_feedrate, 1800.0)
|
self.assertEqual(res_intr.retraction_feedrate, 1800.0)
|
||||||
|
|
||||||
|
def test_gcode_name_from_metadata_paths_to_gcode(self):
|
||||||
|
from NodeSlicer.core.slice import SlicePaths, Pather
|
||||||
|
from NodeSlicer.infra.networking.gcode_utils import get_gcode_name_from_metadata
|
||||||
|
|
||||||
|
# 1. Test SlicePaths with explicit name
|
||||||
|
p1 = np.array([[0.0, 0.0, 0.0], [10.0, 0.0, 0.0]])
|
||||||
|
sp = SlicePaths([p1], name="GearPart")
|
||||||
|
pather = Pather(sp)
|
||||||
|
gcode = pather.to_gcode(include_header=True)
|
||||||
|
self.assertIn("; objects_info =", gcode)
|
||||||
|
name = get_gcode_name_from_metadata(gcode)
|
||||||
|
self.assertEqual(name, "GearPart")
|
||||||
|
|
||||||
|
# 2. Test SlicePaths with objects_info (multiple objects)
|
||||||
|
sp_multi = SlicePaths(
|
||||||
|
[p1],
|
||||||
|
objects_info={"objects": [{"name": "PartA", "polygon": []}, {"name": "PartB", "polygon": []}]}
|
||||||
|
)
|
||||||
|
pather_multi = Pather(sp_multi)
|
||||||
|
gcode_multi = pather_multi.to_gcode(include_header=True)
|
||||||
|
self.assertIn("; objects_info =", gcode_multi)
|
||||||
|
name_multi = get_gcode_name_from_metadata(gcode_multi)
|
||||||
|
self.assertEqual(name_multi, "PartA-PartB")
|
||||||
|
|
||||||
|
# 3. Test get_gcode_name_from_metadata fallback object comments
|
||||||
|
gcode_fallback = "; Generated Gcode\n; OBJECT_NAME = CustomBracket\nG1 X10 Y10\n"
|
||||||
|
self.assertEqual(get_gcode_name_from_metadata(gcode_fallback), "CustomBracket")
|
||||||
|
|
||||||
|
def test_separate_mesh_by_range_padding(self):
|
||||||
|
from NodeSlicer.core.nodeslicer.nodes.mesh import SLICENODE_SeparateMeshByRange
|
||||||
|
from NodeSlicer.infra.blender.blender_mesh_capture import SlicingCollection, SlicingObject
|
||||||
|
|
||||||
|
node = SLICENODE_SeparateMeshByRange()
|
||||||
|
node.end_val = 6
|
||||||
|
|
||||||
|
so = SlicingObject()
|
||||||
|
so.name = "CA"
|
||||||
|
so.mesh = np.zeros((4, 4, 3))
|
||||||
|
so.attributes = {
|
||||||
|
"part_id": {
|
||||||
|
"domain": "FACE",
|
||||||
|
"type": "INT",
|
||||||
|
"values": np.array([1, 1, 2, 2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
coll = SlicingCollection.__new__(SlicingCollection)
|
||||||
|
coll.objects = [so]
|
||||||
|
coll.name = "TestColl"
|
||||||
|
coll.transforms = []
|
||||||
|
node.resolve = lambda name: coll if name == "Mesh" else ("part_id" if name == "Attribute" else None)
|
||||||
|
|
||||||
|
res_1 = node.evaluate_output("1")
|
||||||
|
self.assertIsNotNone(res_1)
|
||||||
|
self.assertEqual(res_1.objects[0].name, "CA01")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue