Updated CadQuery library and updated version number to 1.0.0
This commit is contained in:
parent
60f48dfb78
commit
eae8efd9ee
|
@ -1,7 +1,7 @@
|
|||
What is a CadQuery?
|
||||
========================================
|
||||
|
||||
[](https://travis-ci.org/dcowden/cadquery)
|
||||
[](https://travis-ci.org/dcowden/cadquery?branch=master)
|
||||
[](https://coveralls.io/r/dcowden/cadquery)
|
||||
[](https://github.com/dcowden/cadquery/releases/tag/v0.3.0)
|
||||
[](https://github.com/dcowden/cadquery/blob/master/LICENSE)
|
||||
|
@ -46,6 +46,7 @@ This resin mold was modeled using cadquery and then created on a CNC machine:
|
|||
|
||||
The cadquery script is surprisingly short, and allows easily customizing any of the variables::
|
||||
|
||||
```python
|
||||
import cadquery as cq
|
||||
from Helpers import show
|
||||
BS = cq.selectors.BoxSelector
|
||||
|
@ -108,7 +109,7 @@ The cadquery script is surprisingly short, and allows easily customizing any of
|
|||
]).hole(fhd, mw/2.)
|
||||
|
||||
show(r)
|
||||
|
||||
```
|
||||
|
||||
Thanks go to cadquery contributor hyOzd ( Altu Technology ) for the example!
|
||||
|
||||
|
@ -171,26 +172,30 @@ Use these steps if you would like to write CadQuery scripts as a python API. In
|
|||
preferably one that has virtualenv available. To use FreeCAD from any python interpreter, just append the FreeCAD
|
||||
lib directory to your path. On (*Nix)::
|
||||
|
||||
import sys
|
||||
```python
|
||||
import sys
|
||||
sys.path.append('/usr/lib/freecad/lib')
|
||||
```
|
||||
|
||||
or on Windows::
|
||||
|
||||
import sys
|
||||
```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
|
||||
|
||||
```
|
||||
3. 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
|
||||
|
@ -204,17 +209,16 @@ It includes a distribution of the latest version of cadquery.
|
|||
Roadmap/Future Work
|
||||
=======================
|
||||
|
||||
Work is underway on two other installation methods for cadquery:
|
||||
|
||||
1. a conda package, which will install CQ and all of its depedencies, if you are using Anaconda
|
||||
2. a Docker image, which comes ready-to-run after you have installed docker.
|
||||
|
||||
Work has also begun on Cadquery 2.0, which will feature:
|
||||
Work has begun on Cadquery 2.0, which will feature:
|
||||
|
||||
1. Feature trees, for more powerful selection
|
||||
2. Direct use of OpenCascade Community Edition(OCE), so that it is no longer required to install FreeCAD
|
||||
3. https://github.com/jmwright/cadquery-gui, which will allow visualization of workplanes
|
||||
|
||||
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?
|
||||
========================================
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: cadquery
|
||||
Version: 0.4.0
|
||||
Version: 1.0.0
|
||||
Summary: CadQuery is a parametric scripting language for creating and traversing CAD models
|
||||
Home-page: https://github.com/dcowden/cadquery
|
||||
Author: David Cowden
|
||||
|
|
|
@ -13,9 +13,9 @@ from .cq import *
|
|||
|
||||
__all__ = [
|
||||
'CQ','Workplane','plugins','selectors','Plane','BoundBox','Matrix','Vector','sortWiresByBuildOrder',
|
||||
'Shape','Vertex','Edge','Wire','Solid','Shell','Compound','exporters', 'importers',
|
||||
'Shape','Vertex','Edge','Wire','Face','Solid','Shell','Compound','exporters', 'importers',
|
||||
'NearestToPointSelector','ParallelDirSelector','DirectionSelector','PerpendicularDirSelector',
|
||||
'TypeSelector','DirectionMinMaxSelector','StringSyntaxSelector','Selector','plugins'
|
||||
]
|
||||
|
||||
__version__ = "0.5.1"
|
||||
__version__ = "1.0.0"
|
||||
|
|
|
@ -16,23 +16,19 @@
|
|||
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/>
|
||||
"""
|
||||
import os, sys
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def _fc_path():
|
||||
"""Find FreeCAD"""
|
||||
_PATH = ""
|
||||
if _PATH:
|
||||
# Look for FREECAD_LIB env variable
|
||||
_PATH = os.environ.get('FREECAD_LIB', '')
|
||||
if _PATH and os.path.exists(_PATH):
|
||||
return _PATH
|
||||
|
||||
#look for FREECAD_LIB env variable
|
||||
if os.environ.has_key('FREECAD_LIB'):
|
||||
_PATH = os.environ.get('FREECAD_LIB')
|
||||
if os.path.exists( _PATH):
|
||||
return _PATH
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
#Make some dangerous assumptions...
|
||||
# Make some dangerous assumptions...
|
||||
for _PATH in [
|
||||
os.path.join(os.path.expanduser("~"), "lib/freecad/lib"),
|
||||
"/usr/local/lib/freecad/lib",
|
||||
|
@ -40,12 +36,13 @@ def _fc_path():
|
|||
"/opt/freecad/lib/",
|
||||
"/usr/bin/freecad/lib",
|
||||
"/usr/lib/freecad",
|
||||
"/usr/lib64/freecad/lib",
|
||||
]:
|
||||
if os.path.exists(_PATH):
|
||||
return _PATH
|
||||
|
||||
elif sys.platform.startswith('win'):
|
||||
#try all the usual suspects
|
||||
# Try all the usual suspects
|
||||
for _PATH in [
|
||||
"c:/Program Files/FreeCAD0.12/bin",
|
||||
"c:/Program Files/FreeCAD0.13/bin",
|
||||
|
@ -86,27 +83,24 @@ def _fc_path():
|
|||
]:
|
||||
if os.path.exists(_PATH):
|
||||
return _PATH
|
||||
|
||||
elif sys.platform.startswith('darwin'):
|
||||
#Assume we're dealing with a Mac
|
||||
# Assume we're dealing with a Mac
|
||||
for _PATH in [
|
||||
"/Applications/FreeCAD.app/Contents/lib",
|
||||
os.path.join(os.path.expanduser("~"), "Library/Application Support/FreeCAD/lib"),
|
||||
os.path.join(os.path.expanduser("~"),
|
||||
"Library/Application Support/FreeCAD/lib"),
|
||||
]:
|
||||
if os.path.exists(_PATH):
|
||||
return _PATH
|
||||
|
||||
raise ImportError('cadquery was unable to determine freecad library path')
|
||||
|
||||
|
||||
#Make sure that the correct FreeCAD path shows up in Python's system path
|
||||
no_library_path = ImportError('cadquery was unable to determine freecads library path')
|
||||
# Make sure that the correct FreeCAD path shows up in Python's system path
|
||||
try:
|
||||
import FreeCAD
|
||||
except ImportError:
|
||||
path = _fc_path()
|
||||
if path:
|
||||
sys.path.insert(0, path)
|
||||
try:
|
||||
import FreeCAD
|
||||
except ImportError:
|
||||
raise no_library_path
|
||||
else: raise no_library_path
|
||||
sys.path.insert(0, path)
|
||||
import FreeCAD
|
||||
|
|
|
@ -216,7 +216,8 @@ class Shape(object):
|
|||
else:
|
||||
raise ValueError("Cannot find the center of %s object type" % str(type(self.Solids()[0].wrapped)))
|
||||
|
||||
def CenterOfBoundBox(self):
|
||||
def CenterOfBoundBox(self, tolerance = 0.1):
|
||||
self.wrapped.tessellate(tolerance)
|
||||
if isinstance(self.wrapped, FreeCADPart.Shape):
|
||||
# If there are no Solids, we're probably dealing with a Face or something similar
|
||||
if len(self.Solids()) == 0:
|
||||
|
@ -258,14 +259,18 @@ class Shape(object):
|
|||
return object.wrapped.Mass
|
||||
|
||||
@staticmethod
|
||||
def CombinedCenterOfBoundBox(objects):
|
||||
def CombinedCenterOfBoundBox(objects, tolerance = 0.1):
|
||||
"""
|
||||
Calculates the center of BoundBox of multiple objects.
|
||||
|
||||
:param objects: a list of objects with mass 1
|
||||
"""
|
||||
total_mass = len(objects)
|
||||
weighted_centers = [o.wrapped.BoundBox.Center.multiply(1.0) for o in objects]
|
||||
|
||||
weighted_centers = []
|
||||
for o in objects:
|
||||
o.wrapped.tessellate(tolerance)
|
||||
weighted_centers.append(o.wrapped.BoundBox.Center.multiply(1.0))
|
||||
|
||||
sum_wc = weighted_centers[0]
|
||||
for wc in weighted_centers[1:] :
|
||||
|
@ -470,7 +475,9 @@ class Edge(Shape):
|
|||
|
||||
@classmethod
|
||||
def makeCircle(cls, radius, pnt=(0, 0, 0), dir=(0, 0, 1), angle1=360.0, angle2=360):
|
||||
return Edge(FreeCADPart.makeCircle(radius, toVector(pnt), toVector(dir), angle1, angle2))
|
||||
center = Vector(pnt)
|
||||
normal = Vector(dir)
|
||||
return Edge(FreeCADPart.makeCircle(radius, center.wrapped, normal.wrapped, angle1, angle2))
|
||||
|
||||
@classmethod
|
||||
def makeSpline(cls, listOfVector):
|
||||
|
@ -621,8 +628,10 @@ class Face(Shape):
|
|||
return Vector(self.wrapped.normalAt(u, v).normalize())
|
||||
|
||||
@classmethod
|
||||
def makePlane(cls, length, width, basePnt=None, dir=None):
|
||||
return Face(FreeCADPart.makePlan(length, width, toVector(basePnt), toVector(dir)))
|
||||
def makePlane(cls, length, width, basePnt=(0, 0, 0), dir=(0, 0, 1)):
|
||||
basePnt = Vector(basePnt)
|
||||
dir = Vector(dir)
|
||||
return Face(FreeCADPart.makePlane(length, width, basePnt.wrapped, dir.wrapped))
|
||||
|
||||
@classmethod
|
||||
def makeRuledSurface(cls, edgeOrWire1, edgeOrWire2, dist=None):
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
import re
|
||||
import math
|
||||
from cadquery import Vector,Edge,Vertex,Face,Solid,Shell,Compound
|
||||
from pyparsing import Literal,Word,nums,Optional,Combine,oneOf,\
|
||||
upcaseTokens,CaselessLiteral,Group
|
||||
from pyparsing import Literal,Word,nums,Optional,Combine,oneOf,upcaseTokens,\
|
||||
CaselessLiteral,Group,infixNotation,opAssoc,Forward,\
|
||||
ZeroOrMore,Keyword
|
||||
|
||||
|
||||
class Selector(object):
|
||||
|
@ -288,10 +289,6 @@ class DirectionMinMaxSelector(Selector):
|
|||
|
||||
CQ(aCube).faces( ">Z" )
|
||||
|
||||
Future Enhancements:
|
||||
provide a nicer way to select in arbitrary directions. IE, a bit more code could
|
||||
allow '>(0,0,1)' to work.
|
||||
|
||||
"""
|
||||
def __init__(self, vector, directionMax=True, tolerance=0.0001):
|
||||
self.vector = vector
|
||||
|
@ -423,7 +420,7 @@ class InverseSelector(Selector):
|
|||
|
||||
def _makeGrammar():
|
||||
"""
|
||||
Define the string selector grammar using PyParsing
|
||||
Define the simple string selector grammar using PyParsing
|
||||
"""
|
||||
|
||||
#float definition
|
||||
|
@ -476,44 +473,14 @@ def _makeGrammar():
|
|||
|
||||
_grammar = _makeGrammar() #make a grammar instance
|
||||
|
||||
class StringSyntaxSelector(Selector):
|
||||
class _SimpleStringSyntaxSelector(Selector):
|
||||
"""
|
||||
Filter lists objects using a simple string syntax. All of the filters available in the string syntax
|
||||
are also available ( usually with more functionality ) through the creation of full-fledged
|
||||
selector objects. see :py:class:`Selector` and its subclasses
|
||||
|
||||
Filtering works differently depending on the type of object list being filtered.
|
||||
|
||||
:param selectorString: A two-part selector string, [selector][axis]
|
||||
|
||||
:return: objects that match the specified selector
|
||||
|
||||
***Modfiers*** are ``('|','+','-','<','>','%')``
|
||||
|
||||
:\|:
|
||||
parallel to ( same as :py:class:`ParallelDirSelector` ). Can return multiple objects.
|
||||
:#:
|
||||
perpendicular to (same as :py:class:`PerpendicularDirSelector` )
|
||||
:+:
|
||||
positive direction (same as :py:class:`DirectionSelector` )
|
||||
:-:
|
||||
negative direction (same as :py:class:`DirectionSelector` )
|
||||
:>:
|
||||
maximize (same as :py:class:`DirectionMinMaxSelector` with directionMax=True)
|
||||
:<:
|
||||
minimize (same as :py:class:`DirectionMinMaxSelector` with directionMax=False )
|
||||
:%:
|
||||
curve/surface type (same as :py:class:`TypeSelector`)
|
||||
|
||||
***axisStrings*** are: ``X,Y,Z,XY,YZ,XZ``
|
||||
|
||||
Selectors are a complex topic: see :ref:`selector_reference` for more information
|
||||
|
||||
|
||||
|
||||
This is a private class that converts a parseResults object into a simple
|
||||
selector object
|
||||
"""
|
||||
def __init__(self,selectorString):
|
||||
|
||||
def __init__(self,parseResults):
|
||||
|
||||
#define all token to object mappings
|
||||
self.axes = {
|
||||
'X': Vector(1,0,0),
|
||||
'Y': Vector(0,1,0),
|
||||
|
@ -545,9 +512,8 @@ class StringSyntaxSelector(Selector):
|
|||
'#' : PerpendicularDirSelector,
|
||||
'|' : ParallelDirSelector}
|
||||
|
||||
self.selectorString = selectorString
|
||||
parsing_result = _grammar.parseString(selectorString)
|
||||
self.mySelector = self._chooseSelector(parsing_result)
|
||||
self.parseResults = parseResults
|
||||
self.mySelector = self._chooseSelector(parseResults)
|
||||
|
||||
def _chooseSelector(self,pr):
|
||||
"""
|
||||
|
@ -593,3 +559,113 @@ class StringSyntaxSelector(Selector):
|
|||
[+\|-\|<\|>\|] \<X\|Y\|Z>
|
||||
"""
|
||||
return self.mySelector.filter(objectList)
|
||||
|
||||
def _makeExpressionGrammar(atom):
|
||||
"""
|
||||
Define the complex string selector grammar using PyParsing (which supports
|
||||
logical operations and nesting)
|
||||
"""
|
||||
|
||||
#define operators
|
||||
and_op = Literal('and')
|
||||
or_op = Literal('or')
|
||||
delta_op = oneOf(['exc','except'])
|
||||
not_op = Literal('not')
|
||||
|
||||
def atom_callback(res):
|
||||
return _SimpleStringSyntaxSelector(res)
|
||||
|
||||
atom.setParseAction(atom_callback) #construct a simple selector from every matched
|
||||
|
||||
#define callback functions for all operations
|
||||
def and_callback(res):
|
||||
items = res.asList()[0][::2] #take every secend items, i.e. all operands
|
||||
return reduce(AndSelector,items)
|
||||
|
||||
def or_callback(res):
|
||||
items = res.asList()[0][::2] #take every secend items, i.e. all operands
|
||||
return reduce(SumSelector,items)
|
||||
|
||||
def exc_callback(res):
|
||||
items = res.asList()[0][::2] #take every secend items, i.e. all operands
|
||||
return reduce(SubtractSelector,items)
|
||||
|
||||
def not_callback(res):
|
||||
right = res.asList()[0][1] #take second item, i.e. the operand
|
||||
return InverseSelector(right)
|
||||
|
||||
#construct the final grammar and set all the callbacks
|
||||
expr = infixNotation(atom,
|
||||
[(and_op,2,opAssoc.LEFT,and_callback),
|
||||
(or_op,2,opAssoc.LEFT,or_callback),
|
||||
(delta_op,2,opAssoc.LEFT,exc_callback),
|
||||
(not_op,1,opAssoc.RIGHT,not_callback)])
|
||||
|
||||
return expr
|
||||
|
||||
_expression_grammar = _makeExpressionGrammar(_grammar)
|
||||
|
||||
class StringSyntaxSelector(Selector):
|
||||
"""
|
||||
Filter lists objects using a simple string syntax. All of the filters available in the string syntax
|
||||
are also available ( usually with more functionality ) through the creation of full-fledged
|
||||
selector objects. see :py:class:`Selector` and its subclasses
|
||||
|
||||
Filtering works differently depending on the type of object list being filtered.
|
||||
|
||||
:param selectorString: A two-part selector string, [selector][axis]
|
||||
|
||||
:return: objects that match the specified selector
|
||||
|
||||
***Modfiers*** are ``('|','+','-','<','>','%')``
|
||||
|
||||
:\|:
|
||||
parallel to ( same as :py:class:`ParallelDirSelector` ). Can return multiple objects.
|
||||
:#:
|
||||
perpendicular to (same as :py:class:`PerpendicularDirSelector` )
|
||||
:+:
|
||||
positive direction (same as :py:class:`DirectionSelector` )
|
||||
:-:
|
||||
negative direction (same as :py:class:`DirectionSelector` )
|
||||
:>:
|
||||
maximize (same as :py:class:`DirectionMinMaxSelector` with directionMax=True)
|
||||
:<:
|
||||
minimize (same as :py:class:`DirectionMinMaxSelector` with directionMax=False )
|
||||
:%:
|
||||
curve/surface type (same as :py:class:`TypeSelector`)
|
||||
|
||||
***axisStrings*** are: ``X,Y,Z,XY,YZ,XZ`` or ``(x,y,z)`` which defines an arbitrary direction
|
||||
|
||||
It is possible to combine simple selectors together using logical operations.
|
||||
The following operations are suuported
|
||||
|
||||
:and:
|
||||
Logical AND, e.g. >X and >Y
|
||||
:or:
|
||||
Logical OR, e.g. |X or |Y
|
||||
:not:
|
||||
Logical NOT, e.g. not #XY
|
||||
:exc(ept):
|
||||
Set difference (equivalent to AND NOT): |X exc >Z
|
||||
|
||||
Finally, it is also possible to use even more complex expressions with nesting
|
||||
and arbitrary number of terms, e.g.
|
||||
|
||||
(not >X[0] and #XY) or >XY[0]
|
||||
|
||||
Selectors are a complex topic: see :ref:`selector_reference` for more information
|
||||
"""
|
||||
def __init__(self,selectorString):
|
||||
"""
|
||||
Feed the input string through the parser and construct an relevant complex selector object
|
||||
"""
|
||||
self.selectorString = selectorString
|
||||
parse_result = _expression_grammar.parseString(selectorString,
|
||||
parseAll=True)
|
||||
self.mySelector = parse_result.asList()[0]
|
||||
|
||||
def filter(self,objectList):
|
||||
"""
|
||||
Filter give object list through th already constructed complex selector object
|
||||
"""
|
||||
return self.mySelector.filter(objectList)
|
|
@ -4,32 +4,32 @@ Changes
|
|||
|
||||
v0.1
|
||||
-----
|
||||
* Initial Version
|
||||
* Initial Version
|
||||
|
||||
v0.1.6
|
||||
-----
|
||||
* Added STEP import and supporting tests
|
||||
* Added STEP import and supporting tests
|
||||
|
||||
v0.1.7
|
||||
-----
|
||||
* Added revolve operation and supporting tests
|
||||
* Fixed minor documentation errors
|
||||
* Added revolve operation and supporting tests
|
||||
* Fixed minor documentation errors
|
||||
|
||||
v0.1.8
|
||||
-----
|
||||
* 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
|
||||
* 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.2.0
|
||||
-----
|
||||
|
@ -89,7 +89,12 @@ v0.5.2
|
|||
------
|
||||
* Added the sweep operation #33
|
||||
|
||||
v1.0.0 (unreleased)
|
||||
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)
|
||||
|
|
|
@ -55,9 +55,9 @@ copyright = u'Parametric Products Intellectual Holdings LLC, All Rights Reserved
|
|||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.3'
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.3.0'
|
||||
release = '1.0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
-e .
|
|
@ -19,7 +19,7 @@ from setuptools import setup
|
|||
version = '0.5-SNAPSHOT'
|
||||
if 'TRAVIS_TAG' in os.environ.keys():
|
||||
version= os.environ['TRAVIS_TAG']
|
||||
|
||||
|
||||
|
||||
setup(
|
||||
name='cadquery',
|
||||
|
@ -31,6 +31,7 @@ setup(
|
|||
description='CadQuery is a parametric scripting language for creating and traversing CAD models',
|
||||
long_description=open('README.md').read(),
|
||||
packages=['cadquery','cadquery.contrib','cadquery.freecad_impl','cadquery.plugins','tests'],
|
||||
install_requires=['pyparsing'],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
platforms='any',
|
||||
|
|
|
@ -338,6 +338,10 @@ class TestCQSelectors(BaseTest):
|
|||
# test 'and' (intersection) operator
|
||||
el = c.edges(S('|X') & BS((-2,-2,0.1), (2,2,2))).vals()
|
||||
self.assertEqual(2, len(el))
|
||||
|
||||
# test using extended string syntax
|
||||
v = c.vertices(">X and >Y").vals()
|
||||
self.assertEqual(2, len(v))
|
||||
|
||||
def testSumSelector(self):
|
||||
c = CQ(makeUnitCube())
|
||||
|
@ -354,6 +358,12 @@ class TestCQSelectors(BaseTest):
|
|||
self.assertEqual(2, len(fl))
|
||||
el = c.edges(S("|X") + S("|Y")).vals()
|
||||
self.assertEqual(8, len(el))
|
||||
|
||||
# test using extended string syntax
|
||||
fl = c.faces(">Z or <Z").vals()
|
||||
self.assertEqual(2, len(fl))
|
||||
el = c.edges("|X or |Y").vals()
|
||||
self.assertEqual(8, len(el))
|
||||
|
||||
def testSubtractSelector(self):
|
||||
c = CQ(makeUnitCube())
|
||||
|
@ -366,6 +376,10 @@ class TestCQSelectors(BaseTest):
|
|||
# test the subtract operator
|
||||
fl = c.faces(S("#Z") - S(">X")).vals()
|
||||
self.assertEqual(3, len(fl))
|
||||
|
||||
# test using extended string syntax
|
||||
fl = c.faces("#Z exc >X").vals()
|
||||
self.assertEqual(3, len(fl))
|
||||
|
||||
def testInverseSelector(self):
|
||||
c = CQ(makeUnitCube())
|
||||
|
@ -382,6 +396,19 @@ class TestCQSelectors(BaseTest):
|
|||
self.assertEqual(5, len(fl))
|
||||
el = c.faces('>Z').edges(-S('>X')).vals()
|
||||
self.assertEqual(3, len(el))
|
||||
|
||||
# test using extended string syntax
|
||||
fl = c.faces('not >Z').vals()
|
||||
self.assertEqual(5, len(fl))
|
||||
el = c.faces('>Z').edges('not >X').vals()
|
||||
self.assertEqual(3, len(el))
|
||||
|
||||
def testComplexStringSelector(self):
|
||||
c = CQ(makeUnitCube())
|
||||
|
||||
v = c.vertices('(>X and >Y) or (<X and <Y)').vals()
|
||||
self.assertEqual(4, len(v))
|
||||
|
||||
|
||||
def testFaceCount(self):
|
||||
c = CQ(makeUnitCube())
|
||||
|
@ -406,7 +433,7 @@ class TestCQSelectors(BaseTest):
|
|||
Test if reasonable string selector expressions parse without an error
|
||||
"""
|
||||
|
||||
gram = selectors._makeGrammar()
|
||||
gram = selectors._expression_grammar
|
||||
|
||||
expressions = ['+X ',
|
||||
'-Y',
|
||||
|
@ -423,7 +450,10 @@ class TestCQSelectors(BaseTest):
|
|||
'left',
|
||||
'right',
|
||||
'top',
|
||||
'bottom']
|
||||
|
||||
for e in expressions: gram.parseString(e)
|
||||
'bottom',
|
||||
'not |(1,1,0) and >(0,0,1) or XY except >(1,1,1)[-1]',
|
||||
'(not |(1,1,0) and >(0,0,1)) exc XY and (Z or X)',
|
||||
'not ( <X or >X or <Y or >Y )']
|
||||
|
||||
for e in expressions: gram.parseString(e,parseAll=True)
|
||||
|
|
@ -41,6 +41,24 @@ class TestCadObjects(BaseTest):
|
|||
|
||||
self.assertTupleAlmostEquals((1.0, 2.0, 3.0), e.Center().toTuple(), 3)
|
||||
|
||||
def testEdgeWrapperMakeCircle(self):
|
||||
halfCircleEdge = Edge.makeCircle(radius=10, pnt=(0, 0, 0), dir=(0, 0, 1), angle1=0, angle2=180)
|
||||
|
||||
self.assertTupleAlmostEquals((0.0, 5.0, 0.0), halfCircleEdge.CenterOfBoundBox(0.0001).toTuple(),3)
|
||||
self.assertTupleAlmostEquals((10.0, 0.0, 0.0), halfCircleEdge.startPoint().toTuple(), 3)
|
||||
self.assertTupleAlmostEquals((-10.0, 0.0, 0.0), halfCircleEdge.endPoint().toTuple(), 3)
|
||||
|
||||
def testFaceWrapperMakePlane(self):
|
||||
mplane = Face.makePlane(10,10)
|
||||
|
||||
self.assertTupleAlmostEquals((0.0, 0.0, 1.0), mplane.normalAt().toTuple(), 3)
|
||||
|
||||
def testCenterOfBoundBox(self):
|
||||
pass
|
||||
|
||||
def testCombinedCenterOfBoundBox(self):
|
||||
pass
|
||||
|
||||
def testCompoundCenter(self):
|
||||
"""
|
||||
Tests whether or not a proper weighted center can be found for a compound
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
__author__ = "Jeremy Wright (jmwright)"
|
||||
__copyright__ = "Copyright 2014-2016"
|
||||
__copyright__ = "Copyright 2014-2017"
|
||||
__license__ = "LGPL v3"
|
||||
__version__ = "0.5.2"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Jeremy Wright"
|
||||
__status__ = "Production/Stable"
|
||||
|
|
|
@ -28,7 +28,7 @@ v0.5.1
|
|||
* Version updates for CadQuery v0.4.0, v0.4.1, v0.5.0-stable and v0.5.1
|
||||
* Updated CadQuery license to Apache 2.0
|
||||
|
||||
v1.0.0 (Unreleased)
|
||||
v1.0.0
|
||||
-----
|
||||
* Embedded pyparsing package as a supporting library for new selector syntax
|
||||
* Added a check to remove any disallowed characters from the document name when executing a script
|
||||
|
|
Loading…
Reference in New Issue
Block a user