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
|
||||
mask = vals == target_val
|
||||
|
||||
num_digits = max(2, self.end_val)
|
||||
num_digits = max(2, len(str(self.end_val)))
|
||||
|
||||
if np.all(mask):
|
||||
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)
|
||||
if hasattr(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
|
||||
|
||||
@register_class
|
||||
|
|
@ -109,6 +113,22 @@ class SLICENODE_SliceShells(SliceNode):
|
|||
slices.first_layer_height = fl_height
|
||||
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:
|
||||
mult = fl_height / layer_height
|
||||
z_first = z_values[0]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from numpy import float64
|
|||
import numpy as np
|
||||
import pyclipper
|
||||
from typing import Any, Literal
|
||||
import copy
|
||||
from shapely.geometry.base import BaseGeometry
|
||||
|
||||
from ..infra.blender.blender_mesh_capture import PdfProperties
|
||||
|
|
@ -164,8 +165,10 @@ class SlicePaths(list[np.ndarray]):
|
|||
transforms: list[dict]
|
||||
object_properties: list[tuple[str, str]]
|
||||
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)
|
||||
|
||||
self.groups = []
|
||||
|
|
@ -188,6 +191,8 @@ class SlicePaths(list[np.ndarray]):
|
|||
self.layer_height = layer_height
|
||||
self.first_layer_height = first_layer_height
|
||||
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:
|
||||
"""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_transforms = []
|
||||
merged_names = []
|
||||
merged_objs = []
|
||||
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", []):
|
||||
if t not in merged_transforms:
|
||||
merged_transforms.append(t)
|
||||
|
||||
merged.transforms = merged_transforms
|
||||
if merged_objs:
|
||||
merged.objects_info = {"objects": merged_objs}
|
||||
merged.name = "-".join(merged_names)
|
||||
|
||||
return merged
|
||||
|
||||
|
|
@ -1583,6 +1607,8 @@ class Pather(object):
|
|||
self.retraction_feedrate: float = 0.0
|
||||
self.lift: float = 0.0
|
||||
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
|
||||
def layer_width(self) -> float:
|
||||
|
|
@ -1653,6 +1679,13 @@ class Pather(object):
|
|||
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:
|
||||
import json
|
||||
header.append(f";PREPARATION_TRANSFORMS={json.dumps(self.transforms)}")
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ def parse_gcode_metadata(gcode: str) -> dict[str, Any]:
|
|||
return fields
|
||||
|
||||
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)
|
||||
|
||||
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())
|
||||
parts = [object_names, filament, printer]
|
||||
return "-".join([str(p) for p in parts if p])
|
||||
except:
|
||||
except Exception:
|
||||
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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -706,5 +706,61 @@ class TestSlice(unittest.TestCase):
|
|||
res_intr = node.evaluate_output("SLICESOCK_Intrinsics")
|
||||
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__':
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue