Merge commit '4a105d12413b11bbd29cd50249867d86b41e3965'
This commit is contained in:
commit
4a21c9e665
|
@ -1,27 +1,30 @@
|
|||
---
|
||||
language: python
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:freecad-maintainers/freecad-daily
|
||||
- sudo apt-get update -qq
|
||||
- sudo add-apt-repository -y ppa:freecad-maintainers/freecad-daily
|
||||
- sudo apt-get update -qq
|
||||
install:
|
||||
- sudo apt-get install -y freecad freecad-doc
|
||||
- gcc --version
|
||||
- g++ --version
|
||||
- python ./setup.py install
|
||||
- pip install coverage
|
||||
- pip install coveralls
|
||||
- pip install Sphinx==1.3.2
|
||||
- pip install travis-sphinx
|
||||
|
||||
- sudo apt-get install -y freecad freecad-doc
|
||||
- gcc --version
|
||||
- g++ --version
|
||||
- python ./setup.py install
|
||||
- pip install coverage
|
||||
- pip install coveralls
|
||||
- pip install Sphinx==1.3.2
|
||||
- pip install travis-sphinx
|
||||
script:
|
||||
- coverage run --source=cadquery ./runtests.py
|
||||
- travis-sphinx --nowarn --source=doc build
|
||||
|
||||
- coverage run --source=cadquery ./runtests.py
|
||||
- travis-sphinx --nowarn --source=doc build
|
||||
after_success:
|
||||
- coveralls
|
||||
- travis-sphinx deploy
|
||||
|
||||
- coveralls
|
||||
- travis-sphinx deploy
|
||||
branches:
|
||||
except:
|
||||
- pythonocc
|
||||
- pythonocc
|
||||
- 2_0_branch
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: dcowden
|
||||
password:
|
||||
secure: aP02wBbry1j3hYG/w++siF1lk26teuRQlPAx1c+ec8fxUw+bECa2HbPQHcIvSXB5N6nc6P3L9LjHt9ktm+Dn6FLJu3qWYNGAZx9PTn24ug0iAmB+JyNrsET3nK6WUKR1XpBqvjKgdpukd1Hknh2FSzYoyUvFWH9/CovITCFN3jo=
|
||||
on:
|
||||
tags: true
|
|
@ -1,4 +1,5 @@
|
|||
README.txt
|
||||
README.md
|
||||
setup.cfg
|
||||
setup.py
|
||||
cadquery\cq.py
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include README.md
|
|
@ -742,6 +742,19 @@ class CQ(object):
|
|||
return self.newObject([o.rotate(axisStartPoint, axisEndPoint, angleDegrees)
|
||||
for o in self.objects])
|
||||
|
||||
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
|
||||
:type basePointVector: tuple
|
||||
"""
|
||||
newS = self.newObject([self.objects[0].mirror(mirrorPlane, basePointVector)])
|
||||
return newS.first()
|
||||
|
||||
|
||||
def translate(self, vec):
|
||||
"""
|
||||
Returns a copy of all of the items on the stack moved by the specified translation vector.
|
||||
|
|
|
@ -44,9 +44,11 @@ class CQModel(object):
|
|||
self.ast_tree = ast.parse(script_source, CQSCRIPT)
|
||||
self.script_source = script_source
|
||||
self._find_vars()
|
||||
|
||||
# TODO: pick up other scirpt metadata:
|
||||
# describe
|
||||
# pick up validation methods
|
||||
self._find_descriptions()
|
||||
|
||||
def _find_vars(self):
|
||||
"""
|
||||
|
@ -65,6 +67,9 @@ class CQModel(object):
|
|||
if isinstance(node, ast.Assign):
|
||||
assignment_finder.visit_Assign(node)
|
||||
|
||||
def _find_descriptions(self):
|
||||
description_finder = ParameterDescriptionFinder(self.metadata)
|
||||
description_finder.visit(self.ast_tree)
|
||||
|
||||
def validate(self, params):
|
||||
"""
|
||||
|
@ -75,11 +80,13 @@ class CQModel(object):
|
|||
"""
|
||||
raise NotImplementedError("not yet implemented")
|
||||
|
||||
def build(self, build_parameters=None):
|
||||
def build(self, build_parameters=None, build_options=None):
|
||||
"""
|
||||
Executes the script, using the optional parameters to override those in the model
|
||||
:param build_parameters: a dictionary of variables. The variables must be
|
||||
assignable to the underlying variable type.
|
||||
assignable to the underlying variable type. These variables override default values in the script
|
||||
:param build_options: build options for how to build the model. Build options include things like
|
||||
timeouts, tesselation tolerances, etc
|
||||
:raises: Nothing. If there is an exception, it will be on the exception property of the result.
|
||||
This is the interface so that we can return other information on the result, such as the build time
|
||||
:return: a BuildResult object, which includes the status of the result, and either
|
||||
|
@ -95,10 +102,14 @@ class CQModel(object):
|
|||
self.set_param_values(build_parameters)
|
||||
collector = ScriptCallback()
|
||||
env = EnvironmentBuilder().with_real_builtins().with_cadquery_objects() \
|
||||
.add_entry("build_object", collector.build_object).build()
|
||||
.add_entry("build_object", collector.build_object) \
|
||||
.add_entry("debug", collector.debug) \
|
||||
.add_entry("describe_parameter",collector.describe_parameter) \
|
||||
.build()
|
||||
|
||||
c = compile(self.ast_tree, CQSCRIPT, 'exec')
|
||||
exec (c, env)
|
||||
result.set_debug(collector.debugObjects )
|
||||
if collector.has_results():
|
||||
result.set_success_result(collector.outputObjects)
|
||||
else:
|
||||
|
@ -139,6 +150,7 @@ class BuildResult(object):
|
|||
def __init__(self):
|
||||
self.buildTime = None
|
||||
self.results = []
|
||||
self.debugObjects = []
|
||||
self.first_result = None
|
||||
self.success = False
|
||||
self.exception = None
|
||||
|
@ -147,6 +159,9 @@ class BuildResult(object):
|
|||
self.exception = ex
|
||||
self.success = False
|
||||
|
||||
def set_debug(self, debugObjects):
|
||||
self.debugObjects = debugObjects
|
||||
|
||||
def set_success_result(self, results):
|
||||
self.results = results
|
||||
self.first_result = self.results[0]
|
||||
|
@ -164,6 +179,11 @@ class ScriptMetadata(object):
|
|||
def add_script_parameter(self, p):
|
||||
self.parameters[p.name] = p
|
||||
|
||||
def add_parameter_description(self,name,description):
|
||||
print 'Adding Parameter name=%s, desc=%s' % ( name, description )
|
||||
p = self.parameters[name]
|
||||
p.desc = description
|
||||
|
||||
|
||||
class ParameterType(object):
|
||||
pass
|
||||
|
@ -204,19 +224,15 @@ class InputParameter:
|
|||
self.varType = None
|
||||
|
||||
#: help text describing the variable. Only available if the script used describe_parameter()
|
||||
self.shortDesc = None
|
||||
|
||||
|
||||
self.desc = None
|
||||
|
||||
#: valid values for the variable. Only available if the script used describe_parameter()
|
||||
self.valid_values = []
|
||||
|
||||
|
||||
|
||||
self.ast_node = None
|
||||
|
||||
@staticmethod
|
||||
def create(ast_node, var_name, var_type, default_value, valid_values=None, short_desc=None):
|
||||
def create(ast_node, var_name, var_type, default_value, valid_values=None, desc=None):
|
||||
|
||||
if valid_values is None:
|
||||
valid_values = []
|
||||
|
@ -225,10 +241,7 @@ class InputParameter:
|
|||
p.ast_node = ast_node
|
||||
p.default_value = default_value
|
||||
p.name = var_name
|
||||
if short_desc is None:
|
||||
p.shortDesc = var_name
|
||||
else:
|
||||
p.shortDesc = short_desc
|
||||
p.desc = desc
|
||||
p.varType = var_type
|
||||
p.valid_values = valid_values
|
||||
return p
|
||||
|
@ -270,9 +283,9 @@ class ScriptCallback(object):
|
|||
the build_object() method is exposed to CQ scripts, to allow them
|
||||
to return objects to the execution environment
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.outputObjects = []
|
||||
self.debugObjects = []
|
||||
|
||||
def build_object(self, shape):
|
||||
"""
|
||||
|
@ -281,10 +294,15 @@ class ScriptCallback(object):
|
|||
"""
|
||||
self.outputObjects.append(shape)
|
||||
|
||||
def describe_parameter(self,var, valid_values, short_desc):
|
||||
def debug(self,obj,args={}):
|
||||
"""
|
||||
Not yet implemented: allows a script to document
|
||||
extra metadata about the parameters
|
||||
Debug print/output an object, with optional arguments.
|
||||
"""
|
||||
self.debugObjects.append(DebugObject(obj,args))
|
||||
|
||||
def describe_parameter(self,var_data ):
|
||||
"""
|
||||
Do Nothing-- we parsed the ast ahead of exection to get what we need.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
@ -297,7 +315,15 @@ class ScriptCallback(object):
|
|||
def has_results(self):
|
||||
return len(self.outputObjects) > 0
|
||||
|
||||
|
||||
class DebugObject(object):
|
||||
"""
|
||||
Represents a request to debug an object
|
||||
Object is the type of object we want to debug
|
||||
args are parameters for use during debuging ( for example, color, tranparency )
|
||||
"""
|
||||
def __init__(self,object,args):
|
||||
self.args = args
|
||||
self.object = object
|
||||
|
||||
class InvalidParameterError(Exception):
|
||||
"""
|
||||
|
@ -371,6 +397,30 @@ class EnvironmentBuilder(object):
|
|||
def build(self):
|
||||
return self.env
|
||||
|
||||
class ParameterDescriptionFinder(ast.NodeTransformer):
|
||||
"""
|
||||
Visits a parse tree, looking for function calls to describe_parameter(var, description )
|
||||
"""
|
||||
def __init__(self, cq_model):
|
||||
self.cqModel = cq_model
|
||||
|
||||
def visit_Call(self,node):
|
||||
"""
|
||||
Called when we see a function call. Is it describe_parameter?
|
||||
"""
|
||||
try:
|
||||
if node.func.id == 'describe_parameter':
|
||||
#looks like we have a call to our function.
|
||||
#first parameter is the variable,
|
||||
#second is the description
|
||||
varname = node.args[0].id
|
||||
desc = node.args[1].s
|
||||
self.cqModel.add_parameter_description(varname,desc)
|
||||
|
||||
except:
|
||||
print "Unable to handle function call"
|
||||
pass
|
||||
return node
|
||||
|
||||
class ConstantAssignmentFinder(ast.NodeTransformer):
|
||||
"""
|
||||
|
@ -381,9 +431,6 @@ class ConstantAssignmentFinder(ast.NodeTransformer):
|
|||
self.cqModel = cq_model
|
||||
|
||||
def handle_assignment(self, var_name, value_node):
|
||||
|
||||
|
||||
|
||||
try:
|
||||
|
||||
if type(value_node) == ast.Num:
|
||||
|
|
|
@ -184,9 +184,23 @@ class Shape(object):
|
|||
def isValid(self):
|
||||
return self.wrapped.isValid()
|
||||
|
||||
def BoundingBox(self):
|
||||
def BoundingBox(self, tolerance=0.1):
|
||||
self.wrapped.tessellate(tolerance)
|
||||
return BoundBox(self.wrapped.BoundBox)
|
||||
|
||||
def mirror(self, mirrorPlane="XY", basePointVector=(0, 0, 0)):
|
||||
if mirrorPlane == "XY" or mirrorPlane== "YX":
|
||||
mirrorPlaneNormalVector = FreeCAD.Base.Vector(0, 0, 1)
|
||||
elif mirrorPlane == "XZ" or mirrorPlane == "ZX":
|
||||
mirrorPlaneNormalVector = FreeCAD.Base.Vector(0, 1, 0)
|
||||
elif mirrorPlane == "YZ" or mirrorPlane == "ZY":
|
||||
mirrorPlaneNormalVector = FreeCAD.Base.Vector(1, 0, 0)
|
||||
|
||||
if type(basePointVector) == tuple:
|
||||
basePointVector = Vector(basePointVector)
|
||||
|
||||
return Shape.cast(self.wrapped.mirror(basePointVector.wrapped, mirrorPlaneNormalVector))
|
||||
|
||||
def Center(self):
|
||||
# A Part.Shape object doesn't have the CenterOfMass function, but it's wrapped Solid(s) does
|
||||
if isinstance(self.wrapped, FreeCADPart.Shape):
|
||||
|
@ -223,8 +237,8 @@ class Shape(object):
|
|||
|
||||
:param objects: a list of objects with mass
|
||||
"""
|
||||
total_mass = sum(o.wrapped.Mass for o in objects)
|
||||
weighted_centers = [o.wrapped.CenterOfMass.multiply(o.wrapped.Mass) for o in objects]
|
||||
total_mass = sum(Shape.computeMass(o) for o in objects)
|
||||
weighted_centers = [o.wrapped.CenterOfMass.multiply(Shape.computeMass(o)) for o in objects]
|
||||
|
||||
sum_wc = weighted_centers[0]
|
||||
for wc in weighted_centers[1:] :
|
||||
|
@ -232,6 +246,17 @@ class Shape(object):
|
|||
|
||||
return Vector(sum_wc.multiply(1./total_mass))
|
||||
|
||||
@staticmethod
|
||||
def computeMass(object):
|
||||
"""
|
||||
Calculates the 'mass' of an object. in FreeCAD < 15, all objects had a mass.
|
||||
in FreeCAD >=15, faces no longer have mass, but instead have area.
|
||||
"""
|
||||
if object.wrapped.ShapeType == 'Face':
|
||||
return object.wrapped.Area
|
||||
else:
|
||||
return object.wrapped.Mass
|
||||
|
||||
@staticmethod
|
||||
def CombinedCenterOfBoundBox(objects):
|
||||
"""
|
||||
|
|
|
@ -32,10 +32,26 @@ CQGI compliant containers provide an execution environment for scripts. The envi
|
|||
|
||||
* the cadquery library is automatically imported as 'cq'.
|
||||
* the :py:meth:`cadquery.cqgi.ScriptCallback.build_object()` method is defined that should be used to export a shape to the execution environment
|
||||
* the :py:meth:`cadquery.cqgi.ScriptCallBack.debug()` method is defined, which can be used by scripts to debug model output during execution.
|
||||
|
||||
Scripts must call build_output at least once. Invoking build_object more than once will send multiple objects to
|
||||
the container. An error will occur if the script does not return an object using the build_object() method.
|
||||
|
||||
This CQGI compliant script produces a cube with a circle on top, and displays a workplane as well as an intermediate circle as debug output::
|
||||
|
||||
base_cube = cq.Workplane('XY').rect(1.0,1.0).extrude(1.0)
|
||||
top_of_cube_plane = base_cube.faces(">Z").workplane()
|
||||
debug(top_of_cube_plane, { 'color': 'yellow', } )
|
||||
debug(top_of_cube_plane.center, { 'color' : 'blue' } )
|
||||
|
||||
circle=top_of_cube_plane.circle(0.5)
|
||||
debug(circle, { 'color': 'red' } )
|
||||
|
||||
build_object( circle.extrude(1.0) )
|
||||
|
||||
Note that importing cadquery is not required.
|
||||
At the end of this script, one object will be displayed, in addition to a workplane, a point, and a circle
|
||||
|
||||
Future enhancements will include several other methods, used to provide more metadata for the execution environment:
|
||||
* :py:meth:`cadquery.cqgi.ScriptCallback.add_error()`, indicates an error with an input parameter
|
||||
* :py:meth:`cadquery.cqgi.ScriptCallback.describe_parameter()`, provides extra information about a parameter in the script,
|
||||
|
@ -54,10 +70,29 @@ run code like this::
|
|||
|
||||
The :py:meth:`cadquery.cqgi.parse()` method returns a :py:class:`cadquery.cqgi.CQModel` object.
|
||||
|
||||
The `metadata`p property of the object contains a `cadquery.cqgi.ScriptMetaData` object, which can be used to discover the
|
||||
user parameters available. This is useful if the execution environment would like to present a GUI to allow the user to change the
|
||||
model parameters. Typically, after collecting new values, the environment will supply them in the build() method.
|
||||
|
||||
This code will return a dictionary of parameter values in the model text SCRIPT::
|
||||
|
||||
parameters = cqgi.parse(SCRIPT).metadata.parameters
|
||||
|
||||
The dictionary you get back is a map where key is the parameter name, and value is an InputParameter object,
|
||||
which has a name, type, and default value.
|
||||
|
||||
The type is an object which extends ParameterType-- you can use this to determine what kind of widget to render ( checkbox for boolean, for example ).
|
||||
|
||||
The parameter object also has a description, valid values, minimum, and maximum values, if the user has provided them using the
|
||||
describe_parameter() method.
|
||||
|
||||
|
||||
|
||||
Calling :py:meth:`cadquery.cqgi.CQModel.build()` returns a :py:class:`cadquery.cqgi.BuildResult` object,
|
||||
,which includes the script execution time, and a success flag.
|
||||
|
||||
If the script was successful, the results property will include a list of results returned by the script.
|
||||
If the script was successful, the results property will include a list of results returned by the script,
|
||||
as well as any debug the script produced
|
||||
|
||||
If the script failed, the exception property contains the exception object.
|
||||
|
||||
|
@ -67,12 +102,16 @@ with new values::
|
|||
from cadquery import cqgi
|
||||
|
||||
user_script = ...
|
||||
build_result = cqgi.parse(user_script).build({ 'param': 2 } )
|
||||
build_result = cqgi.parse(user_script).build(build_parameters={ 'param': 2 }, build_options={} )
|
||||
|
||||
If a parameter called 'param' is defined in the model, it will be assigned the value 2 before the script runs.
|
||||
An error will occur if a value is provided that is not defined in the model, or if the value provided cannot
|
||||
be assigned to a variable with the given name.
|
||||
|
||||
build_options is used to set server-side settings like timeouts, tesselation tolerances, and other details about
|
||||
how the model should be built.
|
||||
|
||||
|
||||
More about script variables
|
||||
-----------------------------
|
||||
|
||||
|
|
|
@ -312,6 +312,64 @@ introduce horizontal and vertical lines, which make for slightly easier coding.
|
|||
* :py:meth:`Workplane`
|
||||
* :py:meth:`Workplane.extrude`
|
||||
|
||||
Mirroring 3D Objects
|
||||
-----------------------------
|
||||
|
||||
.. cq_plot::
|
||||
|
||||
result0 = (cadquery.Workplane("XY")
|
||||
.moveTo(10,0)
|
||||
.lineTo(5,0)
|
||||
.threePointArc((3.9393,0.4393),(3.5,1.5))
|
||||
.threePointArc((3.0607,2.5607),(2,3))
|
||||
.lineTo(1.5,3)
|
||||
.threePointArc((0.4393,3.4393),(0,4.5))
|
||||
.lineTo(0,13.5)
|
||||
.threePointArc((0.4393,14.5607),(1.5,15))
|
||||
.lineTo(28,15)
|
||||
.lineTo(28,13.5)
|
||||
.lineTo(24,13.5)
|
||||
.lineTo(24,11.5)
|
||||
.lineTo(27,11.5)
|
||||
.lineTo(27,10)
|
||||
.lineTo(22,10)
|
||||
.lineTo(22,13.2)
|
||||
.lineTo(14.5,13.2)
|
||||
.lineTo(14.5,10)
|
||||
.lineTo(12.5,10 )
|
||||
.lineTo(12.5,13.2)
|
||||
.lineTo(5.5,13.2)
|
||||
.lineTo(5.5,2)
|
||||
.threePointArc((5.793,1.293),(6.5,1))
|
||||
.lineTo(10,1)
|
||||
.close())
|
||||
result = result0.extrude(100)
|
||||
|
||||
result = result.rotate((0, 0, 0),(1, 0, 0), 90)
|
||||
|
||||
result = result.translate(result.val().BoundingBox().center.multiply(-1))
|
||||
|
||||
mirXY_neg = result.mirror(mirrorPlane="XY", basePointVector=(0, 0, -30))
|
||||
mirXY_pos = result.mirror(mirrorPlane="XY", basePointVector=(0, 0, 30))
|
||||
mirZY_neg = result.mirror(mirrorPlane="ZY", basePointVector=(-30,0,0))
|
||||
mirZY_pos = result.mirror(mirrorPlane="ZY", basePointVector=(30,0,0))
|
||||
|
||||
result = result.union(mirXY_neg).union(mirXY_pos).union(mirZY_neg).union(mirZY_pos)
|
||||
|
||||
build_object(result)
|
||||
|
||||
.. topic:: Api References
|
||||
|
||||
.. hlist::
|
||||
:columns: 2
|
||||
|
||||
* :py:meth:`Workplane.moveTo`
|
||||
* :py:meth:`Workplane.lineTo`
|
||||
* :py:meth:`Workplane.threePointArc`
|
||||
* :py:meth:`Workplane.extrude`
|
||||
* :py:meth:`Workplane.mirror`
|
||||
* :py:meth:`Workplane.union`
|
||||
* :py:meth:`CQ.rotate`
|
||||
|
||||
Creating Workplanes on Faces
|
||||
-----------------------------
|
||||
|
|
|
@ -8,11 +8,11 @@ import unittest
|
|||
#on py 2.7.x on win
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQGI.TestCQGI))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadObjects.TestCadObjects))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWorkplanes.TestWorkplanes))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQSelectors.TestCQSelectors))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
|
||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQGI.TestCQGI))
|
||||
unittest.TextTestRunner().run(suite)
|
||||
|
|
|
@ -11,12 +11,19 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
#if we are building in travis, use the build number as the sub-minor version
|
||||
version = '0.5-SNAPSHOT'
|
||||
if 'TRAVIS_TAG' in os.environ.keys():
|
||||
version= os.environ['TRAVIS_TAG']
|
||||
|
||||
|
||||
setup(
|
||||
name='cadquery',
|
||||
version='0.4.0',
|
||||
version=version,
|
||||
url='https://github.com/dcowden/cadquery',
|
||||
license='Apache Public License 2.0',
|
||||
author='David Cowden',
|
||||
|
|
|
@ -23,6 +23,18 @@ TESTSCRIPT = textwrap.dedent(
|
|||
"""
|
||||
)
|
||||
|
||||
TEST_DEBUG_SCRIPT = textwrap.dedent(
|
||||
"""
|
||||
height=2.0
|
||||
width=3.0
|
||||
(a,b) = (1.0,1.0)
|
||||
foo="bar"
|
||||
debug(foo, { "color": 'yellow' } )
|
||||
result = "%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) )
|
||||
build_object(result)
|
||||
debug(height )
|
||||
"""
|
||||
)
|
||||
|
||||
class TestCQGI(BaseTest):
|
||||
def test_parser(self):
|
||||
|
@ -31,6 +43,16 @@ class TestCQGI(BaseTest):
|
|||
|
||||
self.assertEquals(set(metadata.parameters.keys()), {'height', 'width', 'a', 'b', 'foo'})
|
||||
|
||||
def test_build_with_debug(self):
|
||||
model = cqgi.CQModel(TEST_DEBUG_SCRIPT)
|
||||
result = model.build()
|
||||
debugItems = result.debugObjects
|
||||
self.assertTrue(len(debugItems) == 2)
|
||||
self.assertTrue( debugItems[0].object == "bar" )
|
||||
self.assertTrue( debugItems[0].args == { "color":'yellow' } )
|
||||
self.assertTrue( debugItems[1].object == 2.0 )
|
||||
self.assertTrue( debugItems[1].args == {} )
|
||||
|
||||
def test_build_with_empty_params(self):
|
||||
model = cqgi.CQModel(TESTSCRIPT)
|
||||
result = model.build()
|
||||
|
@ -44,6 +66,30 @@ class TestCQGI(BaseTest):
|
|||
result = model.build({'height': 3.0})
|
||||
self.assertTrue(result.results[0] == "3.0|3.0|bar|1.0")
|
||||
|
||||
def test_describe_parameters(self):
|
||||
script = textwrap.dedent(
|
||||
"""
|
||||
a = 2.0
|
||||
describe_parameter(a,'FirstLetter')
|
||||
"""
|
||||
)
|
||||
model = cqgi.CQModel(script)
|
||||
a_param = model.metadata.parameters['a']
|
||||
self.assertTrue(a_param.default_value == 2.0)
|
||||
self.assertTrue(a_param.desc == 'FirstLetter')
|
||||
self.assertTrue(a_param.varType == cqgi.NumberParameterType )
|
||||
|
||||
def test_describe_parameter_invalid_doesnt_fail_script(self):
|
||||
script = textwrap.dedent(
|
||||
"""
|
||||
a = 2.0
|
||||
describe_parameter(a, 2 - 1 )
|
||||
"""
|
||||
)
|
||||
model = cqgi.CQModel(script)
|
||||
a_param = model.metadata.parameters['a']
|
||||
self.assertTrue(a_param.name == 'a' )
|
||||
|
||||
def test_build_with_exception(self):
|
||||
badscript = textwrap.dedent(
|
||||
"""
|
||||
|
|
|
@ -550,6 +550,43 @@ class TestCadQuery(BaseTest):
|
|||
|
||||
self.assertEqual(10,currentS.faces().size())
|
||||
|
||||
def testBoundingBox(self):
|
||||
"""
|
||||
Tests the boudingbox center of a model
|
||||
"""
|
||||
result0 = (Workplane("XY")
|
||||
.moveTo(10,0)
|
||||
.lineTo(5,0)
|
||||
.threePointArc((3.9393,0.4393),(3.5,1.5))
|
||||
.threePointArc((3.0607,2.5607),(2,3))
|
||||
.lineTo(1.5,3)
|
||||
.threePointArc((0.4393,3.4393),(0,4.5))
|
||||
.lineTo(0,13.5)
|
||||
.threePointArc((0.4393,14.5607),(1.5,15))
|
||||
.lineTo(28,15)
|
||||
.lineTo(28,13.5)
|
||||
.lineTo(24,13.5)
|
||||
.lineTo(24,11.5)
|
||||
.lineTo(27,11.5)
|
||||
.lineTo(27,10)
|
||||
.lineTo(22,10)
|
||||
.lineTo(22,13.2)
|
||||
.lineTo(14.5,13.2)
|
||||
.lineTo(14.5,10)
|
||||
.lineTo(12.5,10 )
|
||||
.lineTo(12.5,13.2)
|
||||
.lineTo(5.5,13.2)
|
||||
.lineTo(5.5,2)
|
||||
.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)
|
||||
self.assertAlmostEqual(14.0, bb_center.x, 3)
|
||||
self.assertAlmostEqual(7.5, bb_center.y, 3)
|
||||
self.assertAlmostEqual(50.0, bb_center.z, 3)
|
||||
|
||||
def testCutThroughAll(self):
|
||||
"""
|
||||
Tests a model that uses more than one workplane
|
||||
|
|
Loading…
Reference in New Issue
Block a user