├── pycam
├── Flow
│ └── __init__.py
├── Cutters
│ └── __init__.py
├── Exporters
│ ├── __init__.py
│ ├── LinuxCNCToolExporter.py
│ └── STLExporter.py
├── Physics
│ └── __init__.py
├── Simulation
│ └── __init__.py
├── .gitignore
├── Test
│ ├── assets
│ │ ├── cube_binary.stl
│ │ └── cube_ascii.stl
│ ├── test_dxf_importer.py
│ ├── test_cxf_fonts.py
│ ├── test_stl_loader.py
│ ├── test_svg_loader.py
│ └── __init__.py
├── errors.py
├── Utils
│ ├── progress.py
│ └── rootsolver.py
├── Plugins
│ ├── TaskTypes.py
│ ├── OpenGLViewTool.py
│ ├── PathPatterns.py
│ ├── ModelPlaneMirror.py
│ ├── ModelSwapAxes.py
│ ├── Units.py
│ ├── ModelPolygons.py
│ ├── OpenGLViewSupportModelPreview.py
│ ├── ModelRotation.py
│ └── OpenGLViewAxes.py
├── PathProcessors
│ ├── __init__.py
│ ├── PolygonCutter.py
│ └── ContourCutter.py
├── Toolpath
│ └── Steps.py
├── Geometry
│ ├── PointKdtree.py
│ └── Path.py
├── Importers
│ ├── __init__.py
│ └── TestModel.py
├── PathGenerators
│ └── EngraveCutter.py
├── run_cli.py
└── Gui
│ ├── OpenGLTools.py
│ └── Console.py
├── debian
├── manpages
├── source
│ └── format
├── pycam.mime
├── pycam.sharedmimeinfo
├── docs
├── pycam.install
├── copyright
├── rules
└── control
├── requirements.txt
├── share
├── pycam.ico
├── fonts
│ ├── romanc.cxf
│ ├── romand.cxf
│ ├── romanp.cxf
│ ├── romans.cxf
│ ├── romant.cxf
│ ├── symbol.cxf
│ ├── courier.cxf
│ ├── cursive.cxf
│ ├── italicc.cxf
│ ├── italiccs.cxf
│ ├── italict.cxf
│ ├── romancs.cxf
│ ├── romans2.cxf
│ ├── scriptc.cxf
│ ├── scripts.cxf
│ ├── standard.cxf
│ ├── unicode.cxf
│ ├── iso8859-11.cxf
│ ├── normallatin1.cxf
│ ├── normallatin2.cxf
│ ├── normallatin1.readme
│ └── README
├── ui
│ ├── logo_16px.png
│ ├── logo_32px.png
│ ├── logo_48px.png
│ ├── logo_64px.png
│ ├── logo_gui.bmp
│ ├── logo_gui.png
│ ├── logo_128px.png
│ ├── extrusion_sine.png
│ ├── extrusion_chamfer.png
│ ├── extrusion_radius_up.png
│ ├── extrusion_sigmoidal.png
│ ├── logo_gui_vertical.bmp
│ ├── extrusion_radius_down.png
│ ├── emc_tool_export.ui
│ ├── model_export.ui
│ ├── clipboard.ui
│ ├── menubar.xml
│ ├── gtkrc_windows
│ ├── opengl_view_grid.ui
│ └── progress_bar.ui
├── mime
│ ├── icons
│ │ ├── 32x32
│ │ │ └── application-sla.png
│ │ ├── 64x64
│ │ │ └── application-sla.png
│ │ └── 128x128
│ │ │ └── application-sla.png
│ └── pycam.xml
└── desktop
│ └── pycam.desktop
├── docs
├── img
│ ├── 3d-view.png
│ ├── favicon.ico
│ ├── menu-edit.png
│ ├── menu-file.png
│ ├── menu-help.png
│ ├── touch-off.png
│ ├── menu-extras.png
│ ├── server-mode.png
│ ├── menu-settings.png
│ ├── menu-windows.png
│ ├── pycam-logo-160.png
│ ├── pycam-logo-600.png
│ ├── engrave-font-normal.png
│ ├── engrave-font-symbol.png
│ ├── process-statistics.png
│ ├── screenshot-settings.png
│ ├── screenshot-startup.png
│ ├── touch-off-settings.png
│ ├── 2d-multilayer-engrave.png
│ ├── 3d-view-context-menu.png
│ ├── 3d-view-visible-items.png
│ ├── engrave-font-courier.png
│ ├── engrave-font-cursive.png
│ ├── engrave-font-greek-ol.png
│ ├── engrave-font-japanese.png
│ ├── engrave-font-standard.png
│ ├── engrave-font-unicode.png
│ ├── model-transformations.png
│ ├── process-milling-climb.png
│ ├── engrave-font-cyrillic2.png
│ ├── engrave-font-greek-plain.png
│ ├── engrave-font-iso8859-11.png
│ ├── engrave-font-roman-plain.png
│ ├── process-strategy-surface.png
│ ├── screenshot-toolpath-view.png
│ ├── engrave-font-gothic-german.png
│ ├── engrave-font-greek-complex.png
│ ├── engrave-font-greek-ol-plus.png
│ ├── engrave-font-greek-simplex.png
│ ├── engrave-font-kochi-gothic.png
│ ├── engrave-font-kochi-mincho.png
│ ├── engrave-font-normal-latin1.png
│ ├── engrave-font-normal-latin2.png
│ ├── engrave-font-roman-complex.png
│ ├── engrave-font-roman-duplex.png
│ ├── engrave-font-roman-simplex.png
│ ├── engrave-font-roman-triplex.png
│ ├── engrave-font-symbol-astro.png
│ ├── engrave-font-symbol-misc-1.png
│ ├── engrave-font-symbol-misc-2.png
│ ├── process-strategy-engraving.png
│ ├── screenshot-contour-cutter.png
│ ├── screenshot-polygon-cutter.png
│ ├── 2d-multilayer-engrave-model.png
│ ├── engrave-font-gothic-british.png
│ ├── engrave-font-gothic-italian.png
│ ├── engrave-font-italian-complex.png
│ ├── engrave-font-italian-triplex.png
│ ├── engrave-font-script_complex.png
│ ├── process-milling-conventional.png
│ ├── screenshot-linuxcnc-example.png
│ ├── screenshot-model-operations.png
│ ├── server-mode-gui-preferences.png
│ ├── 2d-modeling-polygon_directions.png
│ ├── 2d-multilayer-engrave-toolpath.png
│ ├── process-strategy-contour-follow.png
│ ├── process-strategy-slice-removal.png
│ ├── screenshot-finishing-operation.png
│ ├── screenshot-processing-settings.png
│ ├── engrave-font-greek-complex-small.png
│ ├── engrave-font-italian-complex-small.png
│ ├── engrave-font-roman-complex-small.png
│ ├── process-strategy-contour-polygon.png
│ └── 2d-multilayer-engrave.svg
├── tool-types.md
├── task-settings.md
├── parallel-processing.md
├── bounding-box.md
├── cli-examples.md
├── screenshots.md
├── installation.md
├── supported-formats.md
├── modeling-openscad-dxf.md
├── articles.md
├── index.md
├── other-programs.md
├── video-translations.md
├── keyboard-shortcuts.md
├── model-transformations.md
├── requirements.md
├── menu-items.md
├── main-page.md
└── installation-macos.md
├── .codespell.exclude
├── samples
├── Sphere_cut.scad
├── problem_1_triangle.stl
├── rectangle.svg
├── SampleScene3.scad
├── SampleScene2.scad
├── pycam-textbox.scad
├── polygon2.svg
├── polygon3.svg
├── polygon5.svg
├── Box2.stl
├── Box1.stl
├── Box0.stl
├── polygon4.svg
└── multilayer_engrave.svg
├── pyinstaller
├── hooks
│ └── hook-pycam.py
├── pyinstaller_fix_module_exception.patch
└── pyinstaller_info.txt
├── Dockerfile
├── scripts
├── pylint.sh
├── list_events.sh
├── run_flake8
└── profile_pycam.py
├── MANIFEST.in
├── .coveragerc
├── .gitignore
├── man
├── Makefile
└── pycam.1.inc
├── setup.cfg
├── LICENSE.TXT
├── .github
└── workflows
│ └── ci.yml
├── technical_details.txt
├── README.md
├── mkdocs.yml
├── INSTALL.md
├── CODE_OF_CONDUCT.md
└── setup.py
/pycam/Flow/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pycam/Cutters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pycam/Exporters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pycam/Physics/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pycam/Simulation/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/debian/manpages:
--------------------------------------------------------------------------------
1 | man/pycam.1
2 |
--------------------------------------------------------------------------------
/pycam/.gitignore:
--------------------------------------------------------------------------------
1 | Version.py
2 |
--------------------------------------------------------------------------------
/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (native)
2 |
--------------------------------------------------------------------------------
/debian/pycam.mime:
--------------------------------------------------------------------------------
1 | ../share/mime/pycam.mime
--------------------------------------------------------------------------------
/debian/pycam.sharedmimeinfo:
--------------------------------------------------------------------------------
1 | ../share/mime/pycam.xml
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | PyOpenGL
2 | PyYAML
3 | svg.path
4 |
--------------------------------------------------------------------------------
/debian/docs:
--------------------------------------------------------------------------------
1 | Changelog
2 | README.md
3 | technical_details.txt
4 |
--------------------------------------------------------------------------------
/debian/pycam.install:
--------------------------------------------------------------------------------
1 | share/desktop/pycam.desktop /usr/share/applications
2 |
--------------------------------------------------------------------------------
/share/pycam.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/pycam.ico
--------------------------------------------------------------------------------
/docs/img/3d-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/3d-view.png
--------------------------------------------------------------------------------
/docs/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/favicon.ico
--------------------------------------------------------------------------------
/docs/img/menu-edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-edit.png
--------------------------------------------------------------------------------
/docs/img/menu-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-file.png
--------------------------------------------------------------------------------
/docs/img/menu-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-help.png
--------------------------------------------------------------------------------
/docs/img/touch-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/touch-off.png
--------------------------------------------------------------------------------
/share/fonts/romanc.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romanc.cxf
--------------------------------------------------------------------------------
/share/fonts/romand.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romand.cxf
--------------------------------------------------------------------------------
/share/fonts/romanp.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romanp.cxf
--------------------------------------------------------------------------------
/share/fonts/romans.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romans.cxf
--------------------------------------------------------------------------------
/share/fonts/romant.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romant.cxf
--------------------------------------------------------------------------------
/share/fonts/symbol.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/symbol.cxf
--------------------------------------------------------------------------------
/share/ui/logo_16px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_16px.png
--------------------------------------------------------------------------------
/share/ui/logo_32px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_32px.png
--------------------------------------------------------------------------------
/share/ui/logo_48px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_48px.png
--------------------------------------------------------------------------------
/share/ui/logo_64px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_64px.png
--------------------------------------------------------------------------------
/share/ui/logo_gui.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_gui.bmp
--------------------------------------------------------------------------------
/share/ui/logo_gui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_gui.png
--------------------------------------------------------------------------------
/.codespell.exclude:
--------------------------------------------------------------------------------
1 | # see http://www.daa.com.au/pipermail/pygtk/2009-May/017052.html
2 |
--------------------------------------------------------------------------------
/docs/img/menu-extras.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-extras.png
--------------------------------------------------------------------------------
/docs/img/server-mode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/server-mode.png
--------------------------------------------------------------------------------
/share/fonts/courier.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/courier.cxf
--------------------------------------------------------------------------------
/share/fonts/cursive.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/cursive.cxf
--------------------------------------------------------------------------------
/share/fonts/italicc.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/italicc.cxf
--------------------------------------------------------------------------------
/share/fonts/italiccs.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/italiccs.cxf
--------------------------------------------------------------------------------
/share/fonts/italict.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/italict.cxf
--------------------------------------------------------------------------------
/share/fonts/romancs.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romancs.cxf
--------------------------------------------------------------------------------
/share/fonts/romans2.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/romans2.cxf
--------------------------------------------------------------------------------
/share/fonts/scriptc.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/scriptc.cxf
--------------------------------------------------------------------------------
/share/fonts/scripts.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/scripts.cxf
--------------------------------------------------------------------------------
/share/fonts/standard.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/standard.cxf
--------------------------------------------------------------------------------
/share/fonts/unicode.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/unicode.cxf
--------------------------------------------------------------------------------
/share/ui/logo_128px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_128px.png
--------------------------------------------------------------------------------
/docs/img/menu-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-settings.png
--------------------------------------------------------------------------------
/docs/img/menu-windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/menu-windows.png
--------------------------------------------------------------------------------
/docs/img/pycam-logo-160.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/pycam-logo-160.png
--------------------------------------------------------------------------------
/docs/img/pycam-logo-600.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/pycam-logo-600.png
--------------------------------------------------------------------------------
/share/fonts/iso8859-11.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/iso8859-11.cxf
--------------------------------------------------------------------------------
/share/ui/extrusion_sine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/extrusion_sine.png
--------------------------------------------------------------------------------
/share/fonts/normallatin1.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/normallatin1.cxf
--------------------------------------------------------------------------------
/share/fonts/normallatin2.cxf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/normallatin2.cxf
--------------------------------------------------------------------------------
/docs/img/engrave-font-normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-normal.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-symbol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-symbol.png
--------------------------------------------------------------------------------
/docs/img/process-statistics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-statistics.png
--------------------------------------------------------------------------------
/docs/img/screenshot-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-settings.png
--------------------------------------------------------------------------------
/docs/img/screenshot-startup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-startup.png
--------------------------------------------------------------------------------
/docs/img/touch-off-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/touch-off-settings.png
--------------------------------------------------------------------------------
/samples/Sphere_cut.scad:
--------------------------------------------------------------------------------
1 | intersection() {
2 | sphere(r=5, center=true, $fn=6);
3 | cube([20,20,5], center=true);
4 | }
--------------------------------------------------------------------------------
/share/fonts/normallatin1.readme:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/fonts/normallatin1.readme
--------------------------------------------------------------------------------
/share/ui/extrusion_chamfer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/extrusion_chamfer.png
--------------------------------------------------------------------------------
/share/ui/extrusion_radius_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/extrusion_radius_up.png
--------------------------------------------------------------------------------
/share/ui/extrusion_sigmoidal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/extrusion_sigmoidal.png
--------------------------------------------------------------------------------
/share/ui/logo_gui_vertical.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/logo_gui_vertical.bmp
--------------------------------------------------------------------------------
/docs/img/2d-multilayer-engrave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/2d-multilayer-engrave.png
--------------------------------------------------------------------------------
/docs/img/3d-view-context-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/3d-view-context-menu.png
--------------------------------------------------------------------------------
/docs/img/3d-view-visible-items.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/3d-view-visible-items.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-courier.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-courier.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-cursive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-cursive.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-ol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-ol.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-japanese.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-japanese.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-standard.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-unicode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-unicode.png
--------------------------------------------------------------------------------
/docs/img/model-transformations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/model-transformations.png
--------------------------------------------------------------------------------
/docs/img/process-milling-climb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-milling-climb.png
--------------------------------------------------------------------------------
/pycam/Test/assets/cube_binary.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/pycam/Test/assets/cube_binary.stl
--------------------------------------------------------------------------------
/share/ui/extrusion_radius_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/ui/extrusion_radius_down.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-cyrillic2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-cyrillic2.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-plain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-plain.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-iso8859-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-iso8859-11.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-plain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-plain.png
--------------------------------------------------------------------------------
/docs/img/process-strategy-surface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-strategy-surface.png
--------------------------------------------------------------------------------
/docs/img/screenshot-toolpath-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-toolpath-view.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-gothic-german.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-gothic-german.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-complex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-ol-plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-ol-plus.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-simplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-simplex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-kochi-gothic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-kochi-gothic.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-kochi-mincho.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-kochi-mincho.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-normal-latin1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-normal-latin1.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-normal-latin2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-normal-latin2.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-complex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-duplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-duplex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-simplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-simplex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-triplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-triplex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-symbol-astro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-symbol-astro.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-symbol-misc-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-symbol-misc-1.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-symbol-misc-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-symbol-misc-2.png
--------------------------------------------------------------------------------
/docs/img/process-strategy-engraving.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-strategy-engraving.png
--------------------------------------------------------------------------------
/docs/img/screenshot-contour-cutter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-contour-cutter.png
--------------------------------------------------------------------------------
/docs/img/screenshot-polygon-cutter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-polygon-cutter.png
--------------------------------------------------------------------------------
/docs/img/2d-multilayer-engrave-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/2d-multilayer-engrave-model.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-gothic-british.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-gothic-british.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-gothic-italian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-gothic-italian.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-italian-complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-italian-complex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-italian-triplex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-italian-triplex.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-script_complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-script_complex.png
--------------------------------------------------------------------------------
/docs/img/process-milling-conventional.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-milling-conventional.png
--------------------------------------------------------------------------------
/docs/img/screenshot-linuxcnc-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-linuxcnc-example.png
--------------------------------------------------------------------------------
/docs/img/screenshot-model-operations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-model-operations.png
--------------------------------------------------------------------------------
/docs/img/server-mode-gui-preferences.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/server-mode-gui-preferences.png
--------------------------------------------------------------------------------
/share/mime/icons/32x32/application-sla.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/mime/icons/32x32/application-sla.png
--------------------------------------------------------------------------------
/share/mime/icons/64x64/application-sla.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/mime/icons/64x64/application-sla.png
--------------------------------------------------------------------------------
/docs/img/2d-modeling-polygon_directions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/2d-modeling-polygon_directions.png
--------------------------------------------------------------------------------
/docs/img/2d-multilayer-engrave-toolpath.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/2d-multilayer-engrave-toolpath.png
--------------------------------------------------------------------------------
/docs/img/process-strategy-contour-follow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-strategy-contour-follow.png
--------------------------------------------------------------------------------
/docs/img/process-strategy-slice-removal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-strategy-slice-removal.png
--------------------------------------------------------------------------------
/docs/img/screenshot-finishing-operation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-finishing-operation.png
--------------------------------------------------------------------------------
/docs/img/screenshot-processing-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/screenshot-processing-settings.png
--------------------------------------------------------------------------------
/share/mime/icons/128x128/application-sla.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/share/mime/icons/128x128/application-sla.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-greek-complex-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-greek-complex-small.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-italian-complex-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-italian-complex-small.png
--------------------------------------------------------------------------------
/docs/img/engrave-font-roman-complex-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/engrave-font-roman-complex-small.png
--------------------------------------------------------------------------------
/docs/img/process-strategy-contour-polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SebKuzminsky/pycam/HEAD/docs/img/process-strategy-contour-polygon.png
--------------------------------------------------------------------------------
/pyinstaller/hooks/hook-pycam.py:
--------------------------------------------------------------------------------
1 | # keysyms does not seem to be recognized by pyinstaller
2 | # There will be exceptions after any keypress without this line.
3 | hiddenimports = ["gtk.keysyms"]
4 |
--------------------------------------------------------------------------------
/share/fonts/README:
--------------------------------------------------------------------------------
1 | The fonts delivered with PyCAM are taken from QCAD:
2 | http://www.qcad.org/
3 |
4 | The fonts are licensed under the GPL v2.0 or later.
5 |
6 | Thanks to the QCAD developers for this great piece of work!
7 |
8 |
--------------------------------------------------------------------------------
/docs/tool-types.md:
--------------------------------------------------------------------------------
1 | Tool types
2 | ==========
3 | Pycam support three tool shapes: Flat bottom (cylindrical), ball nose (spherical), and bull nose (toroidal).
4 | In addition to the tool shape the feedrate and spindle speed are also configured per tool.
5 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:9
2 |
3 | WORKDIR /root/pycam
4 |
5 | COPY . .
6 |
7 | RUN apt-get update && apt-get install -y python3 \
8 | python3-gi \
9 | python3-opengl \
10 | python3-yaml \
11 | gir1.2-gtk-3.0
12 |
13 | CMD [ "pycam/run_gui.py" ]
14 |
--------------------------------------------------------------------------------
/docs/task-settings.md:
--------------------------------------------------------------------------------
1 | Task settings
2 | =============
3 | Toolpaths are generated in tasks, which are formed by a combination of a tool, a process, bounds, and zero or more collision models. This way it is possible to make different combinations for different steps in the milling process.
4 |
--------------------------------------------------------------------------------
/samples/problem_1_triangle.stl:
--------------------------------------------------------------------------------
1 | solid vcg
2 | facet normal -2.847750e-02 1.220272e-01 -9.921181e-01
3 | outer loop
4 | vertex 8.845570e-01 1.323334e+00 8.942510e-01
5 | vertex 8.742290e-01 1.593305e+00 9.277530e-01
6 | vertex 1.152810e+00 1.435092e+00 9.002970e-01
7 | endloop
8 | endfacet
9 | endsolid vcg
10 |
--------------------------------------------------------------------------------
/scripts/pylint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -eu
4 |
5 | BASE_PATH="$(cd "$(dirname "$0")"; pwd)"
6 |
7 | IGNORE_LIST="C0103,C0111,C0301"
8 | IGNORE_LIST="$IGNORE_LIST,W0511,W0602,W0603,W0612,W0613"
9 | IGNORE_LIST="$IGNORE_LIST,R0201,R0902,R0903,R0911,R0912,R0913,R0914,R0915"
10 |
11 | PYTHONPATH="$BASE_PATH/pycam" pylint -i y -d "$IGNORE_LIST" "$1"
12 |
--------------------------------------------------------------------------------
/scripts/list_events.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -eu
4 |
5 | BASE_DIR=$(cd "$(dirname "$0")"; pwd)
6 |
7 | grep -rh _event "$BASE_DIR/../pycam" | \
8 | grep -v " def " | \
9 | grep -v configure_event | \
10 | grep -v expose_event | \
11 | sed 's/.*_event//g' | \
12 | grep '"' | \
13 | cut -f 2 -d '"' | \
14 | grep -E "^[0-9A-Za-z_-]+$" | \
15 | sort | \
16 | uniq -c
17 |
18 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include Changelog
2 | include COPYING.TXT
3 | include INSTALL.TXT
4 | include LICENSE.TXT
5 | include mkdocs.yml
6 | include README.md
7 | include release_info.txt
8 | include requirements.txt
9 | include technical_details.txt
10 | include pycam
11 | recursive-include docs *
12 | recursive-include man *
13 | recursive-include share *
14 | recursive-include samples *
15 | recursive-include Tests *
16 |
--------------------------------------------------------------------------------
/samples/rectangle.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/share/ui/emc_tool_export.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/share/desktop/pycam.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.0
3 | Name=PyCAM
4 | GenericName=CNC Toolpath Generator
5 | Comment=Generate GCode for 3-Axis CNC machining.
6 | Exec=pycam %u
7 | TryExec=pycam
8 | Terminal=false
9 | Type=Application
10 | Categories=Development;Engineering;Robotics;Education;Science;2DGraphics;VectorGraphics;3DGraphics;X-CNC;
11 | MimeType=application/x-yaml;application/sla;image/svg+xml;application/postscript;image/vnd.dxf;
12 | Icon=pycam
13 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | branch = True
3 | source = pycam
4 |
5 | [report]
6 | exclude_lines =
7 | # Have to re-enable the standard pragma
8 | pragma: no cover
9 | # Don't complain about missing debug-only code:
10 | def __repr__
11 | if self\.debug
12 | # Don't complain if tests don't hit defensive assertion code:
13 | raise AssertionError
14 | raise NotImplementedError
15 | # Don't complain if non-runnable code isn't run:
16 | if __name__ == .__main__.:
17 |
18 | [html]
19 | directory = build/coverage-report
20 |
--------------------------------------------------------------------------------
/samples/SampleScene3.scad:
--------------------------------------------------------------------------------
1 | difference() {
2 | sphere(r=30);
3 | translate([-50, -50, -100]) cube([100, 100, 100]);
4 | }
5 |
6 | translate([-30, 50, 0]) union() {
7 | cube([140, 30, 10]);
8 | translate([40, 15, 10]) rotate([0, 90, 0]) cylinder(r=10, h=60);
9 | }
10 |
11 | translate([80, 0, 0]) scale(1.2) union() {
12 | difference() {
13 | cylinder(r1=20, r2=5, h=20);
14 | translate([-25, 30, -10]) rotate([60, 0, 0]) cube([50, 50, 50]);
15 | }
16 | difference() {
17 | translate([0, 35, -21]) rotate([70, 0, 0]) cylinder(r=16, h=50);
18 | translate([-50, -50, -100]) cube([100, 100, 100]);
19 | }
20 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.o
3 | *.so
4 | *.py[cod]
5 |
6 | test.ngc
7 |
8 | man/pycam.1
9 | man/pycam.1.html
10 | docs/release-notes.md
11 |
12 | dist
13 | build
14 | eggs
15 | *.egg-info
16 | .svn
17 | .coverage
18 | .idea
19 | .ropeproject/
20 |
21 | .DS_Store*
22 | ehthumbs.db
23 | Icon?
24 | Thumbs.db
25 |
26 | *~
27 | .*.sw?
28 |
29 | man/pycam.1
30 |
31 | # Generated mkdocs files go into the site directory
32 | site/
33 |
34 | # debian packaging
35 | debian/debhelper-build-stamp
36 | debian/files
37 | debian/pycam/
38 | debian/pycam.debhelper.log
39 | debian/pycam.*.debhelper
40 | debian/pycam.substvars
41 |
--------------------------------------------------------------------------------
/man/Makefile:
--------------------------------------------------------------------------------
1 | RUN_SCRIPT = ../pycam/run_gui.py
2 | PYCAM_MAN_INCLUDE_FILE = pycam.1.inc
3 | MAN_FILES = pycam.1
4 | HTML_FILES = $(patsubst %,%.html,$(MAN_FILES))
5 | RM = rm -f
6 |
7 |
8 | .PHONY: build clean html man
9 |
10 |
11 | man: $(MAN_FILES)
12 |
13 | html: $(HTML_FILES)
14 |
15 | pycam.1: $(RUN_SCRIPT) $(PYCAM_MAN_INCLUDE_FILE)
16 | help2man --no-info --name="Toolpath Generation for 3-Axis CNC machining" \
17 | --section=1 --manual="PyCAM manual" --include="$(PYCAM_MAN_INCLUDE_FILE)" \
18 | --output="$@" "$(RUN_SCRIPT)"
19 |
20 | %.html: %
21 | man2html $* >"$@"
22 |
23 | clean:
24 | $(RM) $(MAN_FILES) $(HTML_FILES)
25 |
--------------------------------------------------------------------------------
/docs/parallel-processing.md:
--------------------------------------------------------------------------------
1 | Parallel processing is fully supported on Linux. Available features on
2 | other platforms are limited.
3 |
4 | | Feature | Linux | MacOS | Windows (.exe) | Windows (installer) |
5 | --------------------------- | ------ | ------ | -------------- | ------------------- |
6 | | Multiple local processes | Yes | Yes | No | Yes |
7 | | Run server locally | Yes | ? | No | Yes |
8 | | Connect to a remote server | Yes | ? | No | Yes |
9 | | Mixed local and remote | Yes | ? | No | No |
10 |
--------------------------------------------------------------------------------
/docs/bounding-box.md:
--------------------------------------------------------------------------------
1 | A bounding box is a 3D area where you want the mill to do its work or
2 | actually stay away.
3 |
4 | This is useful for:
5 |
6 | - Doing work in areas that require specific movements e.g. for more
7 | detailed finish ins small areas or higher speed of material removal
8 | for roughing in larger ones.
9 | - Staying away from areas, f.i. to avoid clamps
10 |
11 | You can set up to work inside the bounding box and outside the bounding
12 | box (plus another option editor has to look up, also not mentioned here
13 | where to find these settings in preferences).
14 |
15 | The bounding box is shown in the model by a set of lines describing the
16 | box.
17 |
--------------------------------------------------------------------------------
/share/mime/pycam.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stereo Lithographic Files (solid 3D models)
5 |
6 |
7 |
8 |
9 |
10 |
11 | Drawing Interchange Files (2D or 3D models)
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wininst]
2 | #install_script = pycam_win32_postinstall.py
3 | bitmap = share/ui/logo_gui_vertical.bmp
4 |
5 | [bdist_msi]
6 | #install_script = pycam_win32_postinstall.py
7 |
8 | [bdist_rpm]
9 | packager = Lars Kruse
10 | doc_files = Changelog
11 | README.md
12 | INSTALL.TXT
13 | LICENSE.TXT
14 | COPYING.TXT
15 | docs/
16 | examples/
17 |
18 | [flake8]
19 | max-line-length = 99
20 | # flake8 defaults: E121,E123,E126,E226,E24,E704,W503,W504
21 | # custom additions:
22 | # E731: sometimes we like lambda
23 | # E741: tolerate short names
24 | # N806: TODO: fix these non-standard naming exceptions
25 | ignore = E121,E123,E126,E226,E24,E704,W503,W504,E731,E741,N806
26 |
--------------------------------------------------------------------------------
/samples/SampleScene2.scad:
--------------------------------------------------------------------------------
1 | // example scene for pycam
2 |
3 | module scene() {
4 | sphere(r=15, center=true);
5 | translate(v=[0,80,5]) cylinder(h = 10, r1 = 20, r2 = 10, center = true);
6 | translate(v=[0,40,15]) {
7 | intersection() {
8 | translate([0,0,-15]) rotate([60,0,90]) cube([30, 20, 20], center=true);
9 | cylinder(h = 30, r = 10, center = true);
10 | }
11 | }
12 | translate([0,130,-5]) {
13 | intersection() {
14 | sphere(20, center=true);
15 | rotate([30,60,0]) cube(30, center=true);
16 | }
17 | }
18 | }
19 |
20 | // remove the parts of the objects below the zero plane
21 | difference() {
22 | scale([0.5, 0.5, 0.3]) scene();
23 | translate([0,0,-20]) cube([200,200,40], center=true);
24 | }
--------------------------------------------------------------------------------
/share/ui/model_export.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/share/ui/clipboard.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/pycam-textbox.scad:
--------------------------------------------------------------------------------
1 | // Combine the PyCAM logo with a slightly depressed rounded-cornered box.
2 |
3 | module block(a, b, height, radius) {
4 | translate([radius, radius, 0]) union() {
5 | translate([-radius, 0, 0]) cube([a, b - 2 * radius, height]);
6 | translate([0, -radius, 0]) cube([a - 2 * radius, b, height]);
7 | cylinder(r=radius, h=height);
8 | translate([a - 2 * radius, 0, 0]) cylinder(r=radius, h=height);
9 | translate([a - 2 * radius, b - 2 * radius, 0]) cylinder(r=radius, h=height);
10 | translate([0, b - 2 * radius, 0]) cylinder(r=radius, h=height);
11 | }
12 | }
13 |
14 | translate([0, 0, -10]) difference() {
15 | block(130, 50, 10, 10);
16 | translate([5, 5, 5]) block(120, 40, 6, 10);
17 | }
18 | translate([15, 17, -5.05]) linear_extrude(file="pycam-text.dxf", height=3);
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | pycam - CNC Toolpath Generation in python
2 | =========================================
3 |
4 | Copyright (C) 2008 Lode Leroy
5 | -----------------------------
6 |
7 | This program is free software; you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation; either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 | See COPYING
21 |
--------------------------------------------------------------------------------
/pyinstaller/pyinstaller_fix_module_exception.patch:
--------------------------------------------------------------------------------
1 | diff -ruN pyinstaller-1.4/iu.py pyinstaller-1.4.fixed//iu.py
2 | --- pyinstaller-1.4/iu.py 2010-02-11 01:23:39.000000000 +0100
3 | +++ pyinstaller-1.4.fixed//iu.py 2010-08-23 19:07:50.000000000 +0200
4 | # see http://www.pyinstaller.org/ticket/205
5 | # Exceptions are thrown for imported modules are not available in Windows.
6 | @@ -451,7 +451,8 @@
7 | if ctx and hasattr(sys.modules[ctx], nmparts[i]):
8 | debug("importHook done with %s %s %s (case 1)" % (name, __globals_name, fromlist))
9 | return sys.modules[nmparts[0]]
10 | - del sys.modules[fqname]
11 | + if fqname in sys.modules:
12 | + del sys.modules[fqname]
13 | raise ImportError, "No module named %s" % fqname
14 | if fromlist is None:
15 | debug("importHook done with %s %s %s (case 2)" % (name, __globals_name, fromlist))
16 |
--------------------------------------------------------------------------------
/docs/cli-examples.md:
--------------------------------------------------------------------------------
1 | Using PyCAM via the command-line
2 | ================================
3 |
4 | **WARNING: this page is outdated. Please refer to the output of
5 | “pycam --help” or [browse it online](/manpages/pycam.1.html).**
6 |
7 | The following examples show some command use-cases for the
8 | non-interactive generation of GCode with PyCAM:
9 |
10 | - load a specific settings file for the GUI:
11 |
12 |
13 |
14 | pycam --config SOME_CONFIG_FILE
15 |
16 | - open a model:
17 |
18 |
19 |
20 | pycam SOME_MODEL_FILE
21 |
22 | - generate a GCode file using all default tasks (taken from the
23 | default settings):
24 |
25 |
26 |
27 | pycam SOME_MODEL_FILE DESTINATION_GCODE_FILE
28 |
29 | - generate a GCode file using a custom settings file and picking just
30 | one specific task:
31 |
32 |
33 |
34 | pycam --config YOUR_SETTINGS_FILE --task 2 SOME_MODEL_FILE DESTINATION_GCODE_FILE
35 |
--------------------------------------------------------------------------------
/scripts/run_flake8:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | This script is just a wrapper around different versions of flake8.
4 | It can be removed as soon as "python -m flake8" works across all common distributions.
5 | """
6 |
7 | import sys
8 |
9 |
10 | def get_flake8_runner():
11 | def import_via_main_or_maincli():
12 | """ try to import "main" from flake8.main or flake8.main.cli
13 |
14 | The "flake8" module in Debian Jessie and Stretch, as well as Ubuntu Trusty/Xenial use
15 | different names.
16 | """
17 | try:
18 | # Debian Stretch
19 | from flake8.main.cli import main
20 | except ImportError:
21 | # Debian Jessie and Ubuntu Trusty
22 | from flake8.main import main
23 | return main
24 | try:
25 | return import_via_main_or_maincli()
26 | except ImportError:
27 | # probably a virtualenv on travis is hiding the system packages from us
28 | sys.path.insert(0, "/usr/lib/python3/dist-packages")
29 | return import_via_main_or_maincli()
30 |
31 |
32 | if __name__ == "__main__":
33 | runner = get_flake8_runner()
34 | runner()
35 |
--------------------------------------------------------------------------------
/pycam/errors.py:
--------------------------------------------------------------------------------
1 | class PycamBaseException(Exception):
2 | pass
3 |
4 |
5 | class AbortOperationException(PycamBaseException):
6 | pass
7 |
8 |
9 | class CommunicationError(PycamBaseException):
10 | pass
11 |
12 |
13 | class InitializationError(PycamBaseException):
14 | pass
15 |
16 |
17 | class InvalidDataError(PycamBaseException):
18 | pass
19 |
20 |
21 | class MissingAttributeError(InvalidDataError):
22 | pass
23 |
24 |
25 | class AmbiguousDataError(InvalidDataError):
26 | pass
27 |
28 |
29 | class UnexpectedAttributeError(InvalidDataError):
30 | pass
31 |
32 |
33 | class InvalidKeyError(InvalidDataError):
34 |
35 | def __init__(self, invalid_key, choice_enum):
36 | # retrieve the pretty name of the enum
37 | enum_name = str(choice_enum).split("'")[1]
38 | super().__init__("Unknown {}: {} (should be one of: {})".format(
39 | enum_name, invalid_key, ", ".join([item.value for item in choice_enum])))
40 |
41 |
42 | class LoadFileError(PycamBaseException):
43 | pass
44 |
45 |
46 | class MissingDependencyError(PycamBaseException):
47 | """ a dependency (e.g. an external python module) is missing """
48 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 | on: [push, pull_request]
3 | jobs:
4 | Run-tests:
5 | runs-on: ubuntu-20.04
6 | container: debian:bullseye
7 | steps:
8 | - name: Check out repository code
9 | uses: actions/checkout@v2
10 | with:
11 | fetch-depth: 0
12 |
13 | # Install build dependencies
14 | - run: apt-get update
15 | - run: apt-get -V --yes --no-install-recommends --no-install-suggests install dpkg-dev devscripts equivs
16 |
17 | - run: dpkg-checkbuilddeps || true
18 | - run: mk-build-deps -i -r -t 'apt-get -V --yes --no-install-recommends --no-install-suggests'
19 | - run: rm pycam-build-deps_*
20 |
21 | - run: pycam/run_gui.py --help
22 | - run: pycam/run_gui.py --version
23 | - run: pycam/run_cli.py --help
24 | - run: pycam/run_cli.py --version
25 |
26 | - run: dpkg-buildpackage -us -uc
27 |
28 | - run: apt-get -V --yes install ../pycam_*.deb
29 |
30 | - run: cd .. ; pycam --help
31 | - run: cd .. ; pycam --version
32 | - run: cd .. ; pycam-cli --help
33 | - run: cd .. ; pycam-cli --version
34 |
35 | - run: ls -al
36 | - run: ls -al ../
37 |
--------------------------------------------------------------------------------
/man/pycam.1.inc:
--------------------------------------------------------------------------------
1 | [EXAMPLES]
2 | .nf
3 | .B pycam \-\-export\-gcode=output.ngc \-\-bounds\-type=relative\-margin \-\-bounds-lower=0.1,0.05,-0.1 foo.stl
4 |
5 | .fi
6 | Use the default settings to process the model \fBfoo.stl\fR with an adjusted
7 | lower margin (minx, miny, minz) of 10% (for x), 5% (for y) and \-10% (for z).
8 |
9 | [ENVIRONMENT]
10 | .IP PYCAM_DATA_DIR
11 | Override the default data directory of PyCAM. This allows
12 | you to provide customized logos, menu files or non-default sample files.
13 | .IP PYCAM_FONT_DIR
14 | Override the default location of engrave fonts.
15 | .IP PYTHONPATH
16 | You may want to define this variable in case that you installed the
17 | \fBPyCAM\fR python package in a non-default location.
18 |
19 | [REPORTING BUGS]
20 | See http://sourceforge.net/tracker/?group_id=237831&atid=1104176
21 |
22 | [SEE ALSO]
23 | Take a look at the output of \fBpycam \-\-help\fR to get a slightly better
24 | formatted list of options. The manual that you are reading right now is
25 | derived from this output.
26 |
27 | Take a look at the wiki for more information about PyCAM:
28 | http://sourceforge.net/apps/mediawiki/pycam/
29 |
30 | The website of the PyCAM project: http://pycam.sourceforge.net
31 |
32 |
--------------------------------------------------------------------------------
/docs/screenshots.md:
--------------------------------------------------------------------------------
1 | Screenshots
2 | ===========
3 |
4 | Startup Screen
5 | --------------
6 |
7 | 
8 |
9 | Model operations
10 | ----------------
11 |
12 | 
13 |
14 | Processing settings
15 | -------------------
16 |
17 | 
18 |
19 | Roughing Operation
20 | ------------------
21 |
22 | 
23 |
24 | Semi-finishing Operation
25 | ------------------------
26 |
27 | 
28 |
29 | Finishing Operation
30 | -------------------
31 |
32 | 
33 |
34 | Toolpath management
35 | -------------------
36 |
37 | 
38 |
39 | Settings
40 | --------
41 |
42 | 
43 |
44 | Importing the GCode in LinuxCNC
45 | ---------------------------
46 |
47 | 
48 |
49 |
--------------------------------------------------------------------------------
/pycam/Utils/progress.py:
--------------------------------------------------------------------------------
1 | from pycam.Utils.events import get_event_handler, get_mainloop
2 |
3 |
4 | class ProgressContext:
5 |
6 | def __init__(self, title):
7 | self._title = title
8 | self._progress = get_event_handler().get("progress")
9 |
10 | def __enter__(self):
11 | if self._progress:
12 | self._progress.update(text=self._title, percent=0)
13 | # start an indefinite pulse (until we receive more details)
14 | self._progress.update()
15 | else:
16 | self._progress = None
17 | return self
18 |
19 | def __exit__(self, exc_type, exc_value, traceback):
20 | if self._progress:
21 | self._progress.finish()
22 |
23 | def update(self, *args, **kwargs):
24 | mainloop = get_mainloop()
25 | if mainloop is None:
26 | return False
27 | mainloop.update()
28 | if self._progress:
29 | return self._progress.update(*args, **kwargs)
30 | else:
31 | return False
32 |
33 | def set_multiple(self, count, base_text=None):
34 | if self._progress:
35 | self._progress.set_multiple(count, base_text=base_text)
36 |
37 | def update_multiple(self):
38 | if self._progress:
39 | self._progress.update_multiple()
40 |
--------------------------------------------------------------------------------
/debian/copyright:
--------------------------------------------------------------------------------
1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: PyCAM
3 | Upstream-Contact: Lars Kruse
4 | Source: https://github.com/SebKuzminsky/pycam
5 |
6 | Files: *
7 | Copyright: 2010-2011, Lars Kruse
8 | 2006-2010, Lode Leroy
9 | License: GPL-3+
10 |
11 | Files: debian/*
12 | Copyright: 2010-2011, Lars Kruse
13 | 2010, Sebastian Kuzminsky
14 | License: GPL-3+
15 |
16 | License: GPL-3+
17 | This program is free software: you can redistribute it and/or modify
18 | it under the terms of the GNU General Public License as published by
19 | the Free Software Foundation, either version 3 of the License, or
20 | (at your option) any later version.
21 | .
22 | This package is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
26 | .
27 | You should have received a copy of the GNU General Public License
28 | along with this program. If not, see .
29 | .
30 | On Debian systems, the full text of the GNU General Public License
31 | version 3 can be found in the file `/usr/share/common-licenses/GPL-3'.
32 |
--------------------------------------------------------------------------------
/pycam/Test/test_dxf_importer.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 | from pycam.Importers.DXFImporter import import_model
23 | import pycam.Test
24 |
25 |
26 | ASSETS_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")
27 |
28 | DXF_TEST_FILES = {"bezier_lines.dxf"}
29 |
30 |
31 | class TestDXFImporter(pycam.Test.PycamTestCase):
32 | """ Checks ability to open some sample .dxf files correctly """
33 |
34 | def test_load_dxf_files(self):
35 | for test_filename in DXF_TEST_FILES:
36 | full_filename = os.path.join(ASSETS_PATH, test_filename)
37 | model = import_model(full_filename)
38 | assert model
39 |
--------------------------------------------------------------------------------
/pycam/Test/test_cxf_fonts.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 | import pycam.Test
23 | import pycam.Utils.FontCache
24 |
25 |
26 | FONT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
27 | os.path.pardir, os.path.pardir, "share", "fonts")
28 |
29 |
30 | class TestCXFImporter(pycam.Test.PycamTestCase):
31 | """
32 | Checks ability to open all included .cxf font files correctly
33 | """
34 |
35 | def test_load_ascii_file(self):
36 | cache = pycam.Utils.FontCache.FontCache(FONT_PATH)
37 | # the number of fonts is lower by one, but "Standard" and "Normal" are aliases
38 | assert len(cache) == 35
39 |
--------------------------------------------------------------------------------
/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # vim: noexpandtab
3 | # See debhelper(7) (uncomment to enable)
4 | # output every command that modifies files on the build system.
5 | DH_VERBOSE = 1
6 |
7 | # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
8 | DPKG_EXPORT_BUILDFLAGS = 1
9 | include /usr/share/dpkg/default.mk
10 |
11 | # see FEATURE AREAS in dpkg-buildflags(1)
12 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all
13 |
14 | # see ENVIRONMENT in dpkg-buildflags(1)
15 | # package maintainers to append CFLAGS
16 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
17 | # package maintainers to append LDFLAGS
18 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
19 |
20 |
21 | # main packaging script based on dh7 syntax
22 | %:
23 | dh $@ --with python3
24 |
25 | # This target updates pycam/Version.py and debian/changelog with current
26 | # information from git. It's intended to be run before generating the
27 | # debian source package.
28 | prep-source:
29 | $(MAKE) update-version
30 | $(MAKE) update-deb-changelog
31 | rm -f pycam/*.pyc
32 |
33 | override_dh_auto_clean:
34 | $(MAKE) clean
35 | debian/rules prep-source
36 |
37 | override_dh_auto_build:
38 | $(MAKE) -C man
39 | python3 setup.py build
40 |
41 | override_dh_auto_install:
42 | python3 setup.py install --root=$(CURDIR)/debian/pycam --prefix=/usr
43 | # remove redundant copy of docs
44 | rm -rf $(CURDIR)/debian/pycam/usr/share/pycam/doc
45 |
--------------------------------------------------------------------------------
/pyinstaller/pyinstaller_info.txt:
--------------------------------------------------------------------------------
1 | PyInstaller (http://pyinstaller.org) can be used to create standalone binaries for Windows.
2 |
3 | How to build a standalone exe file (on Windows only):
4 | 1) install the PyCAM dependency installer:
5 | https://pycam.svn.sourceforge.net/svnroot/pycam/dependency_installer
6 | * add "C:\GtkGLext\1.0\bin" to your PATH environment variable
7 | 2) install UPX (compression)
8 | * Debian/Ubuntu: apt-get install upx-ucl
9 | * Windows: http://upx.sourceforge.net
10 | * extract the archive to your program directory
11 | * add this directory to your PATH environment variable
12 | 3) download pyinstaller (svn co http://svn.pyinstaller.org/tags/1.5 pyinstaller)
13 | 4) run "cmd.exe" (or open a terminal)
14 | 5) "cd PATH_TO_PYCAM"
15 | 6) "python PYINSTALLER_PATH/Configure.py"
16 | 7) "python PYINSTALLER_PATH/Build.py pyinstaller/pycam.spec"
17 | 8) test and upload the binary file "pycam-VERSION_standalone.?"
18 |
19 | Known issues:
20 | * multiprocessing on Windows: no server/client capabilities
21 | * python-setproctitle v1.0.1 causes a segfault - remove it from the build system
22 | * Linux: pre-built executable don't seem to work across different versions of libc
23 | * Linux/MacOS?: you need to remove the reference to "windll" at the top of the "pycam" script (line 32-36)
24 |
25 | Debugging:
26 | * enable the "debug" parameter in the "EXE" call at the end of the spec file
27 |
28 |
--------------------------------------------------------------------------------
/technical_details.txt:
--------------------------------------------------------------------------------
1 |
2 | The DropCutter goes as follows:
3 | 1) make lines along the X-axis (Lines)
4 | 2) for each line, take a number of samples (Samples)
5 | 3) at each sample, drop the cutter until it hits the model, this is a cutter location point
6 | 4) connect the cutter location points along the line
7 |
8 |
9 | The PushCutter goes as follows:
10 | 1) make slices along the Z-axis (Levels)
11 | 2) make lines along the X-axis (Lines)
12 | 3) push the cutter along the line until it hits the model, this is a cutter location
13 | if we do not hit anything, we're finished
14 | 4) skip the parts where the model is above the current z-level
15 | 5) go back to 3
16 |
17 |
18 | The PathAccumulator connects the cutter locations by cutting in between,
19 | it is useful mainly for debugging
20 |
21 | The SimpleCutter connects the cutter locations in an on-off (cut/don't cut) pattern,
22 | it is useful only for debugging
23 |
24 | The ZigZagCutter connects the cutter locations by cutting in between points,
25 | then come back along the next line in reverse direction.
26 | it is useful mainly in combination with the DropCutter
27 |
28 | The PolygonCutter extracts polygonial sections from the cutter scanlines,
29 | then cuts those in a zig-zag pattern
30 | it is useful mainly in combination with the PushCutter
31 |
32 | The ContourCutter extracts contours from the cutter scanlines,
33 | it is useful only in combination with the PushCutter
34 |
--------------------------------------------------------------------------------
/pycam/Plugins/TaskTypes.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 | import pycam.Toolpath
23 |
24 |
25 | class TaskTypeMilling(pycam.Plugins.PluginBase):
26 |
27 | DEPENDS = ["Tasks", "TaskParamCollisionModels", "TaskParamTool", "TaskParamProcess",
28 | "TaskParamBounds"]
29 | CATEGORIES = ["Task"]
30 |
31 | def setup(self):
32 | parameters = {"collision_models": [], "tool": None, "process": None, "bounds": None}
33 | self.core.get("register_parameter_set")("task", "milling", "Milling", None,
34 | parameters=parameters, weight=10)
35 | return True
36 |
37 | def teardown(self):
38 | self.core.get("unregister_parameter_set")("task", "milling")
39 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | Installing the latest release
2 | -----------------------------
3 |
4 | ### Linux / \*BSD
5 |
6 | 1. [download](http://sourceforge.net/projects/pycam/files/) the archive
7 | of your choice
8 | 2. install the [requirements](requirements.md) for your system
9 | 3. run `scripts/pycam` in the PyCAM directory
10 |
11 | ### Mac OS X
12 |
13 | See [Installation MacOS](installation-macos.md) for details.
14 |
15 | ### Windows
16 |
17 | Use the [standalone executable for Windows](https://sourceforge.net/projects/pycam/files/pycam/0.5.1/pycam-0.5.1.1_standalone.exe/download).
18 | There are no further requirements.
19 |
20 | If you want to use [multiple CPU cores or distributed processing](parallel-processing), then you will need to use the
21 | [dependency installer](https://sourceforge.net/projects/pycam/files/pycam/0.5.1/python2.5-gtk-opengl.exe/download)
22 | and the [PyCAM installer package](https://sourceforge.net/projects/pycam/files/pycam/0.5.1/pycam-0.5.1.win32.exe/download).
23 |
24 | Installing the development version
25 | ----------------------------------
26 |
27 | 1. install the [git](http://git-scm.com/) client (via your package
28 | manager or by [downloading](http://git-scm.com/downloads) it)
29 | 2. checkout the PyCAM repository:
30 | `git clone `[`git@github.com:SebKuzminsky/pycam.git`](git@github.com:SebKuzminsky/pycam.git)
31 | 3. install the [requirements](requirements.md) for your system
32 | 4. run `pycam/run_gui.py` in the PyCAM directory
33 |
--------------------------------------------------------------------------------
/debian/control:
--------------------------------------------------------------------------------
1 | Source: pycam
2 | Section: science
3 | Priority: optional
4 | Maintainer: Lars Kruse
5 | Build-Depends:
6 | debhelper-compat (= 13),
7 | codespell,
8 | dh-python,
9 | help2man,
10 | python3,
11 | python3-flake8,
12 | python3-numpy,
13 | python3-pytest,
14 | python3-setuptools,
15 | python3-svg.path,
16 | python3-yaml,
17 | Standards-Version: 3.9.8
18 | Homepage: https://github.com/SebKuzminsky/pycam
19 |
20 | Package: pycam
21 | Architecture: all
22 | Depends:
23 | librecad-data,
24 | python3-gi,
25 | gir1.2-gtk-3.0,
26 | python3-svg.path,
27 | python3-yaml,
28 | ${misc:Depends},
29 | ${python3:Depends},
30 | Recommends:
31 | inkscape,
32 | pstoedit,
33 | python3-numpy,
34 | python3-opengl,
35 | python3-setproctitle,
36 | Description: CAM program & Python library for generating toolpaths
37 | PyCAM is a toolpath generator for 3 axis machines. The generated
38 | GCode can be used with LinuxCNC and other machine controllers.
39 | The included Python library can be used independently from the GUI.
40 | .
41 | Features:
42 | * read and write STL model files (3D)
43 | * support for 2D models (DXF/SVG/PS)
44 | * generate toolpaths (GCode) for various strategies and drill
45 | definitions
46 | * manage and store processing templates
47 | * scale, move, rotate, flip and transform the model
48 | * interactive 3D model view based on OpenGL
49 | * non-interactive generation of GCode via commandline
50 | * render single-line fonts (provided by QCAD)
51 |
--------------------------------------------------------------------------------
/docs/supported-formats.md:
--------------------------------------------------------------------------------
1 | Supported formats of PyCAM
2 | ==========================
3 |
4 | PyCAM can import and export data from and to different formats.
5 |
6 | Read the following pages for hints about creating usable models:
7 |
8 | - [2D modeling with Inkscape (SVG)](modeling-inkscape-svg.md)
9 | - [2D modeling with OpenSCAD (DXF)](modeling-openscad-dxf.md)
10 |
11 | STL
12 | ---
13 |
14 | [STL files](http://en.wikipedia.org/wiki/STL_(file_format)) describe the surface
15 | of 3D models as a mesh of triangles. The STL format definition describes
16 | an ascii and a binary storage format. Both are supported by PyCAM.
17 |
18 | PyCAM can transform 3D models and save the result as an ascii STL file.
19 |
20 | DXF
21 | ---
22 |
23 | [DXF files](http://en.wikipedia.org/wiki/DXF_(file_format)) can describe 3D or
24 | 2D models. PyCAM can import both types. The following DXF primitives are
25 | supported:
26 |
27 | - LINE / POLYLINE / LWPOLYLINE
28 | - ARC / CIRCLE
29 | - TEXT / MTEXT
30 | - 3DFACE
31 |
32 | SVG
33 | ---
34 |
35 | [Scalable vector files](http://en.wikipedia.org/wiki/Scalable_Vector_Graphics) can describe 2D
36 | models. They are supposed to be used as contour models for engravings.
37 |
38 | Before PyCAM v0.7 you needed to install *Inkscape* and *pstoedit* if you want
39 | to import SVG files. Please take a look at the
40 | [requirements](requirements#Optional_external_programs) for more details.
41 |
42 | Additionally you should read the [hints for Inkscape](modeling-inkscape-svg.md) to avoid
43 | common pitfalls.
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/SebKuzminsky/pycam)
2 |
3 | # PyCAM: a toolpath generator
4 |
5 | PyCAM generates toolpaths (GCode) based on 2D or 3D models for 3-axis CNC machining.
6 |
7 |
8 | ## Running
9 |
10 | Extract the archive or clone the repository.
11 |
12 | Graphical Interface: `pycam/run_gui.py`
13 |
14 | Scripted Toolpath Processing: `pycam/run_cli.py FLOW_SPECIFICATION_FILE`
15 |
16 |
17 | ## Resources
18 |
19 | See the [documentation](http://pycam.sourceforge.net/introduction/) for a short introduction.
20 |
21 | * [Website / Documentation](http://pycam.sf.net/)
22 | * [Getting started](http://pycam.sf.net/getting-started.md)
23 | * [FAQ](http://pycam.sf.net/faq.md)
24 | * [Video tutorials](http://vimeo.com/channels/pycam)
25 | * [Screenshots](http://pycam.sourceforge.net/screenshots/)
26 | * [Mailing lists](https://sourceforge.net/p/pycam/mailman/)
27 |
28 |
29 | ## Development
30 |
31 | * [Code Repository](https://github.com/SebKuzminsky/pycam)
32 | * [Issue Tracker](https://github.com/SebKuzminsky/pycam/issues)
33 |
34 |
35 | ## Contributors
36 |
37 | * Lode Leroy: initiated the project; developed the toolpath generation,
38 | collision detection, geometry, Tk interface, ...
39 | * Lars Kruse: GTK interface and many features
40 | * Paul: GCode stepping precision
41 | * Arthur Magill: distutils packaging
42 | * Sebastian Kuzminsky: debian packaging
43 | * Nicholas Humfrey: documentation, recovery of old sourceforge-wiki
44 | * Piers Titus van der Torren: documentation
45 | * Reuben Rissler: gtk3 migration
46 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: PyCAM
2 | site_description: Toolpath generator for 3-axis CNC machining
3 | site_url: http://pycam.sourceforge.net/
4 |
5 | repo_url: https://github.com/SebKuzminsky/pycam
6 | repo_name: GitHub
7 |
8 | theme: readthedocs
9 |
10 | pages:
11 | - Home: index.md
12 | - Installation:
13 | - Installing: installation.md
14 | - Requirements: requirements.md
15 | - MacOS: installation-macos.md
16 | - Release Notes: release-notes.md
17 | - Introduction:
18 | - Introduction: introduction.md
19 | - Features: features.md
20 | - Screenshots: screenshots.md
21 | - Supported Formats: supported-formats.md
22 | - Getting Started: getting-started.md
23 | - Modeling with Inkscape SVG: modeling-inkscape-svg.md
24 | - Modeling with OpenSCAD DXF: modeling-openscad-dxf.md
25 | - FAQ: faq.md
26 | - Using the GUI:
27 | - Menu Items: menu-items.md
28 | - 3D View: 3d-view.md
29 | - Model Transformations: model-transformations.md
30 | - Engrave Fonts: engrave-fonts.md
31 | - Tool Types: tool-types.md
32 | - Process Settings: process-settings.md
33 | - Bounding Box: bounding-box.md
34 | - Task Settings: task-settings.md
35 | - Advanced Usage:
36 | - Keyboard Shortcuts: keyboard-shortcuts.md
37 | - Command-line Examples: cli-examples.md
38 | - Server Mode: server-mode.md
39 | - Parallel Processing: parallel-processing.md
40 | - Touch Off: touch-off.md
41 | - OpenGL Troubles: opengl-troubles.md
42 | - Developers Guide:
43 | - Developers Guide: developers-guide.md
44 | - Video Translations: video-translations.md
45 | - External:
46 | - Other Programs: other-programs.md
47 | - Articles mentioning PyCAM: articles.md
48 |
--------------------------------------------------------------------------------
/docs/modeling-openscad-dxf.md:
--------------------------------------------------------------------------------
1 | Overview
2 | --------
3 |
4 | [OpenSCAD](http://openscad.org) is a parametric (non-interactive) 2D/3D
5 | modeller. The following hints refer to 2D modeling.
6 |
7 | 3D to 2D projection / Sectional drawing
8 | ---------------------------------------
9 |
10 | The following example code creates a sectional drawing of a sphere at a
11 | specific z-level:
12 |
13 | projection(cut=true) translate([0, 0, -3]) sphere(r=10);
14 |
15 | See the [OpenSCAD User
16 | Manual](http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/3D_to_2D_Projection)
17 | for details.
18 |
19 | 2D modeling
20 | ------------
21 |
22 | OpenSCAD supports a variety of 2D primitives. See the [OpenSCAD User
23 | Manual](http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/2D_Primitives)
24 | for details.
25 |
26 | DXF Export
27 | ----------
28 |
29 | OpenSCAD can export 2D models to DXF.
30 |
31 | Sadly there are currently several limitations:
32 |
33 | - The latest release (2010.05) creates single lines (instead of
34 | connected line segments). This makes it hard to manipulate the DXF
35 | file with [Inkscape](http://inkscape.org) or other vector graphic
36 | editors. The latest revision (development repository) fixed this
37 | issue.
38 | - Lines defining outlines and inner holes are currently drawn in the
39 | same direction (clockwise). Thus PyCAM can't distinguish between
40 | inner and outer lines for engraving offsets. You can reverse the
41 | inner lines with a vector graphics editor (e.g. Inkscape).
42 |
43 | Both of the above issues can be easily fixed with PyCAM's [Revise
44 | directions](model-transformations#Miscellaneous) operation.
45 |
--------------------------------------------------------------------------------
/pycam/Test/test_stl_loader.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Ruslan Panasiuk
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 | import pycam.Test
23 | from pycam.Importers.STLImporter import import_model
24 |
25 | cwd = os.path.dirname(os.path.abspath(__file__))
26 |
27 | ASSETS_DIR = 'assets'
28 |
29 |
30 | def path_to_asset(asset_name):
31 | """
32 | Returns abs path for given `asset_name`
33 | :param asset_name: file name of the asset from 'Tests/assets'
34 | :returns: str - abs path to asset
35 | """
36 | return os.path.join(cwd, ASSETS_DIR, asset_name)
37 |
38 |
39 | class TestSTLLoader(pycam.Test.PycamTestCase):
40 | """
41 | Checks ability to load binary .stl files correctly
42 | """
43 |
44 | def test_load_ascii_file(self):
45 | model = import_model(path_to_asset('cube_ascii.stl'))
46 | self.assertEqual(len(model), 12)
47 |
48 | def test_load_binary_file(self):
49 | model = import_model(path_to_asset('cube_binary.stl'))
50 | self.assertEqual(len(model), 12)
51 |
--------------------------------------------------------------------------------
/docs/articles.md:
--------------------------------------------------------------------------------
1 | -
2 | -- this video shows how to turn a picture via Gimp, Inkscape and
3 | PyCAM into GCode
4 | - --
5 | how to set up a FabLab in seven days
6 | - --
7 | turn a puzzle-like shape into GCode
8 | - -- PyCAM installed by Ubuntu
9 | users (registered via popcon)
10 | -
11 | -- modeling chain description
12 | - (as
13 | [HTML](http://cr4.globalspec.com/blogentry/16801/OpenSource-CNC-From-CAD-to-FAB))
14 | -- using PyCAM or Blender for toolpath generation
15 | - (nl) -- using
16 | PyCAM with a Mantis machine
17 | - (german)
18 | -- generating a gear wheel toolpath
19 | - -- using
20 | a Walther 2520
21 | - --
22 | short review of some CAD/CAM packages
23 | - -- list of GCode generators at
24 |
25 | - -
26 | very concise howto
27 | - - very
28 | short article
29 | - -- presentation about
30 | CAM software and format converters (2009)
31 |
--------------------------------------------------------------------------------
/pycam/Exporters/LinuxCNCToolExporter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 |
23 | class LinuxCNCToolExporter:
24 |
25 | def __init__(self, tools):
26 | """ tools are expected to be dictionaries containing the following keys:
27 | - id
28 | - radius
29 | - name
30 | """
31 | self.tools = tools
32 |
33 | def get_tool_definition_string(self):
34 | result = []
35 | tools = list(self.tools)
36 | tools.sort(key=lambda item: item["id"])
37 | # result.append(self.HEADER_ROW)
38 | for tool in tools:
39 | # use an arbitrary length
40 | tool_length = tool["radius"] * 10
41 | line = "T%d P%d D%f Z-%f ;%s" % (tool["id"], tool["id"], 2 * tool["radius"],
42 | tool_length, tool["name"])
43 | result.append(line)
44 | # add the dummy line for the "last" tool
45 | result.append("T99999 P99999 Z+0.100000 ;dummy tool")
46 | return os.linesep.join(result)
47 |
--------------------------------------------------------------------------------
/pycam/Test/assets/cube_ascii.stl:
--------------------------------------------------------------------------------
1 | solid "Solid"
2 | facet normal 0 1 0
3 | outer loop
4 | vertex 0 10 10
5 | vertex 10 10 10
6 | vertex 0 10 0
7 | endloop
8 | endfacet
9 | facet normal 0 1 0
10 | outer loop
11 | vertex 0 10 0
12 | vertex 10 10 10
13 | vertex 10 10 0
14 | endloop
15 | endfacet
16 | facet normal 1 0 0
17 | outer loop
18 | vertex 10 10 10
19 | vertex 10 0 10
20 | vertex 10 10 0
21 | endloop
22 | endfacet
23 | facet normal 1 0 0
24 | outer loop
25 | vertex 10 10 0
26 | vertex 10 0 10
27 | vertex 10 0 0
28 | endloop
29 | endfacet
30 | facet normal -1 0 0
31 | outer loop
32 | vertex 0 0 10
33 | vertex 0 10 10
34 | vertex 0 0 0
35 | endloop
36 | endfacet
37 | facet normal -1 0 0
38 | outer loop
39 | vertex 0 0 0
40 | vertex 0 10 10
41 | vertex 0 10 0
42 | endloop
43 | endfacet
44 | facet normal 0 0 1
45 | outer loop
46 | vertex 10 10 10
47 | vertex 0 10 10
48 | vertex 10 0 10
49 | endloop
50 | endfacet
51 | facet normal 0 0 1
52 | outer loop
53 | vertex 10 0 10
54 | vertex 0 10 10
55 | vertex 0 0 10
56 | endloop
57 | endfacet
58 | facet normal 0 -1 0
59 | outer loop
60 | vertex 10 0 10
61 | vertex 0 0 10
62 | vertex 10 0 0
63 | endloop
64 | endfacet
65 | facet normal 0 -1 0
66 | outer loop
67 | vertex 10 0 0
68 | vertex 0 0 10
69 | vertex 0 0 0
70 | endloop
71 | endfacet
72 | facet normal 0 0 -1
73 | outer loop
74 | vertex 0 10 0
75 | vertex 10 10 0
76 | vertex 0 0 0
77 | endloop
78 | endfacet
79 | facet normal 0 0 -1
80 | outer loop
81 | vertex 0 0 0
82 | vertex 10 10 0
83 | vertex 10 0 0
84 | endloop
85 | endfacet
86 | endsolid
87 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | PyCAM is a toolpath generator for 3-axis CNC machining.
4 | It loads 3D models in STL format or 2D contour models from DXF or SVG files.
5 | The resulting [G-Code](https://en.wikipedia.org/wiki/G-code) can be used
6 | with [LinuxCNC](http://www.linuxcnc.org/) or any other machine controller.
7 |
8 | PyCAM supports a wide range of toolpath strategies for 3D models and 2D contour models.
9 | Take a look at the [Features](features.md) page for a full list features.
10 |
11 | PyCAM runs on Linux, Windows and MacOS. It is free software licensed under the
12 | [GPL v3](https://www.gnu.org/licenses/gpl-3.0).
13 |
14 | ## Download
15 |
16 | Work on PyCAM has paused for five years between 2012 (v0.5.1) and 2017 (v0.6.0).
17 | Currently the code base is being modernized in order to make PyCAM run on recent operating systems
18 | and libraries.
19 |
20 | New releases are available from the GitHub releases page:
21 |
22 |
23 | The Debian package installs and runs on Debian Jessie and Stretch. The
24 | source code may work on other platforms, like Windows and Mac, but is untested.
25 | Before installing you might want to take a look at the [System requirements](requirements.md).
26 |
27 | Older releases are still available on the
28 | [SourceForge download page](https://sourceforge.net/projects/pycam/files/pycam/).
29 |
30 | ## Resources
31 |
32 | * [Development](https://github.com/SebKuzminsky/pycam)
33 | * [Getting started](getting-started.md) / [FAQ](faq.md)
34 | * [Video tutorials](http://vimeo.com/channels/pycam) / [Screenshots](screenshots.md)
35 | * [Mailing lists](https://sourceforge.net/p/pycam/mailman/)
36 | * [Issue Tracker](https://github.com/SebKuzminsky/pycam/issues)
37 |
--------------------------------------------------------------------------------
/pycam/PathProcessors/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2008 Lode Leroy
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | class BasePathProcessor:
22 |
23 | def __init__(self):
24 | self.paths = []
25 |
26 | def new_direction(self, direction):
27 | pass
28 |
29 | def end_direction(self):
30 | pass
31 |
32 | def finish(self):
33 | pass
34 |
35 | def sort_layered(self, upper_first=True):
36 | if upper_first:
37 | def compare_height(path1, path2):
38 | return path1.points[0][2] < path2.points[0][2]
39 | else:
40 | def compare_height(path1, path2):
41 | return path1.points[0][2] > path2.points[0][2]
42 | finished = False
43 | while not finished:
44 | index = 0
45 | finished = True
46 | while index < len(self.paths) - 1:
47 | current_path = self.paths[index]
48 | next_path = self.paths[index + 1]
49 | if compare_height(current_path, next_path):
50 | del self.paths[index]
51 | self.paths.insert(index + 1, current_path)
52 | finished = False
53 | index += 1
54 |
--------------------------------------------------------------------------------
/docs/other-programs.md:
--------------------------------------------------------------------------------
1 | Alternative programs for generating G-Code
2 | ==========================================
3 |
4 | The following list contains only Free Software (GPL/BSD/...):
5 |
6 | - [dxf2gcode](http://code.google.com/p/dxf2gcode/): useful for
7 | engravings
8 | - [FreeCAD](https://sourceforge.net/apps/mediawiki/free-cad/): 3D CAD
9 | design program; G-Code generation partly integrated (2011)
10 | - [HeeksCNC](http://code.google.com/p/heekscnc/): add-on for
11 | [HeeksCAD](http://code.google.com/p/heekscad/); requires STEP files
12 | instead of STL; activity [partly
13 | abandoned](http://code.google.com/p/heekscad/) by its main
14 | author (2011)
15 | - [cam-occ](http://code.google.com/p/cam-occ/): based on solid models
16 | instead of trimeshs (no recent releases, but development seems to be
17 | active (2010))
18 | - [monocam](http://code.google.com/p/monocam/): no official releases,
19 | yet; no recent development activities (2010)
20 | - [camvox](http://sourceforge.net/projects/camvox/): no official
21 | releases, yet; no recent development activities (2010)
22 | - [gcnccam](http://sourceforge.net/projects/gcnccam/): uses DXF as
23 | input; quite active
24 | - [CNC Code Generator](http://sourceforge.net/projects/cnccodegen/):
25 | java-based, recently not very active (2010)
26 | - [GCAM](http://gcam.js.cx): DXF or GERBER input; sparse documentation
27 |
28 | External software lists
29 | =======================
30 |
31 | - [LinuxCNC Wiki](http://wiki.linuxcnc.org/cgi-bin/wiki.pl?Cam):
32 | exhaustive list of CAD/CAM/conversion software
33 | - [xtronics wiki](http://wiki.xtronics.com/index.php/CAD_CAM): broad
34 | overview of CAD/CAM software
35 | - [Simple G-Code generators](https://github.com/linuxcnc/simple-gcode-generators):
36 | a list of small scripts and simple interface for generating basic
37 | toolpaths for LinuxCNC
38 |
--------------------------------------------------------------------------------
/pycam/Toolpath/Steps.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import collections
21 |
22 | from pycam.Toolpath import MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID, MOVE_ARC, MOVE_SAFETY, \
23 | MACHINE_SETTING, COMMENT
24 |
25 |
26 | def get_step_class_by_action(action):
27 | return {
28 | MOVE_STRAIGHT: MoveStraight,
29 | MOVE_STRAIGHT_RAPID: MoveStraightRapid,
30 | MOVE_ARC: MoveArc,
31 | MOVE_SAFETY: MoveSafety,
32 | MACHINE_SETTING: MachineSetting,
33 | COMMENT: Comment,
34 | }[action]
35 |
36 |
37 | MoveClass = collections.namedtuple("Move", ("action", "position"))
38 | MachineSettingClass = collections.namedtuple("MachineSetting", ("action", "key", "value"))
39 | CommentClass = collections.namedtuple("Comment", ("action", "text"))
40 |
41 |
42 | MoveStraight = lambda position: MoveClass(MOVE_STRAIGHT, position)
43 | MoveStraightRapid = lambda position: MoveClass(MOVE_STRAIGHT_RAPID, position)
44 | MoveArc = lambda position: MoveClass(MOVE_ARC, position)
45 | MoveSafety = lambda: MoveClass(MOVE_SAFETY, None)
46 | MachineSetting = lambda key, value: MachineSettingClass(MACHINE_SETTING, key, value)
47 | Comment = lambda text: CommentClass(COMMENT, text)
48 |
--------------------------------------------------------------------------------
/docs/video-translations.md:
--------------------------------------------------------------------------------
1 | Video tutorials are useful for presenting the various features of PyCAM
2 | to new users.
3 |
4 | The existing video tutorials can be found at
5 | [vimeo](http://vimeo.com/channels/158481).
6 |
7 | Providing these videos in different languages is quite simple - you just
8 | need to translate a small subtitles file. This will usually take around
9 | 15 minutes.
10 |
11 | Available videos
12 | ----------------
13 |
14 | Video Subtitle files Languages
15 | ------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------- -----------
16 | [Toolpaths for 2D models](http://vimeo.com/18254871) (incl. simulation) [download](http://pycam.svn.sourceforge.net/viewvc/pycam/video-tutorials/20101227-2D_Toolpaths_and_Simulation/) en, de
17 | [Using multi-layered 2D models](http://vimeo.com/21502122) [download](http://pycam.svn.sourceforge.net/viewvc/pycam/video-tutorials/20110324-Multi_Layered_2D_Model/) en, de
18 |
19 | How to translate
20 | ----------------
21 |
22 | 1. download an existing subtitle file (preferably in English)
23 | 2. copy the file to `YOUR_LANGUAGE.srt` (e.g. `danish.srt`)
24 | 3. open the file with an editor that is capable of handling the UTF-8
25 | character set (almost every modern editor should suffice)
26 | 4. replace the English strings with your translations
27 | 5. store the file - BEWARE: specify the UTF-8 encoding, please!
28 | 6. send the file to the developer's mailing list:
29 |
30 |
31 | Afterwards a PyCAM developer will transcode a new video with your
32 | subtitles and upload it to PyCAM's video channel.
33 |
34 | Thanks for your contribution!
35 |
--------------------------------------------------------------------------------
/pycam/Utils/rootsolver.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2008 Lode Leroy
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | def find_root_subdivide(f, x0, x1, tolerance, scale):
22 | ymin = 0
23 | xmin = 0
24 | while x1 - x0 > tolerance:
25 | for i in range(scale):
26 | x = x1 + (i / scale) * (x1 - x0)
27 | y = f(x)
28 | abs_y = abs(y)
29 | if i == 0:
30 | ymin = abs_y
31 | xmin = x
32 | else:
33 | if abs_y < ymin:
34 | ymin = abs_y
35 | xmin = x
36 | x0 = xmin - 1 / scale
37 | x1 = xmin + 1 / scale
38 | scale /= 10
39 | return xmin
40 |
41 |
42 | def find_root_newton_raphson(f, df, x0, tolerance, maxiter):
43 | x = x0
44 | iter_count = 0
45 | while iter_count < maxiter:
46 | y = f(x)
47 | if y == 0:
48 | return x
49 | dy = df(x)
50 | if dy == 0:
51 | return None
52 | dx = y / dy
53 | x = x - dx
54 | if dx < tolerance:
55 | break
56 | iter_count += 1
57 | return x
58 |
59 |
60 | def find_root(f, df=None, x0=0, x1=1, tolerance=0.001):
61 | return find_root_subdivide(f=f, x0=x0, x1=x1, tolerance=tolerance, scale=10.0)
62 |
--------------------------------------------------------------------------------
/pycam/Test/test_svg_loader.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 | from pycam.Importers.SVGDirectImporter import import_model
23 | import pycam.Test
24 |
25 |
26 | BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
27 | SAMPLES_DIR = os.path.realpath(os.path.join(BASE_DIR, "samples"))
28 |
29 |
30 | class TestSVGLoader(pycam.Test.PycamTestCase):
31 |
32 | @staticmethod
33 | def _get_svg_filenames(path):
34 | for dirpath, dirnames, filenames in os.walk(path):
35 | yield from (os.path.join(dirpath, filename) for filename in filenames
36 | if filename.lower().endswith(".svg"))
37 |
38 | def test_load_sample_svg_files(self):
39 | test_count = 0
40 | for svg_filename in self._get_svg_filenames(SAMPLES_DIR):
41 | model = import_model(svg_filename)
42 | self.assertGreater(len(model), 0,
43 | "Too few imported polygons from {}".format(svg_filename))
44 | test_count += 1
45 | self.assertEqual(test_count, 8)
46 |
47 | def test_polygon_import(self):
48 | model = import_model(os.path.join(SAMPLES_DIR, "polygons.svg"))
49 | self.assertEqual(len(model), 3)
50 |
--------------------------------------------------------------------------------
/share/ui/menubar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/pycam/Plugins/OpenGLViewTool.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2017 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import pycam.Plugins
21 |
22 |
23 | class OpenGLViewTool(pycam.Plugins.PluginBase):
24 |
25 | DEPENDS = ["OpenGLWindow"]
26 | CATEGORIES = ["Visualization", "OpenGL", "Tool"]
27 |
28 | def setup(self):
29 | self.core.register_event("visualize-items", self.draw_tool)
30 | self.core.get("register_display_item")("show_tool", "Show Tool", 70)
31 | self.core.get("register_color")("color_tool", "Tool", 50)
32 | self.core.emit_event("visual-item-updated")
33 | return True
34 |
35 | def teardown(self):
36 | self.core.unregister_event("visualize-items", self.draw_tool)
37 | self.core.get("unregister_display_item")("show_tool")
38 | self.core.get("unregister_color")("color_tool")
39 | self.core.emit_event("visual-item-updated")
40 |
41 | def draw_tool(self):
42 | if self.core.get("show_tool"):
43 | tool = self.core.get("current_tool")
44 | if tool is not None:
45 | color = self.core.get("color_tool")
46 | GL = self._GL
47 | GL.glColor4f(color["red"], color["green"], color["blue"], color["alpha"])
48 | GL.glFinish()
49 | tool.to_opengl()
50 |
--------------------------------------------------------------------------------
/pycam/Geometry/PointKdtree.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2009 Lode Leroy
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | from pycam.Geometry import epsilon
21 | from pycam.Geometry.kdtree import Node, Kdtree
22 |
23 |
24 | class PointKdtree(Kdtree):
25 |
26 | __slots__ = ["_n", "tolerance"]
27 |
28 | def __init__(self, points=None, cutoff=5, cutoff_distance=0.5, tolerance=epsilon):
29 | if points is None:
30 | points = []
31 | self._n = None
32 | self.tolerance = tolerance
33 | nodes = []
34 | for p in points:
35 | n = Node(p, p)
36 | nodes.append(n)
37 | Kdtree.__init__(self, nodes, cutoff, cutoff_distance)
38 |
39 | def dist(self, n1, n2):
40 | dx = n1.bound[0]-n2.bound[0]
41 | dy = n1.bound[1]-n2.bound[1]
42 | dz = n1.bound[2]-n2.bound[2]
43 | return dx*dx+dy*dy+dz*dz
44 |
45 | def point(self, x, y, z):
46 | if self._n:
47 | n = self._n
48 | n.bound = (x, y, z)
49 | else:
50 | n = Node(None, (x, y, z))
51 | (nn, dist) = self.nearest_neighbor(n, self.dist)
52 | if nn and (dist < self.tolerance):
53 | self._n = n
54 | return nn.obj
55 | else:
56 | n.obj = (x, y, z)
57 | self._n = None
58 | self.insert(n)
59 | return n.obj
60 |
--------------------------------------------------------------------------------
/share/ui/gtkrc_windows:
--------------------------------------------------------------------------------
1 | gtk-theme-name = "MS-Windows"
2 |
3 | gtk-icon-sizes = "gtk-menu=13,13:gtk-small-toolbar=16,16:gtk-large-toolbar=24,24:gtk-dnd=32,32"
4 | gtk-toolbar-icon-size = small-toolbar
5 |
6 | # disable images in buttons. i've only seen ugly delphi apps use this feature.
7 | gtk-button-images = 0
8 |
9 | # enable/disable images in menus. most "stock" microsoft apps don't use these, except sparingly.
10 | # the office apps use them heavily, though.
11 | gtk-menu-images = 1
12 |
13 | # use the win32 button ordering instead of the GNOME HIG one, where applicable
14 | gtk-alternative-button-order = 1
15 |
16 | # use the win32 sort indicators direction, as in Explorer
17 | gtk-alternative-sort-arrows = 1
18 |
19 | # Windows users don't expect the PC Speaker beeping at them when they backspace in an empty textview and stuff like that
20 | gtk-error-bell = 0
21 |
22 | style "msw-default"
23 | {
24 | GtkWidget::interior-focus = 1
25 | GtkOptionMenu::indicator-size = { 9, 5 }
26 | GtkOptionMenu::indicator-spacing = { 7, 5, 2, 2 }
27 | GtkSpinButton::shadow-type = in
28 |
29 | # Owen and I disagree that these should be themable
30 | #GtkUIManager::add-tearoffs = 0
31 | #GtkComboBox::add-tearoffs = 0
32 |
33 | GtkComboBox::appears-as-list = 1
34 | GtkComboBox::focus-on-click = 0
35 |
36 | GOComboBox::add_tearoffs = 0
37 |
38 | GtkTreeView::allow-rules = 0
39 | GtkTreeView::expander-size = 12
40 |
41 | GtkExpander::expander-size = 12
42 |
43 | GtkScrolledWindow::scrollbar_spacing = 1
44 |
45 | GtkSeparatorMenuItem::horizontal-padding = 2
46 |
47 | engine "wimp"
48 | {
49 | }
50 | }
51 | class "*" style "msw-default"
52 |
53 | binding "ms-windows-tree-view"
54 | {
55 | bind "Right" { "expand-collapse-cursor-row" (1,1,0) }
56 | bind "Left" { "expand-collapse-cursor-row" (1,0,0) }
57 | }
58 |
59 | class "GtkTreeView" binding "ms-windows-tree-view"
60 |
61 | style "msw-combobox-thickness" = "msw-default"
62 | {
63 | xthickness = 0
64 | ythickness = 0
65 | }
66 |
67 | widget_class "*TreeView*ComboBox*" style "msw-combobox-thickness"
68 | widget_class "*ComboBox*GtkFrame*" style "msw-combobox-thickness"
69 |
--------------------------------------------------------------------------------
/pycam/Geometry/Path.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 | Copyright 2008 Lode Leroy
4 |
5 | This file is part of PyCAM.
6 |
7 | PyCAM is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | PyCAM is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with PyCAM. If not, see .
19 | """
20 |
21 | from collections import namedtuple
22 |
23 | from pycam.Geometry import IDGenerator
24 |
25 | """
26 | The points of a path are only used for describing coordinates. Thus we don't really need complete
27 | "Point" instances that consume a lot of memory.
28 | Since python 2.6 the "namedtuple" factory is available.
29 | This reduces the memory consumption of a toolpath down to 1/3.
30 | """
31 | tuple_point = namedtuple("TuplePoint", "x y z")
32 |
33 |
34 | def get_point_object(point):
35 | return tuple_point(point[0], point[1], point[2])
36 |
37 |
38 | class Path(IDGenerator):
39 |
40 | def __init__(self):
41 | super().__init__()
42 | self.top_join = None
43 | self.bot_join = None
44 | self.winding = 0
45 | self.points = []
46 |
47 | def __repr__(self):
48 | text = ""
49 | text += "path %d: " % self.id
50 | first = True
51 | for point in self.points:
52 | if first:
53 | first = False
54 | else:
55 | text += "-"
56 | text += "%d(%g,%g,%g)" % (id(point), point[0], point[1], point[2])
57 | return text
58 |
59 | def insert(self, index, point):
60 | self.points.insert(index, get_point_object(point))
61 |
62 | def append(self, point):
63 | self.points.append(get_point_object(point))
64 |
65 | def reverse(self):
66 | self.points.reverse()
67 |
--------------------------------------------------------------------------------
/docs/keyboard-shortcuts.md:
--------------------------------------------------------------------------------
1 | Global
2 | ------
3 |
4 | Shortcut | Description
5 | ----------------- | ------------------------------------------------------------------------
6 | F1 | open the introduction page of PyCAM with a browser
7 | [CTRL] o | load model file
8 | [CTRL] s | save model file
9 | [CTRL] [Shift] s | save model file with a different name
10 | [CTRL] [Shift] e | export all toolpaths to a gcode file
11 | [CTRL] t | load task settings file
12 | [CTRL] p | open preferences dialog
13 | [CTRL] [Shift] v | toggle the 3D view window
14 | [CTRL] l | toggle the log window
15 | [CTRL] q | quit the program
16 | [CTRL] t | open the font dialog window
17 | [CTRL] z | undo the latest model operation (scale, shift, rotate) up to ten times
18 |
19 | Visualization window
20 | --------------------
21 |
22 | Shortcut | Description
23 | ----------------------------------------------- | ------------------------------------------------------------
24 | Left, Down, Up, Right | move the viewport
25 | h, j, k, l | same as *Left*, *Down*, *Up*, *Right* (vi-style behaviour)
26 | [Shift] Left, Down, Up, Right (or h, j, k, l) | rotate the view
27 | + / - | zoom in and out of the view
28 | i | toggle OpenGL ligthing
29 | m | toggle polygon and line mode
30 | s | toggle OpenGL shadows
31 | p | switch between perspective and orthogonal view
32 | 1 | reset view direction
33 | 2 | view from front
34 | 3 | view from back
35 | 4 | view from left
36 | 5 | view from right
37 | 6 | view from top
38 | 7 | view from bottom
39 |
40 |
--------------------------------------------------------------------------------
/scripts/profile_pycam.py:
--------------------------------------------------------------------------------
1 | import cProfile
2 | from os.path import join
3 | import pstats
4 | import sys
5 | from time import time
6 |
7 | from pycam.Cutters.CylindricalCutter import CylindricalCutter
8 | from pycam.Geometry import Box3D, Point3D
9 | from pycam.Gui.Console import ConsoleProgressBar
10 | from pycam.Importers.STLImporter import import_model
11 | from pycam.PathGenerators.DropCutter import DropCutter
12 | from pycam.PathProcessors.PathAccumulator import PathAccumulator
13 | from pycam.Toolpath import Bounds
14 | from pycam.Toolpath.MotionGrid import get_fixed_grid
15 | from pycam.Utils.locations import get_data_file_location
16 |
17 | # Disable multi processing
18 | from pycam.Utils import threading
19 | threading.__multiprocessing = False
20 |
21 | """ Profile PyCAM doing several operations, print out the top 10
22 | (sorted by actual local runtime) methods.
23 | """
24 |
25 | model = import_model(get_data_file_location(join('samples', 'pycam-textbox.stl')))
26 |
27 |
28 | def run_dropcutter():
29 | """ Run DropCutter on standard PyCAM sample plaque """
30 | progress_bar = ConsoleProgressBar(sys.stdout)
31 |
32 | overlap = .6
33 | layer_distance = 1
34 | tool = CylindricalCutter(10)
35 | path_generator = DropCutter(PathAccumulator())
36 | bounds = Bounds(Bounds.TYPE_CUSTOM, Box3D(Point3D(model.minx-5, model.miny-5, model.minz),
37 | Point3D(model.maxx+5, model.maxy+5, model.maxz)))
38 |
39 | low, high = bounds.get_absolute_limits()
40 | line_distance = 2 * tool.radius * (1.0 - overlap)
41 |
42 | motion_grid = get_fixed_grid((low, high), layer_distance,
43 | line_distance, tool.radius / 4.0)
44 | path_generator.GenerateToolPath(tool, [model], motion_grid, minz=low[2], maxz=high[2],
45 | draw_callback=progress_bar.update)
46 |
47 |
48 | if __name__ == '__main__':
49 | print(model.minx, model.miny, model.maxx, model.maxy)
50 | start_time = time()
51 | cProfile.run('run_dropcutter()', 'dropcutter.pyprof')
52 | run_time = time() - start_time
53 | print('\nDropcutter took %f seconds' % run_time)
54 | p = pstats.Stats('dropcutter.pyprof')
55 | print('Top ten time-consuming functions:')
56 | p.sort_stats('time').print_stats(10)
57 |
--------------------------------------------------------------------------------
/pycam/Importers/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2008 Lode Leroy
3 | Copyright 2010 Lars Kruse
4 |
5 | This file is part of PyCAM.
6 |
7 | PyCAM is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | PyCAM is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with PyCAM. If not, see .
19 | """
20 |
21 | import collections
22 |
23 | from pycam.Utils import URIHandler
24 | import pycam.Utils.log
25 |
26 |
27 | _log = pycam.Utils.log.get_logger()
28 |
29 |
30 | DetectedFileType = collections.namedtuple("DetectedFileType", ("extension", "importer", "uri"))
31 |
32 |
33 | def detect_file_type(filename, quiet=False):
34 | # also accept URI input
35 | uri = URIHandler(filename)
36 | filename = uri.get_path()
37 | # check all listed importers
38 | # TODO: this should be done by evaluating the header of the file
39 | if filename.lower().endswith(".stl"):
40 | import pycam.Importers.STLImporter
41 | return DetectedFileType("stl", pycam.Importers.STLImporter.import_model, uri)
42 | elif filename.lower().endswith(".dxf"):
43 | import pycam.Importers.DXFImporter
44 | return DetectedFileType("dxf", pycam.Importers.DXFImporter.import_model, uri)
45 | elif filename.lower().endswith(".svg"):
46 | import pycam.Importers.SVGDirectImporter
47 | return DetectedFileType("svg", pycam.Importers.SVGDirectImporter.import_model, uri)
48 | elif filename.lower().endswith(".eps") \
49 | or filename.lower().endswith(".ps"):
50 | import pycam.Importers.PSImporter
51 | return DetectedFileType("ps", pycam.Importers.PSImporter.import_model, uri)
52 | else:
53 | if not quiet:
54 | _log.error("Importers: Failed to detect the model type of '%s'. Is the file extension "
55 | "(stl/dxf/svg/eps/ps) correct?", filename)
56 | return None
57 |
--------------------------------------------------------------------------------
/pycam/Exporters/STLExporter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import datetime
21 | import os
22 |
23 | from pycam import VERSION
24 | from pycam.Geometry.PointUtils import pnormalized
25 |
26 |
27 | class STLExporter:
28 |
29 | def __init__(self, model, name="model", created_by="pycam", linesep=None, **kwargs):
30 | self.model = model
31 | self.name = name
32 | self.created_by = created_by
33 | if linesep is None:
34 | self.linesep = os.linesep
35 | else:
36 | self.linesep = linesep
37 |
38 | def __str__(self):
39 | return self.linesep.join(self.get_output_lines)
40 |
41 | def write(self, stream):
42 | for line in self.get_output_lines():
43 | stream.write(line)
44 | stream.write(self.linesep)
45 |
46 | def get_output_lines(self):
47 | date = datetime.date.today().isoformat()
48 | yield ("""solid "%s"; Produced by %s (v%s), %s"""
49 | % (self.name, self.created_by, VERSION, date))
50 | for triangle in self.model.triangles():
51 | norm = pnormalized(triangle.normal)
52 | yield "facet normal %f %f %f" % (norm[0], norm[1], norm[2])
53 | yield " outer loop"
54 | # Triangle vertices are stored in clockwise order - thus we need
55 | # to reverse the order (STL expects counter-clockwise orientation).
56 | for point in (triangle.p1, triangle.p3, triangle.p2):
57 | yield " vertex %f %f %f" % (point[0], point[1], point[2])
58 | yield " endloop"
59 | yield "endfacet"
60 | yield "endsolid"
61 |
--------------------------------------------------------------------------------
/samples/polygon2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/pycam/Plugins/PathPatterns.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 | import pycam.Toolpath.MotionGrid
23 |
24 |
25 | class PathPatternSpiral(pycam.Plugins.PluginBase):
26 |
27 | DEPENDS = ["ParameterGroupManager", "PathParamPattern", "PathParamMillingStyle",
28 | "PathParamSpiralDirection", "PathParamRoundedSpiralCorners"]
29 | CATEGORIES = ["Process", "Path pattern"]
30 |
31 | def setup(self):
32 | parameters = {"milling_style": pycam.Toolpath.MotionGrid.MillingStyle.IGNORE,
33 | "spiral_direction": None,
34 | "rounded_corners": False}
35 | self.core.get("register_parameter_set")("path_pattern", "spiral", "Spiral", None,
36 | parameters=parameters, weight=30)
37 | return True
38 |
39 | def teardown(self):
40 | self.core.get("unregister_parameter_set")("path_pattern", "spiral")
41 |
42 |
43 | class PathPatternGrid(pycam.Plugins.PluginBase):
44 |
45 | DEPENDS = ["ParameterGroupManager", "PathParamPattern", "PathParamMillingStyle",
46 | "PathParamGridDirection"]
47 | CATEGORIES = ["Process", "Path pattern"]
48 |
49 | def setup(self):
50 | parameters = {"milling_style": pycam.Toolpath.MotionGrid.MillingStyle.IGNORE,
51 | "grid_direction": pycam.Toolpath.MotionGrid.GridDirection.X}
52 | self.core.get("register_parameter_set")("path_pattern", "grid", "Grid",
53 | None, parameters=parameters, weight=10)
54 | return True
55 |
56 | def teardown(self):
57 | self.core.get("unregister_parameter_set")("path_pattern", "grid")
58 |
--------------------------------------------------------------------------------
/pycam/Test/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2013 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import unittest
22 |
23 |
24 | class PycamTestCase(unittest.TestCase):
25 |
26 | def _compare_vectors(self, v1, v2, max_deviance=0.000001):
27 | """ compare two vectors and return 'None' in case of success or an error message """
28 | # provide readable error messages
29 | result_difference = "%s != %s" % (v1, v2)
30 | result_equal = None
31 | if v1 == v2:
32 | return result_equal
33 | if v1 is None or v2 is None:
34 | return False
35 | for index in range(3):
36 | if max_deviance < abs(v1[index] - v2[index]):
37 | return result_difference
38 | return result_equal
39 |
40 | def assert_vector_equal(self, v1, v2, msg=None):
41 | self.assertIsNone(self._compare_vectors(v1, v2), msg=msg)
42 |
43 | def assert_vector_not_equal(self, v1, v2, msg=None):
44 | self.assertIsNotNone(self._compare_vectors(v1, v2), msg=msg)
45 |
46 | def assert_collision_equal(self, collision1, collision2, msg=None):
47 | ccp1, cp1, d1 = collision1
48 | ccp2, cp2, d2 = collision2
49 | self.assert_vector_equal(ccp1, ccp2, msg=("Collisions differ ({} != {}) due to ccp"
50 | .format(collision1, collision2)))
51 | self.assert_vector_equal(cp1, cp2, msg=("Collisions differ ({} != {}) due to cp"
52 | .format(collision1, collision2)))
53 | self.assertAlmostEqual(d1, d2, msg=("Collisions differ ({} != {}) due to distance"
54 | .format(collision1, collision2)))
55 |
56 |
57 | main = unittest.main
58 |
--------------------------------------------------------------------------------
/samples/polygon3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
--------------------------------------------------------------------------------
/samples/polygon5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
61 |
--------------------------------------------------------------------------------
/docs/model-transformations.md:
--------------------------------------------------------------------------------
1 | Model transformations
2 | =====================
3 |
4 | PyCAM can help you to prepare the model for the final processing.
5 |
6 | 
7 |
8 | Rotate, Mirror, Swap
9 | --------------------
10 |
11 | Operation | Description
12 | -------- | -----------
13 | **rotate** | rotate the model clockwise around a given axis
14 | **flip** | mirror the model against a given plane (xy, xz or yz)
15 | **swap** | exchange two axis of the coordinate system (e.g. exchange all x values with the corresponding y values)
16 |
17 | Scale
18 | -----
19 |
20 | Operation | Description
21 | -------- | -----------
22 | **scale** | resize the complete model proportionally with a given factor via an input control (as a percent value). An input of 200% doubles the size of the model. The location center of the model will be preserved.
23 | **fit dimension** | scale one axis to a given value (e.g. if the unit size of your modeling software is not metric). By default all axes are scaled proportionally. This can be changed via the corresponding checkbox.
24 |
25 | Move
26 | ----
27 |
28 | Operation | Description
29 | -------- | -----------
30 | **move to origin** | afterwards the model should start at the center of the coordinate system pointing along the posive values of the three axes.
31 | **shift** | move the model along the three axes by the distances given in the three separate input controls. Negative or zero values are allowed.
32 |
33 | Miscellaneous
34 | -------------
35 |
36 | Buttons referring to 2D operations are not visible if a 3D model is
37 | currently loaded (and vice versa).
38 |
39 | Operation | Description
40 | -------- | -----------
41 | **Toggle direction** | reverse the direction of all lines of a 2D model
42 | **Revise direction** | First try to merge open polygons regardless of their directions. Secondly analyse the inside/outside relationships of all closed polygons in a 2D model. The direction of polygons with an unsuitable winding state is reversed. This usually fixes inconsistent winding combinations created by DXF/SVG export programs.
43 | **Extrude** | add a third dimension to a 2D model. The following parameters of the slope of the edges are configurable: shape, precision, height and width. ([Read more](http://fab.senselab.org/node/227))
44 | **2D Projection** | cut a 3D model at z=0. The resulting contour polygons define the new 2D model. The contour of the bottom of the model is used if the model is completely above or below z=0.
45 | **Inch → mm** | scale the model by the factor 25.4
46 | **mm → Inch** | scale the model size down with the divider 25.4
47 |
--------------------------------------------------------------------------------
/samples/Box2.stl:
--------------------------------------------------------------------------------
1 | solid "model"; Produced by pycam (v0.3), 2010-10-03
2 | facet normal 0.707143 -0.408041 0.577452
3 | outer loop
4 | vertex 5.339321 -3.997340 0.000022
5 | vertex 2.562797 -2.393577 4.533387
6 | vertex 2.563112 -5.599983 2.267282
7 | endloop
8 | endfacet
9 | facet normal 0.707143 -0.408041 0.577452
10 | outer loop
11 | vertex 5.339006 -0.790934 2.266127
12 | vertex 2.562797 -2.393577 4.533387
13 | vertex 5.339321 -3.997340 0.000022
14 | endloop
15 | endfacet
16 | facet normal -0.707143 0.408041 -0.577452
17 | outer loop
18 | vertex -0.213699 -0.791464 2.266105
19 | vertex 2.562824 -2.395226 -2.267260
20 | vertex -0.213384 -3.997869 0.000000
21 | endloop
22 | endfacet
23 | facet normal -0.707143 0.408041 -0.577452
24 | outer loop
25 | vertex 2.562510 0.811179 -0.001155
26 | vertex 2.562824 -2.395226 -2.267260
27 | vertex -0.213699 -0.791464 2.266105
28 | endloop
29 | endfacet
30 | facet normal 0.707070 0.408176 -0.577446
31 | outer loop
32 | vertex 2.562824 -2.395226 -2.267260
33 | vertex 2.562510 0.811179 -0.001155
34 | vertex 5.339006 -0.790934 2.266127
35 | endloop
36 | endfacet
37 | facet normal 0.707070 0.408176 -0.577446
38 | outer loop
39 | vertex 5.339321 -3.997340 0.000022
40 | vertex 2.562824 -2.395226 -2.267260
41 | vertex 5.339006 -0.790934 2.266127
42 | endloop
43 | endfacet
44 | facet normal -0.707070 -0.408176 0.577446
45 | outer loop
46 | vertex 2.562797 -2.393577 4.533387
47 | vertex -0.213699 -0.791464 2.266105
48 | vertex -0.213384 -3.997869 0.000000
49 | endloop
50 | endfacet
51 | facet normal -0.707070 -0.408176 0.577446
52 | outer loop
53 | vertex 2.563112 -5.599983 2.267282
54 | vertex 2.562797 -2.393577 4.533387
55 | vertex -0.213384 -3.997869 0.000000
56 | endloop
57 | endfacet
58 | facet normal -0.000080 0.816637 0.577152
59 | outer loop
60 | vertex 5.339006 -0.790934 2.266127
61 | vertex 2.562510 0.811179 -0.001155
62 | vertex -0.213699 -0.791464 2.266105
63 | endloop
64 | endfacet
65 | facet normal -0.000080 0.816637 0.577152
66 | outer loop
67 | vertex 2.562797 -2.393577 4.533387
68 | vertex 5.339006 -0.790934 2.266127
69 | vertex -0.213699 -0.791464 2.266105
70 | endloop
71 | endfacet
72 | facet normal 0.000080 -0.816637 -0.577152
73 | outer loop
74 | vertex 5.339321 -3.997340 0.000022
75 | vertex 2.563112 -5.599983 2.267282
76 | vertex -0.213384 -3.997869 0.000000
77 | endloop
78 | endfacet
79 | facet normal 0.000080 -0.816637 -0.577152
80 | outer loop
81 | vertex 2.562824 -2.395226 -2.267260
82 | vertex 5.339321 -3.997340 0.000022
83 | vertex -0.213384 -3.997869 0.000000
84 | endloop
85 | endfacet
86 | endsolid
87 |
--------------------------------------------------------------------------------
/share/ui/opengl_view_grid.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
71 |
72 |
--------------------------------------------------------------------------------
/docs/requirements.md:
--------------------------------------------------------------------------------
1 | System requirements for PyCAM
2 | =============================
3 |
4 | PyCAM currently runs on Unix/Linux.
5 |
6 | Older releases of PyCAM were also running on Windows and MacOS ([via
7 | MacPorts](http://sourceforge.net/projects/pycam/forums/forum/860183/topic/3800091)).
8 |
9 | Please document your experiences here, if you successfully used PyCAM
10 | with other operating systems.
11 |
12 | Linux
13 | -----
14 |
15 | Install the following packages with your package manager (see below):
16 |
17 | - **python3**
18 | - **python3-gi**
19 | - **python3-opengl**
20 | - **gir1.2-gtk-3.0** (GTK: at least v3.16)
21 |
22 | If your distribution does not ship GTK v3.16 or newer (e.g. Debian Jessie contains only v3.14),
23 | then you need to use an older release of PyCAM. The older releases (e.g. v0.6.x) depend on Python2
24 | and GTK2 - thus they should work well even with rather old distributions.
25 |
26 | ### Debian / Ubuntu
27 |
28 | Run the following command in a *root* terminal:
29 |
30 | apt-get install python3-gi python3-opengl gir1.2-gtk-3.0
31 |
32 | ### OpenSuSE
33 |
34 | Run the following command in a *root* terminal:
35 |
36 | zypper install python3-gi python3-opengl
37 |
38 | ### Fedora
39 |
40 | Run the following command in a *root* terminal:
41 |
42 | yum install python3-gi python3-opengl
43 |
44 | Windows
45 | -------
46 |
47 | The latest releases do not run under Windows.
48 |
49 | You may want to use the standalone executable of [v0.5.1 (the latest release supporting
50 | Windows)](https://sourceforge.net/projects/pycam/files/pycam/0.5.1/). This old version is not
51 | maintained anymore - but maybe you are lucky and it just works for you.
52 |
53 |
54 | MacOS
55 | -----
56 |
57 | Please take a look at [Installation MacOS](installation-macos.md)
58 | for the details of installing PyCAM's requirements via
59 | [MacPorts](http://www.macports.org/).
60 |
61 |
62 | Optional external programs
63 | ==========================
64 |
65 | Some features of PyCAM require additional external programs.
66 |
67 |
68 | SVG/PS/EPS import
69 | -----------------
70 |
71 | PyCAM supports only STL and DXF files natively. Native SVG support is available
72 | since PyCAM v0.7. For previous versions you need to install external programs
73 | for the conversions of other file formats.
74 |
75 | ### Debian / Ubuntu
76 |
77 | apt-get install inkscape pstoedit
78 |
79 | ### OpenSuSE
80 |
81 | zypper install inkscape pstoedit
82 |
83 | ### Fedora
84 |
85 | yum install inkscape pstoedit
86 |
87 | ### Windows
88 |
89 | Download and install the following programs:
90 |
91 | * inkscape:
92 | * pstoedit:
93 | * ghostscript:
94 |
95 | *Hint: there is no need to install GraphicMagick - even though pstoedit
96 | suggests it.*
97 |
--------------------------------------------------------------------------------
/pycam/Plugins/ModelPlaneMirror.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 |
23 |
24 | class ModelPlaneMirror(pycam.Plugins.PluginBase):
25 |
26 | UI_FILE = "model_plane_mirror.ui"
27 | DEPENDS = ["Models"]
28 | CATEGORIES = ["Model"]
29 |
30 | def setup(self):
31 | if self.gui:
32 | mirror_box = self.gui.get_object("ModelMirrorBox")
33 | mirror_box.unparent()
34 | self.core.register_ui("model_handling", "Mirror", mirror_box, 0)
35 | self._gtk_handlers = ((self.gui.get_object("PlaneMirrorButton"), "clicked",
36 | self._plane_mirror), )
37 | self._event_handlers = (("model-selection-changed", self._update_plane_widgets), )
38 | self.register_gtk_handlers(self._gtk_handlers)
39 | self.register_event_handlers(self._event_handlers)
40 | self._update_plane_widgets()
41 | return True
42 |
43 | def teardown(self):
44 | if self.gui:
45 | self.unregister_event_handlers(self._event_handlers)
46 | self.unregister_gtk_handlers(self._gtk_handlers)
47 |
48 | def _update_plane_widgets(self):
49 | plane_widget = self.gui.get_object("ModelMirrorBox")
50 | if self.core.get("models").get_selected():
51 | plane_widget.show()
52 | else:
53 | plane_widget.hide()
54 |
55 | def _plane_mirror(self, widget=None):
56 | models = self.core.get("models").get_selected()
57 | if not models:
58 | return
59 | for plane, matrix in (("XY", [[1, 0, 0], [0, 1, 0], [0, 0, -1]]),
60 | ("XZ", [[1, 0, 0], [0, -1, 0], [0, 0, 1]]),
61 | ("YZ", [[-1, 0, 0], [0, 1, 0], [0, 0, 1]])):
62 | if self.gui.get_object("MirrorPlane%s" % plane).get_active():
63 | break
64 | else:
65 | assert False, "No mirror plane selected"
66 | for model in models:
67 | model.extend_value("transformations",
68 | [{"action": "multiply_matrix", "matrix": matrix}])
69 |
--------------------------------------------------------------------------------
/pycam/Plugins/ModelSwapAxes.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 |
23 |
24 | class ModelSwapAxes(pycam.Plugins.PluginBase):
25 |
26 | UI_FILE = "model_swap_axes.ui"
27 | DEPENDS = ["Models"]
28 | CATEGORIES = ["Model"]
29 |
30 | def setup(self):
31 | if self.gui:
32 | swap_box = self.gui.get_object("ModelSwapBox")
33 | swap_box.unparent()
34 | self.core.register_ui("model_handling", "Swap axes", swap_box, 0)
35 | self._gtk_handlers = ((self.gui.get_object("SwapAxesButton"), "clicked",
36 | self._swap_axes), )
37 | self._event_handlers = (("model-selection-changed", self._update_controls), )
38 | self.register_gtk_handlers(self._gtk_handlers)
39 | self.register_event_handlers(self._event_handlers)
40 | self._update_controls()
41 | return True
42 |
43 | def teardown(self):
44 | if self.gui:
45 | self.unregister_event_handlers(self._event_handlers)
46 | self.unregister_gtk_handlers(self._gtk_handlers)
47 | self.core.unregister_ui("model_handling", self.gui.get_object("ModelSwapBox"))
48 |
49 | def _update_controls(self):
50 | box = self.gui.get_object("ModelSwapBox")
51 | if self.core.get("models").get_selected():
52 | box.show()
53 | else:
54 | box.hide()
55 |
56 | def _swap_axes(self, widget=None):
57 | models = self.core.get("models").get_selected()
58 | if not models:
59 | return
60 | for axes, matrix in (("XY", [[0, 1, 0], [1, 0, 0], [0, 0, 1]]),
61 | ("XZ", [[0, 0, 1], [0, 1, 0], [1, 0, 0]]),
62 | ("YZ", [[1, 0, 0], [0, 0, 1], [0, 1, 0]])):
63 | if self.gui.get_object("SwapAxes%s" % axes).get_active():
64 | break
65 | else:
66 | assert False, "No axis selected"
67 | for model in models:
68 | model.extend_value("transformations",
69 | [{"action": "multiply_matrix", "matrix": matrix}])
70 |
--------------------------------------------------------------------------------
/pycam/PathProcessors/PolygonCutter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 | Copyright 2008 Lode Leroy
4 |
5 | This file is part of PyCAM.
6 |
7 | PyCAM is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | PyCAM is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with PyCAM. If not, see .
19 | """
20 |
21 | from pycam.Geometry.Path import Path
22 | from pycam.Geometry.PolygonExtractor import PolygonExtractor
23 | import pycam.PathProcessors
24 | from pycam.Toolpath import simplify_toolpath
25 |
26 |
27 | class PolygonCutter(pycam.PathProcessors.BasePathProcessor):
28 | def __init__(self, reverse=False):
29 | super().__init__()
30 | self.curr_path = None
31 | self.scanline = None
32 | self.polygon_extractor = PolygonExtractor(PolygonExtractor.MONOTONE)
33 | self.reverse = reverse
34 |
35 | def append(self, point):
36 | self.polygon_extractor.append(point)
37 |
38 | def new_direction(self, direction):
39 | self.polygon_extractor.new_direction(direction)
40 |
41 | def end_direction(self):
42 | self.polygon_extractor.end_direction()
43 |
44 | def new_scanline(self):
45 | self.polygon_extractor.new_scanline()
46 |
47 | def end_scanline(self):
48 | self.polygon_extractor.end_scanline()
49 |
50 | def finish(self):
51 | self.polygon_extractor.finish()
52 | paths = []
53 | source_paths = []
54 | if self.polygon_extractor.hor_path_list:
55 | source_paths.extend(self.polygon_extractor.hor_path_list)
56 | if self.polygon_extractor.ver_path_list:
57 | source_paths.extend(self.polygon_extractor.ver_path_list)
58 | for path in source_paths:
59 | points = path.points
60 | for i in range((len(points) + 1) // 2):
61 | new_path = Path()
62 | if i % 2 == 0:
63 | new_path.append(points[i])
64 | new_path.append(points[-i-1])
65 | else:
66 | new_path.append(points[-i-1])
67 | new_path.append(points[i])
68 | paths.append(new_path)
69 | if paths:
70 | for path in paths:
71 | simplify_toolpath(path)
72 | if self.reverse:
73 | path.reverse()
74 | self.paths.extend(paths)
75 | self.sort_layered()
76 |
--------------------------------------------------------------------------------
/pycam/PathGenerators/EngraveCutter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 | Copyright 2008-2009 Lode Leroy
4 |
5 | This file is part of PyCAM.
6 |
7 | PyCAM is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | PyCAM is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with PyCAM. If not, see .
19 | """
20 |
21 | import pycam.Utils.log
22 |
23 | log = pycam.Utils.log.get_logger()
24 |
25 |
26 | class EngraveCutter:
27 |
28 | def generate_toolpath(self, cutter, models, motion_grid, minz=None, maxz=None,
29 | draw_callback=None):
30 | quit_requested = False
31 |
32 | model = pycam.Geometry.Model.get_combined_model(models)
33 |
34 | if draw_callback:
35 | draw_callback(text="Engrave: optimizing polygon order")
36 |
37 | # resolve the generator
38 | motion_grid = list(motion_grid)
39 | num_of_layers = len(motion_grid)
40 |
41 | push_layers = motion_grid[:-1]
42 | push_generator = pycam.PathGenerators.PushCutter.PushCutter()
43 | current_layer = 0
44 | push_moves = []
45 | for push_layer in push_layers:
46 | # update the progress bar and check, if we should cancel the process
47 | if draw_callback and draw_callback(
48 | text="Engrave: processing layer %d/%d" % (current_layer + 1, num_of_layers)):
49 | # cancel immediately
50 | quit_requested = True
51 | break
52 | # no callback: otherwise the status text gets lost
53 | push_moves.extend(push_generator.generate_toolpath(cutter, [model], [push_layer]))
54 | if draw_callback and draw_callback():
55 | # cancel requested
56 | quit_requested = True
57 | break
58 | current_layer += 1
59 |
60 | if quit_requested:
61 | return push_moves
62 |
63 | drop_generator = pycam.PathGenerators.DropCutter.DropCutter()
64 | drop_layers = motion_grid[-1:]
65 | if draw_callback:
66 | draw_callback(
67 | text="Engrave: processing layer %d/%d" % (current_layer + 1, num_of_layers))
68 | drop_moves = drop_generator.generate_toolpath(cutter, [model], drop_layers, minz=minz,
69 | maxz=maxz, draw_callback=draw_callback)
70 | return push_moves + drop_moves
71 |
--------------------------------------------------------------------------------
/pycam/Plugins/Units.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import pycam.Plugins
21 |
22 |
23 | class Units(pycam.Plugins.PluginBase):
24 |
25 | UI_FILE = "units.ui"
26 | CATEGORIES = ["System"]
27 |
28 | def setup(self):
29 | self._last_unit = "mm"
30 | if self.gui:
31 | self._gtk_handlers = []
32 | unit_pref_box = self.gui.get_object("UnitPrefBox")
33 | unit_pref_box.unparent()
34 | self.core.register_ui("preferences_general", "Units", unit_pref_box, 20)
35 | # unit control (mm/inch)
36 | unit_field = self.gui.get_object("unit_control")
37 | self._gtk_handlers.append((unit_field, "changed", self.change_unit_init))
38 |
39 | def set_unit(text):
40 | unit_field.set_active(0 if text == "mm" else 1)
41 | self._last_unit = text
42 |
43 | def get_unit_text():
44 | model = unit_field.get_model()
45 | if model:
46 | return model[unit_field.get_active()][0]
47 | else:
48 | return self._last_unit
49 |
50 | self.core.add_item("unit", get_unit_text, set_unit)
51 | # other plugins should use "unit_string" for human readable output
52 | self.core.add_item("unit_string", get_unit_text)
53 | self.register_gtk_handlers(self._gtk_handlers)
54 | self.register_state_item("settings/unit", lambda: self.core.get("unit"),
55 | lambda value: self.core.set("unit", value))
56 | return True
57 |
58 | def teardown(self):
59 | if self.gui:
60 | self.unregister_gtk_handlers(self._gtk_handlers)
61 | self.core.unregister_ui("preferences_general", self.gui.get_object("UnitPrefBox"))
62 | # TODO: reset setting "unit" back to a default value?
63 | self.clear_state_items()
64 |
65 | def change_unit_init(self, widget=None):
66 | # update the "_last_unit" attribute
67 | model = widget.get_model()
68 | self._last_unit = model[widget.get_active()][0]
69 | # redraw the model
70 | self.core.emit_event("model-change-after")
71 |
--------------------------------------------------------------------------------
/pycam/run_cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 |
4 | Copyright 2017 Lars Kruse
5 |
6 | This file is part of PyCAM.
7 |
8 | PyCAM is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | PyCAM is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with PyCAM. If not, see .
20 | """
21 |
22 | import argparse
23 | import logging
24 | import os
25 | import sys
26 |
27 | try:
28 | from pycam import VERSION
29 | except ImportError:
30 | # running locally (without a proper PYTHONPATH) requires manual intervention
31 | sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)),
32 | os.pardir)))
33 | from pycam import VERSION
34 |
35 | import pycam.errors
36 | from pycam.Flow.parser import parse_yaml
37 | import pycam.Utils
38 | import pycam.Utils.log
39 | import pycam.workspace.data_models
40 |
41 |
42 | _log = pycam.Utils.log.get_logger()
43 |
44 | LOG_LEVELS = {"debug": logging.DEBUG,
45 | "info": logging.INFO,
46 | "warning": logging.WARNING,
47 | "error": logging.ERROR, }
48 |
49 |
50 | def get_args():
51 | parser = argparse.ArgumentParser(prog="PyCAM", description="scriptable PyCAM processing flow",
52 | epilog="PyCAM website: https://github.com/SebKuzminsky/pycam")
53 | parser.add_argument("--log-level", choices=LOG_LEVELS.keys(), default="warning",
54 | help="choose the verbosity of log messages")
55 | parser.add_argument("sources", metavar="FLOW_SPEC", type=argparse.FileType('r'), nargs="+",
56 | help="processing flow description files in yaml format")
57 | parser.add_argument("--version", action="version", version="%(prog)s {}".format(VERSION))
58 | return parser.parse_args()
59 |
60 |
61 | def main_func():
62 | args = get_args()
63 | _log.setLevel(LOG_LEVELS[args.log_level])
64 | for fname in args.sources:
65 | try:
66 | parse_yaml(fname)
67 | except pycam.errors.PycamBaseException as exc:
68 | print("Flow description parse failure ({}): {}".format(fname, exc), file=sys.stderr)
69 | sys.exit(1)
70 | pycam.Utils.set_application_key("pycam-cli")
71 | for export in pycam.workspace.data_models.Export.get_collection():
72 | export.run_export()
73 |
74 |
75 | if __name__ == "__main__":
76 | main_func()
77 |
--------------------------------------------------------------------------------
/samples/Box1.stl:
--------------------------------------------------------------------------------
1 | solid box1
2 | facet normal 0.707143 -0.408041 0.577452
3 | outer loop
4 | vertex 2.563112 -5.599983 2.267282
5 | vertex 5.339321 -3.997340 0.000022
6 | vertex 2.562797 -2.393577 4.533387
7 | endloop
8 | endfacet
9 | facet normal 0.707143 -0.408041 0.577452
10 | outer loop
11 | vertex 5.339321 -3.997340 0.000022
12 | vertex 5.339006 -0.790934 2.266127
13 | vertex 2.562797 -2.393577 4.533387
14 | endloop
15 | endfacet
16 | facet normal -0.707143 0.408041 -0.577452
17 | outer loop
18 | vertex -0.213384 -3.997869 0.000000
19 | vertex -0.213699 -0.791464 2.266105
20 | vertex 2.562824 -2.395226 -2.267260
21 | endloop
22 | endfacet
23 | facet normal -0.707143 0.408041 -0.577452
24 | outer loop
25 | vertex -0.213699 -0.791464 2.266105
26 | vertex 2.562510 0.811179 -0.001155
27 | vertex 2.562824 -2.395226 -2.267260
28 | endloop
29 | endfacet
30 | facet normal 0.707070 0.408176 -0.577446
31 | outer loop
32 | vertex 5.339006 -0.790934 2.266127
33 | vertex 2.562824 -2.395226 -2.267260
34 | vertex 2.562510 0.811179 -0.001155
35 | endloop
36 | endfacet
37 | facet normal 0.707070 0.408176 -0.577446
38 | outer loop
39 | vertex 5.339006 -0.790934 2.266127
40 | vertex 5.339321 -3.997340 0.000022
41 | vertex 2.562824 -2.395226 -2.267260
42 | endloop
43 | endfacet
44 | facet normal -0.707070 -0.408176 0.577446
45 | outer loop
46 | vertex -0.213384 -3.997869 0.000000
47 | vertex 2.562797 -2.393577 4.533387
48 | vertex -0.213699 -0.791464 2.266105
49 | endloop
50 | endfacet
51 | facet normal -0.707070 -0.408176 0.577446
52 | outer loop
53 | vertex -0.213384 -3.997869 0.000000
54 | vertex 2.563112 -5.599983 2.267282
55 | vertex 2.562797 -2.393577 4.533387
56 | endloop
57 | endfacet
58 | facet normal -0.000080 0.816637 0.577152
59 | outer loop
60 | vertex -0.213699 -0.791464 2.266105
61 | vertex 5.339006 -0.790934 2.266127
62 | vertex 2.562510 0.811179 -0.001155
63 | endloop
64 | endfacet
65 | facet normal -0.000080 0.816637 0.577152
66 | outer loop
67 | vertex -0.213699 -0.791464 2.266105
68 | vertex 2.562797 -2.393577 4.533387
69 | vertex 5.339006 -0.790934 2.266127
70 | endloop
71 | endfacet
72 | facet normal 0.000080 -0.816637 -0.577152
73 | outer loop
74 | vertex -0.213384 -3.997869 0.000000
75 | vertex 5.339321 -3.997340 0.000022
76 | vertex 2.563112 -5.599983 2.267282
77 | endloop
78 | endfacet
79 | facet normal 0.000080 -0.816637 -0.577152
80 | outer loop
81 | vertex -0.213384 -3.997869 0.000000
82 | vertex 2.562824 -2.395226 -2.267260
83 | vertex 5.339321 -3.997340 0.000022
84 | endloop
85 | endfacet
86 | endsolid box1
87 |
--------------------------------------------------------------------------------
/pycam/PathProcessors/ContourCutter.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2008-2010 Lode Leroy
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | from pycam.Geometry.PolygonExtractor import PolygonExtractor
21 | from pycam.Geometry.PointUtils import pdot, psub
22 | import pycam.PathProcessors
23 | from pycam.Toolpath import simplify_toolpath
24 |
25 |
26 | class ContourCutter(pycam.PathProcessors.BasePathProcessor):
27 | def __init__(self):
28 | super().__init__()
29 | self.curr_path = None
30 | self.scanline = None
31 | self.polygon_extractor = None
32 | self.points = []
33 | self.__forward = (1, 1, 0)
34 |
35 | def append(self, point):
36 | # Sort the points in positive x/y direction - otherwise the
37 | # PolygonExtractor breaks.
38 | if self.points and (pdot(psub(point, self.points[0]), self.__forward) < 0):
39 | self.points.insert(0, point)
40 | else:
41 | self.points.append(point)
42 |
43 | def new_direction(self, direction):
44 | if self.polygon_extractor is None:
45 | self.polygon_extractor = PolygonExtractor(PolygonExtractor.CONTOUR)
46 |
47 | self.polygon_extractor.new_direction(direction)
48 |
49 | def end_direction(self):
50 | self.polygon_extractor.end_direction()
51 |
52 | def new_scanline(self):
53 | self.polygon_extractor.new_scanline()
54 | self.points = []
55 |
56 | def end_scanline(self):
57 | for i in range(1, len(self.points) - 1):
58 | self.polygon_extractor.append(self.points[i])
59 | self.polygon_extractor.end_scanline()
60 |
61 | def finish(self):
62 | self.polygon_extractor.finish()
63 | if self.polygon_extractor.merge_path_list:
64 | paths = self.polygon_extractor.merge_path_list
65 | elif self.polygon_extractor.hor_path_list:
66 | paths = self.polygon_extractor.hor_path_list
67 | else:
68 | paths = self.polygon_extractor.ver_path_list
69 | if paths:
70 | for path in paths:
71 | path.append(path.points[0])
72 | simplify_toolpath(path)
73 | if paths:
74 | self.paths.extend(paths)
75 | self.sort_layered()
76 | self.polygon_extractor = None
77 |
--------------------------------------------------------------------------------
/samples/Box0.stl:
--------------------------------------------------------------------------------
1 | solid box0
2 | facet normal -0.000000 0.000000 1.000000
3 | outer loop
4 | vertex -4.961088 -4.824490 4.188777
5 | vertex -0.772311 -0.635713 4.188777
6 | vertex -4.961088 -0.635713 4.188777
7 | endloop
8 | endfacet
9 | facet normal -0.000000 0.000000 1.000000
10 | outer loop
11 | vertex -4.961088 -4.824490 4.188777
12 | vertex -0.772311 -4.824490 4.188777
13 | vertex -0.772311 -0.635713 4.188777
14 | endloop
15 | endfacet
16 | facet normal 0.000000 0.000000 -1.000000
17 | outer loop
18 | vertex -0.772311 -4.824490 0.000000
19 | vertex -4.961088 -0.635713 0.000000
20 | vertex -0.772311 -0.635713 0.000000
21 | endloop
22 | endfacet
23 | facet normal 0.000000 0.000000 -1.000000
24 | outer loop
25 | vertex -0.772311 -4.824490 0.000000
26 | vertex -4.961088 -4.824490 0.000000
27 | vertex -4.961088 -0.635713 0.000000
28 | endloop
29 | endfacet
30 | facet normal 1.000000 -0.000000 0.000000
31 | outer loop
32 | vertex -0.772311 -4.824490 4.188777
33 | vertex -0.772311 -0.635713 0.000000
34 | vertex -0.772311 -0.635713 4.188777
35 | endloop
36 | endfacet
37 | facet normal 1.000000 -0.000000 0.000000
38 | outer loop
39 | vertex -0.772311 -4.824490 4.188777
40 | vertex -0.772311 -4.824490 0.000000
41 | vertex -0.772311 -0.635713 0.000000
42 | endloop
43 | endfacet
44 | facet normal -1.000000 0.000000 0.000000
45 | outer loop
46 | vertex -4.961088 -4.824490 0.000000
47 | vertex -4.961088 -0.635713 4.188777
48 | vertex -4.961088 -0.635713 0.000000
49 | endloop
50 | endfacet
51 | facet normal -1.000000 0.000000 0.000000
52 | outer loop
53 | vertex -4.961088 -4.824490 0.000000
54 | vertex -4.961088 -4.824490 4.188777
55 | vertex -4.961088 -0.635713 4.188777
56 | endloop
57 | endfacet
58 | facet normal 0.000000 1.000000 0.000000
59 | outer loop
60 | vertex -4.961088 -0.635713 4.188777
61 | vertex -0.772311 -0.635713 0.000000
62 | vertex -4.961088 -0.635713 0.000000
63 | endloop
64 | endfacet
65 | facet normal 0.000000 1.000000 0.000000
66 | outer loop
67 | vertex -4.961088 -0.635713 4.188777
68 | vertex -0.772311 -0.635713 4.188777
69 | vertex -0.772311 -0.635713 0.000000
70 | endloop
71 | endfacet
72 | facet normal 0.000000 -1.000000 0.000000
73 | outer loop
74 | vertex -4.961088 -4.824490 0.000000
75 | vertex -0.772311 -4.824490 4.188777
76 | vertex -4.961088 -4.824490 4.188777
77 | endloop
78 | endfacet
79 | facet normal 0.000000 -1.000000 0.000000
80 | outer loop
81 | vertex -4.961088 -4.824490 0.000000
82 | vertex -0.772311 -4.824490 0.000000
83 | vertex -0.772311 -4.824490 4.188777
84 | endloop
85 | endfacet
86 | endsolid box0
87 |
--------------------------------------------------------------------------------
/docs/menu-items.md:
--------------------------------------------------------------------------------
1 | File menu
2 | ---------
3 |
4 | 
5 |
6 | **Open Model ...** Choose a model file (STL / SVG / PS / DXF) via a dialog. The currently active model is replaced with the new one.
7 |
8 | **Open Recent** Choose a model file from the list of recently used ones (the list also contains files used by other applications).
9 |
10 | **Save Model** Save the currently active model to its original location. This item is disabled if the model was loaded from a remote location (e.g. via http) or it the file is not writeable. No confirmation is requested.
11 |
12 | **Save Model as...** Store the currently active model under a new filename. A file chooser dialog will pop up.
13 |
14 | **Export visible toolpaths ...** Store all currently visible toolpaths in a single GCode file. A file chooser dialog will pop up. The order of toolpaths is important. See the Toolpaths tab for the list of all generated toolpaths and for their visible state.
15 |
16 | **Export all toolpaths ...** Store _all_ generated toolpaths in a single GCode file. A file chooser dialog will pop up. The order of toolpaths is important. See the Toolpaths tab for the list of all generated toolpaths.
17 |
18 | **Quit** Request PyCAM to quit. This may take some seconds if you are connected to remote [processing servers](server-mode.md).
19 |
20 | Edit menu
21 | ---------
22 |
23 | 
24 |
25 | **Undo latest model change** Reverse the latest operation that changed the model. This includes all transformations (scale, rotate, flip, swap, shift) as well as drastic changes (e.g. opening another model or 3D-to-2D projection). Changes regarding the tasks settings (e.g. cutter size) are ignored.
26 |
27 | **Copy** Copy a representation of the current model to the clipboard. Other programs (e.g. Inkscape) can access the model data from the clipboard. 3D models are exported as STL data (ascii). 2D models are represented as plain SVG data.
28 |
29 | **Paste** Read model data from the clipboard and replace the currently active model. 3D models are expected as STL (binary or ascii) or DXF data. 2D models can be transferred as SVG, PS or DXF files.
30 |
31 | PyCAM announces and accepts the following target types via the
32 | clipboard:
33 |
34 | Target type | Data
35 | ------------------------ | ----------
36 | application/sla | STL data
37 | application/postscript | PS / EPS
38 | image/svg+xml | SVG
39 | image/x-inkscape-svg | SVG
40 | image/vnd.dxf | DXF
41 |
42 | Settings menu
43 | -------------
44 |
45 | 
46 |
47 | Extras menu
48 | -----------
49 |
50 | 
51 |
52 | Windows menu
53 | ------------
54 |
55 | 
56 |
57 | Help menu
58 | ---------
59 |
60 | 
61 |
--------------------------------------------------------------------------------
/pycam/Plugins/ModelPolygons.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 |
23 |
24 | class ModelPolygons(pycam.Plugins.PluginBase):
25 |
26 | UI_FILE = "model_polygons.ui"
27 | DEPENDS = ["Models"]
28 | CATEGORIES = ["Model"]
29 |
30 | def setup(self):
31 | if self.gui:
32 | polygon_frame = self.gui.get_object("ModelPolygonFrame")
33 | polygon_frame.unparent()
34 | self.core.register_ui("model_handling", "Polygons", polygon_frame, 0)
35 | self._gtk_handlers = (
36 | (self.gui.get_object("ToggleModelDirectionButton"),
37 | "clicked", self._adjust_polygons, "toggle_polygon_directions"),
38 | (self.gui.get_object("DirectionsGuessButton"),
39 | "clicked", self._adjust_polygons, "revise_polygon_directions"))
40 | self._event_handlers = (
41 | ("model-change-after", self._update_polygon_controls),
42 | ("model-selection-changed", self._update_polygon_controls))
43 | self.register_gtk_handlers(self._gtk_handlers)
44 | self.register_event_handlers(self._event_handlers)
45 | self._update_polygon_controls()
46 | return True
47 |
48 | def teardown(self):
49 | if self.gui:
50 | self.unregister_event_handlers(self._event_handlers)
51 | self.unregister_gtk_handlers(self._gtk_handlers)
52 | self.core.unregister_ui("model_handling", self.gui.get_object("ModelPolygonFrame"))
53 |
54 | def _get_polygon_models(self):
55 | models = []
56 | for model in self.core.get("models").get_selected():
57 | if model and hasattr(model.get_model(), "reverse_directions"):
58 | models.append(model)
59 | return models
60 |
61 | def _update_polygon_controls(self):
62 | models = self._get_polygon_models()
63 | frame = self.gui.get_object("ModelPolygonFrame")
64 | if models:
65 | frame.show()
66 | else:
67 | frame.hide()
68 |
69 | def _adjust_polygons(self, widget=None, action=None):
70 | models = self._get_polygon_models()
71 | for model in models:
72 | model.extend_value("transformations", [{"action": action}])
73 |
--------------------------------------------------------------------------------
/pycam/Importers/TestModel.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2008-2009 Lode Leroy
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | from pycam.Geometry.Triangle import Triangle
21 | from pycam.Geometry.Line import Line
22 | from pycam.Geometry.Model import Model
23 |
24 |
25 | def get_test_model():
26 | points = []
27 | points.append((-2, 1, 4))
28 | points.append((2, 1, 4))
29 | points.append((0, -2, 4))
30 | points.append((-5, 2, 2))
31 | points.append((-1, 3, 2))
32 | points.append((5, 2, 2))
33 | points.append((4, -1, 2))
34 | points.append((2, -4, 2))
35 | points.append((-2, -4, 2))
36 | points.append((-3, -2, 2))
37 |
38 | lines = []
39 | lines.append(Line(points[0], points[1]))
40 | lines.append(Line(points[1], points[2]))
41 | lines.append(Line(points[2], points[0]))
42 | lines.append(Line(points[0], points[3]))
43 | lines.append(Line(points[3], points[4]))
44 | lines.append(Line(points[4], points[0]))
45 | lines.append(Line(points[4], points[1]))
46 | lines.append(Line(points[4], points[5]))
47 | lines.append(Line(points[5], points[1]))
48 | lines.append(Line(points[5], points[6]))
49 | lines.append(Line(points[6], points[1]))
50 | lines.append(Line(points[6], points[2]))
51 | lines.append(Line(points[6], points[7]))
52 | lines.append(Line(points[7], points[2]))
53 | lines.append(Line(points[7], points[8]))
54 | lines.append(Line(points[8], points[2]))
55 | lines.append(Line(points[8], points[9]))
56 | lines.append(Line(points[9], points[2]))
57 | lines.append(Line(points[9], points[0]))
58 | lines.append(Line(points[9], points[3]))
59 |
60 | model = Model()
61 | for p1, p2, p3, l1, l2, l3 in ((0, 1, 2, 0, 1, 2),
62 | (0, 3, 4, 3, 4, 5),
63 | (0, 4, 1, 5, 6, 0),
64 | (1, 4, 5, 6, 7, 8),
65 | (1, 5, 6, 8, 9, 10),
66 | (1, 6, 2, 10, 11, 1),
67 | (2, 6, 7, 11, 12, 13),
68 | (2, 7, 8, 13, 14, 15),
69 | (2, 8, 9, 15, 16, 17),
70 | (2, 9, 0, 17, 18, 2),
71 | (0, 9, 3, 18, 19, 3)):
72 | model.append(Triangle(points[p1], points[p2], points[p3]))
73 | return model
74 |
--------------------------------------------------------------------------------
/samples/polygon4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
73 |
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
1 | # Dependencies of the graphical interface
2 |
3 | ## Windows
4 |
5 | `TODO:` Current Windows installation instructions
6 |
7 | ## Unix
8 |
9 | ### Installation
10 |
11 | Install the following packages with your package manager:
12 |
13 | ```
14 | python3
15 | python3-gi
16 | python3-opengl
17 | python3-yaml
18 | python3-svg.path
19 | gir1.2-gtk-3.0
20 | ```
21 |
22 | On a Debian or Ubuntu system, you would just type the following:
23 | ```bash
24 | sudo apt install python3-gi python3-opengl python3-yaml python3-svg.path gir1.2-gtk-3.0
25 | ```
26 | Please note that you need to enable the `universe` repository in Ubuntu.
27 |
28 | ### Run with Docker
29 |
30 | If you have difficulty with the installation, you can run the application from Docker.
31 |
32 | The `docker run` command will mount your personal Documents folder to `/root/Documents` so that you
33 | can access your files.
34 |
35 | ```bash
36 | sudo docker build -t pycam/pycam .
37 | sudo docker run -it \
38 | -v ~/Documents:/root/Documents \
39 | -v ~/.Xauthority:/root/.Xauthority \
40 | -e DISPLAY \
41 | --net=host \
42 | pycam/pycam
43 | ```
44 |
45 | ## macOS
46 |
47 | ### Installation
48 |
49 | 1\. Install Homebrew if it has not been installed:
50 | ```bash
51 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
52 | ```
53 |
54 | 2\. Install the dependencies (currently only for Python2):
55 | TODO: adjust for Python3
56 | ```bash
57 | brew install gtk+3 pygobject3
58 | pip install pygobject enum34
59 | ```
60 |
61 | ### Run with Docker
62 |
63 | If you have difficulty with the installation, you can run the application from Docker.
64 |
65 | 1\. Make sure that Docker is installed, if not, you can install it with Homebrew.
66 | You will also need XQuartz and socat.
67 |
68 | ```bash
69 | brew cask install docker xquartz
70 | brew install socat
71 | ```
72 |
73 | 2\. Start XQuartz from a terminal with `open -a XQuartz`. In the XQuartz Preferences,
74 | go to the “Security” tab and make sure you’ve got “Allow connections from network
75 | clients” ticked.
76 |
77 | 3a. Run the following in a terminal and leave it running:
78 |
79 | ```bash
80 | socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
81 | ```
82 |
83 | 3b. Run the following in a separate terminal. Your ip address can be found by running `ifconfig`.
84 |
85 | The `docker run` command will mount your personal Documents folder to `/root/Documents` so that you
86 | can access your files.
87 |
88 | ```bash
89 | docker build -t pycam/pycam .
90 | export IP=''
91 | docker run -it \
92 | -v ~/Documents:/root/Documents \
93 | -v /tmp/.X11-unix:/tmp/.X11-unix \
94 | -e DISPLAY=$IP:0 \
95 | pycam/pycam
96 | ```
97 |
98 | # Minimal requirements for non-GUI mode
99 |
100 | If you plan to use PyCAM only in batch mode (without a graphical user interface),
101 | then you just need to install Python.
102 |
103 | See the manpage ( `man pycam` ) or the output of `pycam --help` for further defails.
104 |
--------------------------------------------------------------------------------
/docs/main-page.md:
--------------------------------------------------------------------------------
1 | Use PyCAM to generate toolpaths suitable for 3-Axis CNC machining
2 | -----------------------------------------------------------------
3 |
4 | You can use **svg and dxf files for 2.5D milling** and **stl files for
5 | full 3-axis 3D milling!**
6 |
7 | Take a look at some [screenshots](screenshots.md) for a quick
8 | overview of the features. The [list of features](features.md)
9 | gives you more details.
10 |
11 | Read the [Installation](installation.md) instructions.
12 |
13 | Watch some [Videos Tutorials](http://vimeo.com/channels/pycam) in
14 | multiple languages. You are welcome to
15 | [translate](video-translations.md) the subtitles to your native
16 | language!
17 |
18 | Join the [mailing lists](http://sourceforge.net/mail/?group_id=237831)
19 | if you want to follow recent developments.
20 |
21 | Read our [development blog](http://fab.senselab.org/pycam) about
22 | interesting new features and plans.
23 |
24 | Check the [FAQ](faq.md) section if are looking for answers.
25 |
26 | Look for [alternative programs](other-programs.md) generating
27 | G-Code for CNC machining, if PyCAM should not fulfill your needs. In
28 | this case: please [let us know, what's
29 | missing](wanted-features)!
30 |
31 | Add the features that you want to see in PyCAM to the
32 | [wishlist](wanted-features.md) ....
33 |
34 | Common workflow
35 | ---------------
36 |
37 | A common workflow could look like this:
38 |
39 | 1. open an STL model file
40 | 2. configure cutter settings (e.g. drill shape and size)
41 | 3. configure processing settings (e.g. the toolpath strategy, remaining
42 | material, ...)
43 | 4. start the toolpath generation
44 | 5. repeat steps 2..4 if you want to add more toolpaths
45 | 6. export the generated toolpaths to a file (in GCode format)
46 |
47 | The output (GCode) can be used for [LinuxCNC](http://www.linuxcnc.org/) and other
48 | machine controller software.
49 |
50 | Graphical User Interface
51 | ------------------------
52 |
53 | The graphical user interface of PyCAM is based on GTK. All available
54 | features are configurable in different tabs. The complete setup can be
55 | stored in task settings file for later re-use.
56 |
57 | The [3D View](3d-view) is based on OpenGL. It is not strictly
58 | required for the operation. But it is very helpful for making sure that
59 | the result meets your expectations.
60 |
61 | Alternatively you can also use most features of PyCAM via its
62 | [command line interface](cli-examples.md) (e.g. for batch
63 | processing).
64 |
65 | Command-line Interface
66 | ----------------------
67 |
68 | PyCAM supports non-interactive toolpath generation. This is useful for
69 | batch processing.
70 |
71 | See some [examples](cli-examples.md) for the command-line
72 | usage.
73 |
74 | Requirements
75 | ------------
76 |
77 | See the requirement list for the different platforms: [Requirements](requirements.md).
78 |
79 | Open issues / Plans
80 | -------------------
81 |
82 | Take a look at our [TODO](todo.md) list.
83 |
84 | Development
85 | -----------
86 |
87 | Take a look at [Developer's Guide](developers-guide.md) if you
88 | want to improve PyCAM.
89 |
--------------------------------------------------------------------------------
/pycam/Plugins/OpenGLViewSupportModelPreview.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import pycam.Plugins
21 | import pycam.workspace.data_models
22 |
23 |
24 | class OpenGLViewSupportModelPreview(pycam.Plugins.PluginBase):
25 |
26 | DEPENDS = ["OpenGLWindow", "OpenGLViewModel"]
27 | CATEGORIES = ["Visualization", "OpenGL", "Support bridges"]
28 |
29 | def setup(self):
30 | self.core.register_event("visualize-items", self.draw_support_preview)
31 | self.core.get("register_display_item")("show_support_preview",
32 | "Show Support Model Preview", 30)
33 | self.core.get("register_color")("color_support_preview", "Support model", 30)
34 | self.core.emit_event("visual-item-updated")
35 | return True
36 |
37 | def teardown(self):
38 | self.core.unregister_event("visualize-items", self.draw_support_preview)
39 | self.core.get("unregister_display_item")("show_support_preview")
40 | self.core.get("unregister_color")("color_support_preview")
41 | self.core.emit_event("visual-item-updated")
42 |
43 | def draw_support_preview(self):
44 | if not self.core.get("show_support_preview"):
45 | return
46 | models = []
47 | for model_object in (self.core.get("current_support_models") or []):
48 | model = model_object.get_model()
49 | if model:
50 | models.append(model)
51 | if not models:
52 | return
53 | GL = self._GL
54 | # disable lighting
55 | if self.core.get("view_light"):
56 | GL.glDisable(GL.GL_LIGHTING)
57 | # show a wireframe
58 | if self.core.get("view_polygon"):
59 | GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
60 | # change the color
61 | col = self.core.get("color_support_preview")
62 | color = (col["red"], col["green"], col["blue"], col["alpha"])
63 | GL.glColor4f(*color)
64 | # we need to wait until the color change is active
65 | GL.glFinish()
66 | # draw the models
67 | self.core.call_chain("draw_models", models)
68 | # enable lighting again
69 | if self.core.get("view_light"):
70 | GL.glEnable(GL.GL_LIGHTING)
71 | # enable polygon fill mode again
72 | if self.core.get("view_polygon"):
73 | GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL)
74 |
--------------------------------------------------------------------------------
/samples/multilayer_engrave.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/docs/img/2d-multilayer-engrave.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
88 |
--------------------------------------------------------------------------------
/pycam/Gui/OpenGLTools.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010-2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import math
21 |
22 | # careful import
23 | try:
24 | import OpenGL.GL as GL
25 | import OpenGL.GLUT as GLUT
26 | except (ImportError, RuntimeError):
27 | pass
28 |
29 | from pycam.Geometry import sqrt
30 | from pycam.Geometry.PointUtils import pcross, pnorm, pnormalized, psub
31 |
32 |
33 | def keep_matrix(func):
34 | def keep_matrix_wrapper(*args, **kwargs):
35 | pushed_matrix_mode = GL.glGetIntegerv(GL.GL_MATRIX_MODE)
36 | GL.glPushMatrix()
37 | result = func(*args, **kwargs)
38 | final_matrix_mode = GL.glGetIntegerv(GL.GL_MATRIX_MODE)
39 | GL.glMatrixMode(pushed_matrix_mode)
40 | GL.glPopMatrix()
41 | GL.glMatrixMode(final_matrix_mode)
42 | return result
43 | return keep_matrix_wrapper
44 |
45 |
46 | @keep_matrix
47 | def draw_direction_cone(p1, p2, position=0.5, precision=12, size=0.1):
48 | distance = psub(p2, p1)
49 | length = pnorm(distance)
50 | direction = pnormalized(distance)
51 | if direction is None:
52 | # zero-length line
53 | return
54 | cone_length = length * size
55 | cone_radius = cone_length / 3.0
56 | # move the cone to the middle of the line
57 | GL.glTranslatef((p1[0] + p2[0]) * position,
58 | (p1[1] + p2[1]) * position,
59 | (p1[2] + p2[2]) * position)
60 | # rotate the cone according to the line direction
61 | # The cross product is a good rotation axis.
62 | cross = pcross(direction, (0, 0, -1))
63 | if pnorm(cross) != 0:
64 | # The line direction is not in line with the z axis.
65 | try:
66 | angle = math.asin(sqrt(direction[0] ** 2 + direction[1] ** 2))
67 | except ValueError:
68 | # invalid angle - just ignore this cone
69 | return
70 | # convert from radians to degree
71 | angle = angle / math.pi * 180
72 | if direction[2] < 0:
73 | angle = 180 - angle
74 | GL.glRotatef(angle, cross[0], cross[1], cross[2])
75 | elif direction[2] == -1:
76 | # The line goes down the z axis - turn it around.
77 | GL.glRotatef(180, 1, 0, 0)
78 | else:
79 | # The line goes up the z axis - nothing to be done.
80 | pass
81 | # center the cone
82 | GL.glTranslatef(0, 0, -cone_length * position)
83 | # draw the cone
84 | GLUT.glutWireCone(cone_radius, cone_length, precision, 1)
85 |
--------------------------------------------------------------------------------
/pycam/Plugins/ModelRotation.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 |
21 | import pycam.Plugins
22 |
23 |
24 | class ModelRotation(pycam.Plugins.PluginBase):
25 |
26 | UI_FILE = "model_rotation.ui"
27 | DEPENDS = ["Models"]
28 | CATEGORIES = ["Model"]
29 |
30 | def setup(self):
31 | if self.gui:
32 | rotation_box = self.gui.get_object("ModelRotationBox")
33 | rotation_box.unparent()
34 | self.core.register_ui("model_handling", "Rotation", rotation_box, -10)
35 | self._gtk_handlers = ((self.gui.get_object("RotateModelButton"), "clicked",
36 | self._rotate_model), )
37 | self._event_handlers = (("model-selection-changed", self._update_controls), )
38 | self.register_gtk_handlers(self._gtk_handlers)
39 | self.register_event_handlers(self._event_handlers)
40 | self._update_controls()
41 | return True
42 |
43 | def teardown(self):
44 | if self.gui:
45 | self.unregister_event_handlers(self._event_handlers)
46 | self.unregister_gtk_handlers(self._gtk_handlers)
47 | self.core.unregister_ui("model_handling", self.gui.get_object("ModelRotationBox"))
48 |
49 | def _update_controls(self):
50 | widget = self.gui.get_object("ModelRotationBox")
51 | if self.core.get("models").get_selected():
52 | widget.show()
53 | else:
54 | widget.hide()
55 |
56 | def _rotate_model(self, widget=None):
57 | models = self.core.get("models").get_selected()
58 | if not models:
59 | return
60 | center = [0, 0, 0]
61 | for axis in "XYZ":
62 | if self.gui.get_object("RotationAxis%s" % axis).get_active():
63 | break
64 | axis_vector = {"X": [1, 0, 0], "Y": [0, 1, 0], "Z": [0, 0, 1]}[axis]
65 | for control, angle in (("RotationAngle90CCKW", -90),
66 | ("RotationAngle90CKW", 90),
67 | ("RotationAngle180", 180),
68 | ("RotationAngleCustomCKW",
69 | self.gui.get_object("RotationAngle").get_value())):
70 | if self.gui.get_object(control).get_active():
71 | break
72 | for model in models:
73 | model.extend_value("transformations", [{"action": "rotate", "center": center,
74 | "vector": axis_vector, "angle": angle}])
75 |
--------------------------------------------------------------------------------
/pycam/Plugins/OpenGLViewAxes.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2011 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import pycam.Plugins
21 | from pycam.Gui.OpenGLTools import draw_direction_cone
22 |
23 |
24 | class OpenGLViewAxes(pycam.Plugins.PluginBase):
25 |
26 | DEPENDS = ["OpenGLWindow"]
27 | CATEGORIES = ["Visualization", "OpenGL"]
28 |
29 | def setup(self):
30 | self.core.register_event("visualize-items", self.draw_axes)
31 | self.core.get("register_display_item")("show_axes", "Show Coordinate System", 50)
32 | self.core.emit_event("visual-item-updated")
33 | return True
34 |
35 | def teardown(self):
36 | self.core.unregister_event("visualize-items", self.draw_axes)
37 | self.core.get("unregister_display_item")("show_axes")
38 | self.core.emit_event("visual-item-updated")
39 |
40 | def draw_axes(self):
41 | if not self.core.get("show_axes"):
42 | return
43 | GL = self._GL
44 | GL.glMatrixMode(GL.GL_MODELVIEW)
45 | GL.glLoadIdentity()
46 | low, high = [None, None, None], [None, None, None]
47 | self.core.call_chain("get_draw_dimension", low, high)
48 | if None in low or None in high:
49 | low, high = (0, 0, 0), (10, 10, 10)
50 | length = 1.2 * max(max(high), abs(min(low)))
51 | origin = (0, 0, 0)
52 | cone_length = 0.05
53 | old_line_width = GL.glGetFloatv(GL.GL_LINE_WIDTH)
54 | if self.core.get("view_light"):
55 | GL.glDisable(GL.GL_LIGHTING)
56 | GL.glLineWidth(1.5)
57 | # draw a colored line ending in a cone for each axis
58 | for index in range(3):
59 | end = [0, 0, 0]
60 | end[index] = length
61 | color = [0.0, 0.0, 0.0]
62 | # reduced brightness (not 1.0)
63 | color[index] = 0.8
64 | GL.glColor3f(*color)
65 | # we need to wait until the color change is active
66 | GL.glFinish()
67 | GL.glBegin(GL.GL_LINES)
68 | GL.glVertex3f(*origin)
69 | GL.glVertex3f(*end)
70 | GL.glEnd()
71 | # Position the cone slightly behind the end of the line - otherwise
72 | # the end of the line (width=2) is visible at the top of the cone.
73 | draw_direction_cone(origin, end, position=1.0 + cone_length, precision=32,
74 | size=cone_length)
75 | GL.glLineWidth(old_line_width)
76 | if self.core.get("view_light"):
77 | GL.glEnable(GL.GL_LIGHTING)
78 |
--------------------------------------------------------------------------------
/pycam/Gui/Console.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2010 Lars Kruse
3 |
4 | This file is part of PyCAM.
5 |
6 | PyCAM is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | PyCAM is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with PyCAM. If not, see .
18 | """
19 |
20 | import os
21 |
22 |
23 | class ConsoleProgressBar:
24 |
25 | STYLE_NONE = 0
26 | STYLE_TEXT = 1
27 | STYLE_BAR = 2
28 | STYLE_DOT = 3
29 | PROGRESS_BAR_LENGTH = 70
30 |
31 | def __init__(self, output, style=None):
32 | if style is None:
33 | style = ConsoleProgressBar.STYLE_TEXT
34 | self.output = output
35 | self.style = style
36 | self.last_length = 0
37 | self.text = ""
38 | self.percent = 0
39 |
40 | def _output_current_state(self, progress_happened=True):
41 | if self.style == ConsoleProgressBar.STYLE_TEXT:
42 | text = "%d%% %s" % (self.percent, self.text)
43 | self.last_length = len(text)
44 | elif self.style == ConsoleProgressBar.STYLE_BAR:
45 | bar_length = ConsoleProgressBar.PROGRESS_BAR_LENGTH
46 | hashes = int(bar_length * self.percent / 100.0)
47 | empty = bar_length - hashes
48 | text = "[%s%s]" % ("#" * hashes, "." * empty)
49 | # include a text like " 10% " in the middle
50 | percent_text = " %d%% " % self.percent
51 | start_text = text[:(len(text) - len(percent_text)) / 2]
52 | end_text = text[-(len(text) - len(start_text) - len(percent_text)):]
53 | text = start_text + percent_text + end_text
54 | self.last_length = len(text)
55 | elif self.style == ConsoleProgressBar.STYLE_DOT:
56 | if progress_happened:
57 | text = "."
58 | else:
59 | text = ""
60 | # don't remove any previous characters
61 | self.last_length = 0
62 | else:
63 | raise ValueError("ConsoleProgressBar: invalid style (%d)" % self.style)
64 | self.output.write(text)
65 | self.output.flush()
66 |
67 | def update(self, text=None, percent=None, **kwargs):
68 | if self.style == ConsoleProgressBar.STYLE_NONE:
69 | return
70 | if text is not None:
71 | self.text = text
72 | if percent is not None:
73 | self.percent = int(percent)
74 | if self.last_length > 0:
75 | # delete the previous line
76 | self.output.write("\x08" * self.last_length)
77 | self._output_current_state(progress_happened=(percent is not None))
78 |
79 | def finish(self):
80 | if self.style == ConsoleProgressBar.STYLE_NONE:
81 | return
82 | # show that we are finished
83 | self.update(percent=100)
84 | # finish the line
85 | self.output.write(os.linesep)
86 |
--------------------------------------------------------------------------------
/share/ui/progress_bar.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | False
7 |
8 |
9 | False
10 | False
11 | vertical
12 |
13 |
14 | False
15 | end
16 |
17 |
18 | False
19 | True
20 | 0
21 |
22 |
23 |
24 |
25 | True
26 | False
27 | end
28 |
29 |
30 | False
31 | True
32 | 1
33 |
34 |
35 |
36 |
37 | True
38 | False
39 | vertical
40 |
41 |
42 | Show Progress
43 | True
44 | True
45 | True
46 |
47 |
48 | False
49 | True
50 | 0
51 |
52 |
53 |
54 |
55 | Cancel
56 | True
57 | True
58 | True
59 |
60 |
61 | False
62 | True
63 | 1
64 |
65 |
66 |
67 |
68 | False
69 | True
70 | 2
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at njh@aelius.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Copyright 2010 Lars Kruse
4 | Copyright 2010 Arthur Magill
5 |
6 | This file is part of PyCAM.
7 |
8 | PyCAM is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | PyCAM is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with PyCAM. If not, see .
20 | """
21 |
22 | import glob
23 | import os.path
24 | from setuptools import setup, find_packages
25 |
26 | from pycam import VERSION
27 |
28 | BASE_DIR = os.path.realpath(os.path.abspath(os.path.dirname(__file__)))
29 |
30 |
31 | setup(
32 | name="pycam",
33 | version=VERSION,
34 | license="GPL v3",
35 | description="Open Source CAM - Toolpath Generation for 3-Axis CNC machining",
36 | author="Lars Kruse",
37 | author_email="devel@sumpfralle.de",
38 | provides=["pycam"],
39 | requires=["PyOpenGL", "PyYAML"],
40 | url="http://pycam.sourceforge.net/",
41 | download_url="http://sourceforge.net/projects/pycam/files",
42 | keywords=["3-axis", "cnc", "cam", "toolpath", "machining", "g-code"],
43 | long_description="""IMPORTANT NOTE: Please read the list of requirements:
44 | http://pycam.sourceforge.net/requirements
45 | Basically you will need Python3, GTK and OpenGL.
46 |
47 | Windows: select Python 3.X in the following dialog.
48 | """,
49 | # full list of classifiers at:
50 | # http://pypi.python.org/pypi?:action=list_classifiers
51 | classifiers=[
52 | "Programming Language :: Python",
53 | "Programming Language :: Python :: 3",
54 | "Development Status :: 4 - Beta",
55 | "License :: OSI Approved :: GNU General Public License (GPL)",
56 | "Topic :: Scientific/Engineering",
57 | "Environment :: Win32 (MS Windows)",
58 | "Environment :: X11 Applications :: GTK",
59 | "Intended Audience :: Manufacturing",
60 | "Operating System :: Microsoft :: Windows",
61 | "Operating System :: MacOS :: MacOS X",
62 | "Operating System :: POSIX",
63 | ],
64 | packages=find_packages(exclude=["pycam.Test"]),
65 | entry_points={
66 | "gui_scripts": [
67 | "pycam = pycam.run_gui:main_func",
68 | ],
69 | "console_scripts": [
70 | "pycam-cli = pycam.run_cli:main_func",
71 | ],
72 | },
73 | data_files=[
74 | ("share/pycam/doc", ["COPYING.TXT",
75 | "INSTALL.md",
76 | "LICENSE.TXT",
77 | "README.md",
78 | "Changelog",
79 | "release_info.txt"]),
80 | ("share/pycam/ui", glob.glob(os.path.join("share", "ui", "*"))),
81 | ("share/pycam/fonts", glob.glob(os.path.join("share", "fonts", "*"))),
82 | ("share/pycam", [os.path.join("share", "pycam.ico"),
83 | os.path.join("share", "misc", "DXF.gpl")]),
84 | ("share/pycam/samples", glob.glob(os.path.join("samples", "*"))),
85 | ],
86 | )
87 |
88 | # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
89 |
--------------------------------------------------------------------------------
/docs/installation-macos.md:
--------------------------------------------------------------------------------
1 | Versions, dependencies and complications
2 | ----------------------------------------
3 |
4 | Please note that the most recent successful usage of PyCAM on MacOS was
5 | reported around 2012. Thus you should stick with PyCAM v0.5.1 and be prepared
6 | to tackle weird dependency problems, if you really need to run PyCAM on MacOS.
7 |
8 | You should use Linux instead, if you want to use a more recent release of PyCAM.
9 |
10 | Install requirements via MacPorts
11 | ---------------------------------
12 |
13 | First you need to install [MacPorts](http://www.macports.org/install.php).
14 |
15 | Afterwards you need to install the following packages:
16 |
17 | - py25-gtk
18 | - py25-gtkglext
19 | - py25-opengl (at least v3.0.1b2)
20 |
21 | Simply run the following to install all dependencies:
22 |
23 | sudo port install py25-gtk py25-gtkglext py25-opengl
24 |
25 | Run PyCAM
26 | ---------
27 |
28 | - extract the [PyCAM archive](https://sourceforge.net/projects/pycam/files/pycam/)
29 | - run */opt/local/bin/python2.5 pycam* from within PyCAM's directory
30 | - the above line refers to MacPorts' Python interpreter (instead
31 | of MacOS' native Python) - otherwise it will not find OpenGL and
32 | the other required modules
33 |
34 | Problems? Solutions!
35 | --------------------
36 |
37 | Below you will find a list of potential problems reported by PyCAM
38 | users.
39 |
40 | If these workarounds do not help: please ask a question in the
41 | [*Help* forum](http://sourceforge.net/projects/pycam/forums/forum/860184) and
42 | provide the following relevant information about your setup.
43 |
44 | Get the list of installed python-related packages:
45 |
46 | port installed | grep py
47 |
48 | Get Python's output for every interesting *import* statement:
49 |
50 | foo@bar:~$ /opt/local/bin/python2.5
51 | Python 2.5.5 (r255:77872, Nov 28 2010, 19:00:19)
52 | [GCC 4.4.5] on linux2
53 | Type "help", "copyright", "credits” or "license" for more information.
54 | >>> import gtk.gtkgl
55 | >>> import OpenGL.GL as GL
56 | >>> import OpenGL.GLU as GLU
57 | >>> import OpenGL.GLUT as GLUT
58 |
59 | (the above output of a successful test was taken on Linux - your
60 | installed versions may differ slightly)
61 |
62 | ### OpenGL (python-gtkglext1) missing
63 |
64 | Some users reported the following warning from PyCAM, even though they
65 | installed all required packages:
66 |
67 | > Please install 'python-gtkglext1'
68 |
69 | Since none of the PyCAM developers is a Mac OS user, it is not easy for
70 | us to track down this issue. Currently it looks like a problem of
71 | [Python 2.5 and *ctypes*](https://trac.macports.org/ticket/26186) on Mac
72 | OS X. Please try the following steps to fix it:
73 |
74 | 1. install the libffi package: `port install libffi`
75 | 2. rebuild Python: `port -v upgrade --force python25`
76 |
77 | (suggested on
78 | [stackoverflow](http://stackoverflow.com/questions/4535725/ctypes-import-not-working-on-python-2-5/4536064#4536064))
79 |
80 | Alternatively you could try to update Python to v2.6 and install the
81 | corresponding packages for GTK, OpenGL and so on.
82 |
83 | Please report back, if one of the above suggestions fixes the problem
84 | for you - thanks!
85 |
86 | ### OpenGL is too old
87 |
88 | According to a [forum post from
89 | lilalinux](http://sourceforge.net/projects/pycam/forums/forum/860183/topic/3800091)
90 | you need at least OpenGL v3.0.1b2. Otherwise you will probably get a
91 | blank 3D visualization window.
92 |
--------------------------------------------------------------------------------