Updated cadquery lib

This commit is contained in:
Jeremy Mack Wright 2018-12-17 10:46:52 -05:00
parent 8062976bc4
commit 4dc437e44a
39 changed files with 599 additions and 359 deletions

View File

@ -23,12 +23,16 @@ before_install:
pip install -r requirements-dev.txt; pip install -r requirements-dev.txt;
pip install travis-sphinx; pip install travis-sphinx;
pip install sphinx_rtd_theme; pip install sphinx_rtd_theme;
pip install readme_renderer;
fi fi
install: install:
- python setup.py install; - python setup.py install;
script: script:
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
python setup.py check -r -s;
fi
- coverage run runtests.py - coverage run runtests.py
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
travis-sphinx build --nowarn --source=doc; travis-sphinx build --nowarn --source=doc;

View File

@ -34,7 +34,7 @@ RUN mkdir -p $CQ_HOME
RUN mkdir -p $CQ_HOME/build_data RUN mkdir -p $CQ_HOME/build_data
VOLUME $CQ_HOME/build_data VOLUME $CQ_HOME/build_data
COPY requirements-dev.txt runtests.py cq_cmd.py cq_cmd.sh setup.py README.md MANIFEST setup.cfg $CQ_HOME/ COPY requirements-dev.txt runtests.py cq_cmd.py cq_cmd.sh setup.py README.rst MANIFEST setup.cfg $CQ_HOME/
COPY cadquery $CQ_HOME/cadquery COPY cadquery $CQ_HOME/cadquery
COPY examples $CQ_HOME/examples COPY examples $CQ_HOME/examples
COPY tests $CQ_HOME/tests COPY tests $CQ_HOME/tests

View File

@ -1,5 +1,4 @@
README.txt README.rst
README.md
setup.cfg setup.cfg
setup.py setup.py
cadquery\cq.py cadquery\cq.py

View File

@ -1 +1 @@
include README.md include README.rst LICENSE

View File

@ -1,264 +0,0 @@
<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)
[![Build status](https://ci.appveyor.com/api/projects/status/c7u4yjl8xxlokrw0/branch/master?svg=true)](https://ci.appveyor.com/project/jmwright/cadquery/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/dcowden/cadquery/badge.svg?branch=master)](https://coveralls.io/github/dcowden/cadquery?branch=master)
[![GitHub version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=gh&type=6&v=1.2.0&x2=0)](https://github.com/dcowden/cadquery/releases/tag/v1.2.0)
[![License](https://img.shields.io/badge/license-Apache2-blue.svg)](https://github.com/dcowden/cadquery/blob/master/LICENSE)
CadQuery is an intuitive, easy-to-use python based language for building parametric 3D CAD models. CadQuery is for 3D CAD what jQuery is for javascript. Imagine selecting Faces of a 3d object the same way you select DOM objects with JQuery!
CadQuery has several goals:
* Build lD models with scripts that are as close as possible to how you'd describe the object to a human.
* Create parametric models that can be very easily customized by end users
* Output high quality (loss-less) CAD formats like STEP and AMF in addition to traditional STL
* Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser
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 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:
Display the Documentation::
docker run dcowden/cadquery:latest
Build a local model using stdin/stdout::
cat Ex001_Simple_Block.py | docker run -i dcowden/cadquery:latest build --in_spec stdin --format STEP --out_spec stdout
... STEP output on the console
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'
INFO: Parsed Script 'Ex001_Simple_Block.py'.
INFO: This script provides parameters length,thickness,height, which can be customized at build time.
INFO: The script will run with default variable values
INFO: use --param_file to provide a json file that contains values to override the defaults
INFO: Output Format is 'STEP'. Use --output-format to change it.
INFO: Output Path is './cqobject-%(counter)d.%(format)s'. Use --out_spec to change it.
INFO: Script Generated 1 result Objects
INFO: Writing STEP Output to './cqobject-1.STEP'
Projects Using CadQuery
=========================
This resin mold was modeled using cadquery and then created on a CNC machine:
<p align="center">
<img src="doc/_static/hyOzd-cablefix.png" width="350"/>
<img src="doc/_static/hyOzd-finished.jpg" width="350"/>
</p>
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
# PARAMETERS
mount_holes = True
# mold size
mw = 40
mh = 13
ml = 120
# wire and fix size
wd = 6 # wire diameter
rt = 7 # resin thickness
rl = 50 # resin length
rwpl = 10 # resin to wire pass length
# pocket fillet
pf = 18
# mount holes
mhd = 7 # hole diameter
mht = 3 # hole distance from edge
# filling hole
fhd = 6
# DRAWING
# draw base
base = cq.Workplane("XY").box(ml, mw, mh, (True, True, False))
# draw wire
pocket = cq.Workplane("XY", (0, 0, mh)).moveTo(-ml/2., 0).line(0, wd/2.)\
.line((ml-rl)/2.-rwpl, 0).line(rwpl, rt).line(rl, 0)\
.line(rwpl, -rt).line((ml-rl)/2.-rwpl, 0)\
.line(0, -(wd/2.)).close().revolve(axisEnd=(1, 0))\
.edges(BS((-rl/2.-rwpl-.1, -100, -100), (rl/2.+rwpl+.1, 100, 100)))\
.fillet(pf)
r = base.cut(pocket)
# mount holes
if mount_holes:
px = ml/2.-mht-mhd/2.
py = mw/2.-mht-mhd/2
r = r.faces("<Z").workplane().pushPoints([
(px, py),
(-px, py),
(-px, -py),
(px, -py)
]).hole(mhd)
# fill holes
r = r.faces("<Y").workplane().center(0, mh/2.).pushPoints([
(-rl/2., 0),
(0, 0),
(rl/2., 0)
]).hole(fhd, mw/2.)
show(r)
```
Thanks go to cadquery contributor hyOzd ( Altu Technology ) for the example!
KiCad uses cadquery to build high quality models of electrictronic components. ( https://github.com/KiCad/packages3D )
<p align="center">
<img src="https://forum.freecadweb.org/download/file.php?id=33797&sid=b8584f80928497722e9ee9d582a3fa43" width="350"/>
</p>
This Prusa i3 extruder support uses cadquery to build the model (https://github.com/adam-urbanczyk/cadquery-models) :
<p align="center">
<img src="https://github.com/adam-urbanczyk/cadquery-models/raw/master/extruder_support.png" width="350"/>
</p>
The mach30 project used cadquery to develop a tool that will create a rocket thruster directly from the appropriate equations (https://opendesignengine.net/projects/yavin-thruster/wiki):
<p align="center">
<img src="http://opendesignengine.net/dmsf_files/480?download=" width="700"/>
</p>
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/cqnb/raw/master/showcase.gif" width="350"/>
</p>
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?
========================================
CadQuery is based on OpenCasCade. CadQuery shares many features with OpenSCAD, another open source, script based, parametric model generator.
The primary advantage of OpenSCAD is the large number of already existing model libraries that exist already. So why not simply use OpenSCAD?
CadQuery scripts have several key advantages over OpenSCAD:
1. **The scripts use a standard programming language**, python, and thus can benefit from the associated infrastructure.
This includes many standard libraries and IDEs
2. **More powerful CAD kernel** OpenCascade is much more powerful than CGAL. Features supported natively
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,
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
features based on the position of other features, workplanes, vertices, etc.
5. **Better Performance** CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD.
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
Ongoing and Future Work
============
### CadQuery GUI (under development)
Work is underway on a stand-alone gui here: https://github.com/jmwright/cadquery-gui
### CadQuery Parts / Assembly Handling
Work by Fragmuffin is ongoing with the [cqparts](https://github.com/fragmuffin/cqparts) repo.
### 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:
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
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

315
Libs/cadquery/README.rst Normal file
View File

@ -0,0 +1,315 @@
.. image:: http://dcowden.github.io/cadquery/_static/cadquery_logo_dark.svg
ANNOUNCEMENT! CadQuery is Moving to https://github.com/CadQuery/cadquery!
============================================================
Version 2.0 development is under way It uses pythonOCC instead of FreeCAD, and has tons of cool features
*BUT DONT WORRY!* Version 1.x (this repository ) will be suported until all features are comfortably implemented in the 2.x stream.
We're happy to be moving to a more open organization, but we're sad we're starting over with our stars. Please give us one at our new home!
What is CadQuery?
========================================
|TRAVIS| |APPVEYOR| |COVERALLS| |VERSION| |LICENSE|
.. |TRAVIS| image:: https://travis-ci.org/dcowden/cadquery.svg?branch=master
:alt: Travis Build Status
:target: https://travis-ci.org/dcowden/cadquery?branch=master
.. |APPVEYOR| image:: https://ci.appveyor.com/api/projects/status/c7u4yjl8xxlokrw0/branch/master?svg=true
:alt: Build status
:target: https://ci.appveyor.com/project/jmwright/cadquery/branch/master
.. |COVERALLS| image:: https://coveralls.io/repos/github/dcowden/cadquery/badge.svg?branch=master
:alt: Coverage Status
:target: https://coveralls.io/github/dcowden/cadquery?branch=master
.. |VERSION| image:: https://d25lcipzij17d.cloudfront.net/badge.svg?id=gh&type=6&v=1.2.0&x2=0
:alt: GitHub version
:target: https://github.com/dcowden/cadquery/releases/tag/v1.2.0
.. |LICENSE| image:: https://img.shields.io/badge/license-Apache2-blue.svg
:alt: License
:target: https://github.com/dcowden/cadquery/blob/master/LICENSE
CadQuery is an intuitive, easy-to-use python based language for building parametric 3D CAD models. CadQuery is for 3D CAD what jQuery is for javascript. Imagine selecting Faces of a 3d object the same way you select DOM objects with JQuery!
CadQuery has several goals:
* Build 3d models with scripts that are as close as possible to how you'd describe the object to a human.
* Create parametric models that can be very easily customized by end users
* Output high quality (loss-less) CAD formats like STEP and AMF in addition to traditional STL
* Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser
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 `https://dcowden.github.io/cadquery <https://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|
.. |BINDER| image:: https://mybinder.org/badge.svg
:alt: Binder
:target: 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/ <http://www.freecadweb.org/>`_), and then to use our great CadQuery-FreeCAD plugin here: `https://github.com/jmwright/cadquery-freecad-module <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 CadQuery docker image (`https://hub.docker.com/r/dcowden/cadquery/ <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:
Display the Documentation:
.. code-block:: bash
docker run dcowden/cadquery:latest
Build a local model using stdin/stdout:
.. code-block:: bash
cat Ex001_Simple_Block.py | docker run -i dcowden/cadquery:latest build --in_spec stdin --format STEP --out_spec stdout
... STEP output on the console
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'
INFO: Parsed Script 'Ex001_Simple_Block.py'.
INFO: This script provides parameters length,thickness,height, which can be customized at build time.
INFO: The script will run with default variable values
INFO: use --param_file to provide a json file that contains values to override the defaults
INFO: Output Format is 'STEP'. Use --output-format to change it.
INFO: Output Path is './cqobject-%(counter)d.%(format)s'. Use --out_spec to change it.
INFO: Script Generated 1 result Objects
INFO: Writing STEP Output to './cqobject-1.STEP'
Projects Using CadQuery
=========================
This resin mold was modeled using cadquery and then created on a CNC machine:
|HY0ZD_CABLEFIX| |HY0ZD_FINISHED|
.. |HY0ZD_CABLEFIX| image:: http://dcowden.github.io/cadquery/_static/hyOzd-cablefix.png
:alt: Cable-fix resin mold: Rendered
.. |HY0ZD_FINISHED| image:: http://dcowden.github.io/cadquery/_static/hyOzd-finished_thumb.jpg
:alt: Cable-fix resin mold: Finised
:target: http://dcowden.github.io/cadquery/_static/hyOzd-finished_thumb.jpg
The cadquery script is surprisingly short, and allows easily customizing any of the variables:
.. code-block:: python
import cadquery as cq
from Helpers import show
BS = cq.selectors.BoxSelector
# PARAMETERS
mount_holes = True
# mold size
mw = 40
mh = 13
ml = 120
# wire and fix size
wd = 6 # wire diameter
rt = 7 # resin thickness
rl = 50 # resin length
rwpl = 10 # resin to wire pass length
# pocket fillet
pf = 18
# mount holes
mhd = 7 # hole diameter
mht = 3 # hole distance from edge
# filling hole
fhd = 6
# DRAWING
# draw base
base = cq.Workplane("XY").box(ml, mw, mh, (True, True, False))
# draw wire
pocket = cq.Workplane("XY", (0, 0, mh)).moveTo(-ml/2., 0).line(0, wd/2.)\
.line((ml-rl)/2.-rwpl, 0).line(rwpl, rt).line(rl, 0)\
.line(rwpl, -rt).line((ml-rl)/2.-rwpl, 0)\
.line(0, -(wd/2.)).close().revolve(axisEnd=(1, 0))\
.edges(BS((-rl/2.-rwpl-.1, -100, -100), (rl/2.+rwpl+.1, 100, 100)))\
.fillet(pf)
r = base.cut(pocket)
# mount holes
if mount_holes:
px = ml/2.-mht-mhd/2.
py = mw/2.-mht-mhd/2
r = r.faces("<Z").workplane().pushPoints([
(px, py),
(-px, py),
(-px, -py),
(px, -py)
]).hole(mhd)
# fill holes
r = r.faces("<Y").workplane().center(0, mh/2.).pushPoints([
(-rl/2., 0),
(0, 0),
(rl/2., 0)
]).hole(fhd, mw/2.)
show(r)
Thanks go to cadquery contributor hyOzd ( Altu Technology ) for the example!
KiCad uses cadquery to build high quality models of electronic components. (`https://github.com/KiCad/packages3D <https://github.com/KiCad/packages3D>`_)
.. image:: http://dcowden.github.io/cadquery/_static/KiCad_Capacitors_SMD_thumb.jpg
:target: http://dcowden.github.io/cadquery/_static/KiCad_Capacitors_SMD.jpg
:alt: Surface mount capacitors rendered in KiCad
This Prusa i3 extruder support uses cadquery to build the model (`https://github.com/adam-urbanczyk/cadquery-models <https://github.com/adam-urbanczyk/cadquery-models>`_):
.. image:: http://dcowden.github.io/cadquery/_static/extruder_support.png
:alt: Prusa i3 extruder support - FreeCAD model render
The mach30 project used cadquery to develop a tool that will create a rocket thruster directly from the appropriate equations (`https://opendesignengine.net/projects/yavin-thruster/wiki <https://opendesignengine.net/projects/yavin-thruster/wiki>`_):
.. image:: http://dcowden.github.io/cadquery/_static/march30_landing_page.png
:target: https://opendesignengine.net/projects/yavin-thruster/wiki
:alt: mach30 project landing page
This example uses Jupyter notebook to produce a really cool web-based scripting environment (`https://github.com/RustyVermeer/avnb/blob/master/readme.md <https://github.com/RustyVermeer/avnb/blob/master/readme.md>`_):
.. image:: http://dcowden.github.io/cadquery/_static/jupyter_showcase_thumb.png
:alt: Jupyter notebook showcased as animation
:target: https://github.com/RustyVermeer/cqnb
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?
========================================
CadQuery is based on OpenCasCade. CadQuery shares many features with OpenSCAD, another open source, script based, parametric model generator.
The primary advantage of OpenSCAD is the large number of already existing model libraries that exist already. So why not simply use OpenSCAD?
CadQuery scripts have several key advantages over OpenSCAD:
#. **The scripts use a standard programming language**, Python, and thus can benefit from the associated infrastructure.
This includes many standard libraries and IDEs
#. **More powerful CAD kernel** OpenCascade is much more powerful than CGAL. Features supported natively
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
#. **Ability to import/export STEP** We think 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
#. **Less Code and easier scripting** CadQuery scripts require less code to create most objects, because it is possible to locate
features based on the position of other features, workplanes, vertices, etc.
#. **Better Performance** CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD.
License
====================
CadQuery is licensed under the terms of the `Apache Public License, version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
Ongoing and Future Work
=============================
CadQuery 2.0 (And future versions)
-----------------------------------
Cadquery 2.0 is under way. 2.0 is based on pythonOCC directly ( rather than FreeCAD ), and is under heavy development.
Beginning with version 2.0, CadQuery has moved to a new home at `https://github.com/CadQuery/cadquery` CadQuery/cadquery
CadQuery GUI (under development)
-------------------------------------------
Work is underway on a stand-alone gui here: `https://github.com/jmwright/cadquery-gui <https://github.com/jmwright/cadquery-gui>`_
CadQuery Parts / Assembly Handling
-------------------------------------------
Work by Fragmuffin is ongoing with the `cqparts <https://github.com/fragmuffin/cqparts>`_ repo.
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:
#. Feature trees, for more powerful selection
#. Direct use of OpenCascade Community Edition (OCE), so that it is no longer required to install FreeCAD
The project page can be found here: `https://github.com/dcowden/cadquery/projects/1 <https://github.com/dcowden/cadquery/projects/1>`_
A more detailed description of `the plan for CQ 2.0 <https://docs.google.com/document/d/1cXuxBkVeYmGOo34MGRdG7E3ILypQqkrJ26oVf3CUSPQ>`_

0
Libs/cadquery/build_docker.sh Executable file → Normal file
View File

View File

@ -719,7 +719,7 @@ class CQ(object):
Future Enhancements: Future Enhancements:
* A version of this method that returns a transformed copy, rather than modifying * A version of this method that returns a transformed copy, rather than modifying
the originals the originals
* This method doesnt expose a very good interface, because the axis of rotation * This method doesn't expose a very good interface, because the axis of rotation
could be inconsistent between multiple objects. This is because the beginning could be inconsistent between multiple objects. This is because the beginning
of the axis is variable, while the end is fixed. This is fine when operating on of the axis is variable, while the end is fixed. This is fine when operating on
one object, but is not cool for multiple. one object, but is not cool for multiple.
@ -1082,6 +1082,45 @@ class Workplane(CQ):
return self.pushPoints(lpoints) return self.pushPoints(lpoints)
def polarArray(self, radius, startAngle, angle, count, fill=True):
"""
Creates an polar array of points and pushes them onto the stack.
The 0 degree reference angle is located along the local X-axis.
:param radius: Radius of the array.
:param startAngle: Starting angle (degrees) of array. 0 degrees is
situated along local X-axis.
:param angle: The angle (degrees) to fill with elements. A positive
value will fill in the counter-clockwise direction. If fill is
false, angle is the angle between elements.
:param count: Number of elements in array. ( > 0 )
"""
if count <= 0:
raise ValueError("No elements in array")
# First element at start angle, convert to cartesian coords
x = radius * math.cos(math.radians(startAngle))
y = radius * math.sin(math.radians(startAngle))
points = [(x, y)]
# Calculate angle between elements
if fill:
if angle % 360 == 0:
angle = angle / count
elif count > 1:
# Inclusive start and end
angle = angle / (count - 1)
# Add additional elements
for i in range(1, count):
phi = math.radians(startAngle + (angle * i))
x = radius * math.cos(phi)
y = radius * math.sin(phi)
points.append((x, y))
return self.pushPoints(points)
def pushPoints(self, pntList): def pushPoints(self, pntList):
""" """
Pushes a list of points onto the stack as vertices. Pushes a list of points onto the stack as vertices.
@ -1220,6 +1259,35 @@ class Workplane(CQ):
p = self._findFromPoint(True) p = self._findFromPoint(True)
return self.lineTo(xCoord, p.y, forConstruction) return self.lineTo(xCoord, p.y, forConstruction)
def polarLine(self, distance, angle, forConstruction=False):
"""
Make a line of the given length, at the given angle from the current point
:param float distance: distance of the end of the line from the current point
:param float angle: angle of the vector to the end of the line with the x-axis
:return: the Workplane object with the current point at the end of the new line
"""
x = math.cos(math.radians(angle)) * distance
y = math.sin(math.radians(angle)) * distance
return self.line(x, y, forConstruction)
def polarLineTo(self, distance, angle, forConstruction=False):
"""
Make a line from the current point to the given polar co-ordinates
Useful if it is more convenient to specify the end location rather than
the distance and angle from the current point
:param float distance: distance of the end of the line from the origin
:param float angle: angle of the vector to the end of the line with the x-axis
:return: the Workplane object with the current point at the end of the new line
"""
x = math.cos(math.radians(angle)) * distance
y = math.sin(math.radians(angle)) * distance
return self.lineTo(x, y, forConstruction)
#absolute move in current plane, not drawing #absolute move in current plane, not drawing
def moveTo(self, x=0, y=0): def moveTo(self, x=0, y=0):
""" """
@ -1443,7 +1511,7 @@ class Workplane(CQ):
Produces a flat, heart shaped object Produces a flat, heart shaped object
Future Enhancements: Future Enhancements:
mirrorX().mirrorY() should work but doesnt, due to some FreeCAD weirdness mirrorX().mirrorY() should work but doesn't, due to some FreeCAD weirdness
""" """
tm = Matrix() tm = Matrix()
tm.rotateY(math.pi) tm.rotateY(math.pi)
@ -1461,7 +1529,7 @@ class Workplane(CQ):
Typically used to make creating wires with symmetry easier. Typically used to make creating wires with symmetry easier.
Future Enhancements: Future Enhancements:
mirrorX().mirrorY() should work but doesnt, due to some FreeCAD weirdness mirrorX().mirrorY() should work but doesn't, due to some FreeCAD weirdness
""" """
tm = Matrix() tm = Matrix()
tm.rotateX(math.pi) tm.rotateX(math.pi)
@ -1852,7 +1920,7 @@ class Workplane(CQ):
ctxSolid.wrapped = s.wrapped ctxSolid.wrapped = s.wrapped
return self.newObject([s]) return self.newObject([s])
#but parameter list is different so a simple function pointer wont work #but parameter list is different so a simple function pointer won't work
def cboreHole(self, diameter, cboreDiameter, cboreDepth, depth=None, clean=True): def cboreHole(self, diameter, cboreDiameter, cboreDepth, depth=None, clean=True):
""" """
Makes a counterbored hole for each item on the stack. Makes a counterbored hole for each item on the stack.
@ -1904,7 +1972,7 @@ class Workplane(CQ):
return self.cutEach(_makeCbore, True, clean) return self.cutEach(_makeCbore, True, clean)
#TODO: almost all code duplicated! #TODO: almost all code duplicated!
#but parameter list is different so a simple function pointer wont work #but parameter list is different so a simple function pointer won't work
def cskHole(self, diameter, cskDiameter, cskAngle, depth=None, clean=True): def cskHole(self, diameter, cskDiameter, cskAngle, depth=None, clean=True):
""" """
Makes a countersunk hole for each item on the stack. Makes a countersunk hole for each item on the stack.
@ -1955,7 +2023,7 @@ class Workplane(CQ):
return self.cutEach(_makeCsk, True, clean) return self.cutEach(_makeCsk, True, clean)
#TODO: almost all code duplicated! #TODO: almost all code duplicated!
#but parameter list is different so a simple function pointer wont work #but parameter list is different so a simple function pointer won't work
def hole(self, diameter, depth=None, clean=True): def hole(self, diameter, depth=None, clean=True):
""" """
Makes a hole for each item on the stack. Makes a hole for each item on the stack.
@ -2146,7 +2214,7 @@ class Workplane(CQ):
:param path: A wire along which the pending wires will be swept :param path: A wire along which the pending wires will be swept
:param boolean sweepAlongWires: :param boolean sweepAlongWires:
False to create mutliple swept from wires on the chain along path False to create multiple swept from wires on the chain along path
True to create only one solid swept along path with shape following the list of wires on the chain True to create only one solid swept along path with shape following the list of wires on the chain
:param boolean combine: True to combine the resulting solid with parent solids if found. :param boolean combine: True to combine the resulting solid with parent solids if found.
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape :param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
@ -2473,7 +2541,7 @@ class Workplane(CQ):
:param path: A wire along which the pending wires will be swept :param path: A wire along which the pending wires will be swept
:param boolean sweepAlongWires: :param boolean sweepAlongWires:
False to create mutliple swept from wires on the chain along path False to create multiple swept from wires on the chain along path
True to create only one solid swept along path with shape following the list of wires on the chain True to create only one solid swept along path with shape following the list of wires on the chain
:return:a FreeCAD solid, suitable for boolean operations :return:a FreeCAD solid, suitable for boolean operations
""" """

View File

@ -30,7 +30,7 @@ class CQModel(object):
After construction, the metadata property contains After construction, the metadata property contains
a ScriptMetaData object, which describes the model in more detail, a ScriptMetaData object, which describes the model in more detail,
and can be used to retrive the parameters defined by the model. and can be used to retrieve the parameters defined by the model.
the build method can be used to generate a 3d model the build method can be used to generate a 3d model
""" """
@ -44,7 +44,7 @@ class CQModel(object):
self.script_source = script_source self.script_source = script_source
self._find_vars() self._find_vars()
# TODO: pick up other scirpt metadata: # TODO: pick up other script metadata:
# describe # describe
# pick up validation methods # pick up validation methods
self._find_descriptions() self._find_descriptions()
@ -58,7 +58,7 @@ class CQModel(object):
#are only at the top level of the script. IE, we'll ignore any #are only at the top level of the script. IE, we'll ignore any
#variable definitions at lower levels of the script #variable definitions at lower levels of the script
#we dont want to use the visit interface because here we excplicitly #we don't want to use the visit interface because here we explicitly
#want to walk only the top level of the tree. #want to walk only the top level of the tree.
assignment_finder = ConstantAssignmentFinder(self.metadata) assignment_finder = ConstantAssignmentFinder(self.metadata)
@ -85,7 +85,7 @@ class CQModel(object):
:param build_parameters: a dictionary of variables. The variables must be :param build_parameters: a dictionary of variables. The variables must be
assignable to the underlying variable type. These variables override default values in the script 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 :param build_options: build options for how to build the model. Build options include things like
timeouts, tesselation tolerances, etc timeouts, tessellation tolerances, etc
:raises: Nothing. If there is an exception, it will be on the exception property of the result. :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 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 :return: a BuildResult object, which includes the status of the result, and either
@ -308,7 +308,7 @@ class ScriptCallback(object):
""" """
return an object to the executing environment, with options return an object to the executing environment, with options
:param shape: a cadquery object :param shape: a cadquery object
:param options: a dictionary of options that will be made available to the executing envrionment :param options: a dictionary of options that will be made available to the executing environment
""" """
o = ShapeResult() o = ShapeResult()
o.options=options o.options=options
@ -326,7 +326,7 @@ class ScriptCallback(object):
def describe_parameter(self,var_data ): def describe_parameter(self,var_data ):
""" """
Do Nothing-- we parsed the ast ahead of exection to get what we need. Do Nothing-- we parsed the ast ahead of execution to get what we need.
""" """
pass pass

View File

@ -63,7 +63,7 @@ def _fc_path():
# Try to guess if using Anaconda # Try to guess if using Anaconda
if 'env' in sys.prefix: if 'env' in sys.prefix:
if sys.platform.startswith('linux'): if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
_PATH = os.path.join(sys.prefix,'lib') _PATH = os.path.join(sys.prefix,'lib')
# return PATH if FreeCAD.[so,pyd] is present # return PATH if FreeCAD.[so,pyd] is present
if len(glob.glob(os.path.join(_PATH,'FreeCAD.so'))) > 0: if len(glob.glob(os.path.join(_PATH,'FreeCAD.so'))) > 0:

View File

@ -102,7 +102,7 @@ def disable():
""" """
Disables logging to FreeCAD console (or STDOUT). Disables logging to FreeCAD console (or STDOUT).
Note, logging may be enabled by another imported module, so this isn't a Note, logging may be enabled by another imported module, so this isn't a
guarentee; this function undoes logging_enable(), nothing more. guarantee; this function undoes logging_enable(), nothing more.
""" """
global _logging_handler global _logging_handler
if _logging_handler: if _logging_handler:

View File

@ -78,7 +78,7 @@ def exportShape(shape,exportType,fileLike,tolerance=0.1):
#weird, but we need to close this file. the next step is going to write to #weird, but we need to close this file. the next step is going to write to
#it from c code, so it needs to be closed. #it from c code, so it needs to be closed.
#FreeCAD junks up stdout with a bunch of messages, so this context #FreeCAD junks up stdout with a bunch of messages, so this context
#manager supresses that stuff in the case we're trying to write to stdout #manager suppresses that stuff in the case we're trying to write to stdout
os.close(h) os.close(h)
with suppress_stdout_stderr(): with suppress_stdout_stderr():
if exportType == ExportTypes.STEP: if exportType == ExportTypes.STEP:

View File

@ -192,7 +192,7 @@ class Vector(object):
"""Return the vector itself """Return the vector itself
The center of myself is myself. The center of myself is myself.
Provided so that vectors, vertexes, and other shapes all support a Provided so that vectors, vertices, and other shapes all support a
common interface, when Center() is requested for all objects on the common interface, when Center() is requested for all objects on the
stack. stack.
""" """
@ -216,7 +216,7 @@ class Vector(object):
def __bool__(self): def __bool__(self):
return any(coord != 0 for coord in self.toTuple()) return any(coord != 0 for coord in self.toTuple())
__nonzero__ = __bool__ # python 2.x compatability __nonzero__ = __bool__ # python 2.x compatibility
def __add__(self, v): def __add__(self, v):
return self.add(v) return self.add(v)
@ -433,7 +433,7 @@ class Plane(object):
**Non-orthogonal vectors** **Non-orthogonal vectors**
If the ``xDir`` and ``normal`` vectors are not orthogonal, the ``normal`` If the ``xDir`` and ``normal`` vectors are not orthogonal, the ``normal``
(or ``z`` axis) vector direction is preserved, and truely orthogonal (or ``z`` axis) vector direction is preserved, and truly orthogonal
``x`` and ``y`` axes are calculated with cross products. ``x`` and ``y`` axes are calculated with cross products.
* ``y = z.cross(x)``, and * ``y = z.cross(x)``, and

View File

@ -39,12 +39,16 @@ def importStep(fileName):
try: try:
rshape = Part.read(fileName) rshape = Part.read(fileName)
#Make sure that we extract all the solids # Extract all solids and surfaces
solids = [] geometry = []
for solid in rshape.Solids: for solid in rshape.Solids:
solids.append(Shape.cast(solid)) geometry.append(Shape.cast(solid))
for shell in rshape.Shells:
geometry.append(Shape.cast(shell))
return cadquery.Workplane("XY").newObject(geometry)
return cadquery.Workplane("XY").newObject(solids)
except: except:
raise ValueError("STEP File Could not be loaded") raise ValueError("STEP File Could not be loaded")
@ -64,13 +68,7 @@ def importStepFromURL(url):
webFile.close() webFile.close()
tempFile.close() tempFile.close()
rshape = Part.read(tempFile.name) # Read saved file and return CQ Workplane object
return importStep(tempFile.name)
#Make sure that we extract all the solids
solids = []
for solid in rshape.Solids:
solids.append(Shape.cast(solid))
return cadquery.Workplane("XY").newObject(solids)
except: except:
raise ValueError("STEP File from the URL: " + url + " Could not be loaded") raise ValueError("STEP File from the URL: " + url + " Could not be loaded")

View File

@ -105,7 +105,7 @@ class Shape(object):
return tr return tr
# TODO: all these should move into the exporters folder. # TODO: all these should move into the exporters folder.
# we dont need a bunch of exporting code stored in here! # we don't need a bunch of exporting code stored in here!
# #
def exportStl(self, fileName, tolerance=0.1): def exportStl(self, fileName, tolerance=0.1):
self.wrapped.exportStl(fileName, tolerance) self.wrapped.exportStl(fileName, tolerance)
@ -354,7 +354,7 @@ class Shape(object):
def transformShape(self, tMatrix): def transformShape(self, tMatrix):
""" """
tMatrix is a matrix object. tMatrix is a matrix object.
returns a copy of the ojbect, transformed by the provided matrix, returns a copy of the object, transformed by the provided matrix,
with all objects keeping their type with all objects keeping their type
""" """
tmp = self.wrapped.copy() tmp = self.wrapped.copy()
@ -367,14 +367,14 @@ class Shape(object):
""" """
tMatrix is a matrix object. tMatrix is a matrix object.
returns a copy of the object, but with geometry transformed insetad of just returns a copy of the object, but with geometry transformed instead of just
rotated. rotated.
WARNING: transformGeometry will sometimes convert lines and circles to splines, WARNING: transformGeometry will sometimes convert lines and circles to splines,
but it also has the ability to handle skew and stretching transformations. but it also has the ability to handle skew and stretching transformations.
If your transformation is only translation and rotation, it is safer to use transformShape, If your transformation is only translation and rotation, it is safer to use transformShape,
which doesnt change the underlying type of the geometry, but cannot handle skew transformations which doesn't change the underlying type of the geometry, but cannot handle skew transformations
""" """
tmp = self.wrapped.copy() tmp = self.wrapped.copy()
tmp = tmp.transformGeometry(tMatrix) tmp = tmp.transformGeometry(tMatrix)
@ -449,7 +449,7 @@ class Edge(Shape):
def startPoint(self): def startPoint(self):
""" """
:return: a vector representing the start poing of this edge :return: a vector representing the start point of this edge
Note, circles may have the start and end points the same Note, circles may have the start and end points the same
""" """

View File

@ -155,7 +155,7 @@ class BaseDirSelector(Selector):
#no really good way to avoid a switch here, edges and faces are simply different! #no really good way to avoid a switch here, edges and faces are simply different!
if type(o) == Face: if type(o) == Face:
# a face is only parallell to a direction if it is a plane, and its normal is parallel to the dir # a face is only parallel to a direction if it is a plane, and its normal is parallel to the dir
normal = o.normalAt(None) normal = o.normalAt(None)
if self.test(normal): if self.test(normal):
@ -392,7 +392,7 @@ class SumSelector(BinarySelector):
class SubtractSelector(BinarySelector): class SubtractSelector(BinarySelector):
""" """
Difference selector. Substract results of a selector from another Difference selector. Subtract results of a selector from another
selectors results. selectors results.
""" """
def filterResults(self, r_left, r_right): def filterResults(self, r_left, r_right):
@ -630,7 +630,7 @@ class StringSyntaxSelector(Selector):
***axisStrings*** are: ``X,Y,Z,XY,YZ,XZ`` or ``(x,y,z)`` which defines an arbitrary direction ***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. It is possible to combine simple selectors together using logical operations.
The following operations are suuported The following operations are supported
:and: :and:
Logical AND, e.g. >X and >Y Logical AND, e.g. >X and >Y

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -146,7 +146,7 @@ Selectors
------------------------ ------------------------
Objects that filter and select CAD objects. Selectors are used to select existing geometry Objects that filter and select CAD objects. Selectors are used to select existing geometry
as a basis for futher operations. as a basis for further operations.
.. currentmodule:: cadquery .. currentmodule:: cadquery

View File

@ -108,7 +108,7 @@ If a parameter called 'param' is defined in the model, it will be assigned the v
An error will occur if a value is provided that is not defined in the model, or if the value provided cannot 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. 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 build_options is used to set server-side settings like timeouts, tessellation tolerances, and other details about
how the model should be built. how the model should be built.
@ -141,7 +141,7 @@ You can list the variables defined in the model by using the return value of the
The key of the dictionary is a string , and the value is a :py:class:`cadquery.cqgi.InputParameter` object The key of the dictionary is a string , and the value is a :py:class:`cadquery.cqgi.InputParameter` object
See the CQGI API docs for more details. See the CQGI API docs for more details.
Future enhancments will include a safer sandbox to prevent malicious scripts. Future enhancements will include a safer sandbox to prevent malicious scripts.
Important CQGI Methods Important CQGI Methods
------------------------- -------------------------

View File

@ -38,7 +38,7 @@ If you have experience with 3D CAD systems, you also know that there is a key de
After the base block is created, how the hole is located is key. If it is located from one edge, changing the block After the base block is created, how the hole is located is key. If it is located from one edge, changing the block
size will have a different affect than if the hole is located from the center. size will have a different affect than if the hole is located from the center.
Many scripting langauges do not provide a way to capture design intent-- because they require that you always work in Many scripting languages do not provide a way to capture design intent-- because they require that you always work in
global coordinates. CadQuery is different-- you can locate features relative to others in a relative way-- preserving global coordinates. CadQuery is different-- you can locate features relative to others in a relative way-- preserving
the design intent just like a human would when creating a drawing or building an object. the design intent just like a human would when creating a drawing or building an object.

View File

@ -18,18 +18,18 @@ Items introduced in the example are marked with a **!**
You may want to work through these examples by pasting the text into a scratchpad on the live website. You may want to work through these examples by pasting the text into a scratchpad on the live website.
If you do, make sure to take these steps so that they work: If you do, make sure to take these steps so that they work:
1. paste the content into the build() method, properly intented, and 1. paste the content into the build() method, properly indented, and
2. add the line 'return result' at the end. The samples below are autogenerated, but they use a different 2. add the line 'return result' at the end. The samples below are autogenerated, but they use a different
syntax than the models on the website need to be. syntax than the models on the website need to be.
.. note:: .. note::
We strongly recommend installing FreeCAD, and the `cadquery-freecad-module <https://github.com/jmwright/cadquery-freecad-module>`_, We strongly recommend installing FreeCAD, and the `cadquery-freecad-module <https://github.com/jmwright/cadquery-freecad-module>`_,
so that you can work along with these examples interactively. See :ref:`installation` for more info. so that you can work along with these examples interactively. See :ref:`installation` for more info.
.. warning:: .. warning::
* You have to have an svg capable browser to view these! * You have to have an SVG capable browser to view these!
.. contents:: List of Examples .. contents:: List of Examples
:backlinks: entry :backlinks: entry
@ -199,7 +199,7 @@ like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on
Polygons Polygons
------------------------- -------------------------
You can create polygons for each stack point if you would like. Useful in 3d printers whos firmware does not You can create polygons for each stack point if you would like. Useful in 3d printers whose firmware does not
correct for small hole sizes. correct for small hole sizes.
.. cq_plot:: .. cq_plot::
@ -344,7 +344,7 @@ Mirroring 3D Objects
.lineTo(10,1) .lineTo(10,1)
.close()) .close())
result = result0.extrude(100) result = result0.extrude(100)
result = result.rotate((0, 0, 0),(1, 0, 0), 90) result = result.rotate((0, 0, 0),(1, 0, 0), 90)
result = result.translate(result.val().BoundingBox().center.multiply(-1)) result = result.translate(result.val().BoundingBox().center.multiply(-1))
@ -354,8 +354,8 @@ Mirroring 3D Objects
mirZY_neg = result.mirror(mirrorPlane="ZY", basePointVector=(-30,0,0)) mirZY_neg = result.mirror(mirrorPlane="ZY", basePointVector=(-30,0,0))
mirZY_pos = 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) result = result.union(mirXY_neg).union(mirXY_pos).union(mirZY_neg).union(mirZY_pos)
show_object(result) show_object(result)
.. topic:: Api References .. topic:: Api References
@ -363,13 +363,13 @@ Mirroring 3D Objects
.. hlist:: .. hlist::
:columns: 2 :columns: 2
* :py:meth:`Workplane.moveTo` * :py:meth:`Workplane.moveTo`
* :py:meth:`Workplane.lineTo` * :py:meth:`Workplane.lineTo`
* :py:meth:`Workplane.threePointArc` * :py:meth:`Workplane.threePointArc`
* :py:meth:`Workplane.extrude` * :py:meth:`Workplane.extrude`
* :py:meth:`Workplane.mirror` * :py:meth:`Workplane.mirror`
* :py:meth:`Workplane.union` * :py:meth:`Workplane.union`
* :py:meth:`CQ.rotate` * :py:meth:`CQ.rotate`
Creating Workplanes on Faces Creating Workplanes on Faces
----------------------------- -----------------------------
@ -604,6 +604,35 @@ Here we fillet all of the edges of a simple plate.
* :py:meth:`Workplane.edges` * :py:meth:`Workplane.edges`
* :py:meth:`Workplane` * :py:meth:`Workplane`
A reinforced junction between two pieces with Fillet
-----------------------------------------
The fillet can also be used to reinfoce a junction between two pieces.
.. cq_plot::
s = cq.Workplane("XY")
horizontalPart = s.box(10, 5, 1)
verticalPart = s.box(10, 1, 5).translate((0, 0, 1 + 5/2))
result = horizontalPart.union(verticalPart) \
.faces(">Z[1]").edges("not(<X or >X or <Y or >Y)").fillet(1)
show_object(result)
.. topic:: Api References
.. hlist::
:columns: 2
* :py:meth:`Workplane`
* :py:meth:`Workplane.box`
* :py:meth:`Workplane.faces`
* :py:meth:`Workplane.edges`
* :ref:`selector_reference`
* :py:meth:`Workplane.fillet`
A Parametric Bearing Pillow Block A Parametric Bearing Pillow Block
------------------------------------ ------------------------------------
@ -621,7 +650,6 @@ with just a few lines of code.
show_object(result) show_object(result)
Splitting an Object Splitting an Object
--------------------- ---------------------

View File

@ -4,7 +4,7 @@ Extending CadQuery
====================== ======================
If you find that CadQuery doesnt suit your needs, you can easily extend it. CadQuery provides several extension If you find that CadQuery doesn't suit your needs, you can easily extend it. CadQuery provides several extension
methods: methods:
* You can load plugins others have developed. This is by far the easiest way to access other code * You can load plugins others have developed. This is by far the easiest way to access other code
@ -25,7 +25,7 @@ is actually equivalent to::
return Part.makeBox(1.0,2.0,3.0) return Part.makeBox(1.0,2.0,3.0)
As long as you return a valid FreeCAD Shape, you can use any FreeCAD methods you like. You can even mix and match the As long as you return a valid FreeCAD Shape, you can use any FreeCAD methods you like. You can even mix and match the
two. For example, consider this script, which creates a FreeCAD box, but then uses cadquery to select its faces:: two. For example, consider this script, which creates a FreeCAD box, but then uses CadQuery to select its faces::
box = Part.makeBox(1.0,2.0,3.0) box = Part.makeBox(1.0,2.0,3.0)
cq = CQ(box).faces(">Z").size() # returns 6 cq = CQ(box).faces(">Z").size() # returns 6
@ -108,7 +108,7 @@ are designed to aid in plugin creation:
* :py:meth:`cadquery.Workplane.plane` provides a reference to the workplane, which allows you to convert between workplane * :py:meth:`cadquery.Workplane.plane` provides a reference to the workplane, which allows you to convert between workplane
coordinates and global coordinates: coordinates and global coordinates:
* :py:meth:`cadquery.freecad_impl.geom.Plane.toWorldCoords` will convert local coordinates to global ones * :py:meth:`cadquery.freecad_impl.geom.Plane.toWorldCoords` will convert local coordinates to global ones
* :py:meth:`cadquery.freecad_impl.geom.Plane.toLocalCoords` will convet from global coordinates to local coordinates * :py:meth:`cadquery.freecad_impl.geom.Plane.toLocalCoords` will convert from global coordinates to local coordinates
Coordinate Systems Coordinate Systems
----------------------- -----------------------
@ -140,7 +140,7 @@ That's it!
CadQueryExample Plugins CadQueryExample Plugins
----------------------- -----------------------
Some core cadquery code is intentionally written exactly like a plugin. Some core CadQuery code is intentionally written exactly like a plugin.
If you are writing your own plugins, have a look at these methods for inspiration: If you are writing your own plugins, have a look at these methods for inspiration:
* :py:meth:`cadquery.Workplane.polygon` * :py:meth:`cadquery.Workplane.polygon`
@ -177,4 +177,3 @@ This ultra simple plugin makes cubes of the specified size for each stack point.
.rect(4.0,4.0,forConstruction=True).vertices() \ .rect(4.0,4.0,forConstruction=True).vertices() \
.makeCubes(1.0).combineSolids() .makeCubes(1.0).combineSolids()
show_object(result) show_object(result)

View File

@ -10,8 +10,11 @@ Prerequisites--FreeCAD and Python 2.6 or 2.7
---------------------------------------------- ----------------------------------------------
CadQuery requires FreeCAD and Python version 2.6.x or 2.7.x *Python 3.x is NOT supported* CadQuery requires FreeCAD and Python version 2.6.x or 2.7.x *Python 3.x is NOT supported*
Ubuntu Command Line Installation Installation
------------------------------------------ -------------------
Ubuntu
^^^^^^^^^^^^^^
On Ubuntu, you can type:: On Ubuntu, you can type::
@ -21,22 +24,37 @@ On Ubuntu, you can type::
This `Unix Installation Video <http://youtu.be/InZu8jgaYCA>`_ will walk you through the installation This `Unix Installation Video <http://youtu.be/InZu8jgaYCA>`_ will walk you through the installation
Installation: Other Platforms Windows & Mac
------------------------------------------ ^^^^^^^^^^^^^^^^^^^^
1. Install FreeCAD using the appropriate installer for your platform, on `www.freecadweb.org <http://www.freecadweb.org/wiki/?title=Download>`_ 1. Install FreeCAD using the appropriate installer for your platform, on `www.freecadweb.org <http://www.freecadweb.org/wiki/?title=Download>`_
2. pip install cadquery 2. pip install cadquery
This `Windows Installation video <https://www.youtube.com/watch?v=dWw4Y_ah-8k>`_ will walk you through the installation on Windows This `Windows Installation video <https://www.youtube.com/watch?v=dWw4Y_ah-8k>`_ will walk you through the installation on Windows
Anaconda (cross-platform)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Alternatively you can use Anaconda's package management system to install
cadquery and its dependencies, including FreeCAD.
1. Install `Anaconda <https://www.anaconda.com/download>`_
2. Open an anaconda prompt and run:
::
conda install -c conda-forge cadquery
Test Your Installation Test Your Installation
------------------------ ------------------------
If all has gone well, you can open a command line/prompt, and type:: If all has gone well, you can open a command line/prompt, and type::
$python $ python
$import cadquery >>> import cadquery
$cadquery.Workplane('XY').box(1,2,3).toSvg() >>> cadquery.Workplane('XY').box(1,2,3).toSvg()
Adding a Nicer GUI via the cadquery-freecad-module Adding a Nicer GUI via the cadquery-freecad-module
-------------------------------------------------------- --------------------------------------------------------
@ -51,4 +69,4 @@ Zero Step Install
------------------------------------------------- -------------------------------------------------
If you would like to use cadquery with no installation all, you can If you would like to use cadquery with no installation all, you can
use mybinder to `launch a Jupyter Notebook Server <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_ pre-configured to run CadQuery. use mybinder to `launch a Jupyter Notebook Server <https://mybinder.org/v2/gh/RustyVermeer/tryCQ/master>`_ pre-configured to run CadQuery.

View File

@ -19,7 +19,7 @@ CadQuery is an intuitive, easy-to-use python library for building parametric 3D
* Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser * Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser
CadQuery is based on CadQuery is based on
`FreeCAD <http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page>`_, `FreeCAD <https://www.freecadweb.org/>`_,
which is turn based on the open-source `OpenCascade <http://www.opencascade.com/>`_ modelling kernel. which is turn based on the open-source `OpenCascade <http://www.opencascade.com/>`_ modelling kernel.
Using CadQuery, you can build fully parametric models with a very small amount of code. For example, this simple script Using CadQuery, you can build fully parametric models with a very small amount of code. For example, this simple script

View File

@ -63,7 +63,7 @@ See :ref:`2dOperations` to learn more.
3D Construction 3D Construction
--------------------------- ---------------------------
You can construct 3D primatives such as boxes, spheres, wedges, and cylinders directly. You can also sweep, extrude, You can construct 3D primitives such as boxes, spheres, wedges, and cylinders directly. You can also sweep, extrude,
and loft 2D geometry to form 3D features. Of course the basic primitive operations are also available. and loft 2D geometry to form 3D features. Of course the basic primitive operations are also available.
See :ref:`3doperations` to learn more. See :ref:`3doperations` to learn more.
@ -74,7 +74,7 @@ Selectors
--------------------------- ---------------------------
Selectors allow you to select one or more features, for use to define new features. As an example, you might Selectors allow you to select one or more features, for use to define new features. As an example, you might
extrude a box, and then select the top face as the location for a new feture. Or, you might extrude a box, and extrude a box, and then select the top face as the location for a new feature. Or, you might extrude a box, and
then select all of the vertical edges so that you can apply a fillet to them. then select all of the vertical edges so that you can apply a fillet to them.
You can select Vertices, Edges, Faces, Solids, and Wires using selectors. You can select Vertices, Edges, Faces, Solids, and Wires using selectors.

View File

@ -11,14 +11,14 @@ Want a quick glimpse of what CadQuery can do? This quickstart will demonstrate
Prerequisites: FreeCAD + cadQuery-freeCAD-module in FreeCAD Prerequisites: FreeCAD + cadQuery-freeCAD-module in FreeCAD
============================================================== ==============================================================
If you have not already done so, follow the :ref:`installation`, and to install cadquery, FreeCAD, If you have not already done so, follow the :ref:`installation`, and to install CadQuery, FreeCAD,
and the cadquery-freecad-module and the cadquery-freecad-module
After installation, open the CadQuery workbench: After installation, open the CadQuery workbench:
.. image:: _static/quickstart/001.png .. image:: _static/quickstart/001.png
You'll see that we start out with a single block. Find the cadquery Code Window, at the bottom left. You'll see that we start out with a single block. Find the CadQuery Code Window, at the bottom left.
If you want check out a couple of the examples in the CadQuery->Examples menu. If you want check out a couple of the examples in the CadQuery->Examples menu.
@ -170,7 +170,7 @@ There are a couple of things to note about this line:
tells CadQuery that this rectangle will not form a part of the solid, tells CadQuery that this rectangle will not form a part of the solid,
but we are just using it to help define some other geometry. but we are just using it to help define some other geometry.
2. The center point of a workplane on a face is always at the center of the face, which works well here 2. The center point of a workplane on a face is always at the center of the face, which works well here
3. Unless you specifiy otherwise, a rectangle is drawn with its center on the current workplane center-- in 3. Unless you specify otherwise, a rectangle is drawn with its center on the current workplane center-- in
this case, the center of the top face of the block. So this rectangle will be centered on the face this case, the center of the top face of the block. So this rectangle will be centered on the face
@ -236,7 +236,7 @@ with < 20 lines of code.
Want to learn more? Want to learn more?
==================== ====================
* Use the CadQuery->Examples menu of the cadquery workbench to explore a lot of other examples. * Use the CadQuery->Examples menu of the CadQuery workbench to explore a lot of other examples.
* The :ref:`examples` contains lots of examples demonstrating cadquery features * The :ref:`examples` contains lots of examples demonstrating CadQuery features
* The :ref:`apireference` is a good overview of language features grouped by function * The :ref:`apireference` is a good overview of language features grouped by function
* The :ref:`classreference` is the hard-core listing of all functions available. * The :ref:`classreference` is the hard-core listing of all functions available.

View File

@ -8,10 +8,10 @@ width = 2.2 # Nominal x dimension of the part
height = 0.5 # Height from bottom top to the top of the top :P height = 0.5 # Height from bottom top to the top of the top :P
length = 1.5 # Nominal y dimension of the part length = 1.5 # Nominal y dimension of the part
trapezoidFudge = 0.7 # ratio of trapezoid bases. set to 1.0 for cube trapezoidFudge = 0.7 # ratio of trapezoid bases. set to 1.0 for cube
xHoleOffset = 0.500 # Holes are distributed symetrically about each axis xHoleOffset = 0.500 # Holes are distributed symmetrically about each axis
yHoleOffset = 0.500 yHoleOffset = 0.500
zFilletRadius = 0.50 # Fillet radius of corners perp. to Z axis. zFilletRadius = 0.50 # Fillet radius of corners perp. to Z axis.
yFilletRadius = 0.250 # Fillet readius of the top edge of the case yFilletRadius = 0.250 # Fillet radius of the top edge of the case
lipHeight = 0.1 # The height of the lip on the inside of the cover lipHeight = 0.1 # The height of the lip on the inside of the cover
wallThickness = 0.06 # Wall thickness for the case wallThickness = 0.06 # Wall thickness for the case
coverThickness = 0.2 # Thickness of the cover plate coverThickness = 0.2 # Thickness of the cover plate
@ -23,7 +23,7 @@ yzplane = cq.Workplane("YZ")
def trapezoid(b1, b2, h): def trapezoid(b1, b2, h):
"Defines a symetrical trapezoid in the XY plane." "Defines a symmetrical trapezoid in the XY plane."
y = h / 2 y = h / 2
x1 = b1 / 2 x1 = b1 / 2

View File

@ -104,7 +104,7 @@ res = res.vLine(-support_depth).\
res = res.extrude(main_plate_size_x/2, both=True, clean=True) # extrude the triangle, now the bridge has a nice support making it much more stiff res = res.extrude(main_plate_size_x/2, both=True, clean=True) # extrude the triangle, now the bridge has a nice support making it much more stiff
# Start cutting out a slot for hotend mounting # Start cutting out a slot for hotend mounting
face = res.faces('>Y') # select the most extreme face in Y direction, i.e. top ot the "bridge" face = res.faces('>Y') # select the most extreme face in Y direction, i.e. top of the "bridge"
res = move_to_center(face.workplane(), face.edges('>Z').val()) # shift the workplane to the center of the most extreme edge of the bridge res = move_to_center(face.workplane(), face.edges('>Z').val()) # shift the workplane to the center of the most extreme edge of the bridge

View File

@ -0,0 +1,29 @@
import cadquery as cq
from cadquery import selectors
# This exemple demonstrates the use of a fillet to reinforce a junction between two parts.
# It relies on the selection of an edge of the weak junction, and the use of fillet.
# 1 - The construction of the model : a pipe connector
# In that model, the junction surface between the box and the cylinder is small.
# This makes the junction between the two too weak.
model = cq.Workplane("XY").box(15.0, 15.0, 2.0)\
.faces(">Z").rect(10.0, 10.0, forConstruction=True)\
.vertices().cskHole(2.0, 4.0, 82)\
.faces(">Z").circle(4.0).extrude(10.0)\
.faces(">Z").hole(6)
# 2 - Reinforcement of the junction
# Two steps here :
# - select the edge to reinforce. Here we search the closest edge from the center on the top face of the box.
# - apply a fillet or a chamfer to that edge
result = model.faces('<Z[1]').edges(selectors.NearestToPointSelector((0.0, 0.0))).fillet(1)
# Additional note :
# Using a type selector to select circles on the face would have returned all the circles, including the one to reinforce,
# but also the ones for the countersunk holes.
# The order of the edges returned by the selector is not guaranteed, so selecting the circle in the stack would not be reliable.
# If there was only one circle on the face, then this would have worked perfectly :
# result = model.faces('<Z[1]').edges('%Circle').fillet(1)
show_object(result)

View File

@ -0,0 +1,2 @@
[metadata]
license_file = LICENSE

View File

@ -18,9 +18,7 @@ from setuptools import setup
#if we are building in travis, use the build number as the sub-minor version #if we are building in travis, use the build number as the sub-minor version
version = '1.2.0' version = '1.2.0'
if 'TRAVIS_TAG' in list(os.environ.keys()): version = os.environ.get('TRAVIS_TAG', None) or version
version= os.environ['TRAVIS_TAG']
setup( setup(
name='cadquery', name='cadquery',
@ -30,7 +28,7 @@ setup(
author='David Cowden', author='David Cowden',
author_email='dave.cowden@gmail.com', author_email='dave.cowden@gmail.com',
description='CadQuery is a parametric scripting language for creating and traversing CAD models', description='CadQuery is a parametric scripting language for creating and traversing CAD models',
long_description=codecs.open('README.md', 'rb', 'UTF-8').read(), long_description=codecs.open('README.rst', 'rb', 'UTF-8').read(),
packages=['cadquery','cadquery.contrib','cadquery.freecad_impl','cadquery.plugins','tests'], packages=['cadquery','cadquery.contrib','cadquery.freecad_impl','cadquery.plugins','tests'],
install_requires=['pyparsing'], install_requires=['pyparsing'],
include_package_data=True, include_package_data=True,

View File

@ -107,7 +107,7 @@ class TestCQGI(BaseTest):
def test_that_invalid_syntax_in_script_fails_immediately(self): def test_that_invalid_syntax_in_script_fails_immediately(self):
badscript = textwrap.dedent( badscript = textwrap.dedent(
""" """
this doesnt even compile this doesn't even compile
""" """
) )

View File

@ -519,6 +519,35 @@ class TestCadQuery(BaseTest):
self.saveModel(s) self.saveModel(s)
self.assertEqual(6+NUMX*NUMY*2,s.faces().size()) #6 faces for the box, 2 faces for each cylinder self.assertEqual(6+NUMX*NUMY*2,s.faces().size()) #6 faces for the box, 2 faces for each cylinder
def testPolarArray(self):
radius = 10
# Test for proper number of elements
s = Workplane("XY").polarArray(radius, 0, 180, 1)
self.assertEqual(1, s.size())
s = Workplane("XY").polarArray(radius, 0, 180, 6)
self.assertEqual(6, s.size())
# Test for proper placement when fill == True
s = Workplane("XY").polarArray(radius, 0, 180, 3)
self.assertAlmostEqual(0, s.objects[1].x)
self.assertAlmostEqual(radius, s.objects[1].y)
# Test for proper placement when angle to fill is multiple of 360 deg
s = Workplane("XY").polarArray(radius, 0, 360, 4)
self.assertAlmostEqual(0, s.objects[1].x)
self.assertAlmostEqual(radius, s.objects[1].y)
# Test for proper placement when fill == False
s = Workplane("XY").polarArray(radius, 0, 90, 3, fill=False)
self.assertAlmostEqual(0, s.objects[1].x)
self.assertAlmostEqual(radius, s.objects[1].y)
# Test for proper operation of startAngle
s = Workplane("XY").polarArray(radius, 90, 180, 3)
self.assertAlmostEqual(0, s.objects[0].x)
self.assertAlmostEqual(radius, s.objects[0].y)
def testNestedCircle(self): def testNestedCircle(self):
s = Workplane("XY").box(40,40,5).pushPoints([(10,0),(0,10)]).circle(4).circle(2).extrude(4) s = Workplane("XY").box(40,40,5).pushPoints([(10,0),(0,10)]).circle(4).circle(2).extrude(4)
self.saveModel(s) self.saveModel(s)
@ -608,7 +637,7 @@ class TestCadQuery(BaseTest):
self.assertEqual(0,s.faces().size() ) # the original workplane does not, because it did not have a solid initially self.assertEqual(0,s.faces().size() ) # the original workplane does not, because it did not have a solid initially
t = r.faces(">Z").workplane().rect(0.25,0.25).extrude(0.5,False) t = r.faces(">Z").workplane().rect(0.25,0.25).extrude(0.5,False)
self.assertEqual(6,t.faces().size()) #result has 6 faces, becuase it was not combined with the original self.assertEqual(6,t.faces().size()) #result has 6 faces, because it was not combined with the original
self.assertEqual(6,r.faces().size()) #original is unmodified as well self.assertEqual(6,r.faces().size()) #original is unmodified as well
#subseuent opertions use that context solid afterwards #subseuent opertions use that context solid afterwards
@ -799,7 +828,7 @@ class TestCadQuery(BaseTest):
s = Workplane(Plane.XY()) s = Workplane(Plane.XY())
#TODO: extrude() should imply wire() if not done already #TODO: extrude() should imply wire() if not done already
#most users dont understand what a wire is, they are just drawing #most users don't 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 = s.lineTo(1.0,0).lineTo(0,1.0).close().wire().extrude(0.25)
with suppress_stdout_stderr(): with suppress_stdout_stderr():
@ -881,6 +910,23 @@ class TestCadQuery(BaseTest):
assert(a1.edges().first().val().Length() == a2.edges().first().val().Length()) assert(a1.edges().first().val().Length() == a2.edges().first().val().Length())
assert(a3.edges().first().val().Length() == a4.edges().first().val().Length()) assert(a3.edges().first().val().Length() == a4.edges().first().val().Length())
def testPolarLines(self):
"""
Draw some polar lines and check expected results
"""
# Test the PolarLine* functions
s = Workplane(Plane.XY())
r = s.polarLine(10, 45) \
.polarLineTo(10, -45) \
.polarLine(10, -180) \
.polarLine(-10, -90) \
.close()
# a single wire, 5 edges
self.assertEqual(1, r.wires().size())
self.assertEqual(5, r.wires().edges().size())
def testLargestDimension(self): def testLargestDimension(self):
""" """
Tests the largestDimension function when no solids are on the stack and when there are Tests the largestDimension function when no solids are on the stack and when there are
@ -1488,7 +1534,7 @@ class TestCadQuery(BaseTest):
return cup return cup
""" """
#for some reason shell doesnt work on this simple shape. how disappointing! #for some reason shell doesn't work on this simple shape. how disappointing!
td = 50.0 td = 50.0
bd = 20.0 bd = 20.0
h = 10.0 h = 10.0

View File

@ -43,7 +43,7 @@ def toTuple(v):
elif type(v) == Vector: elif type(v) == Vector:
return v.toTuple() return v.toTuple()
else: else:
raise RuntimeError("dont know how to convert type %s to tuple" % str(type(v)) ) raise RuntimeError("don't know how to convert type %s to tuple" % str(type(v)) )
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):