diff --git a/core/nodeslicer/nodes/mesh.py b/core/nodeslicer/nodes/mesh.py index b4e53ef..7d4ac3c 100644 --- a/core/nodeslicer/nodes/mesh.py +++ b/core/nodeslicer/nodes/mesh.py @@ -231,13 +231,15 @@ 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) if np.all(mask): res.objects.append(so) elif np.any(mask): # Split the object so_new = SlicingObject() - so_new.name = f"{so.name}_{target_val}" + so_new.name = f"{so.name}{target_val:0{num_digits}d}" so_new.parent = so.parent so_new.object_type = so.object_type so_new.extruder = so.extruder diff --git a/core/pdf_exporter/geometry.py b/core/pdf_exporter/geometry.py index e209fb0..be3ce08 100644 --- a/core/pdf_exporter/geometry.py +++ b/core/pdf_exporter/geometry.py @@ -170,6 +170,8 @@ def generate_grid_slice_paths( grid_min_y: float, grid_max_y: float, minor_step: float, + u0: float | None = None, + v0: float | None = None, max_grid_steps: int = 2000, z_level: float = 0.0, plane: str = "XY", @@ -177,41 +179,63 @@ def generate_grid_slice_paths( """ Generates 3D grid line geometry sitting at local depth d=z_level on specified local plane (XY, XZ, YZ) as two SlicePaths objects: (minor_grid_slice_paths, main_grid_slice_paths). + Major grid lines stem from origin u0, v0. """ from ..slice import SlicePaths - k_x_start = int(np.round(grid_min_x / minor_step)) - k_x_end = int(np.round(grid_max_x / minor_step)) - k_x = np.arange(k_x_start, k_x_end + 1) + u_0 = u0 if u0 is not None else grid_min_x + v_0 = v0 if v0 is not None else grid_min_y - k_y_start = int(np.round(grid_min_y / minor_step)) - k_y_end = int(np.round(grid_max_y / minor_step)) - k_y = np.arange(k_y_start, k_y_end + 1) + u_dir = 1.0 if grid_max_x >= u_0 else -1.0 + num_u_steps = int(np.ceil(abs(grid_max_x - u_0) / minor_step)) + if u_min_step := int(np.ceil(abs(grid_min_x - u_0) / minor_step)): + num_u_steps = max(num_u_steps, u_min_step) - if len(k_x) > max_grid_steps or len(k_y) > max_grid_steps: + v_dir = 1.0 if grid_max_y >= v_0 else -1.0 + num_v_steps = int(np.ceil(abs(grid_max_y - v_0) / minor_step)) + if v_min_step := int(np.ceil(abs(grid_min_y - v_0) / minor_step)): + num_v_steps = max(num_v_steps, v_min_step) + + if num_u_steps > max_grid_steps or num_v_steps > max_grid_steps: return SlicePaths(), SlicePaths() minor_paths: list[NDArray[np.float64]] = [] main_paths: list[NDArray[np.float64]] = [] - # Vertical grid lines (constant U) - for k in k_x: - gu = float(k * minor_step) - p1 = map_2d_to_3d(gu, grid_min_y, z_level, plane) - p2 = map_2d_to_3d(gu, grid_max_y, z_level, plane) + # Lines parallel to V (constant U): gu_i = u_0 + u_dir * i * minor_step + # Generate all u positions within [min(grid_min_x, grid_max_x), max(grid_min_x, grid_max_x)] + min_u_val = min(grid_min_x, grid_max_x) + max_u_val = max(grid_min_x, grid_max_x) + min_v_val = min(grid_min_y, grid_max_y) + max_v_val = max(grid_min_y, grid_max_y) + + k_u_start = int(np.floor((min_u_val - u_0) / minor_step)) + k_u_end = int(np.ceil((max_u_val - u_0) / minor_step)) + + for i in range(k_u_start, k_u_end + 1): + gu = u_0 + i * minor_step + if gu < min_u_val - 1e-6 or gu > max_u_val + 1e-6: + continue + p1 = map_2d_to_3d(gu, min_v_val, z_level, plane) + p2 = map_2d_to_3d(gu, max_v_val, z_level, plane) line = np.array([p1, p2], dtype=np.float64) - if k % 10 == 0: + if i % 10 == 0: main_paths.append(line) else: minor_paths.append(line) - # Horizontal grid lines (constant V) - for k in k_y: - gv = float(k * minor_step) - p1 = map_2d_to_3d(grid_min_x, gv, z_level, plane) - p2 = map_2d_to_3d(grid_max_x, gv, z_level, plane) + # Lines parallel to U (constant V): gv_j = v_0 + j * minor_step + k_v_start = int(np.floor((min_v_val - v_0) / minor_step)) + k_v_end = int(np.ceil((max_v_val - v_0) / minor_step)) + + for j in range(k_v_start, k_v_end + 1): + gv = v_0 + j * minor_step + if gv < min_v_val - 1e-6 or gv > max_v_val + 1e-6: + continue + p1 = map_2d_to_3d(min_u_val, gv, z_level, plane) + p2 = map_2d_to_3d(max_u_val, gv, z_level, plane) line = np.array([p1, p2], dtype=np.float64) - if k % 10 == 0: + if j % 10 == 0: main_paths.append(line) else: minor_paths.append(line) diff --git a/core/pdf_exporter/writer.py b/core/pdf_exporter/writer.py index b610af2..5e7fe50 100644 --- a/core/pdf_exporter/writer.py +++ b/core/pdf_exporter/writer.py @@ -927,17 +927,32 @@ class export_mesh_to_pdf: grid_main_paths: list[NDArray[np.float64]] = [] if self.draw_grid_xy: - min_sp, main_sp = generate_grid_slice_paths(self.grid_min_x, self.grid_max_x, self.grid_min_y, self.grid_max_y, self.minor_step, z_level=z0, plane="XY") + min_sp, main_sp = generate_grid_slice_paths( + self.grid_min_x, self.grid_max_x, + self.grid_min_y, self.grid_max_y, + self.minor_step, u0=x0, v0=y0, + z_level=z0, plane="XY" + ) grid_minor_paths.extend(min_sp) grid_main_paths.extend(main_sp) if self.draw_grid_xz: - min_sp, main_sp = generate_grid_slice_paths(self.grid_min_x, self.grid_max_x, self.grid_min_z, self.grid_max_z, self.minor_step, z_level=y0, plane="XZ") + min_sp, main_sp = generate_grid_slice_paths( + self.grid_min_x, self.grid_max_x, + self.grid_min_z, self.grid_max_z, + self.minor_step, u0=x0, v0=z0, + z_level=y0, plane="XZ" + ) grid_minor_paths.extend(min_sp) grid_main_paths.extend(main_sp) if self.draw_grid_yz: - min_sp, main_sp = generate_grid_slice_paths(self.grid_min_y, self.grid_max_y, self.grid_min_z, self.grid_max_z, self.minor_step, z_level=x0, plane="YZ") + min_sp, main_sp = generate_grid_slice_paths( + self.grid_min_y, self.grid_max_y, + self.grid_min_z, self.grid_max_z, + self.minor_step, u0=y0, v0=z0, + z_level=x0, plane="YZ" + ) grid_minor_paths.extend(min_sp) grid_main_paths.extend(main_sp)