cqparts.utils package¶
Submodules¶
cqparts.utils.geometry module¶
-
class
cqparts.utils.geometry.CoordSystem(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 0, 1))¶ Bases:
cadquery.freecad_impl.geom.PlaneDefines the location, and rotation of an orthogonal 3 dimensional coordinate system.
-
__add__(other)¶ For
A+B. WhereAis this coordinate system, andBisother.Raises: TypeError – if addition for the given type is not supported Supported types:
A(CoordSystem) +B(CoordSystem):Returns: world coordinates of BinA’s coordinatesReturn type: CoordSystemA(CoordSystem) +B(cadquery.Vector):Returns: world coordinates of Brepresented inA’s coordinate systemReturn type: cadquery.VectorA(CoordSystem) +B(cadquery.CQ):remember:
cadquery.Workplaneinherits fromcadquery.CQReturns: content of Bmoved toA’s coordinate systemReturn type: cadquery.Workplane
-
__sub__(other)¶ For
A-B. WhereAis this coordinate system, andBisother.Raises: TypeError – if subtraction for the given type is not supported Supported types:
A(CoordSystem) +B(CoordSystem):Returns: local coordinate system of AfromB’s coordinate systemReturn type: CoordSystem
-
classmethod
from_plane(plane)¶ Parameters: plane ( cadquery.Plane) – cadquery plane instance to base coordinate system onReturns: duplicate of the given plane, in this class Return type: CoordSystemusage example:
>>> import cadquery >>> from cqparts.utils.geometry import CoordSystem >>> obj = cadquery.Workplane('XY').circle(1).extrude(5) >>> plane = obj.faces(">Z").workplane().plane >>> isinstance(plane, cadquery.Plane) True >>> coord_sys = CoordSystem.from_plane(plane) >>> isinstance(coord_sys, CoordSystem) True >>> coord_sys.origin.z 5.0
-
classmethod
from_transform(matrix)¶ Parameters: matrix ( FreeCAD.Matrix) – 4x4 3d affine transform matrixReturns: a unit, zero offset coordinate system transformed by the given matrix Return type: CoordSystemIndividual rotation & translation matricies are:
\[\begin{split}R_z & = \begin{bmatrix} cos(\alpha) & -sin(\alpha) & 0 & 0 \\ sin(\alpha) & cos(\alpha) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \qquad & R_y & = \begin{bmatrix} cos(\beta) & 0 & sin(\beta) & 0 \\ 0 & 1 & 0 & 0 \\ -sin(\beta) & 0 & cos(\beta) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \\ \\ R_x & = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & cos(\gamma) & -sin(\gamma) & 0 \\ 0 & sin(\gamma) & cos(\gamma) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \qquad & T_{\text{xyz}} & = \begin{bmatrix} 1 & 0 & 0 & \delta x \\ 0 & 1 & 0 & \delta y \\ 0 & 0 & 1 & \delta z \\ 0 & 0 & 0 & 1 \end{bmatrix}\end{split}\]The
transformis the combination of these:\[\begin{split}transform = T_{\text{xyz}} \cdot R_z \cdot R_y \cdot R_x = \begin{bmatrix} a & b & c & \delta x \\ d & e & f & \delta y \\ g & h & i & \delta z \\ 0 & 0 & 0 & 1 \end{bmatrix}\end{split}\]Where:
\[\begin{split}a & = cos(\alpha) cos(\beta) \\ b & = cos(\alpha) sin(\beta) sin(\gamma) - sin(\alpha) cos(\gamma) \\ c & = cos(\alpha) sin(\beta) cos(\gamma) + sin(\alpha) sin(\gamma) \\ d & = sin(\alpha) cos(\beta) \\ e & = sin(\alpha) sin(\beta) sin(\gamma) + cos(\alpha) cos(\gamma) \\ f & = sin(\alpha) sin(\beta) cos(\gamma) - cos(\alpha) sin(\gamma) \\ g & = -sin(\beta) \\ h & = cos(\beta) sin(\gamma) \\ i & = cos(\beta) cos(\gamma)\end{split}\]
-
local_to_world_transform¶ Returns: 3d affine transform matrix to convert local coordinates to world coordinates. Return type: cadquery.MatrixFor matrix structure, see
from_transform().
-
classmethod
random(span=1, seed=None)¶ Creates a randomized coordinate system.
Useful for confirming that an assembly does not rely on its origin coordinate system to remain intact.
For example, the
CoordSysIndicatorassembly aligns 3 boxes along each of the \(XYZ\) axes. Positioning it randomly by setting itsworld_coordsshows that each box is always positioned orthogonally to the other two.from cqparts_misc.basic.indicators import CoordSysIndicator from cqparts.display import display from cqparts.utils import CoordSystem cs = CoordSysIndicator() cs.world_coords = CoordSystem.random() display(cs)
Parameters: - span – origin of return will be \(\pm span\) per axis
- seed (hashable object) – if supplied, return is psudorandom (repeatable)
Returns: randomized coordinate system
Return type:
-
world_to_local_transform¶ Returns: 3d affine transform matrix to convert world coordinates to local coordinates. Return type: cadquery.MatrixFor matrix structure, see
from_transform().
-
cqparts.utils.misc module¶
-
cqparts.utils.misc.indicate_last(items)¶ iterate through list and indicate which item is the last, intended to assist tree displays of hierarchical content.
Returns: yielding (<bool>, <item>) where bool is True only on last entry Return type: generator
-
cqparts.utils.misc.measure_time(*args, **kwds)¶
-
class
cqparts.utils.misc.property_buffered(getter, name=None)¶ Bases:
objectBuffer the result of a method on the class instance, similar to python builtin
@property, but the result is kept in memory until it’s explicitly deleted.>>> from cqparts.utils.misc import property_buffered >>> class A(object): ... @property_buffered ... def x(self): ... print("x called") ... return 100 >>> a = A() >>> a.x x called 100 >>> a.x 100 >>> del a.x >>> a.x x called 100
Basis of class was sourced from the funkybob/antfarm project. thanks to @funkybob.
-
cqparts.utils.misc.working_dir(*args, **kwds)¶ Change working directory within a context:
>>> import os >>> from cqparts.utils import working_dir >>> print(os.getcwd()) /home/myuser/temp >>> with working_dir('..'): ... print(os.getcwd()) ... /home/myuser
Parameters: path ( str) – working path to use while in context
cqparts.utils.sphinx module¶
This module is only to be referenced from your project’s sphinx autodoc configuration.
http://www.sphinx-doc.org/en/stable/ext/autodoc.html
-
cqparts.utils.sphinx.add_parametric_object_params(prepend=False, hide_private=True)¶ Add
ParametricObjectparameters in a list to the docstring.This is only intended to be used with sphinx autodoc.
In your sphinx
config.pyfile:from cqparts.utils.sphinx import add_parametric_object_params def setup(app): app.connect("autodoc-process-docstring", add_parametric_object_params())
Then, when documenting your
PartorAssemblytheParametricObjectparameters will also be documented in the output.Parameters:
-
cqparts.utils.sphinx.add_search_index_criteria(prepend=False)¶ Add the search criteria used when calling
register()on aComponentas a table to the docstring.This is only intended to be used with sphinx autodoc.
In your sphinx
config.pyfile:from cqparts.utils.sphinx import add_search_index_criteria def setup(app): app.connect("autodoc-process-docstring", add_search_index_criteria())
Then, when documenting your
PartorAssemblythe search criteria will also be documented in the output.Parameters: prepend ( bool) – if True, table is added to the beginning of the docstring. otherwise, it’s appended at the end.
-
cqparts.utils.sphinx.skip_class_parameters()¶ Can be used with
add_parametric_object_params(), this removes duplicate variables cluttering the sphinx docs.This is only intended to be used with sphinx autodoc
In your sphinx
config.pyfile:from cqparts.utils.sphinx import skip_class_parameters def setup(app): app.connect("autodoc-skip-member", skip_class_parameters())
cqparts.utils.test module¶
-
class
cqparts.utils.test.CatalogueTest(methodName='runTest')¶ Bases:
cqparts.utils.test.ComponentTest-
catalogue= None¶
-
classmethod
create_from(catalogue, add_to={}, id_mangler=None, include_cond=None, exclude_cond=None)¶ Create a testcase class that will run generic tests on each item in the given
Catalogue.Parameters: - catalogue (
Catalogue) – catalogue to generatea tests from - add_to (
dict) – dict to add resulting class to (usuallyglobals(). - id_mangler (
function) – convert item id to a valid python method name - include_cond (
function) – returns true if item should be tested - exclude_cond (
function) – returns true if item should not be tested
Returns: a testcase class to be discovered and run by
unittestReturn type: unittest.TestCasesub-class (a class, not an instance)To create a test-case, and add the class with the catalogue’s name to the
globals()namespace:from cqparts.utils.test import CatalogueTest from cqparts.catalogue import JSONCatalogue catalogue = JSONCatalogue('my_catalogue.json') CatalogueTest.create_from(catalogue, add_to=globals())
Alternatively, to control your class name a bit more traditionally:
# alternatively MyTestCase = CatalogueTest.create_from(catalogue)
Test Names / Catalogue IDs
Each test is named for its item’s
id. By default, to translate the ids into valid python method names, this is done by replacing any non-alpha-numeric characters with a_.To illustrate with some examples:
id mangled id test name abc123abc123(same)test_abc1233.141593_14159test_3_14159%$#*_yeah!_____yeah_test______yeah__(@@)yeah&_____yeah_test______yeah_So you can see why a python method name of
test_%$#*_yeah!might be a problem, which is why this is done. But you may also spot that the last 2, although their IDs are unique, the test method names are the same.To change the way ID’s are mangled into test method names, set the
id_manglerparameter:def mangle_id(id_str): return id_str.replace('a', 'X') CatalogueTest.create_from( catalogue, # as defined in the previous example add_to=globals(), id_mangler=mangle_id, )
That would change the first test name to
test_Xbc123.Include / Exclude Items
If you intend on including or excluding certain items from the testlist, you can employ the
include_condand/orexclude_condparameters:def include_item(item): # include item if it has a specific id return item.get('id') in ['a', 'b', 'c'] def exclude_item(item): # exclude everything with a width > 100 return item.get('obj').get('params').get('width', 0) > 100 CatalogueTest.create_from( catalogue, # as defined in the previous example add_to=globals(), include_cond=include_item, exclude_cond=exclude_item, )
Tests will be created if the following conditions are met:
excluded included test case generated? n/a n/a Yes : tests are generated if no include/exclude methods are set n/a TrueYes n/a FalseNo Truen/a No Falsen/a Yes FalseFalseNo : inclusion take precedence (or lack thereof) FalseTrueYes TrueFalseNo TrueTrueYes : inclusion take precedence - catalogue (
-
-
class
cqparts.utils.test.ComponentTest(methodName='runTest')¶ Bases:
unittest.case.TestCaseGeneric testcase with utilities for testing
PartandAssemblyinstances.For example:
import cqparts import cadquery from cqparts.utils.test import ComponentTest class Box(cqparts.Part): def make(self): return cadquery.Workplane('XY').box(1,1,1) class BoxTest(ComponentTest): def test_box(self): box = Box() self.assertComponent(box)
-
assertAssembly(obj)¶ Assert criteria common to any fully formed Assembly.
Parameters: obj ( Assembly) – assembly under test
-
assertAssembyHasComponents(obj)¶
-
assertComponent(obj, recursive=True, _depth=0)¶ Assert criteria common to any fully formed Component.
Parameters:
-
assertPart(obj)¶ Assert criteria common to any fully formed Part.
Parameters: obj ( Part) – part under test
-
assertPartBoundingBox(obj)¶
-
assertPartHasVolume(obj)¶
-
cqparts.utils.wrappers module¶
-
cqparts.utils.wrappers.as_part(func)¶ Converts a function to a
Partinstance.So the conventionally defined part:
import cadquery from cqparts import Part from cqparts.params import Float class Box(Part): x = Float(1) y = Float(2) z = Float(4) def make(self): return cadquery.Workplane('XY').box(self.x, self.y, self.z) box = Box(x=6, y=3, z=1)
May also be written as:
import cadquery from cqparts.utils.wrappers import as_part @as_part def make_box(x=1, y=2, z=4): return cadquery.Workplane('XY').box(x, y, z) box = make_box(x=6, y=3, z=1)
In both cases,
boxis aPartinstance.
Module contents¶
-
class
cqparts.utils.CoordSystem(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 0, 1))¶ Bases:
cadquery.freecad_impl.geom.PlaneDefines the location, and rotation of an orthogonal 3 dimensional coordinate system.
-
__add__(other)¶ For
A+B. WhereAis this coordinate system, andBisother.Raises: TypeError – if addition for the given type is not supported Supported types:
A(CoordSystem) +B(CoordSystem):Returns: world coordinates of BinA’s coordinatesReturn type: CoordSystemA(CoordSystem) +B(cadquery.Vector):Returns: world coordinates of Brepresented inA’s coordinate systemReturn type: cadquery.VectorA(CoordSystem) +B(cadquery.CQ):remember:
cadquery.Workplaneinherits fromcadquery.CQReturns: content of Bmoved toA’s coordinate systemReturn type: cadquery.Workplane
-
__sub__(other)¶ For
A-B. WhereAis this coordinate system, andBisother.Raises: TypeError – if subtraction for the given type is not supported Supported types:
A(CoordSystem) +B(CoordSystem):Returns: local coordinate system of AfromB’s coordinate systemReturn type: CoordSystem
-
classmethod
from_plane(plane)¶ Parameters: plane ( cadquery.Plane) – cadquery plane instance to base coordinate system onReturns: duplicate of the given plane, in this class Return type: CoordSystemusage example:
>>> import cadquery >>> from cqparts.utils.geometry import CoordSystem >>> obj = cadquery.Workplane('XY').circle(1).extrude(5) >>> plane = obj.faces(">Z").workplane().plane >>> isinstance(plane, cadquery.Plane) True >>> coord_sys = CoordSystem.from_plane(plane) >>> isinstance(coord_sys, CoordSystem) True >>> coord_sys.origin.z 5.0
-
classmethod
from_transform(matrix)¶ Parameters: matrix ( FreeCAD.Matrix) – 4x4 3d affine transform matrixReturns: a unit, zero offset coordinate system transformed by the given matrix Return type: CoordSystemIndividual rotation & translation matricies are:
\[\begin{split}R_z & = \begin{bmatrix} cos(\alpha) & -sin(\alpha) & 0 & 0 \\ sin(\alpha) & cos(\alpha) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \qquad & R_y & = \begin{bmatrix} cos(\beta) & 0 & sin(\beta) & 0 \\ 0 & 1 & 0 & 0 \\ -sin(\beta) & 0 & cos(\beta) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \\ \\ R_x & = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & cos(\gamma) & -sin(\gamma) & 0 \\ 0 & sin(\gamma) & cos(\gamma) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \qquad & T_{\text{xyz}} & = \begin{bmatrix} 1 & 0 & 0 & \delta x \\ 0 & 1 & 0 & \delta y \\ 0 & 0 & 1 & \delta z \\ 0 & 0 & 0 & 1 \end{bmatrix}\end{split}\]The
transformis the combination of these:\[\begin{split}transform = T_{\text{xyz}} \cdot R_z \cdot R_y \cdot R_x = \begin{bmatrix} a & b & c & \delta x \\ d & e & f & \delta y \\ g & h & i & \delta z \\ 0 & 0 & 0 & 1 \end{bmatrix}\end{split}\]Where:
\[\begin{split}a & = cos(\alpha) cos(\beta) \\ b & = cos(\alpha) sin(\beta) sin(\gamma) - sin(\alpha) cos(\gamma) \\ c & = cos(\alpha) sin(\beta) cos(\gamma) + sin(\alpha) sin(\gamma) \\ d & = sin(\alpha) cos(\beta) \\ e & = sin(\alpha) sin(\beta) sin(\gamma) + cos(\alpha) cos(\gamma) \\ f & = sin(\alpha) sin(\beta) cos(\gamma) - cos(\alpha) sin(\gamma) \\ g & = -sin(\beta) \\ h & = cos(\beta) sin(\gamma) \\ i & = cos(\beta) cos(\gamma)\end{split}\]
-
local_to_world_transform¶ Returns: 3d affine transform matrix to convert local coordinates to world coordinates. Return type: cadquery.MatrixFor matrix structure, see
from_transform().
-
classmethod
random(span=1, seed=None)¶ Creates a randomized coordinate system.
Useful for confirming that an assembly does not rely on its origin coordinate system to remain intact.
For example, the
CoordSysIndicatorassembly aligns 3 boxes along each of the \(XYZ\) axes. Positioning it randomly by setting itsworld_coordsshows that each box is always positioned orthogonally to the other two.from cqparts_misc.basic.indicators import CoordSysIndicator from cqparts.display import display from cqparts.utils import CoordSystem cs = CoordSysIndicator() cs.world_coords = CoordSystem.random() display(cs)
Parameters: - span – origin of return will be \(\pm span\) per axis
- seed (hashable object) – if supplied, return is psudorandom (repeatable)
Returns: randomized coordinate system
Return type:
-
world_to_local_transform¶ Returns: 3d affine transform matrix to convert world coordinates to local coordinates. Return type: cadquery.MatrixFor matrix structure, see
from_transform().
-
-
class
cqparts.utils.property_buffered(getter, name=None)¶ Bases:
objectBuffer the result of a method on the class instance, similar to python builtin
@property, but the result is kept in memory until it’s explicitly deleted.>>> from cqparts.utils.misc import property_buffered >>> class A(object): ... @property_buffered ... def x(self): ... print("x called") ... return 100 >>> a = A() >>> a.x x called 100 >>> a.x 100 >>> del a.x >>> a.x x called 100
Basis of class was sourced from the funkybob/antfarm project. thanks to @funkybob.
-
cqparts.utils.indicate_last(items)¶ iterate through list and indicate which item is the last, intended to assist tree displays of hierarchical content.
Returns: yielding (<bool>, <item>) where bool is True only on last entry Return type: generator
-
cqparts.utils.working_dir(*args, **kwds)¶ Change working directory within a context:
>>> import os >>> from cqparts.utils import working_dir >>> print(os.getcwd()) /home/myuser/temp >>> with working_dir('..'): ... print(os.getcwd()) ... /home/myuser
Parameters: path ( str) – working path to use while in context
-
cqparts.utils.measure_time(*args, **kwds)¶
-
cqparts.utils.as_part(func)¶ Converts a function to a
Partinstance.So the conventionally defined part:
import cadquery from cqparts import Part from cqparts.params import Float class Box(Part): x = Float(1) y = Float(2) z = Float(4) def make(self): return cadquery.Workplane('XY').box(self.x, self.y, self.z) box = Box(x=6, y=3, z=1)
May also be written as:
import cadquery from cqparts.utils.wrappers import as_part @as_part def make_box(x=1, y=2, z=4): return cadquery.Workplane('XY').box(x, y, z) box = make_box(x=6, y=3, z=1)
In both cases,
boxis aPartinstance.