intrinsics implementation
This commit is contained in:
parent
c57f843092
commit
77bab165af
3 changed files with 100 additions and 5 deletions
84
__init__.py
84
__init__.py
|
|
@ -32,6 +32,18 @@ from .infra.blender_slice_nodes_generic import SliceNode, SliceNodeSocket, resol
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from bpy.stub_internal.rna_enums import OperatorReturnItems
|
from bpy.stub_internal.rna_enums import OperatorReturnItems
|
||||||
|
|
||||||
|
class SliceIntrinsics:
|
||||||
|
bed_x: float
|
||||||
|
bed_y: float
|
||||||
|
feedrate: float
|
||||||
|
extrusion_rate: float
|
||||||
|
|
||||||
|
def __init__(self, bed_x=250.0, bed_y=250.0, feedrate=1200.0, extrusion_rate=0.017):
|
||||||
|
self.bed_x = bed_x
|
||||||
|
self.bed_y = bed_y
|
||||||
|
self.feedrate = feedrate
|
||||||
|
self.extrusion_rate = extrusion_rate
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Node tree
|
# Node tree
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
@ -143,6 +155,12 @@ class SLICESOCK_Gcode(LabelNodeSocket):
|
||||||
default = ""
|
default = ""
|
||||||
color = (1., 1., 1., 1.)
|
color = (1., 1., 1., 1.)
|
||||||
|
|
||||||
|
@register_class
|
||||||
|
class SLICESOCK_Intrinsics(LabelNodeSocket):
|
||||||
|
bl_label = "Intrinsics"
|
||||||
|
default = None
|
||||||
|
color = (0.2, 0.2, 0.2, 1.0)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Nodes
|
# Nodes
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
@ -179,6 +197,33 @@ class SLICENODE_InputObject(InputNode):
|
||||||
input_type = "Object"
|
input_type = "Object"
|
||||||
bl_icon = "OBJECT_DATA"
|
bl_icon = "OBJECT_DATA"
|
||||||
|
|
||||||
|
@register_class
|
||||||
|
class SLICENODE_InputIntrinsics(SliceNode):
|
||||||
|
bl_label = "Printer Intrinsics"
|
||||||
|
|
||||||
|
bed_x: FloatProperty(name="Bed X", default=250.0) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
bed_y: FloatProperty(name="Bed Y", default=250.0) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
feedrate: FloatProperty(name="Feedrate", default=1200.0) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
extrusion_rate: FloatProperty(name="Extrusion Rate", default=0.017, precision=4) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
|
def init(self, context):
|
||||||
|
self.add_output("SLICESOCK_Intrinsics")
|
||||||
|
|
||||||
|
def draw_buttons(self, context, layout):
|
||||||
|
assert layout
|
||||||
|
layout.prop(self, "bed_x")
|
||||||
|
layout.prop(self, "bed_y")
|
||||||
|
layout.prop(self, "feedrate")
|
||||||
|
layout.prop(self, "extrusion_rate")
|
||||||
|
|
||||||
|
def evaluate_output(self, socket_name: str, **_kwargs) -> SliceIntrinsics:
|
||||||
|
return SliceIntrinsics(
|
||||||
|
bed_x=self.bed_x,
|
||||||
|
bed_y=self.bed_y,
|
||||||
|
feedrate=self.feedrate,
|
||||||
|
extrusion_rate=self.extrusion_rate
|
||||||
|
)
|
||||||
|
|
||||||
# Math
|
# Math
|
||||||
|
|
||||||
@register_class
|
@register_class
|
||||||
|
|
@ -372,11 +417,22 @@ class SLICENODE_PathsToGcode(SliceNode):
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_input("SLICESOCK_Paths")
|
self.add_input("SLICESOCK_Paths")
|
||||||
|
self.add_input("SLICESOCK_Intrinsics")
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_Gcode")
|
||||||
|
|
||||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||||
paths: list[np.ndarray] = resolve_input(self.inputs.get("Paths"))
|
paths: list[np.ndarray] = resolve_input(self.inputs.get("Paths"))
|
||||||
|
intrinsics: SliceIntrinsics | None = resolve_input(self.inputs.get("Intrinsics"))
|
||||||
|
|
||||||
pather: Pather = Pather(paths)
|
pather: Pather = Pather(paths)
|
||||||
|
if intrinsics:
|
||||||
|
# Note: Pather currently uses bed_center_x/y as its internal attributes.
|
||||||
|
# We map the bed size center to these attributes if provided.
|
||||||
|
pather.bed_center_x = intrinsics.bed_x / 2.0
|
||||||
|
pather.bed_center_y = intrinsics.bed_y / 2.0
|
||||||
|
pather.feedrate = intrinsics.feedrate
|
||||||
|
pather.extrusion_rate = intrinsics.extrusion_rate
|
||||||
|
|
||||||
gcode: str = pather.to_gcode()
|
gcode: str = pather.to_gcode()
|
||||||
return gcode
|
return gcode
|
||||||
|
|
||||||
|
|
@ -599,11 +655,23 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
||||||
last_x, last_y, last_z = 0.0, 0.0, 0.0
|
last_x, last_y, last_z = 0.0, 0.0, 0.0
|
||||||
last_e = 0.0
|
last_e = 0.0
|
||||||
|
|
||||||
for line in gcode.splitlines():
|
offset_x, offset_y = 0.0, 0.0
|
||||||
line = line.split(';')[0].strip()
|
|
||||||
if not line: continue
|
|
||||||
|
|
||||||
parts = line.split()
|
for line in gcode.splitlines():
|
||||||
|
# Parse metadata from comments
|
||||||
|
if ';' in line:
|
||||||
|
comment = line.split(';', 1)[1].strip()
|
||||||
|
if comment.startswith("OFFSET_X="):
|
||||||
|
try: offset_x = float(comment.split('=')[1])
|
||||||
|
except ValueError: pass
|
||||||
|
elif comment.startswith("OFFSET_Y="):
|
||||||
|
try: offset_y = float(comment.split('=')[1])
|
||||||
|
except ValueError: pass
|
||||||
|
|
||||||
|
line_no_comment = line.split(';')[0].strip()
|
||||||
|
if not line_no_comment: continue
|
||||||
|
|
||||||
|
parts = line_no_comment.split()
|
||||||
cmd = parts[0].upper()
|
cmd = parts[0].upper()
|
||||||
|
|
||||||
params = {}
|
params = {}
|
||||||
|
|
@ -626,7 +694,12 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
||||||
is_extruding = new_e > 0
|
is_extruding = new_e > 0
|
||||||
|
|
||||||
if is_extruding:
|
if is_extruding:
|
||||||
segments.append(((last_x, last_y, last_z), (new_x, new_y, new_z)))
|
# Subtract offsets (scaled to Blender units) to return to original space
|
||||||
|
ox, oy = offset_x * 0.001, offset_y * 0.001
|
||||||
|
segments.append((
|
||||||
|
(last_x - ox, last_y - oy, last_z),
|
||||||
|
(new_x - ox, new_y - oy, new_z)
|
||||||
|
))
|
||||||
|
|
||||||
last_x, last_y, last_z = new_x, new_y, new_z
|
last_x, last_y, last_z = new_x, new_y, new_z
|
||||||
last_e = new_e
|
last_e = new_e
|
||||||
|
|
@ -707,6 +780,7 @@ class SLICENODE_MT_Menu(Menu):
|
||||||
layout.operator("node.add_node", text="Integer").type = "SLICENODE_InputInt"
|
layout.operator("node.add_node", text="Integer").type = "SLICENODE_InputInt"
|
||||||
layout.operator("node.add_node", text="Integer Math").type = "SLICENODE_IntMath"
|
layout.operator("node.add_node", text="Integer Math").type = "SLICENODE_IntMath"
|
||||||
layout.operator("node.add_node", text="Object").type = "SLICENODE_InputObject"
|
layout.operator("node.add_node", text="Object").type = "SLICENODE_InputObject"
|
||||||
|
layout.operator("node.add_node", text="Printer Intrinsics").type = "SLICENODE_InputIntrinsics"
|
||||||
layout.operator("node.add_node", text="Test").type = "SLICENODE_Test"
|
layout.operator("node.add_node", text="Test").type = "SLICENODE_Test"
|
||||||
layout.operator("node.add_node", text="Get Mesh").type = "SLICENODE_GetMesh"
|
layout.operator("node.add_node", text="Get Mesh").type = "SLICENODE_GetMesh"
|
||||||
layout.operator("node.add_node", text="Get Paths").type = "SLICENODE_GetPaths"
|
layout.operator("node.add_node", text="Get Paths").type = "SLICENODE_GetPaths"
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,23 @@ class Pather(object):
|
||||||
if not self.paths:
|
if not self.paths:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
# Centering logic using NumPy
|
||||||
|
all_pts = np.concatenate(self.paths)
|
||||||
|
min_xy = all_pts[:, :2].min(axis=0)
|
||||||
|
max_xy = all_pts[:, :2].max(axis=0)
|
||||||
|
center_xy = (min_xy + max_xy) / 2.0
|
||||||
|
|
||||||
|
offset_x = self.bed_center_x - center_xy[0]
|
||||||
|
offset_y = self.bed_center_y - center_xy[1]
|
||||||
|
|
||||||
|
# Apply offset to all paths
|
||||||
|
centered_paths = []
|
||||||
|
for path in self.paths:
|
||||||
|
new_path = path.copy()
|
||||||
|
new_path[:, 0] += offset_x
|
||||||
|
new_path[:, 1] += offset_y
|
||||||
|
centered_paths.append(new_path)
|
||||||
|
|
||||||
def segment_length_3d(p1, p2) -> float:
|
def segment_length_3d(p1, p2) -> float:
|
||||||
dx = p2[0] - p1[0]
|
dx = p2[0] - p1[0]
|
||||||
dy = p2[1] - p1[1]
|
dy = p2[1] - p1[1]
|
||||||
|
|
@ -324,6 +341,8 @@ class Pather(object):
|
||||||
f";TYPE:Custom",
|
f";TYPE:Custom",
|
||||||
f";FEEDRATE={self.feedrate}",
|
f";FEEDRATE={self.feedrate}",
|
||||||
f";EXTRUSION_RATE={self.extrusion_rate}",
|
f";EXTRUSION_RATE={self.extrusion_rate}",
|
||||||
|
f";OFFSET_X={offset_x:.6f}",
|
||||||
|
f";OFFSET_Y={offset_y:.6f}",
|
||||||
"G21 ; set units to mm",
|
"G21 ; set units to mm",
|
||||||
"G90 ; absolute XYZ positioning",
|
"G90 ; absolute XYZ positioning",
|
||||||
"M83 ; relative extrusion mode",
|
"M83 ; relative extrusion mode",
|
||||||
|
|
@ -333,7 +352,7 @@ class Pather(object):
|
||||||
last_z = -1.0
|
last_z = -1.0
|
||||||
max_z = 0
|
max_z = 0
|
||||||
|
|
||||||
for line in self.paths:
|
for line in centered_paths:
|
||||||
coords = line.tolist()
|
coords = line.tolist()
|
||||||
if len(coords) < 2:
|
if len(coords) < 2:
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,8 @@ def capture_mesh_edges(obj: Object) -> list[NDArray[float64]]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# 1. Scaling & Matrix Setup
|
# 1. Scaling & Matrix Setup
|
||||||
|
assert bpy.context.scene
|
||||||
|
assert bpy.context.scene.unit_settings
|
||||||
scale = 1000.0 * bpy.context.scene.unit_settings.scale_length
|
scale = 1000.0 * bpy.context.scene.unit_settings.scale_length
|
||||||
world_mat = np.array(obj.matrix_world)
|
world_mat = np.array(obj.matrix_world)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue