Created
October 14, 2025 19:12
-
-
Save freckletonj/a7e5f6f730ae8ee6da15ef7fcf714550 to your computer and use it in GitHub Desktop.
Custom FreeCAD CAM Simulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ''' | |
| Use the new CAM simulator with custom stock and custom cutting paths | |
| ''' | |
| import FreeCAD as App | |
| import FreeCADGui as Gui | |
| import Part | |
| import CAMSimulator | |
| from PathScripts import PathUtils | |
| import Path.Dressup.Utils as PathDressup | |
| from Path.Main.Gui import SimulatorGL | |
| doc = App.ActiveDocument | |
| if not doc: | |
| App.Console.PrintError("No active document.\n") | |
| raise RuntimeError("No active document") | |
| # Locate the first Path Job | |
| jobs = PathUtils.GetJobs() | |
| if not jobs: | |
| App.Console.PrintError("No Path Job found in the active document.\n") | |
| raise RuntimeError("No Path Job found") | |
| job = jobs[0] | |
| App.Console.PrintMessage(f"Using job: {job.Label}\n") | |
| # Extract stock and base shape (optional) | |
| stock = job.Stock.Shape if hasattr(job, "Stock") and job.Stock else None | |
| base_shape = None | |
| if hasattr(job, "Model") and job.Model and len(job.Model.OutList) > 0: | |
| base_shape = job.Model.OutList[0].Shape | |
| elif hasattr(job, "Base") and job.Base: | |
| base_shape = job.Base.Shape | |
| if not stock: | |
| App.Console.PrintWarning("Job has no stock defined, using a default box.\n") | |
| stock = Part.makeBox(40, 40, 10) | |
| # Collect all active operations in the job | |
| ops = [] | |
| for obj in job.Operations.Group: | |
| if hasattr(obj, "Path") and hasattr(obj, "Active") and obj.Active: | |
| ops.append(obj) | |
| App.Console.PrintMessage(f" - {obj.Label}\n") | |
| if not ops: | |
| App.Console.PrintError("No active operations found in job.\n") | |
| raise RuntimeError("No active operations found") | |
| App.Console.PrintMessage(f"Found {len(ops)} active operations.\n") | |
| # Create the simulator instance | |
| sim = CAMSimulator.PathSim() | |
| sim.ResetSimulation() | |
| sim_gl = SimulatorGL.CAMSimulation() | |
| # Add the tools and their paths | |
| for op in ops: | |
| tc = PathDressup.toolController(op) | |
| tool = tc.Tool | |
| toolNumber = tc.ToolNumber | |
| App.Console.PrintMessage(f"Adding tool {toolNumber} ({tool.Label})...\n") | |
| resolution = 0.5 | |
| toolProfile = sim_gl.GetToolProfile(tool, resolution) | |
| # AddTool expects: (profile_list, tool_number, diameter, resolution) | |
| # The last parameter (resolution) should be 1 for tool resolution | |
| sim.AddTool(toolProfile, toolNumber, tool.Diameter, 1) | |
| # Add each command from the operation's path | |
| opCommands = PathUtils.getPathWithPlacement(op).Commands | |
| App.Console.PrintMessage(f" Adding {len(opCommands)} commands...\n") | |
| for cmd in opCommands: | |
| sim.AddCommand(cmd) | |
| quality = 5 # int: 1=low, 10=high | |
| App.Console.PrintMessage(f"Starting simulation with quality {quality}...\n") | |
| # Begin Simulation | |
| sim.BeginSimulation(stock, quality) | |
| App.Console.PrintMessage("Simulation initialized successfully.\n") | |
| # must set base shape after BeginSimulation (or else segfault) | |
| if base_shape: | |
| sim.SetBaseShape(base_shape, 1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment