Switched resource compilation over to PySide and added an execute keybinding.

This commit is contained in:
Jeremy Mack Wright 2018-03-10 23:06:30 -05:00
parent ec311d36d4
commit c23e237bad
28 changed files with 1396 additions and 680 deletions

View File

@ -136,7 +136,7 @@ class CadQueryExecuteScript:
def GetResources(self):
return {"MenuText": "Execute Script",
"Accel": "F2",
"Accel": Settings.execute_keybinding,
"ToolTip": "Executes the CadQuery script",
"Pixmap": ":/icons/media-playback-start.svg"}

View File

@ -2,282 +2,16 @@
# Resource object code
#
# Created by: The Resource Compiler for PyQt4 (Qt v4.8.7)
# Created: Sat Mar 10 22:53:44 2018
# by: The Resource Compiler for PySide (Qt v4.8.4)
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore
qt_resource_data = "\
\x00\x00\x0f\x7d\
\x3c\
\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\
\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\
\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\
\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\
\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\
\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\
\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\
\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\
\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\
\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\
\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\
\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\
\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\
\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\
\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\
\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\
\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\
\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\
\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\
\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\
\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\
\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\
\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\
\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x32\x36\
\x2e\x37\x33\x31\x31\x31\x35\x6d\x6d\x22\x0a\x20\x20\x20\x68\x65\
\x69\x67\x68\x74\x3d\x22\x32\x34\x2e\x33\x37\x35\x35\x35\x39\x6d\
\x6d\x22\x0a\x20\x20\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\
\x20\x30\x20\x39\x34\x2e\x37\x31\x36\x35\x35\x20\x38\x36\x2e\x33\
\x37\x30\x30\x39\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\
\x35\x34\x39\x35\x22\x0a\x20\x20\x20\x76\x65\x72\x73\x69\x6f\x6e\
\x3d\x22\x31\x2e\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x39\x31\
\x20\x72\x31\x33\x37\x32\x35\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\
\x70\x6f\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x63\x61\
\x64\x71\x75\x65\x72\x79\x5f\x6c\x6f\x67\x6f\x5f\x64\x61\x72\x6b\
\x2e\x73\x76\x67\x22\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\
\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x35\x34\x39\x37\
\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\
\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\
\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\
\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\
\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\
\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\
\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\
\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\
\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\
\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x34\x2e\x33\x37\x30\x39\x33\x36\
\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\
\x3a\x63\x78\x3d\x22\x34\x37\x2e\x33\x35\x38\x32\x37\x35\x22\x0a\
\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\
\x3d\x22\x34\x33\x2e\x31\x38\x35\x30\x34\x35\x22\x0a\x20\x20\x20\
\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\
\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\
\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\
\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\
\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\x72\x69\
\x64\x3d\x22\x66\x61\x6c\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x66\
\x69\x74\x2d\x6d\x61\x72\x67\x69\x6e\x2d\x74\x6f\x70\x3d\x22\x30\
\x22\x0a\x20\x20\x20\x20\x20\x66\x69\x74\x2d\x6d\x61\x72\x67\x69\
\x6e\x2d\x6c\x65\x66\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\
\x66\x69\x74\x2d\x6d\x61\x72\x67\x69\x6e\x2d\x72\x69\x67\x68\x74\
\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x66\x69\x74\x2d\x6d\x61\
\x72\x67\x69\x6e\x2d\x62\x6f\x74\x74\x6f\x6d\x3d\x22\x30\x22\x0a\
\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\
\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x38\x35\x35\
\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\
\x30\x35\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x36\x35\x22\
\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\
\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x32\x34\x22\x0a\x20\x20\x20\
\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\
\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\
\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\
\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\
\x35\x35\x30\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\
\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\
\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\
\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\
\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\
\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\
\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\
\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\
\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\
\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\
\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\
\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\
\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\
\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\
\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\
\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\
\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\
\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\
\x72\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\
\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\
\x72\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\x74\x65\x28\x2d\x32\
\x38\x34\x2e\x30\x37\x30\x33\x2c\x2d\x34\x37\x37\x2e\x37\x34\x38\
\x35\x39\x29\x22\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\
\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\
\x75\x72\x65\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\
\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x32\x39\x38\x30\
\x62\x39\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\
\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x65\x76\x65\x6e\
\x6f\x64\x64\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x32\x39\x38\x30\
\x62\x39\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\
\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\
\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\
\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\
\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x22\x0a\x20\x20\
\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x32\x38\x35\x2e\x35\x37\
\x30\x33\x2c\x34\x37\x39\x2e\x32\x34\x38\x35\x39\x20\x39\x31\x2e\
\x37\x31\x36\x35\x35\x2c\x30\x20\x30\x2c\x38\x33\x2e\x33\x37\x30\
\x30\x39\x20\x2d\x39\x31\x2e\x37\x31\x36\x35\x35\x2c\x30\x20\x7a\
\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\
\x68\x34\x32\x36\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x67\
\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\
\x6f\x6e\x74\x2d\x73\x74\x79\x6c\x65\x3a\x6e\x6f\x72\x6d\x61\x6c\
\x3b\x66\x6f\x6e\x74\x2d\x77\x65\x69\x67\x68\x74\x3a\x6e\x6f\x72\
\x6d\x61\x6c\x3b\x66\x6f\x6e\x74\x2d\x73\x69\x7a\x65\x3a\x34\x30\
\x70\x78\x3b\x6c\x69\x6e\x65\x2d\x68\x65\x69\x67\x68\x74\x3a\x31\
\x32\x35\x25\x3b\x66\x6f\x6e\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\
\x73\x61\x6e\x73\x2d\x73\x65\x72\x69\x66\x3b\x6c\x65\x74\x74\x65\
\x72\x2d\x73\x70\x61\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x77\x6f\
\x72\x64\x2d\x73\x70\x61\x63\x69\x6e\x67\x3a\x30\x70\x78\x3b\x66\
\x69\x6c\x6c\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\
\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\
\x65\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\
\x64\x74\x68\x3a\x31\x70\x78\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\
\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x6d\x69\x74\x65\
\x72\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\
\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x74\
\x65\x78\x74\x34\x38\x37\x33\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\
\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\
\x3d\x22\x6d\x20\x33\x31\x33\x2e\x34\x33\x32\x39\x38\x2c\x35\x32\
\x39\x2e\x33\x37\x37\x30\x31\x20\x71\x20\x32\x2e\x37\x33\x34\x33\
\x38\x2c\x30\x20\x34\x2e\x34\x34\x33\x33\x36\x2c\x2d\x31\x2e\x35\
\x30\x33\x39\x20\x31\x2e\x37\x30\x38\x39\x39\x2c\x2d\x31\x2e\x35\
\x30\x33\x39\x31\x20\x31\x2e\x37\x37\x37\x33\x35\x2c\x2d\x33\x2e\
\x39\x39\x39\x30\x33\x20\x6c\x20\x39\x2e\x32\x36\x32\x36\x39\x2c\
\x30\x20\x71\x20\x2d\x30\x2e\x30\x33\x34\x32\x2c\x33\x2e\x37\x35\
\x39\x37\x37\x20\x2d\x32\x2e\x30\x35\x30\x37\x38\x2c\x36\x2e\x39\
\x30\x34\x33\x20\x2d\x32\x2e\x30\x31\x36\x36\x2c\x33\x2e\x31\x31\
\x30\x33\x35\x20\x2d\x35\x2e\x35\x33\x37\x31\x31\x2c\x34\x2e\x38\
\x35\x33\x35\x32\x20\x2d\x33\x2e\x34\x38\x36\x33\x33\x2c\x31\x2e\
\x37\x30\x38\x39\x38\x20\x2d\x37\x2e\x37\x32\x34\x36\x31\x2c\x31\
\x2e\x37\x30\x38\x39\x38\x20\x2d\x37\x2e\x39\x32\x39\x36\x39\x2c\
\x30\x20\x2d\x31\x32\x2e\x35\x30\x39\x37\x36\x2c\x2d\x35\x2e\x30\
\x32\x34\x34\x31\x20\x2d\x34\x2e\x35\x38\x30\x30\x38\x2c\x2d\x35\
\x2e\x30\x35\x38\x36\x20\x2d\x34\x2e\x35\x38\x30\x30\x38\x2c\x2d\
\x31\x33\x2e\x39\x34\x35\x33\x32\x20\x6c\x20\x30\x2c\x2d\x30\x2e\
\x36\x34\x39\x34\x31\x20\x71\x20\x30\x2c\x2d\x38\x2e\x35\x34\x34\
\x39\x32\x20\x34\x2e\x35\x34\x35\x39\x2c\x2d\x31\x33\x2e\x36\x33\
\x37\x36\x39\x20\x34\x2e\x35\x34\x35\x38\x39\x2c\x2d\x35\x2e\x30\
\x39\x32\x37\x38\x20\x31\x32\x2e\x34\x37\x35\x35\x38\x2c\x2d\x35\
\x2e\x30\x39\x32\x37\x38\x20\x36\x2e\x39\x33\x38\x34\x38\x2c\x30\
\x20\x31\x31\x2e\x31\x30\x38\x34\x2c\x33\x2e\x39\x36\x34\x38\x35\
\x20\x34\x2e\x32\x30\x34\x31\x2c\x33\x2e\x39\x33\x30\x36\x36\x20\
\x34\x2e\x32\x37\x32\x34\x36\x2c\x31\x30\x2e\x34\x39\x33\x31\x36\
\x20\x6c\x20\x2d\x39\x2e\x32\x36\x32\x36\x39\x2c\x30\x20\x71\x20\
\x2d\x30\x2e\x30\x36\x38\x34\x2c\x2d\x32\x2e\x38\x37\x31\x30\x39\
\x20\x2d\x31\x2e\x37\x37\x37\x33\x35\x2c\x2d\x34\x2e\x36\x34\x38\
\x34\x34\x20\x2d\x31\x2e\x37\x30\x38\x39\x38\x2c\x2d\x31\x2e\x38\
\x31\x31\x35\x32\x20\x2d\x34\x2e\x35\x31\x31\x37\x32\x2c\x2d\x31\
\x2e\x38\x31\x31\x35\x32\x20\x2d\x33\x2e\x34\x35\x32\x31\x34\x2c\
\x30\x20\x2d\x35\x2e\x32\x32\x39\x34\x39\x2c\x32\x2e\x35\x32\x39\
\x33\x20\x2d\x31\x2e\x37\x34\x33\x31\x36\x2c\x32\x2e\x34\x39\x35\
\x31\x31\x20\x2d\x31\x2e\x37\x34\x33\x31\x36\x2c\x38\x2e\x31\x33\
\x34\x37\x36\x20\x6c\x20\x30\x2c\x31\x2e\x30\x32\x35\x33\x39\x20\
\x71\x20\x30\x2c\x35\x2e\x37\x30\x38\x30\x31\x20\x31\x2e\x37\x34\
\x33\x31\x36\x2c\x38\x2e\x32\x30\x33\x31\x33\x20\x31\x2e\x37\x34\
\x33\x31\x37\x2c\x32\x2e\x34\x39\x35\x31\x31\x20\x35\x2e\x32\x39\
\x37\x38\x35\x2c\x32\x2e\x34\x39\x35\x31\x31\x20\x7a\x22\x0a\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\
\x6f\x6e\x74\x2d\x73\x74\x79\x6c\x65\x3a\x6e\x6f\x72\x6d\x61\x6c\
\x3b\x66\x6f\x6e\x74\x2d\x76\x61\x72\x69\x61\x6e\x74\x3a\x6e\x6f\
\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\x74\x2d\x77\x65\x69\x67\x68\x74\
\x3a\x62\x6f\x6c\x64\x3b\x66\x6f\x6e\x74\x2d\x73\x74\x72\x65\x74\
\x63\x68\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\x74\x2d\x73\
\x69\x7a\x65\x3a\x37\x30\x70\x78\x3b\x66\x6f\x6e\x74\x2d\x66\x61\
\x6d\x69\x6c\x79\x3a\x52\x6f\x62\x6f\x74\x6f\x3b\x2d\x69\x6e\x6b\
\x73\x63\x61\x70\x65\x2d\x66\x6f\x6e\x74\x2d\x73\x70\x65\x63\x69\
\x66\x69\x63\x61\x74\x69\x6f\x6e\x3a\x27\x52\x6f\x62\x6f\x74\x6f\
\x20\x42\x6f\x6c\x64\x27\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\x66\
\x66\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\
\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\
\x22\x70\x61\x74\x68\x34\x32\x34\x31\x22\x20\x2f\x3e\x0a\x20\x20\
\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x64\x3d\x22\x6d\x20\x33\x33\x33\x2e\x30\x31\x37\x39\
\x34\x2c\x35\x31\x37\x2e\x38\x32\x34\x32\x38\x20\x71\x20\x30\x2c\
\x2d\x38\x2e\x37\x31\x35\x38\x32\x20\x33\x2e\x38\x36\x32\x33\x31\
\x2c\x2d\x31\x33\x2e\x37\x37\x34\x34\x31\x20\x33\x2e\x38\x39\x36\
\x34\x38\x2c\x2d\x35\x2e\x30\x35\x38\x36\x20\x31\x30\x2e\x36\x36\
\x34\x30\x36\x2c\x2d\x35\x2e\x30\x35\x38\x36\x20\x35\x2e\x39\x34\
\x37\x32\x37\x2c\x30\x20\x39\x2e\x34\x36\x37\x37\x37\x2c\x34\x2e\
\x35\x34\x35\x39\x20\x6c\x20\x30\x2e\x36\x34\x39\x34\x32\x2c\x2d\
\x33\x2e\x38\x36\x32\x33\x20\x38\x2e\x36\x38\x31\x36\x34\x2c\x30\
\x20\x30\x2c\x35\x31\x2e\x32\x30\x31\x31\x37\x20\x2d\x39\x2e\x39\
\x31\x32\x31\x31\x2c\x30\x20\x30\x2c\x2d\x31\x37\x2e\x33\x39\x37\
\x34\x36\x20\x71\x20\x2d\x33\x2e\x34\x31\x37\x39\x37\x2c\x33\x2e\
\x38\x36\x32\x33\x20\x2d\x38\x2e\x39\x35\x35\x30\x38\x2c\x33\x2e\
\x38\x36\x32\x33\x20\x2d\x36\x2e\x35\x39\x36\x36\x38\x2c\x30\x20\
\x2d\x31\x30\x2e\x35\x32\x37\x33\x34\x2c\x2d\x35\x2e\x31\x32\x36\
\x39\x35\x20\x2d\x33\x2e\x39\x33\x30\x36\x37\x2c\x2d\x35\x2e\x31\
\x32\x36\x39\x35\x20\x2d\x33\x2e\x39\x33\x30\x36\x37\x2c\x2d\x31\
\x34\x2e\x33\x38\x39\x36\x35\x20\x7a\x20\x6d\x20\x39\x2e\x38\x37\
\x37\x39\x33\x2c\x30\x2e\x37\x31\x37\x37\x37\x20\x71\x20\x30\x2c\
\x35\x2e\x32\x39\x37\x38\x35\x20\x31\x2e\x38\x34\x35\x37\x31\x2c\
\x38\x2e\x30\x36\x36\x34\x31\x20\x31\x2e\x38\x37\x39\x38\x38\x2c\
\x32\x2e\x37\x36\x38\x35\x35\x20\x35\x2e\x32\x36\x33\x36\x37\x2c\
\x32\x2e\x37\x36\x38\x35\x35\x20\x34\x2e\x35\x34\x35\x39\x2c\x30\
\x20\x36\x2e\x34\x32\x35\x37\x38\x2c\x2d\x33\x2e\x36\x32\x33\x30\
\x34\x20\x6c\x20\x30\x2c\x2d\x31\x35\x2e\x32\x37\x38\x33\x32\x20\
\x71\x20\x2d\x31\x2e\x38\x34\x35\x37\x2c\x2d\x33\x2e\x34\x38\x36\
\x33\x33\x20\x2d\x36\x2e\x33\x35\x37\x34\x32\x2c\x2d\x33\x2e\x34\
\x38\x36\x33\x33\x20\x2d\x33\x2e\x34\x31\x37\x39\x37\x2c\x30\x20\
\x2d\x35\x2e\x32\x39\x37\x38\x35\x2c\x32\x2e\x37\x36\x38\x35\x35\
\x20\x2d\x31\x2e\x38\x37\x39\x38\x39\x2c\x32\x2e\x37\x36\x38\x35\
\x36\x20\x2d\x31\x2e\x38\x37\x39\x38\x39\x2c\x38\x2e\x37\x38\x34\
\x31\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\
\x74\x79\x6c\x65\x3d\x22\x66\x6f\x6e\x74\x2d\x73\x74\x79\x6c\x65\
\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\x74\x2d\x76\x61\x72\
\x69\x61\x6e\x74\x3a\x6e\x6f\x72\x6d\x61\x6c\x3b\x66\x6f\x6e\x74\
\x2d\x77\x65\x69\x67\x68\x74\x3a\x62\x6f\x6c\x64\x3b\x66\x6f\x6e\
\x74\x2d\x73\x74\x72\x65\x74\x63\x68\x3a\x6e\x6f\x72\x6d\x61\x6c\
\x3b\x66\x6f\x6e\x74\x2d\x73\x69\x7a\x65\x3a\x37\x30\x70\x78\x3b\
\x66\x6f\x6e\x74\x2d\x66\x61\x6d\x69\x6c\x79\x3a\x52\x6f\x62\x6f\
\x74\x6f\x3b\x2d\x69\x6e\x6b\x73\x63\x61\x70\x65\x2d\x66\x6f\x6e\
\x74\x2d\x73\x70\x65\x63\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x3a\
\x27\x52\x6f\x62\x6f\x74\x6f\x20\x42\x6f\x6c\x64\x27\x3b\x66\x69\
\x6c\x6c\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x66\x69\x6c\x6c\x2d\
\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x22\x0a\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x34\x32\x34\x33\
\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\
\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
"
qt_resource_name = "\
\x00\x05\
\x00\x6f\xa6\x53\
\x00\x69\
\x00\x63\x00\x6f\x00\x6e\x00\x73\
\x00\x0b\
\x05\x72\xb2\xa7\
\x00\x43\
\x00\x51\x00\x5f\x00\x4c\x00\x6f\x00\x67\x00\x6f\x00\x2e\x00\x73\x00\x76\x00\x67\
"
qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
"
from PySide import QtCore
qt_resource_data = "\x00\x00\x0f}<?xml version=\x221.0\x22 encoding=\x22UTF-8\x22 standalone=\x22no\x22?>\x0a<!-- Created with Inkscape (http://www.inkscape.org/) -->\x0a\x0a<svg\x0a xmlns:dc=\x22http://purl.org/dc/elements/1.1/\x22\x0a xmlns:cc=\x22http://creativecommons.org/ns#\x22\x0a xmlns:rdf=\x22http://www.w3.org/1999/02/22-rdf-syntax-ns#\x22\x0a xmlns:svg=\x22http://www.w3.org/2000/svg\x22\x0a xmlns=\x22http://www.w3.org/2000/svg\x22\x0a xmlns:sodipodi=\x22http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\x22\x0a xmlns:inkscape=\x22http://www.inkscape.org/namespaces/inkscape\x22\x0a width=\x2226.731115mm\x22\x0a height=\x2224.375559mm\x22\x0a viewBox=\x220 0 94.71655 86.37009\x22\x0a id=\x22svg5495\x22\x0a version=\x221.1\x22\x0a inkscape:version=\x220.91 r13725\x22\x0a sodipodi:docname=\x22cadquery_logo_dark.svg\x22>\x0a <defs\x0a id=\x22defs5497\x22 />\x0a <sodipodi:namedview\x0a id=\x22base\x22\x0a pagecolor=\x22#ffffff\x22\x0a bordercolor=\x22#666666\x22\x0a borderopacity=\x221.0\x22\x0a inkscape:pageopacity=\x220.0\x22\x0a inkscape:pageshadow=\x222\x22\x0a inkscape:zoom=\x224.3709362\x22\x0a inkscape:cx=\x2247.358275\x22\x0a inkscape:cy=\x2243.185045\x22\x0a inkscape:document-units=\x22px\x22\x0a inkscape:current-layer=\x22layer1\x22\x0a showgrid=\x22false\x22\x0a fit-margin-top=\x220\x22\x0a fit-margin-left=\x220\x22\x0a fit-margin-right=\x220\x22\x0a fit-margin-bottom=\x220\x22\x0a inkscape:window-width=\x221855\x22\x0a inkscape:window-height=\x221056\x22\x0a inkscape:window-x=\x2265\x22\x0a inkscape:window-y=\x2224\x22\x0a inkscape:window-maximized=\x221\x22 />\x0a <metadata\x0a id=\x22metadata5500\x22>\x0a <rdf:RDF>\x0a <cc:Work\x0a rdf:about=\x22\x22>\x0a <dc:format>image/svg+xml</dc:format>\x0a <dc:type\x0a rdf:resource=\x22http://purl.org/dc/dcmitype/StillImage\x22 />\x0a <dc:title />\x0a </cc:Work>\x0a </rdf:RDF>\x0a </metadata>\x0a <g\x0a inkscape:label=\x22Layer 1\x22\x0a inkscape:groupmode=\x22layer\x22\x0a id=\x22layer1\x22\x0a transform=\x22translate(-284.0703,-477.74859)\x22>\x0a <path\x0a inkscape:connector-curvature=\x220\x22\x0a style=\x22fill:#2980b9;fill-opacity:1;fill-rule:evenodd;stroke:#2980b9;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1\x22\x0a d=\x22m 285.5703,479.24859 91.71655,0 0,83.37009 -91.71655,0 z\x22\x0a id=\x22path4266\x22 />\x0a <g\x0a style=\x22font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\x22\x0a id=\x22text4873\x22>\x0a <path\x0a d=\x22m 313.43298,529.37701 q 2.73438,0 4.44336,-1.5039 1.70899,-1.50391 1.77735,-3.99903 l 9.26269,0 q -0.0342,3.75977 -2.05078,6.9043 -2.0166,3.11035 -5.53711,4.85352 -3.48633,1.70898 -7.72461,1.70898 -7.92969,0 -12.50976,-5.02441 -4.58008,-5.0586 -4.58008,-13.94532 l 0,-0.64941 q 0,-8.54492 4.5459,-13.63769 4.54589,-5.09278 12.47558,-5.09278 6.93848,0 11.1084,3.96485 4.2041,3.93066 4.27246,10.49316 l -9.26269,0 q -0.0684,-2.87109 -1.77735,-4.64844 -1.70898,-1.81152 -4.51172,-1.81152 -3.45214,0 -5.22949,2.5293 -1.74316,2.49511 -1.74316,8.13476 l 0,1.02539 q 0,5.70801 1.74316,8.20313 1.74317,2.49511 5.29785,2.49511 z\x22\x0a style=\x22font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:70px;font-family:Roboto;-inkscape-font-specification:'Roboto Bold';fill:#ffffff;fill-opacity:1\x22\x0a id=\x22path4241\x22 />\x0a <path\x0a d=\x22m 333.01794,517.82428 q 0,-8.71582 3.86231,-13.77441 3.89648,-5.0586 10.66406,-5.0586 5.94727,0 9.46777,4.5459 l 0.64942,-3.8623 8.68164,0 0,51.20117 -9.91211,0 0,-17.39746 q -3.41797,3.8623 -8.95508,3.8623 -6.59668,0 -10.52734,-5.12695 -3.93067,-5.12695 -3.93067,-14.38965 z m 9.87793,0.71777 q 0,5.29785 1.84571,8.06641 1.87988,2.76855 5.26367,2.76855 4.5459,0 6.42578,-3.62304 l 0,-15.27832 q -1.8457,-3.48633 -6.35742,-3.48633 -3.41797,0 -5.29785,2.76855 -1.87989,2.76856 -1.87989,8.78418 z\x22\x0a style=\x22font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:70px;font-family:Roboto;-inkscape-font-specification:'Roboto Bold';fill:#ffffff;fill-opacity:1\x22\x0a id=\x22path4243\x22 />\x0a </g>\x0a </g>\x0a</svg>\x0a"
qt_resource_name = "\x00\x05\x00o\xa6S\x00i\x00c\x00o\x00n\x00s\x00\x0b\x05r\xb2\xa7\x00C\x00Q\x00_\x00L\x00o\x00g\x00o\x00.\x00s\x00v\x00g"
qt_resource_struct = "\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)

View File

@ -1,21 +1,42 @@
language: python
matrix:
include:
- python: 2.7
- python: 3.6
env: FREECAD_LIB="$HOME/miniconda/envs/freecad_cq3/lib/"
before_install:
- sudo add-apt-repository -y ppa:freecad-maintainers/freecad-stable
- sudo apt-get update -qq
- if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
bash miniconda.sh -b -p $HOME/miniconda;
export PATH="$HOME/miniconda/bin:$PATH";
hash -r;
conda config --set always_yes yes --set changeps1 no;
conda update -q conda;
conda info -a;
conda create -y -q -n freecad_cq3 -c freecad -c conda-forge freecad=0.17=py36_11 occt=7.2.0=occt7.2.0_0 python=3.6 pyparsing conda mock;
source ~/miniconda/bin/activate freecad_cq3;
else
sudo add-apt-repository -y ppa:freecad-maintainers/freecad-stable;
sudo apt-get update -qq;
sudo apt-get install -y freecad freecad-doc;
pip install -r requirements-dev.txt;
pip install travis-sphinx;
pip install sphinx_rtd_theme;
fi
install:
- sudo apt-get install -y freecad freecad-doc
- gcc --version
- g++ --version
- python ./setup.py install
- pip install -r requirements-dev.txt
- pip install travis-sphinx
- pip install sphinx_rtd_theme
- python setup.py install;
script:
- coverage run --source=cadquery ./runtests.py
- travis-sphinx build --nowarn --source=doc
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
coverage run --source=cadquery --omit=cadquery/cq_directive.py ./runtests.py;
travis-sphinx build --nowarn --source=doc;
fi
- python runtests.py
after_success:
after_script:
- coveralls
- travis-sphinx deploy
@ -23,11 +44,10 @@ branches:
except:
- pythonocc
- 2_0_branch
deploy:
deploy:
provider: pypi
user: dcowden
password:
secure: aP02wBbry1j3hYG/w++siF1lk26teuRQlPAx1c+ec8fxUw+bECa2HbPQHcIvSXB5N6nc6P3L9LjHt9ktm+Dn6FLJu3qWYNGAZx9PTn24ug0iAmB+JyNrsET3nK6WUKR1XpBqvjKgdpukd1Hknh2FSzYoyUvFWH9/CovITCFN3jo=
on:
tags: true
tags: true

View File

@ -1,8 +1,12 @@
<p align="center">
<img src="http://dcowden.github.io/cadquery/_static/cadquery_logo_dark.svg" width="100"/>
</p>
What is a CadQuery?
========================================
[![Travis Build Status](https://travis-ci.org/dcowden/cadquery.svg?branch=master)](https://travis-ci.org/dcowden/cadquery?branch=master)
[![Coverage Status](https://coveralls.io/repos/dcowden/cadquery/badge.svg)](https://coveralls.io/r/dcowden/cadquery)
[![Coverage Status](https://coveralls.io/repos/github/dcowden/cadquery/badge.svg?branch=master)](https://coveralls.io/github/dcowden/cadquery?branch=master)
[![GitHub version](https://badge.fury.io/gh/dcowden%2Fcadquery.svg)](https://github.com/dcowden/cadquery/releases/tag/v0.3.0)
[![License](https://img.shields.io/badge/license-Apache2-blue.svg)](https://github.com/dcowden/cadquery/blob/master/LICENSE)
@ -17,9 +21,46 @@ CadQuery has several goals:
Using CadQuery, you can write short, simple scripts that produce high quality CAD models. It is easy to make many different objects using a single script that can be customized.
Full Documentation and a Welcoming Community
============================
You can find the full cadquery documentation at http://dcowden.github.io/cadquery
We also have a Google Group to make it easy to get help from other CadQuery users. We want you to feel welcome and encourage you to join the group and introduce yourself. We would also love to hear what you are doing with CadQuery. https://groups.google.com/forum/#!forum/cadquery
Getting Started With CadQuery
========================================
Installation instructions for all following use cases can be found [here](http://dcowden.github.io/cadquery/installation.html).
It is currently possible to use CadQuery for your own projects in 4 different ways:
* as a plugin for FreeCAD
* using the Docker Image to operate CadQuery as a CLI
* as a plugin running on a Jupyter Notebook server
* a standalone installation
## I just want to try things out!
If you are interested in trying CadQuery without installing anything, your best option is to experiment with CadQuery scripts running on a Jupyter server.
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master)
That button will launch a Jupyter Server pre-configured with CadQuery and its dependencies. It contains a folder with many useful examples to showcase CadQuery's features.
## I'd like to use CadQuery on my own setup
The easiest way to get started with CadQuery is to Install FreeCAD (version 16+) (http://www.freecadweb.org/), and then to use our great CadQuery-FreeCAD plugin here: https://github.com/jmwright/cadquery-freecad-module
It includes the latest version of cadquery already bundled, and has super-easy installation on Mac, Windows, and Unix.
It has tons of awesome features like integration with FreeCAD so you can see your objects, code-autocompletion, an examples bundle, and script saving/loading. Its definitely the best way to kick the tires!
## I have other ideas and want to run things my own way
Awesome! CadQuery is built with this attitude in mind. If none of the existing usage methods work for you, you are more than welcome to forge your own path. You'll probably find the most success using the Docker image. You can alternatively install CadQuery as a standalone package.
Getting Started with the docker image
=======================================
The caduery docker image (https://hub.docker.com/r/dcowden/cadquery/) includes cadquery and all of its dependencies. It can be used to run cadquery scripts without any installation required ( other than docker, of course)
The CadQuery docker image (https://hub.docker.com/r/dcowden/cadquery/) includes cadquery and all of its dependencies. It can be used to run cadquery scripts without any installation required ( other than docker, of course)
Examples:
@ -33,7 +74,7 @@ Build a local model using stdin/stdout::
... STEP output on the console
Build local models and output to the same directory::
Build local models and output to the same directory:
docker run -v $PWD:/home/cq -i dcowden/cadquery:latest build --in_spec Ex001_Simple_Block.py --format STEP
INFO: Reading from file 'Ex001_Simple_Block.py'
@ -46,26 +87,8 @@ Build local models and output to the same directory::
INFO: Script Generated 1 result Objects
INFO: Writing STEP Output to './cqobject-1.STEP'
Full Documentation
============================
You can find the full cadquery documentation at http://dcowden.github.io/cadquery
Getting Started With CadQuery
========================================
The easiest way to get started with CadQuery is to Install FreeCAD (version 16+) (http://www.freecadweb.org/), and then to use our great CadQuery-FreeCAD plugin here: https://github.com/jmwright/cadquery-freecad-module
It includes the latest version of cadquery alreadby bundled, and has super-easy installation on Mac, Windows, and Unix.
It has tons of awesome features like integration with FreeCAD so you can see your objects, code-autocompletion, an examples bundle, and script saving/loading. Its definitely the best way to kick the tires!
We also have a Google Group to make it easy to get help from other CadQuery users. Please join the group and introduce yourself, and we would also love to hear what you are doing with CadQuery. https://groups.google.com/forum/#!forum/cadquery
Examples
======================
Projects Using CadQuery
=========================
This resin mold was modeled using cadquery and then created on a CNC machine:
@ -143,8 +166,6 @@ The cadquery script is surprisingly short, and allows easily customizing any of
Thanks go to cadquery contributor hyOzd ( Altu Technology ) for the example!
Projects Using CadQuery
=========================
KiCad uses cadquery to build high quality models of electrictronic components. ( https://github.com/KiCad/packages3D )
@ -166,7 +187,7 @@ The mach30 project used cadquery to develop a tool that will create a rocket thr
This example uses Jupyter notebook to produce a really cool web-based scripting environment ( https://github.com/RustyVermeer/avnb/blob/master/readme.md ) :
<p align="center">
<img src="https://github.com/RustyVermeer/avnb/raw/master/example.gif" width="700"/>
<img src="https://github.com/RustyVermeer/cqnb/raw/master/showcase.gif" width="350"/>
</p>
@ -176,7 +197,19 @@ This example uses Jupyter notebook to produce a really cool web-based scripting
We would love to link to your cadquery based project. Just let us know and we'll add it here.
Where does the name CadQuery come from?
========================================
CadQuery is inspired by jQuery, a popular framework that
revolutionized web development involving javascript.
If you are familiar with jQuery, you will probably recognize several jQuery features that CadQuery uses:
* A fluent api to create clean, easy to read code
* Language features that make selection and iteration incredibly easy
*
* Ability to use the library along side other python libraries
* Clear and complete documentation, with plenty of samples.
Why CadQuery instead of OpenSCAD?
========================================
@ -208,74 +241,17 @@ License
CadQuery is licensed under the terms of the Apache Public License, version 2.0.
A copy of the license can be found at http://www.apache.org/licenses/LICENSE-2.0
CadQuery GUI Interfaces
=======================
Ongoing and Future Work
============
There are currently several known CadQuery GUIs:
### CadQuery FreeCAD Module
You can use CadQuery inside of FreeCAD. There's an excellent plugin module here https://github.com/jmwright/cadquery-freecad-module
### CadQuery GUI (under active development)
### CadQuery GUI (under development)
Work is underway on a stand-alone gui here: https://github.com/jmwright/cadquery-gui
### ParametricParts.com
If you are impatient and want to see a working example with no installation, have a look at this lego brick example http://parametricparts.com/parts/vqb5dy69/.
### CadQuery Parts / Assembly Handling
Work by Fragmuffin is ongoing with the [cqparts](https://github.com/fragmuffin/cqparts) repo.
The script that generates the model is on the 'modelscript' tab.
Installing -- FreeStanding Installation
========================================
Use these steps if you would like to write CadQuery scripts as a python API. In this case, FreeCAD is used only as a CAD kernel.
1. install FreeCAD, version 0.15 or greater for your platform. https://github.com/FreeCAD/FreeCAD/releases.
2. adjust your path if necessary. FreeCAD bundles a python interpreter, but you'll probably want to use your own,
preferably one that has virtualenv available. To use FreeCAD from any python interpreter, just append the FreeCAD
lib directory to your path. On (*Nix)::
```python
import sys
sys.path.append('/usr/lib/freecad/lib')
```
or on Windows::
```python
import sys
sys.path.append('/c/apps/FreeCAD/bin')
```
*NOTE* FreeCAD on Windows will not work with python 2.7-- you must use pthon 2.6.X!!!!
3. install cadquery::
```bash
pip install cadquery
```
4. installing cadquery should install pyparsing as well, but if not::
```bash
pip install pyparsing
```
5. test your installation::
```python
from cadquery import *
box = Workplane("XY").box(1,2,3)
exporters.toString(box,'STL')
```
You're up and running!
Installing -- Using CadQuery from Inside FreeCAD
=================================================
Use the CadQuery module for FreeCAD here:
https://github.com/jmwright/cadquery-freecad-module
It includes a distribution of the latest version of cadquery.
Roadmap/Future Work
=======================
### Moving to Python3 and away from FreeCAD as a dependency
Adam Urbańczyk has been working hard on his own [CQ fork](https://github.com/adam-urbanczyk/cadquery) which uses only PythonOCC instead of FreeCAD.
Work has begun on Cadquery 2.0, which will feature:
@ -286,17 +262,3 @@ Work has begun on Cadquery 2.0, which will feature:
The project page can be found here: https://github.com/dcowden/cadquery/projects/1
A more detailed description of the plan for CQ 2.0 is here: https://docs.google.com/document/d/1cXuxBkVeYmGOo34MGRdG7E3ILypQqkrJ26oVf3CUSPQ
Where does the name CadQuery come from?
========================================
CadQuery is inspired by jQuery, a popular framework that
revolutionized web development involving javascript.
If you are familiar with how jQuery, you will probably recognize several jQuery features that CadQuery uses:
* A fluent api to create clean, easy to read code
* Language features that make selection and iteration incredibly easy
*
* Ability to use the library along side other python libraries
* Clear and complete documentation, with plenty of samples.

View File

@ -12,7 +12,7 @@ cp examples/FreeCAD/Ex001_Simple_Block.py $CQ_TEST_DIR
fail_test( ){
"Test Failed."
echo "Test Failed."
}
echo "Running Tests..."

View File

@ -23,6 +23,8 @@ from cadquery import *
from cadquery import selectors
from cadquery import exporters
from copy import copy, deepcopy
class CQContext(object):
"""
@ -75,7 +77,7 @@ class CQ(object):
Custom plugins and subclasses should use this method to create new CQ objects
correctly.
"""
r = CQ(None) # create a completely blank one
r = type(self)(None) # create a completely blank one
r.parent = self
r.ctx = self.ctx # context solid remains the same
r.objects = list(objlist)
@ -237,7 +239,7 @@ class CQ(object):
"""
if type(obj) == list:
self.objects.extend(obj)
elif type(obj) == CQ or type(obj) == Workplane:
elif isinstance(obj, CQ):
self.objects.extend(obj.objects)
else:
self.objects.append(obj)
@ -479,9 +481,10 @@ class CQ(object):
toReturn = self._collectProperty(objType)
if selector is not None:
if isinstance(selector, str) or isinstance(selector, str):
# if isinstance(selector, str) or isinstance(selector, str):
try:
selectorObj = selectors.StringSyntaxSelector(selector)
else:
except:
selectorObj = selector
toReturn = selectorObj.filter(toReturn)
@ -668,7 +671,7 @@ class CQ(object):
"""
return self._selectObjects('Compounds', selector)
def toSvg(self, opts=None):
def toSvg(self, opts=None, view_vector=(-1.75,1.1,5)):
"""
Returns svg text that represents the first item on the stack.
@ -676,20 +679,26 @@ class CQ(object):
:param opts: svg formatting options
:type opts: dictionary, width and height
:param view_vector: camera's view direction vector
:type view_vector: tuple, (x, y, z)
:return: a string that contains SVG that represents this item.
"""
return exporters.getSVG(self.val().wrapped, opts)
return exporters.getSVG(self.val().wrapped, opts=opts, view_vector=view_vector)
def exportSvg(self, fileName):
def exportSvg(self, fileName, view_vector=(-1.75,1.1,5)):
"""
Exports the first item on the stack as an SVG file
For testing purposes mainly.
:param fileName: the filename to export
:param view_vector: camera's view direction vector
:type view_vector: tuple, (x, y, z)
:type fileName: String, absolute path to the file
"""
exporters.exportSVG(self, fileName)
exporters.exportSVG(self, fileName, view_vector)
def rotateAboutCenter(self, axisEndPoint, angleDegrees):
"""
@ -745,7 +754,7 @@ class CQ(object):
def mirror(self, mirrorPlane="XY", basePointVector=(0, 0, 0)):
"""
Mirror a single CQ object. This operation is the same as in the FreeCAD PartWB's mirroring
:param mirrorPlane: the plane to mirror about
:type mirrorPlane: string, one of "XY", "YX", "XZ", "ZX", "YZ", "ZY" the planes
:param basePointVector: the base point to mirror about
@ -882,6 +891,12 @@ class CQ(object):
solid.wrapped = s.wrapped
return self.newObject([s])
def __copy__(self):
return self.newObject(copy(self.objects))
def __deepcopy__(self, memo):
return self.newObject(deepcopy(self.objects, memo))
class Workplane(CQ):
"""
@ -935,10 +950,11 @@ class Workplane(CQ):
if inPlane.__class__.__name__ == 'Plane':
tmpPlane = inPlane
elif isinstance(inPlane, str) or isinstance(inPlane, str):
tmpPlane = Plane.named(inPlane, origin)
else:
tmpPlane = None
try:
tmpPlane = Plane.named(inPlane, origin)
except ValueError:
tmpPlane = None
if tmpPlane is None:
raise ValueError(
@ -991,7 +1007,7 @@ class Workplane(CQ):
"""
#copy the current state to the new object
ns = Workplane("XY")
ns = type(self)("XY")
ns.plane = self.plane
ns.parent = self
ns.objects = list(objlist)
@ -2123,7 +2139,7 @@ class Workplane(CQ):
"""
#first collect all of the items together
if type(toUnion) == CQ or type(toUnion) == Workplane:
if isinstance(toUnion, CQ):
solids = toUnion.solids().vals()
if len(solids) < 1:
raise ValueError("CQ object must have at least one solid on the stack to union!")

View File

@ -139,8 +139,8 @@ class ShapeResult(object):
"""
def __init__(self):
self.shape = None
self.options = None
self.options = None
class BuildResult(object):
"""
The result of executing a CadQuery script.
@ -253,7 +253,6 @@ class InputParameter:
return p
def set_value(self, new_value):
if len(self.valid_values) > 0 and new_value not in self.valid_values:
raise InvalidParameterError(
"Cannot set value '{0:s}' for parameter '{1:s}': not a valid value. Valid values are {2:s} "
@ -277,9 +276,15 @@ class InputParameter:
self.ast_node.s = str(new_value)
elif self.varType == BooleanParameterType:
if new_value:
self.ast_node.id = 'True'
if hasattr(ast, 'NameConstant'):
self.ast_node.value = True
else:
self.ast_node.id = 'True'
else:
self.ast_node.id = 'False'
if hasattr(ast, 'NameConstant'):
self.ast_node.value = False
else:
self.ast_node.id = 'False'
else:
raise ValueError("Unknown Type of var: ", str(self.varType))
@ -449,13 +454,20 @@ class ConstantAssignmentFinder(ast.NodeTransformer):
elif type(value_node) == ast.Str:
self.cqModel.add_script_parameter(
InputParameter.create(value_node, var_name, StringParameterType, value_node.s))
elif type(value_node == ast.Name):
elif type(value_node) == ast.Name:
if value_node.id == 'True':
self.cqModel.add_script_parameter(
InputParameter.create(value_node, var_name, BooleanParameterType, True))
elif value_node.id == 'False':
self.cqModel.add_script_parameter(
InputParameter.create(value_node, var_name, BooleanParameterType, False))
elif hasattr(ast, 'NameConstant') and type(value_node) == ast.NameConstant:
if value_node.value == True:
self.cqModel.add_script_parameter(
InputParameter.create(value_node, var_name, BooleanParameterType, True))
else:
self.cqModel.add_script_parameter(
InputParameter.create(value_node, var_name, BooleanParameterType, False))
except:
print("Unable to handle assignment for variable '%s'" % var_name)
pass
@ -469,7 +481,12 @@ class ConstantAssignmentFinder(ast.NodeTransformer):
if isinstance(left_side,ast.Attribute):
return
if type(node.value) in [ast.Num, ast.Str, ast.Name]:
# Handle the NamedConstant type that is only present in Python 3
astTypes = [ast.Num, ast.Str, ast.Name]
if hasattr(ast, 'NameConstant'):
astTypes.append(ast.NameConstant)
if type(node.value) in astTypes:
self.handle_assignment(left_side.id, node.value)
elif type(node.value) == ast.Tuple:
# we have a multi-value assignment

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import cadquery
import FreeCAD
@ -82,11 +84,11 @@ def exportShape(shape,exportType,fileLike,tolerance=0.1):
if exportType == ExportTypes.STEP:
shape.exportStep(outFileName)
elif exportType == ExportTypes.STL:
shape.wrapped.exportStl(outFileName)
shape.wrapped.exportStl(outFileName,tolerance)
else:
raise ValueError("No idea how i got here")
res = readAndDeleteFile(outFileName)
res = '{}'.format(readAndDeleteFile(outFileName))
fileLike.write(res)
def readAndDeleteFile(fileName):
@ -94,7 +96,7 @@ def readAndDeleteFile(fileName):
read data from file provided, and delete it when done
return the contents as a string
"""
res = ""
res = ''
with open(fileName,'r') as f:
res = f.read()
@ -159,7 +161,7 @@ class AmfWriter(object):
v3 = ET.SubElement(triangle,'v3')
v3.text = str(t[2])
ET.ElementTree(amf).write(outFile,encoding="unicode",xml_declaration=True)
ET.ElementTree(amf).write(outFile,xml_declaration=True)
"""
Objects that represent
@ -169,20 +171,20 @@ class AmfWriter(object):
class JsonMesh(object):
def __init__(self):
self.vertices = [];
self.faces = [];
self.nVertices = 0;
self.nFaces = 0;
self.vertices = []
self.faces = []
self.nVertices = 0
self.nFaces = 0
def addVertex(self,x,y,z):
self.nVertices += 1;
self.vertices.extend([x,y,z]);
def addVertex(self, x, y, z):
self.nVertices += 1
self.vertices.extend([x,y,z])
#add triangle composed of the three provided vertex indices
def addTriangleFace(self, i,j,k):
def addTriangleFace(self, i, j, k):
#first position means justa simple triangle
self.nFaces += 1;
self.faces.extend([0,int(i),int(j),int(k)]);
self.nFaces += 1
self.faces.extend([0, int(i), int(j), int(k)])
"""
Get a json model from this model.
@ -193,7 +195,7 @@ class JsonMesh(object):
'vertices' : str(self.vertices),
'faces' : str(self.faces),
'nVertices': self.nVertices,
'nFaces' : self.nFaces
'nFaces': self.nFaces,
};
@ -234,11 +236,11 @@ def getPaths(freeCadSVG):
return ([],[])
def getSVG(shape,opts=None):
def getSVG(shape, opts=None, view_vector=(-1.75, 1.1, 5.0)):
"""
Export a shape to SVG
"""
d = {'width':800,'height':240,'marginLeft':200,'marginTop':20}
if opts:
@ -253,7 +255,7 @@ def getSVG(shape,opts=None):
marginTop=float(d['marginTop'])
#TODO: provide option to give 3 views
viewVector = FreeCAD.Base.Vector(-1.75,1.1,5)
viewVector = FreeCAD.Base.Vector(view_vector)
(visibleG0,visibleG1,hiddenG0,hiddenG1) = Drawing.project(shape,viewVector)
(hiddenPaths,visiblePaths) = getPaths(Drawing.projectToSVG(shape,viewVector,"ShowHiddenLines")) #this param is totally undocumented!
@ -281,16 +283,16 @@ def getSVG(shape,opts=None):
svg = SVG_TEMPLATE % (
{
"unitScale" : str(unitScale),
"strokeWidth" : str(1.0/unitScale),
"hiddenContent" : hiddenContent ,
"visibleContent" :visibleContent,
"xTranslate" : str(xTranslate),
"yTranslate" : str(yTranslate),
"width" : str(width),
"height" : str(height),
"textboxY" :str(height - 30),
"uom" : str(uom)
'unitScale': str(unitScale),
'strokeWidth': str(1.0 / unitScale),
'hiddenContent': hiddenContent ,
'visibleContent': visibleContent,
'xTranslate': str(xTranslate),
'yTranslate': str(yTranslate),
'width': str(width),
'height': str(height),
'textboxY': str(height - 30),
'uom': str(uom)
}
)
#svg = SVG_TEMPLATE % (
@ -299,14 +301,13 @@ def getSVG(shape,opts=None):
return svg
def exportSVG(shape, fileName):
def exportSVG(shape, fileName, view_vector=(-1.75,1.1,5)):
"""
accept a cadquery shape, and export it to the provided file
TODO: should use file-like objects, not a fileName, and/or be able to return a string instead
export a view of a part to svg
"""
svg = getSVG(shape.val().wrapped)
svg = getSVG(shape.val().wrapped, opts=None, view_vector=view_vector)
f = open(fileName,'w')
f.write(svg)
f.close()
@ -376,20 +377,6 @@ SVG_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
%(visibleContent)s
</g>
</g>
<g transform="translate(20,%(textboxY)s)" stroke="rgb(0,0,255)">
<line x1="30" y1="-30" x2="75" y2="-33" stroke-width="3" stroke="#000000" />
<text x="80" y="-30" style="stroke:#000000">X </text>
<line x1="30" y1="-30" x2="30" y2="-75" stroke-width="3" stroke="#000000" />
<text x="25" y="-85" style="stroke:#000000">Y </text>
<line x1="30" y1="-30" x2="58" y2="-15" stroke-width="3" stroke="#000000" />
<text x="65" y="-5" style="stroke:#000000">Z </text>
<!--
<line x1="0" y1="0" x2="%(unitScale)s" y2="0" stroke-width="3" />
<text x="0" y="20" style="stroke:#000000">1 %(uom)s </text>
-->
</g>
</svg>
"""

View File

@ -16,8 +16,9 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>
"""
from __future__ import division
import math
from copy import copy
import cadquery
import FreeCAD
import Part as FreeCADPart
@ -58,92 +59,134 @@ def sortWiresByBuildOrder(wireList, plane, result=[]):
class Vector(object):
"""Create a 3-dimensional vector
:param args: a 3-d vector, with x-y-z parts.
**you can provide any of:**
you can either provide:
* nothing (in which case the null vector is return)
* a FreeCAD vector
* a vector ( in which case it is copied )
* a 3-tuple
* three float values, x, y, and z
* nothing (in which case a zero vector is return)
* a :class:`FreeCAD.Base.Vector` instance to wrap
* a :class:`Vector` (in which case it is copied)
* a 2-tuple of :class:`float`, ``(x, y)`` (z=0)
* a 3-tuple of :class:`float`, ``(x, y, z)``
* 2 :class:`float` values, as ``x``, and ``y``
* 3 :class:`float` values, as ``x``, ``y``, and ``z``
* named coordinates, like ``Vector(x=1, z=2)``
.. doctest::
>>> from cadquery import Vector
>>> import FreeCAD
>>> Vector()
Vector (0.0, 0.0, 0.0)
>>> Vector(FreeCAD.Base.Vector(1,2,3))
Vector (1.0, 2.0, 3.0)
>>> Vector(Vector(4,5,6))
Vector (4.0, 5.0, 6.0)
>>> Vector((1, 2))
Vector (1.0, 2.0, 0.0)
>>> Vector((1, 2, 3))
Vector (1.0, 2.0, 3.0)
>>> Vector(4, 5)
Vector (4.0, 5.0, 0.0)
>>> Vector(4, 5, 6)
Vector (4.0, 5.0, 6.0)
>>> Vector(x=1, z=2)
Vector (1.0, 0.0, 2.0)
"""
def __init__(self, *args):
if len(args) == 3:
fV = FreeCAD.Base.Vector(args[0], args[1], args[2])
elif len(args) == 1:
if isinstance(args[0], Vector):
fV = args[0].wrapped
elif isinstance(args[0], tuple):
fV = FreeCAD.Base.Vector(args[0][0], args[0][1], args[0][2])
elif isinstance(args[0], FreeCAD.Base.Vector):
fV = args[0]
def __init__(self, *args, **kwargs):
fV = None
if args and not kwargs:
if (1 <= len(args) <= 3): # 1, 2, or 3 arguments (no keyword arguments given)
if isinstance(args[0], (int, float)):
# First argument is a number, pass list through to freecad
fV = FreeCAD.Base.Vector(*args)
elif len(args) == 1:
arg = args[0] # only 1 argument given
if isinstance(arg, Vector):
v = arg.wrapped
fV = FreeCAD.Base.Vector(v.x, v.y, v.z) # create copy
elif isinstance(arg, FreeCAD.Base.Vector):
v = arg
fV = FreeCAD.Base.Vector(v.x, v.y, v.z) # create copy
elif isinstance(arg, (list, tuple)):
if (1 <= len(arg) <= 3):
fV = FreeCAD.Base.Vector(*arg)
elif not args:
if set(kwargs.keys()) - set('xyz'):
pass # kwargs contains invalid arguments, raise exception
else:
fV = args[0]
elif len(args) == 0:
fV = FreeCAD.Base.Vector(0, 0, 0)
else:
raise ValueError("Expected three floats, FreeCAD Vector, or 3-tuple")
fV = FreeCAD.Base.Vector(
kwargs.get('x', 0),
kwargs.get('y', 0),
kwargs.get('z', 0),
)
if fV is None:
raise ValueError(
"Expected 2 or 3 floats, FreeCAD Vector, 2 or 3-tuple, or named lower-case coords. " + \
("%r %r" % (args, kwargs))
)
self._wrapped = fV
@property
def x(self):
return self.wrapped.x
return self._wrapped.x
@x.setter
def x(self, value):
self.wrapped.x = value
self._wrapped.x = value
@property
def y(self):
return self.wrapped.y
return self._wrapped.y
@y.setter
def y(self, value):
self.wrapped.y = value
self._wrapped.y = value
@property
def z(self):
return self.wrapped.z
return self._wrapped.z
@z.setter
def z(self, value):
self.wrapped.z = value
self._wrapped.z = value
@property
def Length(self):
return self.wrapped.Length
return self._wrapped.Length
@property
def wrapped(self):
return self._wrapped
def toTuple(self):
return (self.x, self.y, self.z)
v = self._wrapped
return (v.x, v.y, v.z)
# TODO: is it possible to create a dynamic proxy without all this code?
def cross(self, v):
return Vector(self.wrapped.cross(v.wrapped))
return type(self)(self._wrapped.cross(v.wrapped))
def dot(self, v):
return self.wrapped.dot(v.wrapped)
return self._wrapped.dot(v.wrapped)
def sub(self, v):
return Vector(self.wrapped.sub(v.wrapped))
return type(self)(self._wrapped.sub(v.wrapped))
def add(self, v):
return Vector(self.wrapped.add(v.wrapped))
return type(self)(self._wrapped.add(v.wrapped))
def multiply(self, scale):
"""Return a copy multiplied by the provided scalar"""
tmp_fc_vector = FreeCAD.Base.Vector(self.wrapped)
return Vector(tmp_fc_vector.multiply(scale))
tmp_fc_vector = FreeCAD.Base.Vector(self._wrapped)
return type(self)(tmp_fc_vector.multiply(scale))
def normalized(self):
"""Return a normalized version of this vector"""
tmp_fc_vector = FreeCAD.Base.Vector(self.wrapped)
tmp_fc_vector = FreeCAD.Base.Vector(self._wrapped)
tmp_fc_vector.normalize()
return Vector(tmp_fc_vector)
return type(self)(tmp_fc_vector)
def Center(self):
"""Return the vector itself
@ -156,7 +199,7 @@ class Vector(object):
return self
def getAngle(self, v):
return self.wrapped.getAngle(v.wrapped)
return self._wrapped.getAngle(v.wrapped)
def distanceToLine(self):
raise NotImplementedError("Have not needed this yet, but FreeCAD supports it!")
@ -170,17 +213,36 @@ class Vector(object):
def projectToPlane(self):
raise NotImplementedError("Have not needed this yet, but FreeCAD supports it!")
def __bool__(self):
return any(coord != 0 for coord in self.toTuple())
__nonzero__ = __bool__ # python 2.x compatability
def __add__(self, v):
return self.add(v)
def __sub__(self, v):
return self.sub(v)
def __mul__(self, scalar):
return self.multiply(scalar)
def __truediv__(self, scalar):
if scalar == 0:
raise ZeroDivisionError("%r division by zero" % (type(self)))
return self.multiply(1. / scalar)
def __neg__(self):
return type(self)(self.wrapped.negative())
def __abs__(self):
return self.Length
def __repr__(self):
return self.wrapped.__repr__()
return self._wrapped.__repr__()
def __str__(self):
return self.wrapped.__str__()
return self._wrapped.__str__()
def __ne__(self, other):
if isinstance(other, Vector):
@ -192,6 +254,9 @@ class Vector(object):
return self.wrapped.__eq__(other.wrapped)
return False
def __copy__(self):
return type(self)(self._wrapped)
class Matrix:
"""A 3d , 4x4 transformation matrix.
@ -224,6 +289,10 @@ class Plane(object):
created automatically from faces.
"""
# equality tolerances
_eq_tolerance_origin = 1e-6
_eq_tolerance_dot = 1e-6
@classmethod
def named(cls, stdName, origin=(0, 0, 0)):
"""Create a predefined Plane based on the conventional names.
@ -256,18 +325,18 @@ class Plane(object):
namedPlanes = {
# origin, xDir, normal
'XY': Plane(origin, (1, 0, 0), (0, 0, 1)),
'YZ': Plane(origin, (0, 1, 0), (1, 0, 0)),
'ZX': Plane(origin, (0, 0, 1), (0, 1, 0)),
'XZ': Plane(origin, (1, 0, 0), (0, -1, 0)),
'YX': Plane(origin, (0, 1, 0), (0, 0, -1)),
'ZY': Plane(origin, (0, 0, 1), (-1, 0, 0)),
'front': Plane(origin, (1, 0, 0), (0, 0, 1)),
'back': Plane(origin, (-1, 0, 0), (0, 0, -1)),
'left': Plane(origin, (0, 0, 1), (-1, 0, 0)),
'right': Plane(origin, (0, 0, -1), (1, 0, 0)),
'top': Plane(origin, (1, 0, 0), (0, 1, 0)),
'bottom': Plane(origin, (1, 0, 0), (0, -1, 0))
'XY': cls(origin, (1, 0, 0), (0, 0, 1)),
'YZ': cls(origin, (0, 1, 0), (1, 0, 0)),
'ZX': cls(origin, (0, 0, 1), (0, 1, 0)),
'XZ': cls(origin, (1, 0, 0), (0, -1, 0)),
'YX': cls(origin, (0, 1, 0), (0, 0, -1)),
'ZY': cls(origin, (0, 0, 1), (-1, 0, 0)),
'front': cls(origin, (1, 0, 0), (0, 0, 1)),
'back': cls(origin, (-1, 0, 0), (0, 0, -1)),
'left': cls(origin, (0, 0, 1), (-1, 0, 0)),
'right': cls(origin, (0, 0, -1), (1, 0, 0)),
'top': cls(origin, (1, 0, 0), (0, 1, 0)),
'bottom': cls(origin, (1, 0, 0), (0, -1, 0))
}
try:
@ -278,73 +347,73 @@ class Plane(object):
@classmethod
def XY(cls, origin=(0, 0, 0), xDir=Vector(1, 0, 0)):
plane = Plane.named('XY', origin)
plane = cls.named('XY', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def YZ(cls, origin=(0, 0, 0), xDir=Vector(0, 1, 0)):
plane = Plane.named('YZ', origin)
plane = cls.named('YZ', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def ZX(cls, origin=(0, 0, 0), xDir=Vector(0, 0, 1)):
plane = Plane.named('ZX', origin)
plane = cls.named('ZX', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def XZ(cls, origin=(0, 0, 0), xDir=Vector(1, 0, 0)):
plane = Plane.named('XZ', origin)
plane = cls.named('XZ', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def YX(cls, origin=(0, 0, 0), xDir=Vector(0, 1, 0)):
plane = Plane.named('YX', origin)
plane = cls.named('YX', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def ZY(cls, origin=(0, 0, 0), xDir=Vector(0, 0, 1)):
plane = Plane.named('ZY', origin)
plane = cls.named('ZY', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def front(cls, origin=(0, 0, 0), xDir=Vector(1, 0, 0)):
plane = Plane.named('front', origin)
plane = cls.named('front', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def back(cls, origin=(0, 0, 0), xDir=Vector(-1, 0, 0)):
plane = Plane.named('back', origin)
plane = cls.named('back', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def left(cls, origin=(0, 0, 0), xDir=Vector(0, 0, 1)):
plane = Plane.named('left', origin)
plane = cls.named('left', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def right(cls, origin=(0, 0, 0), xDir=Vector(0, 0, -1)):
plane = Plane.named('right', origin)
plane = cls.named('right', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def top(cls, origin=(0, 0, 0), xDir=Vector(1, 0, 0)):
plane = Plane.named('top', origin)
plane = cls.named('top', origin)
plane._setPlaneDir(xDir)
return plane
@classmethod
def bottom(cls, origin=(0, 0, 0), xDir=Vector(1, 0, 0)):
plane = Plane.named('bottom', origin)
plane = cls.named('bottom', origin)
plane._setPlaneDir(xDir)
return plane
@ -360,17 +429,30 @@ class Plane(object):
:type normal: a FreeCAD Vector
:raises: ValueError if the specified xDir is not orthogonal to the provided normal.
:return: a plane in the global space, with the xDirection of the plane in the specified direction.
**Non-orthogonal vectors**
If the ``xDir`` and ``normal`` vectors are not orthogonal, the ``normal``
(or ``z`` axis) vector direction is preserved, and truely orthogonal
``x`` and ``y`` axes are calculated with cross products.
* ``y = z.cross(x)``, and
* ``x = y.cross(z)``
"""
# z-axis
normal = Vector(normal)
if (normal.Length == 0.0):
raise ValueError('normal should be non null')
self.zDir = normal.normalized()
# x-axis
xDir = Vector(xDir)
if (xDir.Length == 0.0):
raise ValueError('xDir should be non null')
self._setPlaneDir(xDir)
self.invZDir = self.zDir.multiply(-1.0)
self.invZDir = -self.zDir
self.origin = origin
@ -513,7 +595,7 @@ class Plane(object):
newXdir = Vector(m.multiply(self.xDir.wrapped))
newZdir = Vector(m.multiply(self.zDir.wrapped))
return Plane(self.origin, newXdir, newZdir)
return type(self)(self.origin, newXdir, newZdir)
def rotateShapes(self, listOfShapes, rotationMatrix):
"""Rotate the listOfShapes by the supplied rotationMatrix
@ -560,11 +642,9 @@ class Plane(object):
def _setPlaneDir(self, xDir):
"""Set the vectors parallel to the plane, i.e. xDir and yDir"""
if (self.zDir.dot(xDir) > 1e-5):
raise ValueError('xDir must be parralel to the plane')
xDir = Vector(xDir)
self.xDir = xDir.normalized()
self.xDir = Vector(xDir)
self.yDir = self.zDir.cross(self.xDir).normalized()
self.xDir = self.yDir.cross(self.zDir).normalized()
def _calcTransforms(self):
"""Computes transformation matrices to convert between coordinates
@ -596,6 +676,22 @@ class Plane(object):
return Matrix(self.fG.multiply(tMatrix.wrapped).multiply(self.rG))
# Equality
def __eq__(self, other):
def equality_iter():
cls = type(self)
yield isinstance(other, Plane) # comparison is with another Plane
# origins are the same
yield abs(self.origin - other.origin) < cls._eq_tolerance_origin
# z-axis vectors are parallel (assumption: both are unit vectors)
yield abs(self.zDir.dot(other.zDir) - 1) < cls._eq_tolerance_dot
# x-axis vectors are parallel (assumption: both are unit vectors)
yield abs(self.xDir.dot(other.xDir) - 1) < cls._eq_tolerance_dot
return all(equality_iter())
def __ne__(self, other):
return not self.__eq__(other)
class BoundBox(object):
"""A BoundingBox for an object or set of objects. Wraps the FreeCAD one"""

View File

@ -8,7 +8,7 @@ import sys
import os
import urllib as urlreader
import tempfile
class ImportTypes:
STEP = "STEP"
@ -34,10 +34,9 @@ def importStep(fileName):
"""
Accepts a file name and loads the STEP file into a cadquery shape
:param fileName: The path and name of the STEP file to be imported
"""
"""
#Now read and return the shape
try:
#print fileName
rshape = Part.read(fileName)
#Make sure that we extract all the solids
@ -50,14 +49,20 @@ def importStep(fileName):
raise ValueError("STEP File Could not be loaded")
#Loads a STEP file from an URL into a CQ.Workplane object
def importStepFromURL(url):
def importStepFromURL(url):
#Now read and return the shape
try:
webFile = urlreader.urlopen(url)
# Account for differences in urllib between Python 2 and 3
if hasattr(urlreader, "urlopen"):
webFile = urlreader.urlopen(url)
else:
import urllib.request
webFile = urllib.request.urlopen(url)
tempFile = tempfile.NamedTemporaryFile(suffix='.step', delete=False)
tempFile.write(webFile.read())
webFile.close()
tempFile.close()
tempFile.close()
rshape = Part.read(tempFile.name)

View File

@ -107,15 +107,15 @@ class Shape(object):
# TODO: all these should move into the exporters folder.
# we dont need a bunch of exporting code stored in here!
#
def exportStl(self, fileName):
self.wrapped.exportStl(fileName)
def exportStl(self, fileName, tolerance=0.1):
self.wrapped.exportStl(fileName, tolerance)
def exportStep(self, fileName):
self.wrapped.exportStep(fileName)
def exportShape(self, fileName, fileFormat):
def exportShape(self, fileName, fileFormat, tolerance=0.1):
if fileFormat == ExportFormats.STL:
self.wrapped.exportStl(fileName)
self.wrapped.exportStl(fileName, tolerance)
elif fileFormat == ExportFormats.BREP:
self.wrapped.exportBrep(fileName)
elif fileFormat == ExportFormats.STEP:
@ -165,7 +165,7 @@ class Shape(object):
if the provide object is not a shape at all
"""
if hasattr(obj, 'ShapeType'):
return obj.ShapeType == strType
return obj.ShapeType() == strType
else:
return False
@ -306,7 +306,13 @@ class Shape(object):
return [Solid(i) for i in self.wrapped.Solids]
def Area(self):
return self.wrapped.Area
"""
Returns the area of a shape, but only if it is a face
"""
if self.wrapped.ShapeType == 'Face':
return self.wrapped.Area
else:
raise ValueError("shape type must be 'Face' to calculate the area")
def Length(self):
return self.wrapped.Length
@ -650,7 +656,7 @@ class Face(Shape):
Create a ruled surface out of two edges or wires. If wires are used then
these must have the same
"""
return Shape.cast(FreeCADPart.makeRuledSurface(edgeOrWire1.obj, edgeOrWire2.obj, dist))
return Shape.cast(FreeCADPart.makeRuledSurface(edgeOrWire1.wrapped, edgeOrWire2.wrapped))
def cut(self, faceToCut):
"Remove a face from another one"

View File

@ -2,35 +2,72 @@ Changes
=======
v0.1
-----
* Initial Version
v1.1.0 (Unreleased)
------
* Fixes and addition of graphical examples for selectors (thanks @adam-urbanczyk) #181
* Added intersect operation (thanks @fragmuffin) #189
* CQGI updates (changed `build_object` function name to `show_object`) #194
* Added `lefthand` and `heightstyle` options to makeHelix function (thanks @fragmuffin) #197
* Test suite cleanup (thanks @fragmuffin) #198
* Added formal logging mechanism (thanks @fragmuffin) #200
* Merged examples into this library (they were spread out before) #201
* Fixed vector equality error (thanks @fragmuffin) #202
* Expanded CQGI to handle float variables in addition to int #204
* Dockerfile added by @dcowden for Docker build and command line interface #205
* Initial Python 3 support for the FreeCAD backend was added by @adam-urbanczyk #207
* Fixed Line versus LineSegment incompatibility between FreeCAD 0.16 and 0.17 #209
* @RustyVermeer fixed a long-standing bug with the extrusion of invalid faces #210
* @adam-urbanczyk fixed a Python 2 versus Python 3 (unicode) issue with SVG export #215
v1.0.0
------
* Added an option to do symmetric extrusion about the workplane (thanks @adam-urbanczyk)
* Extended selector syntax to include Nth selector and re-implemented selectors using pyparsing (thanks @adam-urbanczyk)
* Added logical operations to string selectors (thanks @adam-urbanczyk)
* Cleanup of README.md and changes.md (thanks @baoboa)
* Fixed bugs with toVector and Face 'Not Defined' errors (thanks @huskier)
* Refactor of the initialization code for PEP8 compliance and Python 3 compatibility (thanks @Peque)
* Making sure that the new pyparsing library dependency is handled properly (thanks @Peque)
v0.1.6
-----
* Added STEP import and supporting tests
v0.5.2
------
* Added the sweep operation #33
v0.5.1
------
* Mirroring fixes (thanks @huskier)
* Added a mirroring example (thanks @huskier)
v0.1.7
-----
* Added revolve operation and supporting tests
* Fixed minor documentation errors
v0.5.0-stable
------
* Configuring Travis to push to PyPI on version releases.
v0.1.8
v0.4.1
------
* Minor CQGI updates
v0.4.0
------
* Added Documentation, which is available on dcowden.github.io/cadquery
* Added CQGI, an adapter API that standardizes use of cadquery from within structured execution environments
* Added ability to import STEP files from a web URL (thanks @huskier ) #128
v0.3.0
-----
* Added toFreecad() function as a convenience for val().wrapped
* Converted all examples to use toFreecad()
* Updated all version numbers that were missed before
* Fixed import issues in Windows caused by fc_import
* Added/fixed Mac OS support
* Improved STEP import
* Fixed bug in rotateAboutCenter that negated its effect on solids
* Added Travis config (thanks @krasin)
* Removed redundant workplane.py file left over from the PParts.com migration
* Fixed toWorldCoordinates bug in moveTo (thanks @xix-xeaon)
* Added new tests for 2D drawing functions
* Integrated Coveralls.io, with a badge in README.md
* Integrated version badge in README.md
* Fixed a bug where clean() could not be called on appropriate objects other than solids (thanks @hyOzd) #108
* Implemented new selectors that allow existing selectors to be combined with arithmetic/boolean operations (thanks @hyOzd) #110
* Fixed a bug where only 1 random edge was returned with multiple min/max selector matches (thanks @hyOzd) #111
* Implemented the creation of a workplane from multiple co-planar faces (thanks @hyOzd) #113
* Fixed the operation of Center() when called on a compound with multiple solids
* Add the named planes ZX YX ZY to define different normals (thanks @galou) #115
* Code cleanup in accordance with PEP 8 (thanks @galou)
* Fixed a bug with the close function not resetting the first point of the context correctly (thanks @huskier)
* Fixed the findSolid function so that it handles compounds #107
* Changed the polyline function so that it adds edges to the stack instead of a wire #102
* Add the ability to find the center of the bounding box, rather than the center of mass (thanks @huskier) #122
* Changed normalize function to normalized to match OCC/PythonOCC nomenclature #124
* Added a label attribute to all freecad_impl.shapes so that they can have IDs attached to them #124
v0.2.0
-----
* Fixed versioning to match the semantic versioning scheme
@ -50,56 +87,31 @@ v0.2.0
* Added a clean function to keep some operations from failing on solids that need simplified (thanks @hyOzd)
* Added a mention of the new Google Group to the readme
v0.3.0
v0.1.8
-----
* Fixed a bug where clean() could not be called on appropriate objects other than solids (thanks @hyOzd) #108
* Implemented new selectors that allow existing selectors to be combined with arithmetic/boolean operations (thanks @hyOzd) #110
* Fixed a bug where only 1 random edge was returned with multiple min/max selector matches (thanks @hyOzd) #111
* Implemented the creation of a workplane from multiple co-planar faces (thanks @hyOzd) #113
* Fixed the operation of Center() when called on a compound with multiple solids
* Add the named planes ZX YX ZY to define different normals (thanks @galou) #115
* Code cleanup in accordance with PEP 8 (thanks @galou)
* Fixed a bug with the close function not resetting the first point of the context correctly (thanks @huskier)
* Fixed the findSolid function so that it handles compounds #107
* Changed the polyline function so that it adds edges to the stack instead of a wire #102
* Add the ability to find the center of the bounding box, rather than the center of mass (thanks @huskier) #122
* Changed normalize function to normalized to match OCC/PythonOCC nomenclature #124
* Added a label attribute to all freecad_impl.shapes so that they can have IDs attached to them #124
* Added toFreecad() function as a convenience for val().wrapped
* Converted all examples to use toFreecad()
* Updated all version numbers that were missed before
* Fixed import issues in Windows caused by fc_import
* Added/fixed Mac OS support
* Improved STEP import
* Fixed bug in rotateAboutCenter that negated its effect on solids
* Added Travis config (thanks @krasin)
* Removed redundant workplane.py file left over from the PParts.com migration
* Fixed toWorldCoordinates bug in moveTo (thanks @xix-xeaon)
* Added new tests for 2D drawing functions
* Integrated Coveralls.io, with a badge in README.md
* Integrated version badge in README.md
v0.4.0
------
* Added Documentation, which is available on dcowden.github.io/cadquery
* Added CQGI, an adapter API that standardizes use of cadquery from within structured execution environments
* Added ability to import STEP files from a web URL (thanks @huskier ) #128
v0.4.1
------
* Minor CQGI updates
v0.5.0-stable
------
* Configuring Travis to push to PyPI on version releases.
v0.5.1
------
* Mirroring fixes (thanks @huskier)
* Added a mirroring example (thanks @huskier)
v0.5.2
------
* Added the sweep operation #33
v1.0.0
------
* Added an option to do symmetric extrusion about the workplane (thanks @adam-urbanczyk)
* Extended selector syntax to include Nth selector and re-implemented selectors using pyparsing (thanks @adam-urbanczyk)
* Added logical operations to string selectors (thanks @adam-urbanczyk)
* Cleanup of README.md and changes.md (thanks @baoboa)
* Fixed bugs with toVector and Face 'Not Defined' errors (thanks @huskier)
* Refactor of the initialization code for PEP8 compliance and Python 3 compatibility (thanks @Peque)
* Making sure that the new pyparsing library dependency is handled properly (thanks @Peque)
v0.1.7
-----
* Added revolve operation and supporting tests
* Fixed minor documentation errors
v1.1.0 (Unreleased)
------
* Fixes and addition of graphical examples for selectors (thanks @adam-urbanczyk)
* Added intersect operation (thanks @fragmuffin)
v0.1.6
-----
* Added STEP import and supporting tests
v0.1
-----
* Initial Version

View File

@ -6,7 +6,7 @@
# if no output filename is provided, output goes to stdout
# default output format is STEP
#
from __future__ import print_function
import sys,os
@ -21,6 +21,7 @@ import os.path
import json
import tempfile
class FilepathShapeWriter(object):
#a shape writer that writes a new file in a directory for each object
def __init__(self,file_pattern, shape_format):

View File

@ -0,0 +1,428 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('FreeCAD Model'),'2;1');
FILE_NAME(
'/home/jwright/Downloads/repos/cadquery-freecad-module/Libs/cadquery/doc
/_static/example_step_export.step','2018-02-15T09:43:34',('Author'),('')
,'Open CASCADE STEP processor 7.1','FreeCAD','Unknown');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1 = APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2000,#2);
#2 = APPLICATION_CONTEXT(
'core data for automotive mechanical design processes');
#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);
#4 = PRODUCT_DEFINITION_SHAPE('','',#5);
#5 = PRODUCT_DEFINITION('design','',#6,#9);
#6 = PRODUCT_DEFINITION_FORMATION('','',#7);
#7 = PRODUCT('Body','Body','',(#8));
#8 = PRODUCT_CONTEXT('',#2,'mechanical');
#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#345);
#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);
#12 = CARTESIAN_POINT('',(0.,0.,0.));
#13 = DIRECTION('',(0.,0.,1.));
#14 = DIRECTION('',(1.,0.,-0.));
#15 = MANIFOLD_SOLID_BREP('',#16);
#16 = CLOSED_SHELL('',(#17,#137,#237,#284,#331,#338));
#17 = ADVANCED_FACE('',(#18),#32,.F.);
#18 = FACE_BOUND('',#19,.F.);
#19 = EDGE_LOOP('',(#20,#55,#83,#111));
#20 = ORIENTED_EDGE('',*,*,#21,.F.);
#21 = EDGE_CURVE('',#22,#24,#26,.T.);
#22 = VERTEX_POINT('',#23);
#23 = CARTESIAN_POINT('',(0.,0.,0.));
#24 = VERTEX_POINT('',#25);
#25 = CARTESIAN_POINT('',(0.,0.,10.));
#26 = SURFACE_CURVE('',#27,(#31,#43),.PCURVE_S1.);
#27 = LINE('',#28,#29);
#28 = CARTESIAN_POINT('',(0.,0.,0.));
#29 = VECTOR('',#30,1.);
#30 = DIRECTION('',(0.,0.,1.));
#31 = PCURVE('',#32,#37);
#32 = PLANE('',#33);
#33 = AXIS2_PLACEMENT_3D('',#34,#35,#36);
#34 = CARTESIAN_POINT('',(0.,0.,0.));
#35 = DIRECTION('',(1.,0.,0.));
#36 = DIRECTION('',(0.,0.,1.));
#37 = DEFINITIONAL_REPRESENTATION('',(#38),#42);
#38 = LINE('',#39,#40);
#39 = CARTESIAN_POINT('',(0.,0.));
#40 = VECTOR('',#41,1.);
#41 = DIRECTION('',(1.,0.));
#42 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#43 = PCURVE('',#44,#49);
#44 = PLANE('',#45);
#45 = AXIS2_PLACEMENT_3D('',#46,#47,#48);
#46 = CARTESIAN_POINT('',(0.,0.,0.));
#47 = DIRECTION('',(0.,1.,0.));
#48 = DIRECTION('',(0.,0.,1.));
#49 = DEFINITIONAL_REPRESENTATION('',(#50),#54);
#50 = LINE('',#51,#52);
#51 = CARTESIAN_POINT('',(0.,0.));
#52 = VECTOR('',#53,1.);
#53 = DIRECTION('',(1.,0.));
#54 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#55 = ORIENTED_EDGE('',*,*,#56,.T.);
#56 = EDGE_CURVE('',#22,#57,#59,.T.);
#57 = VERTEX_POINT('',#58);
#58 = CARTESIAN_POINT('',(0.,10.,0.));
#59 = SURFACE_CURVE('',#60,(#64,#71),.PCURVE_S1.);
#60 = LINE('',#61,#62);
#61 = CARTESIAN_POINT('',(0.,0.,0.));
#62 = VECTOR('',#63,1.);
#63 = DIRECTION('',(0.,1.,0.));
#64 = PCURVE('',#32,#65);
#65 = DEFINITIONAL_REPRESENTATION('',(#66),#70);
#66 = LINE('',#67,#68);
#67 = CARTESIAN_POINT('',(0.,0.));
#68 = VECTOR('',#69,1.);
#69 = DIRECTION('',(0.,-1.));
#70 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#71 = PCURVE('',#72,#77);
#72 = PLANE('',#73);
#73 = AXIS2_PLACEMENT_3D('',#74,#75,#76);
#74 = CARTESIAN_POINT('',(0.,0.,0.));
#75 = DIRECTION('',(0.,0.,1.));
#76 = DIRECTION('',(1.,0.,0.));
#77 = DEFINITIONAL_REPRESENTATION('',(#78),#82);
#78 = LINE('',#79,#80);
#79 = CARTESIAN_POINT('',(0.,0.));
#80 = VECTOR('',#81,1.);
#81 = DIRECTION('',(0.,1.));
#82 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#83 = ORIENTED_EDGE('',*,*,#84,.T.);
#84 = EDGE_CURVE('',#57,#85,#87,.T.);
#85 = VERTEX_POINT('',#86);
#86 = CARTESIAN_POINT('',(0.,10.,10.));
#87 = SURFACE_CURVE('',#88,(#92,#99),.PCURVE_S1.);
#88 = LINE('',#89,#90);
#89 = CARTESIAN_POINT('',(0.,10.,0.));
#90 = VECTOR('',#91,1.);
#91 = DIRECTION('',(0.,0.,1.));
#92 = PCURVE('',#32,#93);
#93 = DEFINITIONAL_REPRESENTATION('',(#94),#98);
#94 = LINE('',#95,#96);
#95 = CARTESIAN_POINT('',(0.,-10.));
#96 = VECTOR('',#97,1.);
#97 = DIRECTION('',(1.,0.));
#98 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#99 = PCURVE('',#100,#105);
#100 = PLANE('',#101);
#101 = AXIS2_PLACEMENT_3D('',#102,#103,#104);
#102 = CARTESIAN_POINT('',(0.,10.,0.));
#103 = DIRECTION('',(0.,1.,0.));
#104 = DIRECTION('',(0.,0.,1.));
#105 = DEFINITIONAL_REPRESENTATION('',(#106),#110);
#106 = LINE('',#107,#108);
#107 = CARTESIAN_POINT('',(0.,0.));
#108 = VECTOR('',#109,1.);
#109 = DIRECTION('',(1.,0.));
#110 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#111 = ORIENTED_EDGE('',*,*,#112,.F.);
#112 = EDGE_CURVE('',#24,#85,#113,.T.);
#113 = SURFACE_CURVE('',#114,(#118,#125),.PCURVE_S1.);
#114 = LINE('',#115,#116);
#115 = CARTESIAN_POINT('',(0.,0.,10.));
#116 = VECTOR('',#117,1.);
#117 = DIRECTION('',(0.,1.,0.));
#118 = PCURVE('',#32,#119);
#119 = DEFINITIONAL_REPRESENTATION('',(#120),#124);
#120 = LINE('',#121,#122);
#121 = CARTESIAN_POINT('',(10.,0.));
#122 = VECTOR('',#123,1.);
#123 = DIRECTION('',(0.,-1.));
#124 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#125 = PCURVE('',#126,#131);
#126 = PLANE('',#127);
#127 = AXIS2_PLACEMENT_3D('',#128,#129,#130);
#128 = CARTESIAN_POINT('',(0.,0.,10.));
#129 = DIRECTION('',(0.,0.,1.));
#130 = DIRECTION('',(1.,0.,0.));
#131 = DEFINITIONAL_REPRESENTATION('',(#132),#136);
#132 = LINE('',#133,#134);
#133 = CARTESIAN_POINT('',(0.,0.));
#134 = VECTOR('',#135,1.);
#135 = DIRECTION('',(0.,1.));
#136 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#137 = ADVANCED_FACE('',(#138),#152,.T.);
#138 = FACE_BOUND('',#139,.T.);
#139 = EDGE_LOOP('',(#140,#170,#193,#216));
#140 = ORIENTED_EDGE('',*,*,#141,.F.);
#141 = EDGE_CURVE('',#142,#144,#146,.T.);
#142 = VERTEX_POINT('',#143);
#143 = CARTESIAN_POINT('',(10.,0.,0.));
#144 = VERTEX_POINT('',#145);
#145 = CARTESIAN_POINT('',(10.,0.,10.));
#146 = SURFACE_CURVE('',#147,(#151,#163),.PCURVE_S1.);
#147 = LINE('',#148,#149);
#148 = CARTESIAN_POINT('',(10.,0.,0.));
#149 = VECTOR('',#150,1.);
#150 = DIRECTION('',(0.,0.,1.));
#151 = PCURVE('',#152,#157);
#152 = PLANE('',#153);
#153 = AXIS2_PLACEMENT_3D('',#154,#155,#156);
#154 = CARTESIAN_POINT('',(10.,0.,0.));
#155 = DIRECTION('',(1.,0.,0.));
#156 = DIRECTION('',(0.,0.,1.));
#157 = DEFINITIONAL_REPRESENTATION('',(#158),#162);
#158 = LINE('',#159,#160);
#159 = CARTESIAN_POINT('',(0.,0.));
#160 = VECTOR('',#161,1.);
#161 = DIRECTION('',(1.,0.));
#162 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#163 = PCURVE('',#44,#164);
#164 = DEFINITIONAL_REPRESENTATION('',(#165),#169);
#165 = LINE('',#166,#167);
#166 = CARTESIAN_POINT('',(0.,10.));
#167 = VECTOR('',#168,1.);
#168 = DIRECTION('',(1.,0.));
#169 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#170 = ORIENTED_EDGE('',*,*,#171,.T.);
#171 = EDGE_CURVE('',#142,#172,#174,.T.);
#172 = VERTEX_POINT('',#173);
#173 = CARTESIAN_POINT('',(10.,10.,0.));
#174 = SURFACE_CURVE('',#175,(#179,#186),.PCURVE_S1.);
#175 = LINE('',#176,#177);
#176 = CARTESIAN_POINT('',(10.,0.,0.));
#177 = VECTOR('',#178,1.);
#178 = DIRECTION('',(0.,1.,0.));
#179 = PCURVE('',#152,#180);
#180 = DEFINITIONAL_REPRESENTATION('',(#181),#185);
#181 = LINE('',#182,#183);
#182 = CARTESIAN_POINT('',(0.,0.));
#183 = VECTOR('',#184,1.);
#184 = DIRECTION('',(0.,-1.));
#185 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#186 = PCURVE('',#72,#187);
#187 = DEFINITIONAL_REPRESENTATION('',(#188),#192);
#188 = LINE('',#189,#190);
#189 = CARTESIAN_POINT('',(10.,0.));
#190 = VECTOR('',#191,1.);
#191 = DIRECTION('',(0.,1.));
#192 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#193 = ORIENTED_EDGE('',*,*,#194,.T.);
#194 = EDGE_CURVE('',#172,#195,#197,.T.);
#195 = VERTEX_POINT('',#196);
#196 = CARTESIAN_POINT('',(10.,10.,10.));
#197 = SURFACE_CURVE('',#198,(#202,#209),.PCURVE_S1.);
#198 = LINE('',#199,#200);
#199 = CARTESIAN_POINT('',(10.,10.,0.));
#200 = VECTOR('',#201,1.);
#201 = DIRECTION('',(0.,0.,1.));
#202 = PCURVE('',#152,#203);
#203 = DEFINITIONAL_REPRESENTATION('',(#204),#208);
#204 = LINE('',#205,#206);
#205 = CARTESIAN_POINT('',(0.,-10.));
#206 = VECTOR('',#207,1.);
#207 = DIRECTION('',(1.,0.));
#208 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#209 = PCURVE('',#100,#210);
#210 = DEFINITIONAL_REPRESENTATION('',(#211),#215);
#211 = LINE('',#212,#213);
#212 = CARTESIAN_POINT('',(0.,10.));
#213 = VECTOR('',#214,1.);
#214 = DIRECTION('',(1.,0.));
#215 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#216 = ORIENTED_EDGE('',*,*,#217,.F.);
#217 = EDGE_CURVE('',#144,#195,#218,.T.);
#218 = SURFACE_CURVE('',#219,(#223,#230),.PCURVE_S1.);
#219 = LINE('',#220,#221);
#220 = CARTESIAN_POINT('',(10.,0.,10.));
#221 = VECTOR('',#222,1.);
#222 = DIRECTION('',(0.,1.,0.));
#223 = PCURVE('',#152,#224);
#224 = DEFINITIONAL_REPRESENTATION('',(#225),#229);
#225 = LINE('',#226,#227);
#226 = CARTESIAN_POINT('',(10.,0.));
#227 = VECTOR('',#228,1.);
#228 = DIRECTION('',(0.,-1.));
#229 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#230 = PCURVE('',#126,#231);
#231 = DEFINITIONAL_REPRESENTATION('',(#232),#236);
#232 = LINE('',#233,#234);
#233 = CARTESIAN_POINT('',(10.,0.));
#234 = VECTOR('',#235,1.);
#235 = DIRECTION('',(0.,1.));
#236 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#237 = ADVANCED_FACE('',(#238),#44,.F.);
#238 = FACE_BOUND('',#239,.F.);
#239 = EDGE_LOOP('',(#240,#261,#262,#283));
#240 = ORIENTED_EDGE('',*,*,#241,.F.);
#241 = EDGE_CURVE('',#22,#142,#242,.T.);
#242 = SURFACE_CURVE('',#243,(#247,#254),.PCURVE_S1.);
#243 = LINE('',#244,#245);
#244 = CARTESIAN_POINT('',(0.,0.,0.));
#245 = VECTOR('',#246,1.);
#246 = DIRECTION('',(1.,0.,0.));
#247 = PCURVE('',#44,#248);
#248 = DEFINITIONAL_REPRESENTATION('',(#249),#253);
#249 = LINE('',#250,#251);
#250 = CARTESIAN_POINT('',(0.,0.));
#251 = VECTOR('',#252,1.);
#252 = DIRECTION('',(0.,1.));
#253 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#254 = PCURVE('',#72,#255);
#255 = DEFINITIONAL_REPRESENTATION('',(#256),#260);
#256 = LINE('',#257,#258);
#257 = CARTESIAN_POINT('',(0.,0.));
#258 = VECTOR('',#259,1.);
#259 = DIRECTION('',(1.,0.));
#260 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#261 = ORIENTED_EDGE('',*,*,#21,.T.);
#262 = ORIENTED_EDGE('',*,*,#263,.T.);
#263 = EDGE_CURVE('',#24,#144,#264,.T.);
#264 = SURFACE_CURVE('',#265,(#269,#276),.PCURVE_S1.);
#265 = LINE('',#266,#267);
#266 = CARTESIAN_POINT('',(0.,0.,10.));
#267 = VECTOR('',#268,1.);
#268 = DIRECTION('',(1.,0.,0.));
#269 = PCURVE('',#44,#270);
#270 = DEFINITIONAL_REPRESENTATION('',(#271),#275);
#271 = LINE('',#272,#273);
#272 = CARTESIAN_POINT('',(10.,0.));
#273 = VECTOR('',#274,1.);
#274 = DIRECTION('',(0.,1.));
#275 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#276 = PCURVE('',#126,#277);
#277 = DEFINITIONAL_REPRESENTATION('',(#278),#282);
#278 = LINE('',#279,#280);
#279 = CARTESIAN_POINT('',(0.,0.));
#280 = VECTOR('',#281,1.);
#281 = DIRECTION('',(1.,0.));
#282 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#283 = ORIENTED_EDGE('',*,*,#141,.F.);
#284 = ADVANCED_FACE('',(#285),#100,.T.);
#285 = FACE_BOUND('',#286,.T.);
#286 = EDGE_LOOP('',(#287,#308,#309,#330));
#287 = ORIENTED_EDGE('',*,*,#288,.F.);
#288 = EDGE_CURVE('',#57,#172,#289,.T.);
#289 = SURFACE_CURVE('',#290,(#294,#301),.PCURVE_S1.);
#290 = LINE('',#291,#292);
#291 = CARTESIAN_POINT('',(0.,10.,0.));
#292 = VECTOR('',#293,1.);
#293 = DIRECTION('',(1.,0.,0.));
#294 = PCURVE('',#100,#295);
#295 = DEFINITIONAL_REPRESENTATION('',(#296),#300);
#296 = LINE('',#297,#298);
#297 = CARTESIAN_POINT('',(0.,0.));
#298 = VECTOR('',#299,1.);
#299 = DIRECTION('',(0.,1.));
#300 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#301 = PCURVE('',#72,#302);
#302 = DEFINITIONAL_REPRESENTATION('',(#303),#307);
#303 = LINE('',#304,#305);
#304 = CARTESIAN_POINT('',(0.,10.));
#305 = VECTOR('',#306,1.);
#306 = DIRECTION('',(1.,0.));
#307 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#308 = ORIENTED_EDGE('',*,*,#84,.T.);
#309 = ORIENTED_EDGE('',*,*,#310,.T.);
#310 = EDGE_CURVE('',#85,#195,#311,.T.);
#311 = SURFACE_CURVE('',#312,(#316,#323),.PCURVE_S1.);
#312 = LINE('',#313,#314);
#313 = CARTESIAN_POINT('',(0.,10.,10.));
#314 = VECTOR('',#315,1.);
#315 = DIRECTION('',(1.,0.,0.));
#316 = PCURVE('',#100,#317);
#317 = DEFINITIONAL_REPRESENTATION('',(#318),#322);
#318 = LINE('',#319,#320);
#319 = CARTESIAN_POINT('',(10.,0.));
#320 = VECTOR('',#321,1.);
#321 = DIRECTION('',(0.,1.));
#322 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#323 = PCURVE('',#126,#324);
#324 = DEFINITIONAL_REPRESENTATION('',(#325),#329);
#325 = LINE('',#326,#327);
#326 = CARTESIAN_POINT('',(0.,10.));
#327 = VECTOR('',#328,1.);
#328 = DIRECTION('',(1.,0.));
#329 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
) );
#330 = ORIENTED_EDGE('',*,*,#194,.F.);
#331 = ADVANCED_FACE('',(#332),#72,.F.);
#332 = FACE_BOUND('',#333,.F.);
#333 = EDGE_LOOP('',(#334,#335,#336,#337));
#334 = ORIENTED_EDGE('',*,*,#56,.F.);
#335 = ORIENTED_EDGE('',*,*,#241,.T.);
#336 = ORIENTED_EDGE('',*,*,#171,.T.);
#337 = ORIENTED_EDGE('',*,*,#288,.F.);
#338 = ADVANCED_FACE('',(#339),#126,.T.);
#339 = FACE_BOUND('',#340,.T.);
#340 = EDGE_LOOP('',(#341,#342,#343,#344));
#341 = ORIENTED_EDGE('',*,*,#112,.F.);
#342 = ORIENTED_EDGE('',*,*,#263,.T.);
#343 = ORIENTED_EDGE('',*,*,#217,.T.);
#344 = ORIENTED_EDGE('',*,*,#310,.F.);
#345 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#349)) GLOBAL_UNIT_ASSIGNED_CONTEXT
((#346,#347,#348)) REPRESENTATION_CONTEXT('Context #1',
'3D Context with UNIT and UNCERTAINTY') );
#346 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
#347 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
#348 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
#349 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#346,
'distance_accuracy_value','confusion accuracy');
#350 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7));
#351 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#352)
,#345);
#352 = STYLED_ITEM('color',(#353),#15);
#353 = PRESENTATION_STYLE_ASSIGNMENT((#354,#360));
#354 = SURFACE_STYLE_USAGE(.BOTH.,#355);
#355 = SURFACE_SIDE_STYLE('',(#356));
#356 = SURFACE_STYLE_FILL_AREA(#357);
#357 = FILL_AREA_STYLE('',(#358));
#358 = FILL_AREA_STYLE_COLOUR('',#359);
#359 = COLOUR_RGB('',0.800000011921,0.800000011921,0.800000011921);
#360 = CURVE_STYLE('',#361,POSITIVE_LENGTH_MEASURE(0.1),#359);
#361 = DRAUGHTING_PRE_DEFINED_CURVE_FONT('continuous');
ENDSEC;
END-ISO-10303-21;

View File

@ -144,7 +144,7 @@ html_title = "CadQuery Documentation"
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "_static/cqlogo.png"
html_logo = "_static/logo/cadquery_logo_dark.svg"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32

View File

@ -3,7 +3,6 @@
The CadQuery Gateway Interface
====================================
CadQuery is first and foremost designed as a library, which can be used as a part of any project.
In this context, there is no need for a standard script format or gateway api.
@ -19,12 +18,10 @@ Today, three execution environments exist:
inside of the FreeCAD IDE, and displays objects in the display window
* the cq-directive, which is used to execute scripts inside of sphinx-doc,
producing documented examples that include both a script and an SVG representation of the object that results
* `ParametricParts.com <https://www.parametricparts.com>`_, which provides a web-based way to prompt user input for
variables, and then display the result output in a web page.
* `Jupyter Notebooks <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_, which provide a web-based way to build, view, and export scripts.
The CQGI is distributed with cadquery, and standardizes the interface between execution environments and cadquery scripts.
The Script Side
-----------------

View File

@ -9,9 +9,9 @@ If you are using cadquery as a library, there are no constraints.
If you are using cadquery scripts inside of a cadquery execution environment,
like `The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_ or
`parametricParts.com <https://www.parametricparts.com>`_, there are a few conventions you need to be aware of:
`Jupyter notebooks <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_, there are a few conventions you need to be aware of:
* cadquery is already imported as 'cq'
* cadquery is imported as 'cq'
* to return an object to the container, you need to call the show_object() method.
Each script generally has three sections:

View File

@ -47,12 +47,8 @@ If you prefer to have a GUI available, your best option is to use
Simply extract cadquery-freecad-module into your FreeCAD installation. You'll end up
with a cadquery workbench that allows you to interactively run scripts, and then see the results in the FreeCAD GUI
Zero Step Install
Zero Step Install
-------------------------------------------------
If you would like to use cadquery with no installation all, you can
use `ParametricParts.com <https://www.parametricparts.com>`_, a web-based platform that runs cadquery scripts
It is free, and allows running and viewing cadquery scripts in your web browser or mobile phone
use mybinder to `launch a Jupyter Notebook Server <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_ pre-configured to run CadQuery.

View File

@ -31,7 +31,7 @@ produces a flat plate with a hole in the middle::
.. image:: _static/simpleblock.png
That's a bit of a dixie-cup example. But it is pretty similar to a more useful part: a parametric pillow block for a
That is a simple example, but it is similar to a more useful part: a parametric pillow block for a
standard 608-size ball bearing::
(length,height,diam, thickness,padding) = ( 30.0,40.0,22.0,10.0,8.0)
@ -43,7 +43,7 @@ standard 608-size ball bearing::
.. image:: _static/pillowblock.png
Lots more examples are available in the :ref:`examples`
Many examples are available in the :ref:`examples`
CadQuery is a library, GUIs are separate
==============================================
@ -51,16 +51,16 @@ CadQuery is a library, GUIs are separate
CadQuery is a library, that's intentionally designed to be usable as a GUI-less library. This enables
its use in a variety of engineering and scientific applications that create 3d models programmatically.
If you'd like a GUI, you have a couple of options:
If you would like a GUI, you have a couple of options:
* Install cadquery as a part of `The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_
* Use `ParametricParts.com <https://www.parametricparts.com>`_, a web-based platform that runs cadQuery scripts
* Use `tryCQ <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_, a Jupyter Notebook server using `mybinder.org <https://mybinder.org/>`_. This solution runs entirely in your browser.
Why CadQuery instead of OpenSCAD?
============================================
Like OpenSCAD, CadQuery is an open-source, script based, parametric model generator. But CadQuery has several key advantages:
Like OpenSCAD, CadQuery is an open-source, script based, parametric model generator. However, CadQuery stands out in many ways and has several key advantages:
1. **The scripts use a standard programming language**, python, and thus can benefit from the associated infrastructure.
This includes many standard libraries and IDEs
@ -69,7 +69,7 @@ Like OpenSCAD, CadQuery is an open-source, script based, parametric model genera
by OCC include NURBS, splines, surface sewing, STL repair, STEP import/export, and other complex operations,
in addition to the standard CSG operations supported by CGAL
3. **Ability to import/export STEP** We think the ability to begin with a STEP model, created in a CAD package,
3. **Ability to import/export STEP** the ability to begin with a STEP model, created in a CAD package,
and then add parametric features is key. This is possible in OpenSCAD using STL, but STL is a lossy format
4. **Less Code and easier scripting** CadQuery scripts require less code to create most objects, because it is possible to locate

View File

@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import division
from collections import namedtuple
import cadquery as cq
# text_lines is a list of text lines.
# FreeCAD in braille (converted with braille-converter:
# "CadQuery" in braille (converted with braille-converter:
# https://github.com/jpaugh/braille-converter.git).
text_lines = ['⠠ ⠋ ⠗ ⠑ ⠑ ⠠ ⠉ ⠠ ⠁ ⠠ ⠙']
text_lines = [u'⠠ ⠉ ⠁ ⠙ ⠠ ⠟ ⠥ ⠻ ⠽']
# See http://www.tiresias.org/research/reports/braille_cell.htm for examples
# of braille cell geometry.
horizontal_interdot = 2.5
@ -40,16 +40,18 @@ class Point(object):
return Point(self.x + other.x, self.y + other.y)
def __len__(self):
"""Necessary to have it accepted as input to CadQuery"""
return 2
def __getitem__(self, index):
"""Necessary to have it accepted as input to CadQuery"""
return (self.x, self.y)[index]
def __str__(self):
return '({}, {})'.format(self.x, self.y)
def brailleToPoints(text, cell_geometry):
def braille_to_points(text, cell_geometry):
# Unicode bit pattern (cf. https://en.wikipedia.org/wiki/Braille_Patterns).
mask1 = 0b00000001
mask2 = 0b00000010
@ -75,7 +77,7 @@ def brailleToPoints(text, cell_geometry):
pos = (pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8)
# Braille blank pattern (u'\u2800').
blank = ''
blank = u''
points = []
# Position of dot1 along the x-axis (horizontal).
character_origin = 0
@ -108,8 +110,8 @@ def get_plate_width(text_lines, cell_geometry):
def get_cylinder_radius(cell_geometry):
"""Return the radius the cylinder should have
The cylinder have the same radius as the half-sphere make the dots (the
hidden and the shown part of the dots).
The cylinder have the same radius as the half-sphere that make the dots
(the hidden and the shown part of the dots).
The radius is such that the spherical cap with diameter
cell_geometry.dot_diameter has a height of cell_geometry.dot_height.
"""
@ -138,7 +140,7 @@ def make_embossed_plate(text_lines, cell_geometry):
"""Make an embossed plate with dots as spherical caps
Method:
- make a thin plate on which sit cylinders
- make a thin plate, called base, on which sit cylinders
- fillet the upper edge of the cylinders so to get pseudo half-spheres
- make the union with a thicker plate so that only the sphere caps stay
"visible".
@ -151,7 +153,7 @@ def make_embossed_plate(text_lines, cell_geometry):
y = base_height - 3 * cell_geometry.vertical_interdot
line_start_pos = Point(cell_geometry.horizontal_interdot, y)
for text in text_lines:
dots = brailleToPoints(text, cell_geometry)
dots = braille_to_points(text, cell_geometry)
dots = [p + line_start_pos for p in dots]
dot_pos += dots
line_start_pos += Point(0, -cell_geometry.interline)

View File

@ -4,7 +4,8 @@ from tests import *
import cadquery
import unittest
#if you are on python 2.7, you can use -m uniitest discover.
#if you are on python 2.7, you can use.
# python -m unittest discover -s tests -p "Test*" --verbose
#but this is required for python 2.6.6 on windows. FreeCAD0.12 will not load
#on py 2.7.x on win
suite = unittest.TestSuite()
@ -17,4 +18,7 @@ suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQ
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestLogging.TestLogging))
unittest.TextTestRunner().run(suite)
if __name__ == '__main__':
result = unittest.TextTestRunner().run(suite)
sys.exit(not result.wasSuccessful())

View File

@ -102,7 +102,7 @@ class TestCQGI(BaseTest):
result = model.build({})
self.assertFalse(result.success)
self.assertIsNotNone(result.exception)
self.assertTrue(result.exception.message == "ERROR")
self.assertTrue(result.exception.args[0] == "ERROR")
def test_that_invalid_syntax_in_script_fails_immediately(self):
badscript = textwrap.dedent(
@ -114,7 +114,7 @@ class TestCQGI(BaseTest):
with self.assertRaises(Exception) as context:
model = cqgi.CQModel(badscript)
self.assertTrue('invalid syntax' in context.exception)
self.assertTrue('invalid syntax' in context.exception.args)
def test_that_two_results_are_returned(self):
script = textwrap.dedent(

View File

@ -1,32 +1,143 @@
#system modules
from __future__ import division
import sys
import unittest
from math import pi, sin, sqrt, radians
from tests import BaseTest
import FreeCAD
import Part
from copy import copy
from cadquery import *
class TestCadObjects(BaseTest):
def testVectorConstructors(self):
v1 = Vector(1, 2, 3)
v2 = Vector((1, 2, 3))
v3 = Vector(FreeCAD.Base.Vector(1, 2, 3))
# Assert 3 ints represents x, y, z respectively
# (why?, this is assumed for all other assertions)
v = Vector(1, 2, 3)
self.assertEqual((v.x, v.y, v.z), (1, 2, 3))
for v in [v1, v2, v3]:
self.assertTupleAlmostEquals((1, 2, 3), v.toTuple(), 4)
# --- Positive Cases
# empty
self.assertEquals(Vector(), Vector(0, 0, 0))
# tuples
self.assertEquals(Vector((1, 2, 3)), Vector(1, 2, 3))
self.assertEquals(Vector((1, 2)), Vector(1, 2, 0))
self.assertEquals(Vector((1,)), Vector(1, 0, 0))
# lists
self.assertEquals(Vector([1, 2, 3]), Vector(1, 2, 3))
self.assertEquals(Vector([1, 2]), Vector(1, 2, 0))
self.assertEquals(Vector([1]), Vector(1, 0, 0))
# < 3 numbers
self.assertEquals(Vector(1, 2), Vector(1, 2, 0))
self.assertEquals(Vector(1), Vector(1, 0, 0))
# wrappers
self.assertEquals(Vector(Vector(1, 2, 3)), Vector(1, 2, 3))
self.assertEquals(Vector(FreeCAD.Base.Vector(1, 2, 3)), Vector(1, 2, 3))
# named coords
self.assertEquals(Vector(x=1, y=2, z=3), Vector(1, 2, 3))
self.assertEquals(Vector(x=1), Vector(1, 0, 0))
self.assertEquals(Vector(y=2), Vector(0, 2, 0))
self.assertEquals(Vector(z=3), Vector(0, 0, 3))
# --- Negative Cases
with self.assertRaises(ValueError):
Vector('blah') # invalid type
with self.assertRaises(ValueError):
Vector(1, 2, 3, 4)
with self.assertRaises(ValueError):
Vector((1, 2, 3, 4))
with self.assertRaises(ValueError):
Vector([1, 2, 3, 4])
with self.assertRaises(ValueError):
# mixing listed and named args not supported
Vector(1, 2, z=3)
with self.assertRaises(ValueError):
# non-numeric as first parameter
Vector(FreeCAD.Base.Vector(1, 2, 3), 1)
def testVectorCopy(self):
a = Vector(1, 2, 3)
b = copy(a)
# assert copy is equal
self.assertEqual(a.toTuple(), (1, 2, 3))
self.assertEqual(b.toTuple(), (1, 2, 3))
# assert changes to original don't effect copy
a.x = 100
self.assertEqual(a.toTuple(), (100, 2, 3))
self.assertEqual(b.toTuple(), (1, 2, 3))
def testVertex(self):
"""
Tests basic vertex functions
"""
# Tests casting a vertex
vc = Vertex.cast(Part.Vertex(1, 1, 1))
self.assertEqual(1, vc.X)
self.assertEqual(Vector, type(vc.Center()))
# Tests vertex instantiation
v = Vertex(Part.Vertex(1, 1, 1))
self.assertEqual(1, v.X)
self.assertEqual(Vector, type(v.Center()))
def testFace(self):
"""
Test basic face functions, cast and instantiation
"""
edge1 = Part.makeLine((0, 0, 0), (0, 10, 0))
edge2 = Part.makeLine((0, 10, 0), (10, 10, 0))
edge3 = Part.makeLine((10, 10, 0), (10, 0, 0))
edge4 = Part.makeLine((10, 0, 0), (0, 0, 0))
wire1 = Part.Wire([edge1,edge2,edge3,edge4])
face1 = Part.Face(wire1)
mplanec = Face.cast(face1)
mplane = Face(face1)
self.assertTupleAlmostEquals((5.0, 5.0, 0.0), mplane.Center().toTuple(), 3)
def testShapeProps(self):
"""
Tests miscellaneous properties of the shape object
"""
e = Shape(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3)))
# Geometry type
self.assertEqual(e.geomType(), 'Edge')
# Dynamic type checking
self.assertTrue(e.isType(e, 'Edge'))
self.assertFalse(e.isType(None, 'Edge'))
# Checking null objects
self.assertFalse(e.isNull())
# Checking for sameness
self.assertTrue(e.isSame(e))
# Checking for equality
self.assertTrue(e.isEqual(e))
# Checking for shape validity
self.assertTrue(e.isValid())
# Testing whether shape is closed
self.assertTrue(e.Closed())
# Trying to get the area of the circular edge
with self.assertRaises(ValueError):
e.Area()
# Getting the area of the square face
mplane = Face.makePlane(10.0, 10.0)
self.assertAlmostEqual(100.0, mplane.Area(), 3)
# Getting the center of a solid
s = Solid.makeCylinder(10.0, 10.0)
self.assertTupleAlmostEquals((0.0, 0.0, 5.0), s.Center().toTuple(), 3)
def testBasicBoundingBox(self):
v = Vertex(Part.Vertex(1, 1, 1))
v2 = Vertex(Part.Vertex(2, 2, 2))
@ -55,10 +166,57 @@ class TestCadObjects(BaseTest):
self.assertTupleAlmostEquals((0.0, 0.0, 1.0), mplane.normalAt().toTuple(), 3)
def testCenterOfBoundBox(self):
pass
"""
Tests whether or not a proper geometric center can be found for an object
"""
def cylinders(self, radius, height):
def _cyl(pnt):
# Inner function to build a cylinder
return Solid.makeCylinder(radius, height, pnt)
# Combine all the cylinders into a single compound
r = self.eachpoint(_cyl, True).combineSolids()
return r
Workplane.cyl = cylinders
# One solid in the compound
s = Workplane("XY").pushPoints([(0.0, 0.0, 0.0)]).cyl(0.25, 0.5)
self.assertEqual(1, len(s.val().Solids()))
self.assertTupleAlmostEquals((0.0, 0.0, 0.25), s.val().CenterOfBoundBox().toTuple(), 2)
def testCombinedCenterOfBoundBox(self):
pass
"""
Tests whether or not a proper geometric center can be found for multiple
objects in a compound.
"""
def cylinders(self, radius, height):
def _cyl(pnt):
# Inner function to build a cylinder
return Solid.makeCylinder(radius, height, pnt)
# Combine all the cylinders into a single compound
r = self.eachpoint(_cyl, True).combineSolids()
return r
Workplane.cyl = cylinders
# Multiple solids in the compound
s = Workplane("XY").rect(2.0, 3.0, forConstruction=True).vertices().cyl(0.25, 0.5)
self.assertEqual(4, len(s.val().Solids()))
self.assertTupleAlmostEquals((0.0, 0.0, 0.25), s.val().CenterOfBoundBox().toTuple(), 2)
def testCenter(self):
"""
Tests finding the center of shapes and solids
"""
circle = Workplane("XY").circle(10.0)
cylinder = circle.extrude(10.0)
self.assertTupleAlmostEquals((0.0, 0.0, 0.0), circle.val().Center().toTuple(), 3)
self.assertTupleAlmostEquals((0.0, 0.0, 5.0), cylinder.val().Center().toTuple(), 3)
def testCompoundCenter(self):
"""
@ -92,6 +250,39 @@ class TestCadObjects(BaseTest):
self.assertIsInstance(result, Vector)
self.assertTupleAlmostEquals((1.0, 2.0, 3.0), result.toTuple(), 3)
def testVectorArithmeticOverides(self):
V = lambda x,y,z: Vector(x,y,z)
self.assertEqual(V(1,2,3) + V(4,5,6), V(5,7,9)) # addition
self.assertEqual(V(1,2,3) - V(5,4,3), V(-4,-2,0)) # subtraction
self.assertEqual((V(1,2,3) * 2).toTuple(), (2,4,6)) # multiplication
self.assertEqual((V(1,2,3) / 2).toTuple(), (0.5,1,1.5)) # division
def testVectorBoolCast(self):
# zero vector
self.assertEqual(bool(Vector(0,0,0)), False)
# positive axes
self.assertEqual(bool(Vector(1,0,0)), True)
self.assertEqual(bool(Vector(0,1,0)), True)
self.assertEqual(bool(Vector(0,0,1)), True)
# negative axes
self.assertEqual(bool(Vector(-1,0,0)), True)
self.assertEqual(bool(Vector(0,-1,0)), True)
self.assertEqual(bool(Vector(0,0,-1)), True)
def testVectorDivideByZero(self):
with self.assertRaises(ZeroDivisionError):
Vector(1, 2, 3) / 0
def testVectorLength(self):
calc_length = lambda v: sqrt(v.x**2 + v.y**2 + v.z**2)
vectors = [
Vector(0,0,0), Vector(1,2,3), Vector(-1,-5,10),
]
for v in vectors:
expected = calc_length(v)
self.assertEqual(v.Length, expected)
self.assertEqual(abs(v), expected)
def testVectorSub(self):
result = Vector(1, 2, 3) - Vector(6, 5, 4)
self.assertIsInstance(result, Vector)
@ -116,12 +307,101 @@ class TestCadObjects(BaseTest):
self.assertEqual(getattr(v, coord), new_val)
setattr(v, coord, init_val)
def testVectorNegative(self):
v = Vector(1, -2, 3)
self.assertEqual(-v, Vector(-1, 2, -3))
def testShapeInit(self):
"""
Tests whether a Shape object can be instantiated without
throwing an error.
"""
e = Shape(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3)))
def testPlaneEqual(self):
# default orientation
self.assertEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1)),
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1))
)
# moved origin
self.assertEqual(
Plane(origin=(2,1,-1), xDir=(1,0,0), normal=(0,0,1)),
Plane(origin=(2,1,-1), xDir=(1,0,0), normal=(0,0,1))
)
# moved x-axis
self.assertEqual(
Plane(origin=(0,0,0), xDir=(1,1,0), normal=(0,0,1)),
Plane(origin=(0,0,0), xDir=(1,1,0), normal=(0,0,1))
)
# moved z-axis
self.assertEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,1,1)),
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,1,1))
)
def testPlaneNotEqual(self):
# type difference
for value in [None, 0, 1, 'abc']:
self.assertNotEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1)),
value
)
# origin difference
self.assertNotEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1)),
Plane(origin=(0,0,1), xDir=(1,0,0), normal=(0,0,1))
)
# x-axis difference
self.assertNotEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1)),
Plane(origin=(0,0,0), xDir=(1,1,0), normal=(0,0,1))
)
# z-axis difference
self.assertNotEqual(
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,0,1)),
Plane(origin=(0,0,0), xDir=(1,0,0), normal=(0,1,1))
)
def testTranslate(self):
e = Shape.cast(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3)))
e2 = e.translate(Vector(0, 0, 1))
self.assertTupleAlmostEquals((1.0, 2.0, 4.0), e2.Center().toTuple(), 3)
def testScale(self):
"""
Tests scaling a shape and whether the dimensions are correct afterwards
"""
e = Shape.cast(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3)))
e2 = e.scale(0.5)
self.assertAlmostEquals(2.0, e2.BoundingBox(tolerance=0.0001).xlen, 3)
self.assertAlmostEquals(2.0, e2.BoundingBox(tolerance=0.0001).ylen, 3)
def testCopy(self):
"""
Tests making a copy of a shape object and whether the new one has the
same properties as the original.
"""
e = Shape.cast(Part.makeCircle(2.0, FreeCAD.Base.Vector(1, 2, 3)))
e2 = e.copy()
self.assertEquals(e.BoundingBox().xlen, e2.BoundingBox().xlen)
self.assertEquals(e.BoundingBox().ylen, e2.BoundingBox().ylen)
def testRuledSurface(self):
"""
Tests making a ruled surface from two edges/wires.
"""
edge1 = Shape(Part.makeLine((0, 0, 5), (0, 10, 5)))
edge2 = Shape(Part.makeLine((5, 5, 0), (10, 10, 0)))
surf1 = Face.makeRuledSurface(edge1, edge2)
self.assertEquals(surf1.ShapeType(), 'Face')
self.assertTrue(surf1.isValid())
def testVertices(self):
e = Shape.cast(Part.makeLine((0, 0, 0), (1, 1, 0)))
self.assertEqual(2, len(e.Vertices()))

View File

@ -8,7 +8,15 @@ import math,sys,os.path,time
#my modules
from cadquery import *
from cadquery import exporters
from tests import BaseTest,writeStringToFile,makeUnitCube,readFileAsString,makeUnitSquareWire,makeCube
from tests import (
BaseTest,
writeStringToFile,
makeUnitCube,
readFileAsString,
makeUnitSquareWire,
makeCube,
)
from cadquery.freecad_impl import suppress_stdout_stderr
#where unit test output will be saved
import sys
@ -73,10 +81,13 @@ class TestCadQuery(BaseTest):
def saveModel(self, shape):
"""
shape must be a CQ object
Save models in SVG and STEP format
Save models in SVG, STEP and STL format
"""
shape.exportSvg(os.path.join(OUTDIR,self._testMethodName + ".svg"))
shape.val().exportStep(os.path.join(OUTDIR,self._testMethodName + ".step"))
with suppress_stdout_stderr():
shape.exportSvg(os.path.join(OUTDIR,self._testMethodName + ".svg"))
shape.val().exportStep(os.path.join(OUTDIR,self._testMethodName + ".step"))
shape.val().exportStl(os.path.join(OUTDIR,self._testMethodName + ".stl"))
def testToFreeCAD(self):
"""
@ -98,7 +109,6 @@ class TestCadQuery(BaseTest):
# Make sure that a couple of sections from the SVG output make sense
self.assertTrue(r_str.index('path d=" M 2.35965 -2.27987 L 4.0114 -3.23936 "') > 0)
self.assertTrue(r_str.index('line x1="30" y1="-30" x2="58" y2="-15" stroke-width="3"') > 0)
def testCubePlugin(self):
"""
@ -226,6 +236,42 @@ class TestCadQuery(BaseTest):
self.assertEqual(type(r.val()), Solid)
self.assertEqual(type(r.first().val()),Solid)
def testMirror(self):
box = Workplane("XY").box(1, 1, 5)
box2 = box.mirror()
box3 = box.mirror("XZ")
box4 = box.mirror("YZ")
# Box 2 (XY mirror)
startPoint2 = box2.faces("<Y").edges("<X").first().val().startPoint().toTuple()
endPoint2 = box2.faces("<Y").edges("<X").first().val().endPoint().toTuple()
self.assertEqual(-0.5, startPoint2[0])
self.assertEqual(-0.5, startPoint2[1])
self.assertEqual(2.5, startPoint2[2])
self.assertEqual(-0.5, endPoint2[0])
self.assertEqual(-0.5, endPoint2[1])
self.assertEqual(-2.5, endPoint2[2])
# Box 3 (XZ mirror)
startPoint3 = box3.faces("<Y").edges("<X").first().val().startPoint().toTuple()
endPoint3 = box3.faces("<Y").edges("<X").first().val().endPoint().toTuple()
self.assertEqual(-0.5, startPoint3[0])
self.assertEqual(-0.5, startPoint3[1])
self.assertEqual(-2.5, startPoint3[2])
self.assertEqual(-0.5, endPoint3[0])
self.assertEqual(-0.5, endPoint3[1])
self.assertEqual(2.5, endPoint3[2])
# Box 4 (YZ mirror)
startPoint4 = box4.faces("<Y").edges("<X").first().val().startPoint().toTuple()
endPoint4 = box4.faces("<Y").edges("<X").first().val().endPoint().toTuple()
self.assertEqual(-0.5, startPoint4[0])
self.assertEqual(-0.5, startPoint4[1])
self.assertEqual(-2.5, startPoint4[2])
self.assertEqual(-0.5, endPoint4[0])
self.assertEqual(-0.5, endPoint4[1])
self.assertEqual(2.5, endPoint4[2])
def testRotate(self):
"""Test solid rotation at the CQ object level."""
box = Workplane("XY").box(1, 1, 5)
@ -648,7 +694,7 @@ class TestCadQuery(BaseTest):
.threePointArc((5.793,1.293),(6.5,1))
.lineTo(10,1)
.close())
result = result0.extrude(100)
bb_center = result.val().BoundingBox().center
self.saveModel(result)
@ -681,7 +727,8 @@ class TestCadQuery(BaseTest):
try:
t = r.faces(">Y").workplane().circle(0.125).cutToOffsetFromFace(r.faces().mminDist(Dir.Y),0.1)
self.assertEqual(10,t.faces().size() ) #should end up being a blind hole
t.first().val().exportStep('c:/temp/testCutToFace.STEP')
with suppress_stdout_stderr():
t.first().val().exportStep('c:/temp/testCutToFace.STEP')
except:
pass
#Not Implemented Yet
@ -711,7 +758,8 @@ class TestCadQuery(BaseTest):
#most users dont understand what a wire is, they are just drawing
r = s.lineTo(1.0,0).lineTo(0,1.0).close().wire().extrude(0.25)
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesStep1.STEP'))
with suppress_stdout_stderr():
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesStep1.STEP'))
self.assertEqual(0,s.faces().size()) #no faces on the original workplane
self.assertEqual(5,r.faces().size() ) # 5 faces on newly created object
@ -719,12 +767,14 @@ class TestCadQuery(BaseTest):
#now add a circle through a side face
r.faces("+XY").workplane().circle(0.08).cutThruAll()
self.assertEqual(6,r.faces().size())
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesXY.STEP'))
with suppress_stdout_stderr():
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesXY.STEP'))
#now add a circle through a top
r.faces("+Z").workplane().circle(0.08).cutThruAll()
self.assertEqual(9,r.faces().size())
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesZ.STEP'))
with suppress_stdout_stderr():
r.val().exportStep(os.path.join(OUTDIR, 'testBasicLinesZ.STEP'))
self.saveModel(r)
@ -1275,6 +1325,80 @@ class TestCadQuery(BaseTest):
line(-10,0).close().extrude(10,clean=False).clean()
self.assertEqual(6, s.faces().size())
def testPlanes(self):
"""
Test other planes other than the normal ones (XY, YZ)
"""
# ZX plane
s = Workplane(Plane.ZX())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# YX plane
s = Workplane(Plane.YX())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# YX plane
s = Workplane(Plane.YX())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# ZY plane
s = Workplane(Plane.ZY())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# front plane
s = Workplane(Plane.front())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# back plane
s = Workplane(Plane.back())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# left plane
s = Workplane(Plane.left())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# right plane
s = Workplane(Plane.right())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# top plane
s = Workplane(Plane.top())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
# bottom plane
s = Workplane(Plane.bottom())
result = s.rect(2.0, 4.0).extrude(0.5).faces(">Z").workplane()\
.rect(1.5, 3.5, forConstruction=True).vertices().cskHole(0.125, 0.25, 82, depth=None)
self.saveModel(result)
def testIsIndide(self):
"""
Testing if one box is inside of another.
"""
box1 = Workplane(Plane.XY()).box(10, 10, 10)
box2 = Workplane(Plane.XY()).box(5, 5, 5)
self.assertFalse(box2.val().BoundingBox().isInside(box1.val().BoundingBox()))
self.assertTrue(box1.val().BoundingBox().isInside(box2.val().BoundingBox()))
def testCup(self):
"""

View File

@ -1,6 +1,8 @@
"""
Tests basic workplane functionality
"""
#from __future__ import unicode_literals
#core modules
import io
@ -18,13 +20,20 @@ class TestExporters(BaseTest):
returns the result in case the case wants to do more checks also
"""
p = Workplane("XY").box(1,2,3)
s = io.StringIO()
exporters.exportShape(p,eType,s,0.1)
result = s.getvalue()
#print result
for q in stringsToFind:
self.assertTrue(result.find(q) > -1 )
if eType == exporters.ExportTypes.AMF:
s = io.BytesIO()
exporters.exportShape(p,eType,s,0.1)
result = s.getvalue()
for q in stringsToFind:
self.assertTrue(result.decode().find(q) > -1 )
else:
s = io.StringIO()
exporters.exportShape(p,eType,s,0.1)
result = s.getvalue()
for q in stringsToFind:
self.assertTrue(q in result)
return result
def testSTL(self):

View File

@ -7,6 +7,7 @@ import io
from cadquery import *
from cadquery import exporters
from cadquery import importers
from cadquery.freecad_impl import suppress_stdout_stderr
from tests import BaseTest
#where unit test output will be saved
@ -35,10 +36,10 @@ class TestImporters(BaseTest):
# Reimport the shape from the new STEP file
importedShape = importers.importShape(importType,fileName)
#Check to make sure we got a solid back
# Check to make sure we got a solid back
self.assertTrue(importedShape.val().ShapeType() == "Solid")
#Check the number of faces and vertices per face to make sure we have a box shape
# Check the number of faces and vertices per face to make sure we have a box shape
self.assertTrue(importedShape.faces("+X").size() == 1 and importedShape.faces("+X").vertices().size() == 4)
self.assertTrue(importedShape.faces("+Y").size() == 1 and importedShape.faces("+Y").vertices().size() == 4)
self.assertTrue(importedShape.faces("+Z").size() == 1 and importedShape.faces("+Z").vertices().size() == 4)
@ -47,7 +48,24 @@ class TestImporters(BaseTest):
"""
Tests STEP file import
"""
self.importBox(importers.ImportTypes.STEP, OUTDIR + "/tempSTEP.step")
with suppress_stdout_stderr():
self.importBox(importers.ImportTypes.STEP, OUTDIR + "/tempSTEP.step")
def testSTEPFromURL(self):
"""
Tests STEP file import from a URL
"""
stepURL = "https://raw.githubusercontent.com/dcowden/cadquery/master/doc/_static/box_export.step"
importedShape = importers.importStepFromURL(stepURL)
# Check to make sure we got a solid back
self.assertTrue(importedShape.val().ShapeType() == "Solid")
# Check the number of faces and vertices per face to make sure we have a box shape
self.assertTrue(importedShape.faces("+X").size() == 1 and importedShape.faces("+X").vertices().size() == 4)
self.assertTrue(importedShape.faces("+Y").size() == 1 and importedShape.faces("+Y").vertices().size() == 4)
self.assertTrue(importedShape.faces("+Z").size() == 1 and importedShape.faces("+Z").vertices().size() == 4)
if __name__ == '__main__':
import unittest

View File

@ -2,6 +2,7 @@ from cadquery import *
import unittest
import sys
import os
from contextlib import contextmanager
import FreeCAD
@ -51,7 +52,7 @@ class BaseTest(unittest.TestCase):
for i, j in zip(actual, expected):
self.assertAlmostEqual(i, j, places)
__all__ = ['TestCadObjects', 'TestCadQuery', 'TestCQSelectors', 'TestWorkplanes', 'TestExporters', 'TestCQSelectors', 'TestImporters','TestCQGI']
__all__ = [
'TestCQGI',
'TestCQSelectors',

View File

@ -2,3 +2,4 @@ execute_on_save = False # Automatically execute a script every time you
use_external_editor = False # Automatically reloads and executes a file when an external change is made
max_line_length = 79 # The number of characters per line that is allowed before a warning is given
font_size = 10 # Sets the font size of the Python editor
execute_keybinding = 'F2' # The key(s) that is pressed to execute the currently active script