-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Plugin for local coordinate system selectors (#35)
* First working version of it; TODO pare it down * Simplify monkeypatch * Simplify further and remove unused imports * Add some description to the README Co-authored-by: nobkd <44443899+nobkd@users.noreply.github.com> * Update plugins/localselectors/README.md Co-authored-by: nobkd <44443899+nobkd@users.noreply.github.com> * Fix linter errors --------- Co-authored-by: nobkd <44443899+nobkd@users.noreply.github.com>
- Loading branch information
Showing
4 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Sample Plugin | ||
|
||
This plugin modifies `Workplane` selectors so that they can be used to specify axes in the local coordinate plane. | ||
This is done by using the lowercase letters `x`, `y`, and `z` instead of the uppercase ones. | ||
|
||
## Installation | ||
|
||
``` | ||
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=localcoordinates&subdirectory=plugins/localcoordinates" | ||
``` | ||
|
||
|
||
## Dependencies | ||
|
||
This plugin has no dependencies other than the cadquery library. To install CadQuery, follow the [instructions in its readme](https://github.com/CadQuery/cadquery#getting-started). | ||
It uses a lot of internal structures, so it may break more easily on later versions of CadQuery than other plugins. | ||
It was tested on CadQuery 2.5, feel free to post an issue in my [fork](https://github.com/cactorium/cadquery-plugins) if you run into any issues | ||
|
||
## Usage | ||
|
||
To use this plugin after it has been installed, import it to automatically patch its function(s) into the `cadquery.Workplane` class. Any function that uses string selectors should now work with these new selectors after import, but be sure to import `cadquery` first. | ||
|
||
```python | ||
import cadquery as cq | ||
|
||
result = (cq.Workplane().rect(50, 50) | ||
.extrude(50)) | ||
|
||
new_workplane = (result.faces(">x") # this should be the same as '>X' because we're starting off in the default coordinate system | ||
.workplane()) | ||
result2 = (new_workplane.rect(30, 30) | ||
.extrude(30)) | ||
|
||
new_workplane = (result2 | ||
.faces(">z") | ||
.workplane()) # this should be the face sticking away from the first cube | ||
``` |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import cadquery as cq | ||
|
||
from cadquery.occ_impl.geom import Vector | ||
from cadquery.occ_impl.shape_protocols import ( | ||
geom_LUT_EDGE, | ||
geom_LUT_FACE, | ||
) | ||
|
||
from pyparsing import ( | ||
pyparsing_common, | ||
Literal, | ||
Word, | ||
nums, | ||
Optional, | ||
Combine, | ||
oneOf, | ||
Group, | ||
infixNotation, | ||
opAssoc, | ||
) | ||
|
||
|
||
def _makeGrammar(): | ||
""" | ||
Define the simple string selector grammar using PyParsing | ||
""" | ||
|
||
# float definition | ||
point = Literal(".") | ||
plusmin = Literal("+") | Literal("-") | ||
number = Word(nums) | ||
integer = Combine(Optional(plusmin) + number) | ||
floatn = Combine(integer + Optional(point + Optional(number))) | ||
|
||
# vector definition | ||
lbracket = Literal("(") | ||
rbracket = Literal(")") | ||
comma = Literal(",") | ||
vector = Combine( | ||
lbracket + floatn("x") + comma + floatn("y") + comma + floatn("z") + rbracket, | ||
adjacent=False, | ||
) | ||
|
||
# direction definition | ||
simple_dir = oneOf( | ||
["X", "Y", "Z", "XY", "XZ", "YZ"] + ["x", "y", "z", "xy", "xz", "yz"] | ||
) | ||
direction = simple_dir("simple_dir") | vector("vector_dir") | ||
|
||
# CQ type definition | ||
cqtype = oneOf( | ||
set(geom_LUT_EDGE.values()) | set(geom_LUT_FACE.values()), caseless=True, | ||
) | ||
cqtype = cqtype.setParseAction(pyparsing_common.upcaseTokens) | ||
|
||
# type operator | ||
type_op = Literal("%") | ||
|
||
# direction operator | ||
direction_op = oneOf([">", "<"]) | ||
|
||
# center Nth operator | ||
center_nth_op = oneOf([">>", "<<"]) | ||
|
||
# index definition | ||
ix_number = Group(Optional("-") + Word(nums)) | ||
lsqbracket = Literal("[").suppress() | ||
rsqbracket = Literal("]").suppress() | ||
|
||
index = lsqbracket + ix_number("index") + rsqbracket | ||
|
||
# other operators | ||
other_op = oneOf(["|", "#", "+", "-"]) | ||
|
||
# named view | ||
named_view = oneOf(["front", "back", "left", "right", "top", "bottom"]) | ||
|
||
return ( | ||
direction("only_dir") | ||
| (type_op("type_op") + cqtype("cq_type")) | ||
| (direction_op("dir_op") + direction("dir") + Optional(index)) | ||
| (center_nth_op("center_nth_op") + direction("dir") + Optional(index)) | ||
| (other_op("other_op") + direction("dir")) | ||
| named_view("named_view") | ||
) | ||
|
||
|
||
old_getVector = cq.selectors._SimpleStringSyntaxSelector._getVector | ||
|
||
|
||
def _getVector(self, pr): | ||
if ( | ||
"simple_dir" in pr | ||
and pr.simple_dir in cq.selectors._SimpleStringSyntaxSelector.local_axes | ||
): | ||
return cq.selectors._SimpleStringSyntaxSelector.local_axes[pr.simple_dir] | ||
else: | ||
return old_getVector(self, pr) | ||
|
||
|
||
class LocalCoordinates: | ||
def __init__(self, plane): | ||
self.plane = plane | ||
self.old_axes = None | ||
|
||
def __enter__(self): | ||
self.old_axes, cq.selectors._SimpleStringSyntaxSelector.local_axes = ( | ||
cq.selectors._SimpleStringSyntaxSelector.local_axes, | ||
{ | ||
"x": self.plane.xDir, | ||
"y": self.plane.yDir, | ||
"z": self.plane.zDir, | ||
"xy": self.plane.xDir + self.plane.yDir, | ||
"yz": self.plane.yDir + self.plane.zDir, | ||
"xz": self.plane.xDir + self.plane.zDir, | ||
}, | ||
) | ||
|
||
def __exit__(self, _exc_type, _exc_value, _traceback): | ||
cq.selectors._SimpleStringSyntaxSelector.local_axes = self.old_axes | ||
|
||
|
||
def _filter(self, objs, selector): | ||
selectorObj: Selector | ||
if selector: | ||
if isinstance(selector, str): | ||
with LocalCoordinates(self.plane): | ||
selectorObj = cq.selectors.StringSyntaxSelector(selector) | ||
else: | ||
selectorObj = selector | ||
toReturn = selectorObj.filter(objs) | ||
else: | ||
toReturn = objs | ||
|
||
return toReturn | ||
|
||
|
||
cq.selectors._SimpleStringSyntaxSelector.local_axes = { | ||
"x": Vector(1, 0, 0), | ||
"y": Vector(0, 1, 0), | ||
"z": Vector(0, 0, 1), | ||
"xy": Vector(1, 1, 0), | ||
"yz": Vector(0, 1, 1), | ||
"xz": Vector(1, 0, 1), | ||
} | ||
cq.selectors._SimpleStringSyntaxSelector._getVector = _getVector | ||
|
||
cq.selectors._grammar = _makeGrammar() # make a grammar instance | ||
cq.selectors._expression_grammar = cq.selectors._makeExpressionGrammar( | ||
cq.selectors._grammar | ||
) | ||
|
||
cq.Workplane._filter = _filter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from setuptools import setup, find_packages | ||
|
||
# Change these variables to set the information for your plugin | ||
version = "1.0.0" # Please update this version number when updating the plugin | ||
plugin_name = "localselectors" # The name of your plugin | ||
description = "Adds local coordinator selectors to CadQuery" | ||
long_description = ( | ||
"Monkey patches in local coordinate selectors so you can use things like '>x'" | ||
) | ||
author = "Kelvin Ly" | ||
author_email = "cactorium" | ||
packages = [] # List of packages that will be installed with this plugin | ||
py_modules = ["localselectors"] # Put the name of your plugin's .py file here | ||
install_requires = ( | ||
[] | ||
) # Any dependencies that pip also needs to install to make this plugin work | ||
|
||
|
||
setup( | ||
name=plugin_name, | ||
version=version, | ||
url="https://github.com/CadQuery/cadquery-plugins", | ||
license="Apache Public License 2.0", | ||
author=author, | ||
author_email=author_email, | ||
description=description, | ||
long_description=long_description, | ||
packages=packages, | ||
py_modules=py_modules, | ||
install_requires=install_requires, | ||
include_package_data=True, | ||
zip_safe=False, | ||
platforms="any", | ||
test_suite="tests", | ||
classifiers=[ | ||
"Development Status :: 5 - Production/Stable", | ||
"Intended Audience :: Developers", | ||
"Intended Audience :: End Users/Desktop", | ||
"Intended Audience :: Information Technology", | ||
"Intended Audience :: Science/Research", | ||
"Intended Audience :: System Administrators", | ||
"License :: OSI Approved :: Apache Software License", | ||
"Operating System :: POSIX", | ||
"Operating System :: MacOS", | ||
"Operating System :: Unix", | ||
"Programming Language :: Python", | ||
"Topic :: Software Development :: Libraries :: Python Modules", | ||
"Topic :: Internet", | ||
"Topic :: Scientific/Engineering", | ||
], | ||
) |