Renaming to pymkcam

parent 515e79c2
...@@ -4,9 +4,9 @@ Dependencies of the graphical interface: ...@@ -4,9 +4,9 @@ Dependencies of the graphical interface:
Windows: Windows:
-------- --------
Please note that there are two ways of using PyCAM on Windows: Please note that there are two ways of using pyMKcam on Windows:
1) use the standalone executable (experimental - but it does not require further dependencies) 1) use the standalone executable (experimental - but it does not require further dependencies)
http://sourceforge.net/projects/pycam/files/ http://sourceforge.net/projects/pymkcam/files/
2) the installer package - it requires the following dependencies: 2) the installer package - it requires the following dependencies:
...@@ -56,7 +56,7 @@ Please note that you need to enable the "universe" repository in Ubuntu. ...@@ -56,7 +56,7 @@ Please note that you need to enable the "universe" repository in Ubuntu.
BEWARE: Debian "Lenny" and Ubuntu "Jaunty" (maybe also Dapper/Hardy/Intrepid) BEWARE: Debian "Lenny" and Ubuntu "Jaunty" (maybe also Dapper/Hardy/Intrepid)
contain older "python-opengl" and "python-pyode" packages, that expose problems contain older "python-opengl" and "python-pyode" packages, that expose problems
with PyCAM. with pyMKcam.
You need to add "Squeeze" (for Debian) or "Karmic/Lucid" (for Ubuntu) to your You need to add "Squeeze" (for Debian) or "Karmic/Lucid" (for Ubuntu) to your
package repository list and run the following: package repository list and run the following:
apt-get update apt-get update
...@@ -70,14 +70,14 @@ Users of Python 2.5 with multiple CPU cores may want to install the package ...@@ -70,14 +70,14 @@ Users of Python 2.5 with multiple CPU cores may want to install the package
MacOS MacOS
----- -----
Please read http://sourceforge.net/projects/pycam/forums/forum/860183/topic/3800091 Please read http://sourceforge.net/projects/pymkcam/forums/forum/860183/topic/3800091
for the issues involved with installing PyCAM's dependencies via MacPorts. for the issues involved with installing pyMKcam's dependencies via MacPorts.
(thanks to lilalinux for this description) (thanks to lilalinux for this description)
Minimal requirements for non-GUI mode Minimal requirements for non-GUI mode
===================================== =====================================
If you plan to use PyCAM only in batch mode (without a graphical user If you plan to use pyMKcam only in batch mode (without a graphical user
interface), then you just need to install Python. interface), then you just need to install Python.
See the manpage (man pycam) or the output of "pycam --help" for further defails. See the manpage (man pymkcam) or the output of "pymkcam --help" for further defails.
include LICENSE.TXT include LICENSE
include technical_details.txt include technical_details.txt
include INSTALL.TXT include INSTALL.TXT
include COPYING.TXT include README.md
include README.TXT
include Changelog include Changelog
include release_info.txt include release_info.txt
include pycam include pymkcam
recursive-include desktop * recursive-include desktop *
recursive-include man * recursive-include man *
recursive-include src *.py recursive-include src *.py
......
# export SVN_REPO_BASE=. if you want to use the local version instead of trunk
# from the subversion repository.
# use something like "VERSION=0.2 make" to override the VERSION on the command line
VERSION ?= $(shell sed -n "s/^.*[\t ]*VERSION[\t ]*=[\t ]*[\"']\([^\"']*\)[\"'].*/\1/gp" pycam/__init__.py)
REPO_TAGS ?= https://pycam.svn.sourceforge.net/svnroot/pycam/tags
RELEASE_PREFIX ?= pycam-
ARCHIVE_DIR_RELATIVE ?= release-archives
EXPORT_DIR = $(RELEASE_PREFIX)$(VERSION)
EXPORT_FILE_PREFIX = $(EXPORT_DIR)
EXPORT_ZIP = $(EXPORT_FILE_PREFIX).zip
EXPORT_TGZ = $(EXPORT_FILE_PREFIX).tar.gz
EXPORT_WIN32 = $(EXPORT_FILE_PREFIX).win32.exe
PYTHON_EXE ?= python
# check if the local version of python's distutils support "--plat-name"
# (introduced in python 2.6)
DISTUTILS_PLAT_NAME = $(shell $(PYTHON_EXE) setup.py --help build_ext | grep -q -- "--plat-name" && echo "--plat-name win32")
# turn the destination directory into an absolute path
ARCHIVE_DIR := $(shell pwd)/$(ARCHIVE_DIR_RELATIVE)
.PHONY: zip tgz win32 clean dist git_export upload create_archive_dir man
dist: zip tgz win32
@# remove the tmp directory when everything is done
@rm -rf "$(EXPORT_DIR)"
clean:
@rm -rf "$(EXPORT_DIR)"
man: git_export
@make -C "$(EXPORT_DIR)/man"
git_export: clean
@if git status 2>/dev/null >&2;\
then git clone . "$(EXPORT_DIR)";\
else echo "No git repo found."; exit 1;\
fi
# Windows needs a different name for the startup script - due to process creation (no fork/exec)
@cp "$(EXPORT_DIR)/scripts/pycam" "$(EXPORT_DIR)/scripts/pycam-loader.py"
create_archive_dir:
@mkdir -p "$(ARCHIVE_DIR)"
zip: create_archive_dir man git_export
cd "$(EXPORT_DIR)"; $(PYTHON_EXE) setup.py sdist --format zip --dist-dir "$(ARCHIVE_DIR)"
tgz: create_archive_dir man git_export
cd "$(EXPORT_DIR)"; $(PYTHON_EXE) setup.py sdist --format gztar --dist-dir "$(ARCHIVE_DIR)"
win32: create_archive_dir man git_export
# this is a binary release
cd "$(EXPORT_DIR)"; $(PYTHON_EXE) setup.py bdist_wininst --user-access-control force --dist-dir "$(ARCHIVE_DIR)" $(DISTUTILS_PLAT_NAME)
upload:
svn cp "$(SVN_REPO_BASE)" "$(REPO_TAGS)/release-$(VERSION)" -m "tag release $(VERSION)"
svn import "$(ARCHIVE_DIR)/$(EXPORT_ZIP)" "$(REPO_TAGS)/archives/$(EXPORT_ZIP)" -m "added released zip file for version $(VERSION)"
svn import "$(ARCHIVE_DIR)/$(EXPORT_TGZ)" "$(REPO_TAGS)/archives/$(EXPORT_TGZ)" -m "added released tgz file for version $(VERSION)"
svn import "$(ARCHIVE_DIR)/$(EXPORT_WIN32)" "$(REPO_TAGS)/archives/$(EXPORT_WIN32)" -m "added released win32 installer for version $(VERSION)"
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
------------------------------------------------- -------------------------------------------------
Toolpath Generation for 3-Axis CNC machining based on MK4duo controllers Toolpath Generation for 3-Axis CNC machining based on MK4duo controllers
forked from the well known pycam forked from the well known pymkcam
If you like to help me work on pyMKcam If you like to help me work on pyMKcam
...@@ -41,7 +41,7 @@ https://www.nexlab.net/donations/k40-laser/ ...@@ -41,7 +41,7 @@ https://www.nexlab.net/donations/k40-laser/
### CONTRIBUTORS: ### CONTRIBUTORS:
* Lode Leroy: initiated pycam the project; developed the toolpath generation, * Lode Leroy: initiated pymkcam the project; developed the toolpath generation,
collision detection, geometry, Tk interface, ... collision detection, geometry, Tk interface, ...
* Lars Kruse: GTK interface and many features * Lars Kruse: GTK interface and many features
......
...@@ -5,29 +5,29 @@ $Id$ ...@@ -5,29 +5,29 @@ $Id$
Copyright 2008 Lode Leroy Copyright 2008 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Cutters.CylindricalCutter import * from pymkcam.Cutters.CylindricalCutter import *
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -5,37 +5,37 @@ $Id$ ...@@ -5,37 +5,37 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Cutters.SphericalCutter import * from pymkcam.Cutters.SphericalCutter import *
from pycam.Cutters.CylindricalCutter import * from pymkcam.Cutters.CylindricalCutter import *
from pycam.Cutters.ToroidalCutter import * from pymkcam.Cutters.ToroidalCutter import *
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
from pycam.Importers.TestModel import TestModel from pymkcam.Importers.TestModel import TestModel
from pycam.PathGenerators.DropCutter import DropCutter from pymkcam.PathGenerators.DropCutter import DropCutter
from pycam.Exporters.SimpleGCodeExporter import SimpleGCodeExporter from pymkcam.Exporters.SimpleGCodeExporter import SimpleGCodeExporter
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -5,26 +5,26 @@ $Id$ ...@@ -5,26 +5,26 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry.PolygonExtractor import * from pymkcam.Geometry.PolygonExtractor import *
import sys import sys
print "" print ""
......
...@@ -5,37 +5,37 @@ $Id$ ...@@ -5,37 +5,37 @@ $Id$
Copyright 2008 Lode Leroy Copyright 2008 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Cutters.SphericalCutter import * from pymkcam.Cutters.SphericalCutter import *
from pycam.Cutters.CylindricalCutter import * from pymkcam.Cutters.CylindricalCutter import *
from pycam.Cutters.ToroidalCutter import * from pymkcam.Cutters.ToroidalCutter import *
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
from pycam.Importers import STLImporter from pymkcam.Importers import STLImporter
from pycam.PathGenerators.PushCutter import PushCutter from pymkcam.PathGenerators.PushCutter import PushCutter
from pycam.PathProcessors import * from pymkcam.PathProcessors import *
from pycam.Exporters.SimpleGCodeExporter import SimpleGCodeExporter from pymkcam.Exporters.SimpleGCodeExporter import SimpleGCodeExporter
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -5,28 +5,28 @@ $Id$ ...@@ -5,28 +5,28 @@ $Id$
Copyright 2010 Lode Leroy Copyright 2010 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys, time import sys, time
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Importers import STLImporter from pymkcam.Importers import STLImporter
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
if len(sys.argv)>1: if len(sys.argv)>1:
......
...@@ -5,31 +5,31 @@ $Id$ ...@@ -5,31 +5,31 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Gui.Visualization import Visualization from pymkcam.Gui.Visualization import Visualization
from pycam.Simulation.ZBuffer import ZBuffer from pymkcam.Simulation.ZBuffer import ZBuffer
from pycam.Importers.TestModel import TestModel from pymkcam.Importers.TestModel import TestModel
from pycam.Geometry.Triangle import Triangle from pymkcam.Geometry.Triangle import Triangle
from pycam.Geometry.Point import Point from pymkcam.Geometry.Point import Point
from pycam.Cutters.SphericalCutter import SphericalCutter from pymkcam.Cutters.SphericalCutter import SphericalCutter
from OpenGL.GL import * from OpenGL.GL import *
......
...@@ -5,20 +5,20 @@ $Id$ ...@@ -5,20 +5,20 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
...@@ -26,10 +26,10 @@ sys.path.insert(0,'.') ...@@ -26,10 +26,10 @@ sys.path.insert(0,'.')
import math import math
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Cutters.SphericalCutter import * from pymkcam.Cutters.SphericalCutter import *
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -5,29 +5,29 @@ $Id$ ...@@ -5,29 +5,29 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Cutters.ToroidalCutter import * from pymkcam.Cutters.ToroidalCutter import *
from pycam.Gui.Visualization import ShowTestScene from pymkcam.Gui.Visualization import ShowTestScene
import math import math
......
...@@ -5,28 +5,28 @@ $Id$ ...@@ -5,28 +5,28 @@ $Id$
Copyright 2009 Lode Leroy Copyright 2009 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Geometry.TriangleKdtree import * from pymkcam.Geometry.TriangleKdtree import *
from pycam.Geometry.Model import Model from pymkcam.Geometry.Model import Model
from pycam.Importers.TestModel import TestModel from pymkcam.Importers.TestModel import TestModel
print "# get model" print "# get model"
testmodel = TestModel() testmodel = TestModel()
......
...@@ -5,20 +5,20 @@ $Id$ ...@@ -5,20 +5,20 @@ $Id$
Copyright 2010 Lode Leroy Copyright 2010 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
...@@ -26,8 +26,8 @@ sys.path.insert(0,'.') ...@@ -26,8 +26,8 @@ sys.path.insert(0,'.')
import math import math
from pycam.Geometry import * from pymkcam.Geometry import *
from pycam.Gui.Visualization import Visualization from pymkcam.Gui.Visualization import Visualization
p1 = Point(1,0,0) p1 = Point(1,0,0)
......
...@@ -5,27 +5,27 @@ $Id$ ...@@ -5,27 +5,27 @@ $Id$
Copyright 2008 Lode Leroy Copyright 2008 Lode Leroy
This file is part of PyCAM. This file is part of pyMKcam.
PyCAM is free software: you can redistribute it and/or modify pyMKcam is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, pyMKcam is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with pyMKcam. If not, see <http://www.gnu.org/licenses/>.
""" """
import sys import sys
sys.path.insert(0,'.') sys.path.insert(0,'.')
from pycam.Gui.Visualization import Visualization from pymkcam.Gui.Visualization import Visualization
from pycam.Importers.TestModel import TestModel from pymkcam.Importers.TestModel import TestModel
model = TestModel() model = TestModel()
......
pycam (0.5.1-1) unstable; urgency=low pymkcam (0.5.1-1) unstable; urgency=low
* initial debian package * initial debian package
* Closes: #600779 * Closes: #600779
......
Source: pycam Source: pymkcam
Section: python Section: python
Priority: extra Priority: extra
Maintainer: Lars Kruse <devel@sumpfralle.de> Maintainer: Lars Kruse <devel@sumpfralle.de>
Build-Depends: python, debhelper (>= 7), cdbs, patchutils Build-Depends: python, debhelper (>= 7), cdbs, patchutils
Build-Depends-Indep: python-support, help2man Build-Depends-Indep: python-support, help2man
Standards-Version: 3.9.2 Standards-Version: 3.9.2
Homepage: http://sourceforge.net/projects/pycam/ Homepage: http://sourceforge.net/projects/pymkcam/
Package: pycam Package: pymkcam
Architecture: all Architecture: all
Depends: python-gtk2, python-opengl (>>3.0.0~b6-3), python-gtkglext1, Depends: python-gtk2, python-opengl (>>3.0.0~b6-3), python-gtkglext1,
python-rsvg, ${misc:Depends}, ${python:Depends} python-rsvg, ${misc:Depends}, ${python:Depends}
...@@ -15,7 +15,7 @@ Recommends: python-pyode (>>1.2.0-3), python-psyco, python-setproctitle, ...@@ -15,7 +15,7 @@ Recommends: python-pyode (>>1.2.0-3), python-psyco, python-setproctitle,
python-guppy, inkscape, pstoedit python-guppy, inkscape, pstoedit
Suggests: qcad-data | librecad-data Suggests: qcad-data | librecad-data
Description: CAM program & Python library for generating toolpaths Description: CAM program & Python library for generating toolpaths
PyCAM is a toolpath generator for 3 axis machines. The generated pyMKcam is a toolpath generator for 3 axis machines. The generated
GCode can be used with EMC2 and other machine controllers. GCode can be used with EMC2 and other machine controllers.
The included Python library can be used independently from the GUI. The included Python library can be used independently from the GUI.
. .
......
Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135 Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
Name: PyCAM Name: pyMKcam
Maintainer: Lars Kruse <devel@sumpfralle.de> Maintainer: Lars Kruse <devel@sumpfralle.de>
Source: http://pycam.sourceforge.net Source: http://pymkcam.sourceforge.net
Files: * Files: *
Copyright: 2010-2011, Lars Kruse <devel@sumpfralle.de> Copyright: 2010-2011, Lars Kruse <devel@sumpfralle.de>
......
man/pycam.1 man/pymkcam.1
../share/mime/pycam.mime
\ No newline at end of file
../share/mime/pycam.xml
\ No newline at end of file
...@@ -22,19 +22,19 @@ clean:: ...@@ -22,19 +22,19 @@ clean::
make -C man clean make -C man clean
# build the manpage # build the manpage
build/pycam:: build/pymkcam::
make -C man make -C man
# install the .desktop file # install the .desktop file
install/pycam:: install/pymkcam::
# "desktop" file # "desktop" file
cp -v share/desktop/pycam.desktop `pwd`/debian/pycam/usr/share/applications/ cp -v share/desktop/pymkcam.desktop `pwd`/debian/pymkcam/usr/share/applications/
# application logo for the menu entry # application logo for the menu entry
cp -v share/ui/logo_scalable.svg `pwd`/debian/pycam/usr/share/icons/hicolor/scalable/apps/pycam.svg cp -v share/ui/logo_scalable.svg `pwd`/debian/pymkcam/usr/share/icons/hicolor/scalable/apps/pymkcam.svg
# remove "doc" directory from /usr/share/pycam/ # remove "doc" directory from /usr/share/pymkcam/
rm -rf `pwd`/debian/pycam/usr/share/pycam/doc rm -rf `pwd`/debian/pymkcam/usr/share/pymkcam/doc
# the CXF fonts are distributed by QCAD - use them instead of the embedded ones # the CXF fonts are distributed by QCAD - use them instead of the embedded ones
rm -rf `pwd`/debian/pycam/usr/share/pycam/fonts rm -rf `pwd`/debian/pymkcam/usr/share/pymkcam/fonts
# the gtkrc file for Windows is useless # the gtkrc file for Windows is useless
rm `pwd`/debian/pycam/usr/share/pycam/ui/gtkrc_windows rm `pwd`/debian/pymkcam/usr/share/pymkcam/ui/gtkrc_windows
version=3 version=3
http://sf.net/pycam/pycam-(.+)\.tar\.gz http://sf.net/pymkcam/pymkcam-(.+)\.tar\.gz
.PHONY: clean .PHONY: clean
pycam.1: ../pycam pycam.1.inc pymkcam.1: ../pymkcam pymkcam.1.inc
help2man --no-info --name="Toolpath Generation for 3-Axis CNC machining" \ help2man --no-info --name="Toolpath Generation for 3-Axis CNC machining based on MK4duo" \
--section=1 --manual="PyCAM manual" --include=pycam.1.inc --output=pycam.1 ../scripts/pycam --section=1 --manual="pyMKcam manual" --include=pymkcam.1.inc --output=pymkcam.1 ../scripts/pymkcam
clean: clean:
@rm -f pycam.1 @rm -f pymkcam.1
[EXAMPLES]
.nf
.B pycam \-\-export\-gcode=output.ngc \-\-bounds\-type=relative\-margin \-\-bounds-lower=0.1,0.05,-0.1 foo.stl
.fi
Use the default settings to process the model \fBfoo.stl\fR with an adjusted
lower margin (minx, miny, minz) of 10% (for x), 5% (for y) and \-10% (for z).
[ENVIRONMENT]
.IP PYCAM_DATA_DIR
Override the default data directory of PyCAM. This allows
you to provide customized logos, menu files or non-default sample files.
.IP PYCAM_FONT_DIR
Override the default location of engrave fonts.
.IP PYTHONPATH
You may want to define this variable in case that you installed the
\fBPyCAM\fR python package in a non-default location.
[REPORTING BUGS]
See http://sourceforge.net/tracker/?group_id=237831&atid=1104176
[SEE ALSO]
Take a look at the output of \fBpycam \-\-help\fR to get a slightly better
formatted list of options. The manual that you are reading right now is
derived from this output.
Take a look at the wiki for more information about PyCAM:
http://sourceforge.net/apps/mediawiki/pycam/
The website of the PyCAM project: http://pycam.sourceforge.net
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2008-2010 Lode Leroy
Copyright 2010-2011 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry import IDGenerator
from pycam.Geometry.PointUtils import *
from pycam.Geometry.utils import number, INFINITE, epsilon
from pycam.Geometry.intersection import intersect_cylinder_point, \
intersect_cylinder_line
import uuid
class BaseCutter(IDGenerator):
vertical = (0, 0, -1)
def __init__(self, radius, location=None, height=None):
super(BaseCutter, self).__init__()
if location is None:
location = (0, 0, 0)
if height is None:
height = 10
radius = number(radius)
self.height = number(height)
self.radius = radius
self.radiussq = radius ** 2
self.required_distance = 0
self.distance_radius = self.radius
self.distance_radiussq = self.distance_radius ** 2
self.shape = {}
self.location = location
self.moveto(self.location)
self.uuid = None
self.update_uuid()
def get_minx(self, start=None):
if start is None:
start = self.location
return start[0] - self.distance_radius
def get_maxx(self, start=None):
if start is None:
start = self.location
return start[0] + self.distance_radius
def get_miny(self, start=None):
if start is None:
start = self.location
return start[1] - self.distance_radius
def get_maxy(self, start=None):
if start is None:
start = self.location
return start[1] + self.distance_radius
def update_uuid(self):
self.uuid = uuid.uuid4()
def __repr__(self):
return "BaseCutter"
def __cmp__(self, other):
""" Compare Cutters by shape and size (ignoring the location)
This function should be overridden by subclasses, if they describe
cutters with a shape depending on more than just the radius.
See the ToroidalCutter for an example.
"""
if self.__class__ == other.__class__:
return cmp(self.radius, other.radius)
else:
# just return a string comparison
return cmp(str(self), str(other))
def set_required_distance(self, value):
if value >= 0:
self.required_distance = number(value)
self.distance_radius = self.radius + self.get_required_distance()
self.distance_radiussq = self.distance_radius * self.distance_radius
self.update_uuid()
def get_required_distance(self):
return self.required_distance
def moveto(self, location):
# "moveto" is used for collision detection calculation.
self.location = location
for shape, set_pos_func in self.shape.values():
set_pos_func(location[0], location[1], location[2])
def intersect(self, direction, triangle, start=None):
raise NotImplementedError("Inherited class of BaseCutter does not " \
+ "implement the required function 'intersect'.")
def drop(self, triangle, start=None):
if start is None:
start = self.location
# check bounding box collision
if self.get_minx(start) > triangle.maxx + epsilon:
return None
if self.get_maxx(start) < triangle.minx - epsilon:
return None
if self.get_miny(start) > triangle.maxy + epsilon:
return None
if self.get_maxy(start) < triangle.miny - epsilon:
return None
# check bounding circle collision
c = triangle.middle
if (c[0] - start[0]) ** 2 + (c[1] - start[1]) ** 2 \
> (self.distance_radiussq + 2 * self.distance_radius \
* triangle.radius + triangle.radiussq) + epsilon:
return None
return self.intersect(BaseCutter.vertical, triangle, start=start)[0]
def intersect_circle_triangle(self, direction, triangle, start=None):
(cl, ccp, cp, d) = self.intersect_circle_plane(direction, triangle,
start=start)
if cp and triangle.is_point_inside(cp):
return (cl, d, cp)
return (None, INFINITE, None)
def intersect_circle_vertex(self, direction, point, start=None):
(cl, ccp, cp, l) = self.intersect_circle_point(direction, point,
start=start)
return (cl, l, cp)
def intersect_circle_edge(self, direction, edge, start=None):
(cl, ccp, cp, l) = self.intersect_circle_line(direction, edge,
start=start)
if cp:
# check if the contact point is between the endpoints
m = pdot(psub(cp, edge.p1), edge.dir)
if (m < -epsilon) or (m > edge.len + epsilon):
return (None, INFINITE, cp)
return (cl, l, cp)
def intersect_cylinder_point(self, direction, point, start=None):
if start is None:
start = self.location
(ccp, cp, l) = intersect_cylinder_point(
padd(psub(start, self.location), self.center),
self.axis, self.distance_radius, self.distance_radiussq, direction, point)
# offset intersection
if ccp:
cl = padd(start, psub(cp, ccp))
return (cl, ccp, cp, l)
return (None, None, None, INFINITE)
def intersect_cylinder_vertex(self, direction, point, start=None):
if start is None:
start = self.location
(cl, ccp, cp, l) = self.intersect_cylinder_point(direction, point,
start=start)
if ccp and ccp[2] < padd(psub(start, self.location), self.center)[2]:
return (None, INFINITE, None)
return (cl, l, cp)
def intersect_cylinder_line(self, direction, edge, start=None):
if start is None:
start = self.location
(ccp, cp, l) = intersect_cylinder_line(
padd(psub(start, self.location), self.center),
self.axis, self.distance_radius, self.distance_radiussq, direction, edge)
# offset intersection
if ccp:
cl = padd(start, psub(cp, ccp))
return (cl, ccp, cp, l)
return (None, None, None, INFINITE)
def intersect_cylinder_edge(self, direction, edge, start=None):
if start is None:
start = self.location
(cl, ccp, cp, l) = self.intersect_cylinder_line(direction, edge,
start=start)
if not ccp:
return (None, INFINITE, None)
m = pdot(psub(cp, edge.p1), edge.dir)
if (m < -epsilon) or (m > edge.len + epsilon):
return (None, INFINITE, None)
if ccp[2] < padd(psub(start, self.location), self.center)[2]:
return (None, INFINITE, None)
return (cl, l, cp)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
__all__ = [ "SphericalCutter", "CylindricalCutter", "ToroidalCutter",
"BaseCutter" ]
from pycam.Cutters.BaseCutter import BaseCutter
from pycam.Cutters.SphericalCutter import SphericalCutter
from pycam.Cutters.CylindricalCutter import CylindricalCutter
from pycam.Cutters.ToroidalCutter import ToroidalCutter
def get_tool_from_settings(tool_settings, height=None):
""" get the tool specified by the relevant settings
The settings must include:
- "shape": one of "SphericalCutter", "CylindricalCutter" and
"ToroidalCutter"
- "radius": the tool radius
The following settings are optional or shape specific:
- "torus_radius": necessary for ToroidalCutter
@type tool_settings: dict
@value tool_settings: contains the attributes of the tool
@type height: float
@value height: the height of the tool
@rtype: BaseCutter | basestring
@return: a tool object or an error string
"""
cuttername = tool_settings["shape"]
radius = tool_settings["tool_radius"]
if cuttername == "SphericalCutter":
return SphericalCutter(radius, height=height)
elif cuttername == "CylindricalCutter":
return CylindricalCutter(radius, height=height)
elif cuttername == "ToroidalCutter":
toroid = tool_settings["torus_radius"]
return ToroidalCutter(radius, toroid, height=height)
else:
return "Invalid cutter shape: '%s' is not known" % str(cuttername)
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import os
class EMCToolExporter(object):
def __init__(self, tools):
""" tools are expected to be dictionaries containing the following keys:
- id
- radius
- name
"""
self.tools = tools
def get_tool_definition_string(self):
result = []
tools = list(self.tools)
tools.sort(key=lambda item: item["id"])
#result.append(self.HEADER_ROW)
for tool in tools:
# use an arbitrary length
tool_length = tool["radius"] * 10
line = "T%d P%d D%f Z-%f ;%s" % (tool["id"], tool["id"],
2 * tool["radius"], tool_length, tool["name"])
result.append(line)
# add the dummy line for the "last" tool
result.append("T99999 P99999 Z+0.100000 ;dummy tool")
return os.linesep.join(result)
# -*- coding: utf-8 -*-
"""
Copyright 2012 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import os
import pycam.Exporters.GCode
from pycam.Toolpath import CORNER_STYLE_EXACT_PATH, CORNER_STYLE_EXACT_STOP, \
CORNER_STYLE_OPTIMIZE_SPEED, CORNER_STYLE_OPTIMIZE_TOLERANCE
DEFAULT_HEADER = (("G40", "disable tool radius compensation"),
("G49", "disable tool length compensation"),
("G80", "cancel modal motion"),
("G54", "select coordinate system 1"),
("G90", "disable incremental moves"))
DEFAULT_DIGITS = 6
def _render_number(number):
if int(number) == number:
return "%d" % number
else:
return ("%%.%df" % DEFAULT_DIGITS) % number
class LinuxCNC(pycam.Exporters.GCode.BaseGenerator):
def add_header(self):
for command, comment in DEFAULT_HEADER:
self.add_command(command, comment=comment)
# TODO: use a "unit" filter
if True:
self.add_command("G21", "metric")
else:
self.add_command("G20", "imperial")
def add_footer(self):
self.add_command("M2", "end program")
def add_comment(self, comment):
self.add_command("; %s" % comment)
def add_command(self, command, comment=None):
self.destination.write(command)
if comment:
self.destination.write("\t")
self.add_comment(comment)
else:
self.destination.write(os.linesep)
def add_move(self, coordinates, is_rapid=False):
components = []
# the cached value may be:
# True: the last move was G0
# False: the last move was G1
# None: some non-move happened before
if self._get_cache("rapid_move", None) != is_rapid:
components.append("G0" if is_rapid else "G1")
else:
# improve gcode style
components.append(" ")
axes = [axis for axis in "XYZABCUVW"]
previous = self._get_cache("position", [None] * len(coordinates))
for (axis, value, last) in zip(axes, coordinates, previous):
if (last is None) or (last != value):
components.append("%s%.6f" % (axis, value))
command = " ".join(components)
if command.strip():
self.add_command(command)
def command_feedrate(self, feedrate):
self.add_command("F%s" % _render_number(feedrate), "set feedrate")
def command_select_tool(self, tool_id):
self.add_command("T%d M6" % tool_id, "select tool")
def command_spindle_speed(self, speed):
self.add_command("S%s" % _render_number(speed), "set spindle speed")
def command_spindle_enabled(self, state):
if state:
self.add_command("M3", "start spindle")
else:
self.add_command("M5", "stop spindle")
def command_delay(self, seconds):
self.add_command("G04 P%d" % seconds, "wait for %d seconds" % seconds)
def command_corner_style(self,
(path_mode, motion_tolerance, naive_tolerance)):
if path_mode == CORNER_STYLE_EXACT_PATH:
self.add_command("G61", "exact path mode")
elif path_mode == CORNER_STYLE_EXACT_STOP:
self.add_command("G61.1", "exact stop mode")
elif path_mode == CORNER_STYLE_OPTIMIZE_SPEED:
self.add_command("G64", "continuous mode with maximum speed")
else:
if not naive_tolerance:
self.add_command("G64 P%f" % motion_tolerance,
"continuous mode with tolerance")
else:
self.add_command("G64 P%f Q%f" % \
(motion_tolerance, naive_tolerance),
"continuous mode with tolerance and cleanup")
# -*- coding: utf-8 -*-
"""
Copyright 2012 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import decimal
import os
import pycam.Utils.log
import pycam.Toolpath.Filters
from pycam.Toolpath import MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID, \
MACHINE_SETTING, COMMENT
_log = pycam.Utils.log.get_logger()
class BaseGenerator(object):
def __init__(self, destination):
if isinstance(destination, basestring):
# open the file
self.destination = file(destination,"w")
self._close_stream_on_exit = True
else:
# assume that "destination" is something like a StringIO instance
# or an open file
self.destination = destination
# don't close the stream if we did not open it on our own
self._close_stream_on_exit = False
self._filters = []
self._cache = {}
self.add_header()
def _get_cache(self, key, default_value):
return self._cache.get(key, default_value)
def add_filters(self, filters):
self._filters.extend(filters)
self._filters.sort()
def add_comment(self, comment):
raise NotImplementedError("someone forgot to implement 'add_comment'")
def add_command(self, command, comment=None):
raise NotImplementedError("someone forgot to implement 'add_command'")
def add_move(self, coordinates, is_rapid=False):
raise NotImplementedError("someone forgot to implement 'add_move'")
def add_footer(self):
raise NotImplementedError("someone forgot to implement 'add_footer'")
def finish(self):
self.add_footer()
if self._close_stream_on_exit:
self.destination.close()
def add_moves(self, moves, filters=None):
# combine both lists/tuples in a type-agnostic way
all_filters = list(self._filters)
if filters:
all_filters.extend(filters)
filtered_moves = pycam.Toolpath.Filters.get_filtered_moves(moves,
all_filters)
for move_type, args in filtered_moves:
if move_type in (MOVE_STRAIGHT, MOVE_STRAIGHT_RAPID):
is_rapid = move_type == MOVE_STRAIGHT_RAPID
self.add_move(args, is_rapid)
self._cache["position"] = args
self._cache["rapid_move"] = is_rapid
elif move_type == COMMENT:
self.add_comment(args)
elif move_type == MACHINE_SETTING:
key, value = args
func_name = "command_%s" % key
if hasattr(self, func_name):
_log.debug("GCode: machine setting '%s': %s" % (key, value))
getattr(self, func_name)(value)
self._cache[key] = value
self._cache["rapid_move"] = None
else:
_log.warn("The current GCode exporter does not support " + \
"the machine setting '%s=%s' -> ignore" % (key, value))
else:
_log.warn(("A non-basic toolpath item (%d -> %s) remained in the " + \
"queue -> ignore") % (move_type, args))
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam import VERSION
from pycam.Geometry.PointUtils import pnormalized
import datetime
import os
class STLExporter(object):
def __init__(self, model, name="model", created_by="pycam", linesep=None,
**kwargs):
self.model = model
self.name = name
self.created_by = created_by
if linesep is None:
self.linesep = os.linesep
else:
self.linesep = linesep
def __str__(self):
return self.linesep.join(self.get_output_lines)
def write(self, stream):
for line in self.get_output_lines():
stream.write(line)
stream.write(self.linesep)
def get_output_lines(self):
date = datetime.date.today().isoformat()
yield """solid "%s"; Produced by %s (v%s), %s""" \
% (self.name, self.created_by, VERSION, date)
for triangle in self.model.triangles():
norm = pnormalized(triangle.normal)
yield "facet normal %f %f %f" % (norm[0], norm[1], norm[2])
yield " outer loop"
# Triangle vertices are stored in clockwise order - thus we need
# to reverse the order (STL expects counter-clockwise orientation).
for point in (triangle.p1, triangle.p3, triangle.p2):
yield " vertex %f %f %f" % (point[0], point[1], point[2])
yield " endloop"
yield "endfacet"
yield "endsolid"
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
# Inkscape uses a fixed resolution of 90 dpi
SVG_OUTPUT_DPI = 90
class SVGExporter(object):
def __init__(self, output, unit="mm", maxx=None, maxy=None):
if isinstance(output, basestring):
# a filename was given
self.output = file(output,"w")
else:
# a stream was given
self.output = output
if unit == "mm":
dots_per_px = SVG_OUTPUT_DPI / 25.4
else:
dots_per_px = SVG_OUTPUT_DPI
if maxx is None:
width = 640
else:
width = dots_per_px * maxx
if width <= 0:
width = 640
if maxy is None:
height = 800
else:
height = dots_per_px * maxy
if height <= 0:
height = 800
self.output.write("""<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' width='%f' height='%f'>
<g transform='translate(0,%f) scale(%.10f)' stroke-width='0.05' font-size='0.2'>
""" % (width, height, height, dots_per_px))
self._fill = 'none'
self._stroke = 'black'
def close(self, close_stream=True):
self.output.write("""</g>
</svg>
""")
if close_stream:
self.output.close()
def stroke(self, stroke):
self._stroke = stroke
def fill(self, fill):
self._fill = fill
def AddDot(self, x, y):
l = "<circle fill='" + self._fill +"'" + (" cx='%g'" % x) \
+ (" cy='%g'" % -y) + " r='0.04'/>\n"
self.output.write(l)
def AddText(self, x, y, text):
l = "<text fill='" + self._fill +"'" + (" x='%g'" % x) \
+ (" y='%g'" % -y) + " dx='0.07'>" + text + "</text>\n"
self.output.write(l)
def AddLine(self, x1, y1, x2, y2):
l = "<line fill='" + self._fill +"' stroke='" + self._stroke + "'" \
+ (" x1='%.8f'" % x1) + (" y1='%.8f'" % -y1) + (" x2='%.8f'" % x2) \
+ (" y2='%.8f'" % -y2) + " />\n"
self.output.write(l)
def AddPoint(self, p):
self.AddDot(p[0], p[1])
def AddPath(self, path):
self.AddLines(path.points)
def AddLines(self, points):
l = "<path fill='" + self._fill +"' stroke='" + self._stroke + "' d='"
for i in range(0, len(points)):
p = points[i]
if i == 0:
l += "M "
else:
l += " L "
l += "%.8f %.8f" % (p[0], -p[1])
l += "'/>\n"
self.output.write(l)
def AddPathList(self, pathlist):
for path in pathlist:
self.AddPath(path)
#TODO: we need to create a unified "Exporter" interface and base class
class SVGExporterContourModel(object):
def __init__(self, model, unit="mm", **kwargs):
self.model = model
self.unit = unit
def write(self, stream):
writer = SVGExporter(stream, unit=self.unit, maxx=self.model.maxx,
maxy=self.model.maxy)
for polygon in self.model.get_polygons():
points = polygon.get_points()
if polygon.is_closed:
points.append(points[0])
writer.AddLines(points)
writer.close(close_stream=False)
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
__all__ = [ "GCodeExporter", "SVGExporter", "STLExporter", "EMCToolExporter"]
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2008-2010 Lode Leroy
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry import TransformableContainer
from pycam.Geometry.Model import ContourModel
from pycam.Geometry.Line import Line
from pycam.Geometry.PointUtils import *
TEXT_ALIGN_LEFT = 0
TEXT_ALIGN_CENTER = 1
TEXT_ALIGN_RIGHT = 2
class Letter(TransformableContainer):
def __init__(self, lines):
self.lines = lines
def minx(self):
return min([line.minx for line in self.lines])
def maxx(self):
return max([line.maxx for line in self.lines])
def miny(self):
return min([line.miny for line in self.lines])
def maxy(self):
return max([line.maxy for line in self.lines])
def get_positioned_lines(self, base_point, skew=None):
result = []
get_skewed_point = lambda p: (base_point[0] + p[0] + (p[1] * skew / 100.0), base_point[1] + p[1], base_point[2])
for line in self.lines:
skewed_p1 = get_skewed_point(line.p1)
skewed_p2 = get_skewed_point(line.p2)
# Some triplex fonts contain zero-length lines
# (e.g. "/" in italict.cxf). Ignore these.
if skewed_p1 != skewed_p2:
new_line = Line(skewed_p1, skewed_p2)
result.append(new_line)
return result
class Charset(object):
def __init__(self, name=None, author=None, letterspacing=3.0,
wordspacing=6.75, linespacingfactor=1.0, encoding=None):
self.letters = {}
self.letterspacing = letterspacing
self.wordspacing = wordspacing
self.linespacingfactor = linespacingfactor
self.default_linespacing = 1.6
self.default_height = 10.0
if name is None:
self.names = []
else:
if isinstance(name, (list, set, tuple)):
self.names = name
else:
self.names = [name]
if author is None:
self.authors = []
else:
if isinstance(author, (list, set, tuple)):
self.authors = author
else:
self.authors = [author]
if encoding is None:
self.encoding = "iso-8859-1"
else:
self.encoding = encoding
def add_character(self, character, lines):
if len(lines) > 0:
self.letters[character] = Letter(lines)
def get_names(self):
return self.names
def get_authors(self):
return self.authors
def render(self, text, origin=None, skew=0, line_spacing=1.0, pitch=1.0,
align=None):
result = ContourModel()
if origin is None:
origin = (0, 0, 0)
if align is None:
align = TEXT_ALIGN_LEFT
base = origin
letter_spacing = self.letterspacing * pitch
word_spacing = self.wordspacing * pitch
line_factor = self.default_linespacing * self.linespacingfactor \
* line_spacing
for line in text.splitlines():
current_line = ContourModel()
line_height = self.default_height
for character in line:
if character == " ":
base = padd(base, (word_spacing, 0, 0))
elif character in self.letters.keys():
charset_letter = self.letters[character]
new_model = ContourModel()
for line in charset_letter.get_positioned_lines(base,
skew=skew):
new_model.append(line, allow_reverse=True)
for polygon in new_model.get_polygons():
# add polygons instead of lines -> more efficient
current_line.append(polygon)
# update line height
line_height = max(line_height, charset_letter.maxy())
# shift the base position
base = padd(base, (charset_letter.maxx() + letter_spacing, 0, 0))
else:
# unknown character - add a small whitespace
base = padd(base, (letter_spacing, 0, 0))
# go to the next line
base = (origin[0], base[1] - line_height * line_factor, origin[2])
if not current_line.maxx is None:
if align == TEXT_ALIGN_CENTER:
current_line.shift(-current_line.maxx / 2, 0, 0)
elif align == TEXT_ALIGN_RIGHT:
current_line.shift(-current_line.maxx, 0, 0)
else:
# left align
if current_line.minx != 0:
current_line.shift(-current_line.minx, 0, 0)
for polygon in current_line.get_polygons():
result.append(polygon)
# the text should be just above the x axis
if result.miny:
# don't shift, if result.miny is None (e.g.: no content) or zero
result.shift(0, -result.miny, 0)
return result
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
# various matrix related functions for PyCAM
from pycam.Geometry.PointUtils import *
from pycam.Geometry.utils import sqrt, number, epsilon
import math
TRANSFORMATIONS = {
"normal": ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0)),
"x": ((1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0)),
"y": ((0, 0, -1, 0), (0, 1, 0, 0), (1, 0, 0, 0)),
"z": ((0, 1, 0, 0), (-1, 0, 0, 0), (0, 0, 1, 0)),
"x_swap_y": ((0, 1, 0, 0), (1, 0, 0, 0), (0, 0, 1, 0)),
"x_swap_z": ((0, 0, 1, 0), (0, 1, 0, 0), (1, 0, 0, 0)),
"y_swap_z": ((1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0)),
"xy_mirror": ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, -1, 0)),
"xz_mirror": ((1, 0, 0, 0), (0, -1, 0, 0), (0, 0, 1, 0)),
"yz_mirror": ((-1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0)),
}
def get_dot_product(a, b):
""" calculate the dot product of two 3d vectors
@type a: tuple(float) | list(float)
@value a: the first vector to be multiplied
@type b: tuple(float) | list(float)
@value b: the second vector to be multiplied
@rtype: float
@return: the dot product is (a0*b0 + a1*b1 + a2*b2)
"""
return sum(l1 * l2 for l1, l2 in zip(a, b))
def get_length(vector):
""" calculate the lengt of a 3d vector
@type vector: tuple(float) | list(float)
@value vector: the given 3d vector
@rtype: float
@return: the length of a vector is the square root of the dot product
of the vector with itself
"""
return sqrt(get_dot_product(vector, vector))
def get_rotation_matrix_from_to(v_orig, v_dest):
""" calculate the rotation matrix used to transform one vector into another
The result is useful for modifying the rotation matrix of a 3d object.
See the "extend_shape" code in each of the cutter classes (for ODE).
The simplest example is the following with the original vector pointing
along the x axis, while the destination vectors goes along the y axis:
get_rotation_matrix((1, 0, 0), (0, 1, 0))
Basically this describes a rotation around the z axis by 90 degrees.
The resulting 3x3 matrix (tuple of tuple of floats) can be multiplied with
any other vector to rotate it in the same way around the z axis.
@type v_orig: tuple(float) | list(float) | pycam.Geometry.Point
@value v_orig: the original 3d vector
@type v_dest: tuple(float) | list(float) | pycam.Geometry.Point
@value v_dest: the destination 3d vector
@rtype: tuple(tuple(float))
@return: the roation matrix (3x3)
"""
v_orig_length = get_length(v_orig)
v_dest_length = get_length(v_dest)
cross_product = get_length(pcross(v_orig, v_dest))
try:
arcsin = cross_product / (v_orig_length * v_dest_length)
except ZeroDivisionError:
return None
# prevent float inaccuracies to crash the calculation (within limits)
if 1 < arcsin < 1 + epsilon:
arcsin = 1.0
elif -1 - epsilon < arcsin < -1:
arcsin = -1.0
rot_angle = math.asin(arcsin)
# calculate the rotation axis
# The rotation axis is equal to the cross product of the original and
# destination vectors.
rot_axis = pnormalized((v_orig[1] * v_dest[2] - v_orig[2] * v_dest[1],
v_orig[2] * v_dest[0] - v_orig[0] * v_dest[2],
v_orig[0] * v_dest[1] - v_orig[1] * v_dest[0]))
if not rot_axis:
return None
# get the rotation matrix
# see http://www.fastgraph.com/makegames/3drotation/
c = math.cos(rot_angle)
s = math.sin(rot_angle)
t = 1 - c
return ((t * rot_axis[0] * rot_axis[0] + c,
t * rot_axis[0] * rot_axis[1] - s * rot_axis[2],
t * rot_axis[0] * rot_axis[2] + s * rot_axis[1]),
(t * rot_axis[0] * rot_axis[1] + s * rot_axis[2],
t * rot_axis[1] * rot_axis[1] + c,
t * rot_axis[1] * rot_axis[2] - s * rot_axis[0]),
(t * rot_axis[0] * rot_axis[2] - s * rot_axis[1],
t * rot_axis[1] * rot_axis[2] + s * rot_axis[0],
t * rot_axis[2] * rot_axis[2] + c))
def get_rotation_matrix_axis_angle(rot_axis, rot_angle, use_radians=True):
""" calculate rotation matrix for a normalized vector and an angle
see http://mathworld.wolfram.com/RotationMatrix.html
@type rot_axis: tuple(float)
@value rot_axis: the vector describes the rotation axis. Its length should
be 1.0 (normalized).
@type rot_angle: float
@value rot_angle: rotation angle (radiant)
@rtype: tuple(tuple(float))
@return: the roation matrix (3x3)
"""
if not use_radians:
rot_angle *= math.pi / 180
sin = number(math.sin(rot_angle))
cos = number(math.cos(rot_angle))
return ((cos + rot_axis[0]*rot_axis[0]*(1-cos),
rot_axis[0]*rot_axis[1]*(1-cos) - rot_axis[2]*sin,
rot_axis[0]*rot_axis[2]*(1-cos) + rot_axis[1]*sin),
(rot_axis[1]*rot_axis[0]*(1-cos) + rot_axis[2]*sin,
cos + rot_axis[1]*rot_axis[1]*(1-cos),
rot_axis[1]*rot_axis[2]*(1-cos) - rot_axis[0]*sin),
(rot_axis[2]*rot_axis[0]*(1-cos) - rot_axis[1]*sin,
rot_axis[2]*rot_axis[1]*(1-cos) + rot_axis[0]*sin,
cos + rot_axis[2]*rot_axis[2]*(1-cos)))
def multiply_vector_matrix(v, m):
""" Multiply a 3d vector with a 3x3 matrix. The result is a 3d vector.
@type v: tuple(float) | list(float)
@value v: a 3d vector as tuple or list containing three floats
@type m: tuple(tuple(float)) | list(list(float))
@value m: a 3x3 list/tuple of floats
@rtype: tuple(float)
@return: a tuple of 3 floats as the matrix product
"""
if len(m) == 9:
m = [number(value) for value in m]
m = ((m[0], m[1], m[2]), (m[3], m[4], m[5]), (m[6], m[7], m[8]))
else:
new_m = []
for column in m:
new_m.append([number(value) for value in column])
v = [number(value) for value in v]
return (v[0] * m[0][0] + v[1] * m[0][1] + v[2] * m[0][2],
v[0] * m[1][0] + v[1] * m[1][1] + v[2] * m[1][2],
v[0] * m[2][0] + v[1] * m[2][1] + v[2] * m[2][2])
def multiply_matrix_matrix(m1, m2):
def multi(row1, col2):
return (m1[row1][0] * m2[0][col2] + m1[row1][1] * m2[1][col2] \
+ m1[row1][2] * m2[2][col2])
return ((multi(0, 0), multi(0, 1), multi(0, 2)),
(multi(1, 0), multi(1, 1), multi(1, 2)),
(multi(2, 0), multi(2, 1), multi(2, 2)))
def get_inverse_matrix(m):
_a = m[1][1] * m[2][2] - m[1][2] * m[2][1]
_b = m[0][2] * m[2][1] - m[0][1] * m[2][2]
_c = m[0][1] * m[1][2] - m[0][2] * m[1][1]
_d = m[1][2] * m[2][0] - m[1][0] * m[2][2]
_e = m[0][0] * m[2][2] - m[0][2] * m[2][0]
_f = m[0][2] * m[1][0] - m[0][0] * m[1][2]
_g = m[1][0] * m[2][1] - m[1][1] * m[2][0]
_h = m[0][1] * m[2][0] - m[0][0] * m[2][1]
_k = m[0][0] * m[1][1] - m[0][1] * m[1][0]
det = m[0][0] * _a + m[0][1] * _d + m[0][2] * _g
if det == 0:
return None
else:
return ((_a / det, _b / det, _c / det),
(_d / det, _e / det, _f / det),
(_g / det, _h / det, _k / det))
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
""" the points of a path are only used for describing coordinates. Thus we
don't really need complete "Point" instances that consume a lot of memory.
Since python 2.6 the "namedtuple" factory is available.
This reduces the memory consumption of a toolpath down to 1/3.
"""
try:
# this works for python 2.6 or above (saves memory)
# TODO: disabled for now - check if we could enable it later ...
import INVALID_IMPORT
from collections import namedtuple
tuple_point = namedtuple("TuplePoint", "x y z")
get_point_object = lambda point: tuple_point(point[0], point[1], point[2])
except ImportError:
# dummy for python < v2.6 (consumes more memory)
get_point_object = lambda point: point
from pycam.Geometry import IDGenerator
class Path(IDGenerator):
def __init__(self):
super(Path, self).__init__()
self.top_join = None
self.bot_join = None
self.winding = 0
self.points = []
def __repr__(self):
text = ""
text += "path %d: " % self.id
first = True
for point in self.points:
if first:
first = False
else:
text += "-"
text += "%d(%g,%g,%g)" % (id(point), point[0], point[1], point[2])
return text
def insert(self, index, point):
self.points.insert(index, get_point_object(point))
def append(self, point):
self.points.append(get_point_object(point))
def reverse(self):
self.points.reverse()
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2008-2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry import TransformableContainer, IDGenerator
from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry.PointUtils import *
# "Line" is imported later to avoid circular imports
#from pycam.Geometry.Line import Line
class Plane(IDGenerator, TransformableContainer):
__slots__ = ["id", "p", "n"]
def __init__(self, point, normal=None):
super(Plane, self).__init__()
if normal is None:
normal = (0, 0, 1, 'v')
self.p = point
self.n = normal
if not len(self.n) > 3:
self.n = (self.n[0], self.n[1], self.n[2], 'v')
def __repr__(self):
return "Plane<%s,%s>" % (self.p, self.n)
def __cmp__(self, other):
if self.__class__ == other.__class__:
if self.p == other.p:
return cmp(self.n, other.n)
else:
return cmp(self.p, other.p)
else:
return cmp(str(self), str(other))
def copy(self):
return self.__class__(self.p, self.n)
def next(self):
yield "p"
yield "n"
def get_children_count(self):
# a plane always consists of two points
return 2
def reset_cache(self):
# we need to prevent the "normal" from growing
norm = pnormalized(self.n)
if norm:
self.n = norm
def intersect_point(self, direction, point):
if (not direction is None) and (pnorm(direction) != 1):
# calculations will go wrong, if the direction is not a unit vector
direction = pnormalized(direction)
if direction is None:
return (None, INFINITE)
denom = pdot(self.n, direction)
if denom == 0:
return (None, INFINITE)
l = -(pdot(self.n, point) - pdot(self.n, self.p)) / denom
cp = padd(point, pmul(direction, l))
return (cp, l)
def intersect_triangle(self, triangle, counter_clockwise=False):
""" Returns the line of intersection of a triangle with a plane.
"None" is returned, if:
- the triangle does not intersect with the plane
- all vertices of the triangle are on the plane
The line always runs clockwise through the triangle.
"""
# don't import Line in the header -> circular import
from pycam.Geometry.Line import Line
collisions = []
for edge, point in ((triangle.e1, triangle.p1),
(triangle.e2, triangle.p2),
(triangle.e3, triangle.p3)):
cp, l = self.intersect_point(edge.dir, point)
# filter all real collisions
# We don't want to count vertices double -> thus we only accept
# a distance that is lower than the length of the edge.
if (not cp is None) and (-epsilon < l < edge.len - epsilon):
collisions.append(cp)
elif (cp is None) and (pdot(self.n, edge.dir) == 0):
cp, dist = self.intersect_point(self.n, point)
if abs(dist) < epsilon:
# the edge is on the plane
collisions.append(point)
if len(collisions) == 3:
# All points of the triangle are on the plane.
# We don't return a waterline, as there should be another non-flat
# triangle with the same waterline.
return None
if len(collisions) == 2:
collision_line = Line(collisions[0], collisions[1])
# no further calculation, if the line is zero-sized
if collision_line.len == 0:
return collision_line
cross = pcross(self.n, collision_line.dir)
if (pdot(cross, triangle.normal) < 0) == bool(not counter_clockwise):
# anti-clockwise direction -> revert the direction of the line
collision_line = Line(collision_line.p2, collision_line.p1)
return collision_line
elif len(collisions) == 1:
# only one point is on the plane
# This waterline (with zero length) should be of no use.
return None
else:
return None
def get_point_projection(self, point):
return self.intersect_point(self.n, point)[0]
def get_line_projection(self, line):
# don't import Line in the header -> circular import
from pycam.Geometry.Line import Line
proj_p1 = self.get_point_projection(line.p1)
proj_p2 = self.get_point_projection(line.p2)
return Line(proj_p1, proj_p2)
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.utils import epsilon
from pycam.Geometry.kdtree import Node, kdtree
class PointKdtree(kdtree):
__slots__ = ["_n", "tolerance"]
def __init__(self, points=None, cutoff=5, cutoff_distance=0.5,
tolerance=epsilon):
if points is None:
points = []
self._n = None
self.tolerance = tolerance
nodes = []
for p in points:
n = Node(p, p)
nodes.append(n)
kdtree.__init__(self, nodes, cutoff, cutoff_distance)
def dist(self, n1, n2):
dx = n1.bound[0]-n2.bound[0]
dy = n1.bound[1]-n2.bound[1]
dz = n1.bound[2]-n2.bound[2]
return dx*dx+dy*dy+dz*dz
def Point(self, x, y, z):
if self._n:
n = self._n
n.bound = (x, y, z)
else:
n = Node(None, (x, y, z))
(nn, dist) = self.nearest_neighbor(n, self.dist)
if nn and (dist < self.tolerance):
self._n = n
return nn.obj
else:
n.obj = (x, y, z)
self._n = None
self.insert(n)
return n.obj
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry.utils import epsilon, sqrt, number
def pnorm(a):
return sqrt(pdot(a,a))
def pnormsq(a):
return pdot(a,a)
def pdist(a, b, axes=None):
return sqrt(pdist_sq(a, b, axes=axes))
def pdist_sq(a, b, axes=None):
if axes is None:
axes = (0, 1, 2)
return sum([(a[index] - b[index]) ** 2 for index in axes])
def pnear(a, b, axes=None):
return pcmp(a, b, axes=axes) == 0
def pcmp(a, b, axes=None):
""" Two points are equal if all dimensions are identical.
Otherwise the result is based on the individual x/y/z comparisons.
"""
if axes is None:
axes = (0, 1, 2)
for axis in axes:
if abs(a[axis] - b[axis]) > epsilon:
return cmp(a[axis], b[axis])
# both points are at the same position
return 0
def ptransform_by_matrix(a, matrix):
if len(a) > 3:
return (a[0] * matrix[0][0] + a[1] * matrix[0][1] + a[2] * matrix[0][2],
a[0] * matrix[1][0] + a[1] * matrix[1][1] + a[2] * matrix[1][2],
a[0] * matrix[2][0] + a[1] * matrix[2][1] + a[2] * matrix[2][2]) + a[3:]
else:
# accept 3x4 matrices as well as 3x3 matrices
offsets = []
for column in matrix:
if len(column) < 4:
offsets.append(0)
else:
offsets.append(column[3])
return (a[0] * matrix[0][0] + a[1] * matrix[0][1] + a[2] * matrix[0][2] + offsets[0],
a[0] * matrix[1][0] + a[1] * matrix[1][1] + a[2] * matrix[1][2] + offsets[1],
a[0] * matrix[2][0] + a[1] * matrix[2][1] + a[2] * matrix[2][2] + offsets[2])
def pmul(a, c):
c = number(c)
return (a[0] * c, a[1] * c, a[2] * c)
def pdiv(a, c):
c = number(c)
return (a[0] / c, a[1] / c, a[2] / c)
def padd(a, b):
return (a[0] + b[0], a[1] + b[1], a[2] + b[2])
def psub(a, b):
return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
def pdot(a, b):
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
def pcross(a, b):
return (a[1] * b[2] - b[1] * a[2], b[0] * a[2] - a[0] * b[2], a[0] * b[1] - b[0] * a[1])
def pnormalized(a):
n = pnorm(a)
if n == 0:
return None
else:
return (a[0] / n, a[1] / n, a[2] / n) + a[3:]
def pis_inside(a, minx=None, maxx=None, miny=None, maxy=None, minz=None, maxz=None):
return ((minx is None) or (minx - epsilon <= a[0])) \
and ((maxx is None) or (a[0] <= maxx + epsilon)) \
and ((miny is None) or (miny - epsilon <= a[1])) \
and ((maxy is None) or (a[1] <= maxy + epsilon)) \
and ((minz is None) or (minz - epsilon <= a[2])) \
and ((maxz is None) or (a[2] <= maxz + epsilon))
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2008 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import decimal
import math
INFINITE = 100000
epsilon = 0.00001
# use the "decimal" module for fixed precision numbers (only for debugging)
_use_precision = False
# the lambda functions below are more efficient than function definitions
if _use_precision:
ceil = lambda value: int((value + number(1).next_minus()) // 1)
else:
ceil = lambda value: int(math.ceil(value))
# return "0" for "-epsilon < value < 0" (to work around floating inaccuracies)
# otherwise: return the sqrt function of the current type (could even raise
# exceptions)
if _use_precision:
sqrt = lambda value: (((value < -epsilon) or (value > 0)) and \
value.sqrt()) or 0
else:
sqrt = lambda value: (((value < -epsilon) or (value > 0)) and \
math.sqrt(value)) or 0
if _use_precision:
number = lambda value: decimal.Decimal(str(value))
else:
number = float
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2008 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
__all__ = ["common", "Console", "OpenGLTools", "Project", "Settings",
"Vizualisation"]
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment