CS-Lab Support Forum for CNC Community
Help to run this brand-new forum and stay with us.
Ask your questions, we are here to help!
SimCNC 4th Axis Toolpath Viewer and Analyzer.
Quote from custom2 on 16 June 2025, 23:06Good Day Gents/Ladys
Since SimCNC does not have the ability to preview 4th Axis rotary toolpaths and because I desperately needed this functionality as a sanity check, I created a app that visualizes and animates a given tool path. (2.5D and 4th Axis rotary)
I added feed rate analysis by color coding the toolpath, PNG export and a couple of other functions.
The problem Im having is integrating it to SimCNC via maybe the load Gcode Button. Not replacing SimCNC functionality but just as a extra visual aid.
I was thinking of hooking on to Device.py as below but it seems not to have any gcode loading commands
import sys
import os# Add debug information
print("Python version:", sys.version)
print("Current working directory:", os.getcwd())
print("Python path:", sys.path)# Add the SimCNC scripts directory to the Python path
scripts_dir = os.path.join(os.environ["PROGRAMFILES"], "simCNC", "profiles", "RF45", "scripts")
if scripts_dir not in sys.path:
sys.path.append(scripts_dir)
print(f"Added to Python path: {scripts_dir}")try:
import ___DEVICE as device_module # SimCNC device library (note the triple underscores)
print("___DEVICE module imported successfully")
print("Available classes/methods in ___DEVICE:", [method for method in dir(device_module) if not method.startswith('_')])# Create a Device instance
d = device_module.Device()
print("Device instance created successfully")
print("Available methods in Device instance:", [method for method in dir(d) if not method.startswith('_')])except ImportError as e:
print(f"Failed to import ___DEVICE module: {e}")
print("Available files in scripts directory:")
if os.path.exists(scripts_dir):
print(os.listdir(scripts_dir))
else:
print(f"Scripts directory does not exist: {scripts_dir}")
except Exception as e:
print(f"Error creating Device instance: {e}")# Update the HTML file path to reference the ToolpathViewer folder
html_file = os.path.join(os.environ["PROGRAMFILES"], "simCNC", "screens", "SmuQScreenV2", "ToolpathViewer", "NCViewer2.html")
print(f"HTML file path: {html_file}")def open_html_view():
print(f"Attempting to open HTML file: {html_file}")
if os.path.exists(html_file):
print("HTML file exists, opening...")
os.system(f'start "{html_file}"') # Opens in default browser
else:
print("Error: HTML file not found!")
print("Files in ToolpathViewer directory:")
viewer_dir = os.path.dirname(html_file)
if os.path.exists(viewer_dir):
print(os.listdir(viewer_dir))# Hook into G-code load event
def on_gcode_load():
print("G-code load event triggered")
open_html_view()# Only attach function if ___DEVICE module was imported successfully
try:
if 'd' in locals():
print("Available methods in Device instance:", [method for method in dir(d) if not method.startswith('_')])
# Try different possible event hook methods
if hasattr(d, 'onGCodeLoad'):
d.onGCodeLoad(on_gcode_load)
print("Successfully attached to G-code load event using onGCodeLoad")
elif hasattr(d, 'on_gcode_load'):
d.on_gcode_load(on_gcode_load)
print("Successfully attached to G-code load event using on_gcode_load")
elif hasattr(d, 'setGCodeLoadCallback'):
d.setGCodeLoadCallback(on_gcode_load)
print("Successfully attached to G-code load event using setGCodeLoadCallback")
elif hasattr(d, 'addCallback'):
# Try generic callback registration
d.addCallback('gcode_load', on_gcode_load)
print("Successfully attached to G-code load event using addCallback")
else:
print("No known G-code load event method found. Manual trigger available.")
print("You can call on_gcode_load() manually to test the HTML viewer.")
# Test the HTML viewer manually
print("Testing HTML viewer...")
on_gcode_load()
else:
print("___DEVICE module not available, cannot attach to events")
except Exception as e:
print(f"Error attaching to G-code load event: {e}")print("Hook script initialization complete")
Any Idea how to go about automating the loading of the Gcode.
Any help would be apreciated.
Deon Gerber
Good Day Gents/Ladys
Since SimCNC does not have the ability to preview 4th Axis rotary toolpaths and because I desperately needed this functionality as a sanity check, I created a app that visualizes and animates a given tool path. (2.5D and 4th Axis rotary)
I added feed rate analysis by color coding the toolpath, PNG export and a couple of other functions.
The problem Im having is integrating it to SimCNC via maybe the load Gcode Button. Not replacing SimCNC functionality but just as a extra visual aid.
I was thinking of hooking on to Device.py as below but it seems not to have any gcode loading commands
import sys
import os
# Add debug information
print("Python version:", sys.version)
print("Current working directory:", os.getcwd())
print("Python path:", sys.path)
# Add the SimCNC scripts directory to the Python path
scripts_dir = os.path.join(os.environ["PROGRAMFILES"], "simCNC", "profiles", "RF45", "scripts")
if scripts_dir not in sys.path:
sys.path.append(scripts_dir)
print(f"Added to Python path: {scripts_dir}")
try:
import ___DEVICE as device_module # SimCNC device library (note the triple underscores)
print("___DEVICE module imported successfully")
print("Available classes/methods in ___DEVICE:", [method for method in dir(device_module) if not method.startswith('_')])
# Create a Device instance
d = device_module.Device()
print("Device instance created successfully")
print("Available methods in Device instance:", [method for method in dir(d) if not method.startswith('_')])
except ImportError as e:
print(f"Failed to import ___DEVICE module: {e}")
print("Available files in scripts directory:")
if os.path.exists(scripts_dir):
print(os.listdir(scripts_dir))
else:
print(f"Scripts directory does not exist: {scripts_dir}")
except Exception as e:
print(f"Error creating Device instance: {e}")
# Update the HTML file path to reference the ToolpathViewer folder
html_file = os.path.join(os.environ["PROGRAMFILES"], "simCNC", "screens", "SmuQScreenV2", "ToolpathViewer", "NCViewer2.html")
print(f"HTML file path: {html_file}")
def open_html_view():
print(f"Attempting to open HTML file: {html_file}")
if os.path.exists(html_file):
print("HTML file exists, opening...")
os.system(f'start "{html_file}"') # Opens in default browser
else:
print("Error: HTML file not found!")
print("Files in ToolpathViewer directory:")
viewer_dir = os.path.dirname(html_file)
if os.path.exists(viewer_dir):
print(os.listdir(viewer_dir))
# Hook into G-code load event
def on_gcode_load():
print("G-code load event triggered")
open_html_view()
# Only attach function if ___DEVICE module was imported successfully
try:
if 'd' in locals():
print("Available methods in Device instance:", [method for method in dir(d) if not method.startswith('_')])
# Try different possible event hook methods
if hasattr(d, 'onGCodeLoad'):
d.onGCodeLoad(on_gcode_load)
print("Successfully attached to G-code load event using onGCodeLoad")
elif hasattr(d, 'on_gcode_load'):
d.on_gcode_load(on_gcode_load)
print("Successfully attached to G-code load event using on_gcode_load")
elif hasattr(d, 'setGCodeLoadCallback'):
d.setGCodeLoadCallback(on_gcode_load)
print("Successfully attached to G-code load event using setGCodeLoadCallback")
elif hasattr(d, 'addCallback'):
# Try generic callback registration
d.addCallback('gcode_load', on_gcode_load)
print("Successfully attached to G-code load event using addCallback")
else:
print("No known G-code load event method found. Manual trigger available.")
print("You can call on_gcode_load() manually to test the HTML viewer.")
# Test the HTML viewer manually
print("Testing HTML viewer...")
on_gcode_load()
else:
print("___DEVICE module not available, cannot attach to events")
except Exception as e:
print(f"Error attaching to G-code load event: {e}")
print("Hook script initialization complete")
Any Idea how to go about automating the loading of the Gcode.
Any help would be apreciated.
Deon Gerber
Uploaded files:Quote from custom2 on 17 June 2025, 11:12Hi
Maybe I need to elaborate. I was mostly thinking of making a button "Anylize Toolpath" to launchthe app when needed. This is done and is functional.
But I would like to retrieve the gcode that was loaded into SimCNC appon opening the app, import it into the app for analisys. Edit if needed and revers the process when I close the app. Meaning exporting the Gcode back to SimCNC.
I think the last part is redundant because Ive edited gcode outside of SimCNC where appon SimCNC prompted me that it was edited and wanted permission to apply.
Thats in a nutshell.
Regards
Deon
Hi
Maybe I need to elaborate. I was mostly thinking of making a button "Anylize Toolpath" to launchthe app when needed. This is done and is functional.
But I would like to retrieve the gcode that was loaded into SimCNC appon opening the app, import it into the app for analisys. Edit if needed and revers the process when I close the app. Meaning exporting the Gcode back to SimCNC.
I think the last part is redundant because Ive edited gcode outside of SimCNC where appon SimCNC prompted me that it was edited and wanted permission to apply.
Thats in a nutshell.
Regards
Deon
Quote from custom2 on 17 June 2025, 13:06Hi all
Think I might have figured it out. Will see tonight when I get home.
Will keep you informed.
Regards
Deon
Hi all
Think I might have figured it out. Will see tonight when I get home.
Will keep you informed.
Regards
Deon
Quote from CS-Lab Support on 23 June 2025, 08:37Unfortunately, implementing this feature right now would be quite difficult. The ___DEVICE class is merely a wrapper for communicating with simCNC and doesn’t provide any hooks into its internal functions.As a workaround, you could add a custom “Open File” button in the GUI editor and attach a Python script to it. In that script, you can:
* Display a file-selection dialog.
* Create and show the visualization window.
* Load the chosen file into simCNC viad.openGCodeFile(<filename>)I realize it’s not a particularly elegant solution, but it should at least get the job done. I’ve also added a request to our internal TODO list to support simple kinematic visualizations (for example, a rotary axis on the table).
As a workaround, you could add a custom “Open File” button in the GUI editor and attach a Python script to it. In that script, you can:
* Display a file-selection dialog.
* Create and show the visualization window.
* Load the chosen file into simCNC via
d.openGCodeFile(<filename>)
Quote from custom2 on 14 July 2025, 20:08Hi
Thanks for the reply. Yes I managed to do a work around.
Editor was mainly just for visualizing the 4th axis toolpath as a sanity check but as always this is getting more involved by the day.
Im piggybacking off SimCNCs ability to recognize the file was changed when I edit a file thats loaded currently inside off SimCNC but opened in my editor. This works quite well as long as I keep my files in the same trusted folder all is well.
Added a GCode validation function that uses a machine settings menu for machine specific parameters which will flag unrealistic feeds and speeds, Z Hight warnings etc.
Added the ability to click on anywhere specific on the toolpath display then it jumps to that line in the code editor to make things easier to edit. And of coarse vice versa by clicking on the line of code highlights the path apropreiate segment
Almost done.Added the ability to run the toolpath simulation as a animation so all movement can be studied before actualy runing the file on the machine.
Color coded the different feed rates.
In the process of color coding chipload.
Will send you a copy soon for validation.
Regards
Deon Gerber
Hi
Thanks for the reply. Yes I managed to do a work around.
Editor was mainly just for visualizing the 4th axis toolpath as a sanity check but as always this is getting more involved by the day.
Im piggybacking off SimCNCs ability to recognize the file was changed when I edit a file thats loaded currently inside off SimCNC but opened in my editor. This works quite well as long as I keep my files in the same trusted folder all is well.
Added a GCode validation function that uses a machine settings menu for machine specific parameters which will flag unrealistic feeds and speeds, Z Hight warnings etc.
Added the ability to click on anywhere specific on the toolpath display then it jumps to that line in the code editor to make things easier to edit. And of coarse vice versa by clicking on the line of code highlights the path apropreiate segment
Almost done.
Added the ability to run the toolpath simulation as a animation so all movement can be studied before actualy runing the file on the machine.
Color coded the different feed rates.
In the process of color coding chipload.
Will send you a copy soon for validation.
Regards
Deon Gerber
Quote from CS-Lab Support on 17 July 2025, 09:37Great, I’d love to see it in action 👍






















