| | |
| |
|
| | import re |
| | from typing import Any, List, Tuple |
| |
|
| | import Path |
| | import Path.Base.Util as PathUtil |
| | import Path.Tool.Controller as PathToolController |
| |
|
| |
|
| | class _FixtureSetupObject: |
| | Path = None |
| | Name = "Fixture" |
| | InList = [] |
| | Label = "Fixture" |
| |
|
| |
|
| | class _CommandObject: |
| | def __init__(self, command): |
| | self.Path = Path.Path([command]) |
| | self.Name = "Command" |
| | self.InList = [] |
| | self.Label = "Command" |
| |
|
| |
|
| | def needsTcOp(oldTc: Any, newTc: Any) -> bool: |
| | return ( |
| | oldTc is None |
| | or oldTc.ToolNumber != newTc.ToolNumber |
| | or oldTc.SpindleSpeed != newTc.SpindleSpeed |
| | or oldTc.SpindleDir != newTc.SpindleDir |
| | ) |
| |
|
| |
|
| | def create_fixture_setup(processor: Any, order: int, fixture: str) -> _FixtureSetupObject: |
| | fobj = _FixtureSetupObject() |
| | c1 = Path.Command(fixture) |
| | fobj.Path = Path.Path([c1]) |
| |
|
| | if order != 0: |
| | clearance_z = ( |
| | processor._job.Stock.Shape.BoundBox.ZMax |
| | + processor._job.SetupSheet.ClearanceHeightOffset.Value |
| | ) |
| | c2 = Path.Command(f"G0 Z{clearance_z}") |
| | fobj.Path.addCommands(c2) |
| |
|
| | fobj.InList.append(processor._job) |
| | return fobj |
| |
|
| |
|
| | def build_postlist_by_fixture(processor: Any, early_tool_prep: bool = False) -> list: |
| | Path.Log.debug("Ordering by Fixture") |
| | postlist = [] |
| | wcslist = processor._job.Fixtures |
| | currTc = None |
| |
|
| | for index, f in enumerate(wcslist): |
| | sublist = [create_fixture_setup(processor, index, f)] |
| |
|
| | for obj in processor._operations: |
| | tc = PathUtil.toolControllerForOp(obj) |
| | if tc is not None and PathUtil.activeForOp(obj): |
| | if needsTcOp(currTc, tc): |
| | sublist.append(tc) |
| | Path.Log.debug(f"Appending TC: {tc.Name}") |
| | currTc = tc |
| | sublist.append(obj) |
| |
|
| | postlist.append((f, sublist)) |
| |
|
| | return postlist |
| |
|
| |
|
| | def build_postlist_by_tool(processor: Any, early_tool_prep: bool = False) -> list: |
| | Path.Log.debug("Ordering by Tool") |
| | postlist = [] |
| | wcslist = processor._job.Fixtures |
| | toolstring = "None" |
| | currTc = None |
| |
|
| | fixturelist = [] |
| | for index, f in enumerate(wcslist): |
| | fixturelist.append(create_fixture_setup(processor, index, f)) |
| |
|
| | curlist = [] |
| | sublist = [] |
| |
|
| | def commitToPostlist(): |
| | if len(curlist) > 0: |
| | for fixture in fixturelist: |
| | sublist.append(fixture) |
| | sublist.extend(curlist) |
| | postlist.append((toolstring, sublist)) |
| |
|
| | Path.Log.track(processor._job.PostProcessorOutputFile) |
| | for _, obj in enumerate(processor._operations): |
| | Path.Log.track(obj.Label) |
| |
|
| | if not PathUtil.activeForOp(obj): |
| | Path.Log.track() |
| | continue |
| |
|
| | tc = PathUtil.toolControllerForOp(obj) |
| |
|
| | if tc is None or not needsTcOp(currTc, tc): |
| | curlist.append(obj) |
| | else: |
| | commitToPostlist() |
| |
|
| | sublist = [tc] |
| | curlist = [obj] |
| | currTc = tc |
| |
|
| | if "%T" in processor._job.PostProcessorOutputFile: |
| | toolstring = f"{tc.ToolNumber}" |
| | else: |
| | toolstring = re.sub(r"[^\w\d-]", "_", tc.Label) |
| |
|
| | commitToPostlist() |
| |
|
| | return postlist |
| |
|
| |
|
| | def build_postlist_by_operation(processor: Any, early_tool_prep: bool = False) -> list: |
| | Path.Log.debug("Ordering by Operation") |
| | postlist = [] |
| | wcslist = processor._job.Fixtures |
| | currTc = None |
| |
|
| | for obj in processor._operations: |
| | if not PathUtil.activeForOp(obj): |
| | continue |
| |
|
| | sublist = [] |
| | Path.Log.debug(f"obj: {obj.Name}") |
| |
|
| | for index, f in enumerate(wcslist): |
| | sublist.append(create_fixture_setup(processor, index, f)) |
| | tc = PathUtil.toolControllerForOp(obj) |
| | if tc is not None: |
| | if processor._job.SplitOutput or needsTcOp(currTc, tc): |
| | sublist.append(tc) |
| | currTc = tc |
| | sublist.append(obj) |
| |
|
| | postlist.append((obj.Label, sublist)) |
| |
|
| | return postlist |
| |
|
| |
|
| | def buildPostList(processor: Any, early_tool_prep: bool = False) -> List[Tuple[str, List]]: |
| | orderby = processor._job.OrderOutputBy |
| | Path.Log.debug(f"Ordering by {orderby}") |
| |
|
| | if orderby == "Fixture": |
| | postlist = build_postlist_by_fixture(processor, early_tool_prep) |
| | elif orderby == "Tool": |
| | postlist = build_postlist_by_tool(processor, early_tool_prep) |
| | elif orderby == "Operation": |
| | postlist = build_postlist_by_operation(processor, early_tool_prep) |
| | else: |
| | raise ValueError(f"Unknown order: {orderby}") |
| |
|
| | Path.Log.debug(f"Postlist: {postlist}") |
| |
|
| | if processor._job.SplitOutput: |
| | final_postlist = postlist |
| | else: |
| | final_postlist = [("allitems", [item for sublist in postlist for item in sublist[1]])] |
| |
|
| | if early_tool_prep: |
| | return apply_early_tool_prep(final_postlist) |
| | return final_postlist |
| |
|
| |
|
| | def apply_early_tool_prep(postlist: List[Tuple[str, List]]) -> List[Tuple[str, List]]: |
| | """ |
| | Apply early tool preparation optimization to the postlist. |
| | |
| | This function modifies tool change commands to enable early tool preparation: |
| | - Always outputs tool changes as "Tn M6" (tool number followed by change command) |
| | - Additionally emits standalone "Tn" prep commands immediately after the previous M6 |
| | to allow the machine to prepare the next tool while the current tool is working |
| | |
| | Example output: |
| | T4 M6 <- change to tool 4 |
| | T5 <- prep tool 5 early (while T4 is working) |
| | <gcode> <- operations with T4 |
| | T5 M6 <- change to tool 5 (already prepped) |
| | T7 <- prep tool 7 early (while T5 is working) |
| | <gcode> <- operations with T5 |
| | T7 M6 <- change to tool 7 (already prepped) |
| | """ |
| | |
| | all_tool_controllers = [] |
| | for group_idx, (name, sublist) in enumerate(postlist): |
| | for item_idx, item in enumerate(sublist): |
| | if hasattr(item, "Proxy") and isinstance(item.Proxy, PathToolController.ToolController): |
| | all_tool_controllers.append((group_idx, item_idx, item)) |
| |
|
| | new_postlist = [] |
| | for group_idx, (name, sublist) in enumerate(postlist): |
| | new_sublist = [] |
| | i = 0 |
| | while i < len(sublist): |
| | item = sublist[i] |
| | |
| | if hasattr(item, "Proxy") and isinstance(item.Proxy, PathToolController.ToolController): |
| | |
| | |
| | m6_cmd = None |
| | for cmd in item.Path.Commands: |
| | if cmd.Name == "M6": |
| | m6_cmd = cmd |
| | break |
| |
|
| | if m6_cmd and len(m6_cmd.Parameters) > 0: |
| | |
| | tool_number = m6_cmd.Parameters.get("T", item.ToolNumber) |
| |
|
| | |
| | tc_position = next( |
| | ( |
| | idx |
| | for idx, (g_idx, i_idx, tc) in enumerate(all_tool_controllers) |
| | if g_idx == group_idx and i_idx == i |
| | ), |
| | None, |
| | ) |
| |
|
| | next_tc = ( |
| | all_tool_controllers[tc_position + 1][2] |
| | if tc_position is not None and tc_position + 1 < len(all_tool_controllers) |
| | else None |
| | ) |
| |
|
| | |
| | |
| | new_sublist.append(item) |
| |
|
| | |
| | if next_tc is not None: |
| | next_tool_number = next_tc.ToolNumber |
| | prep_next = Path.Command(f"T{next_tool_number}") |
| | prep_next_object = _CommandObject(prep_next) |
| | new_sublist.append(prep_next_object) |
| | else: |
| | |
| | new_sublist.append(item) |
| | else: |
| | new_sublist.append(item) |
| | i += 1 |
| | new_postlist.append((name, new_sublist)) |
| | return new_postlist |
| |
|