Merge commit 'f6a4222e3a60c6ec1c49cdd8363d88bdd88530e7'
2
CadQuery/Libs/cadquery-lib/.gitignore
vendored
|
@ -1,5 +1,7 @@
|
||||||
|
build/
|
||||||
*.pyc
|
*.pyc
|
||||||
doc/_build/*
|
doc/_build/*
|
||||||
dist/*
|
dist/*
|
||||||
.idea/*
|
.idea/*
|
||||||
cadquery.egg-info
|
cadquery.egg-info
|
||||||
|
target/*
|
||||||
|
|
|
@ -11,12 +11,16 @@ install:
|
||||||
- python ./setup.py install
|
- python ./setup.py install
|
||||||
- pip install coverage
|
- pip install coverage
|
||||||
- pip install coveralls
|
- pip install coveralls
|
||||||
|
- pip install Sphinx==1.3.2
|
||||||
|
- pip install travis-sphinx
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- coverage run --source=cadquery ./runtests.py
|
- coverage run --source=cadquery ./runtests.py
|
||||||
|
- travis-sphinx --nowarn --source=doc build
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- coveralls
|
- coveralls
|
||||||
|
- travis-sphinx deploy
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -2,182 +2,207 @@ CadQuery
|
||||||
Copyright (C) 2015 Parametric Products Intellectual Holdings, LLC
|
Copyright (C) 2015 Parametric Products Intellectual Holdings, LLC
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the Apache Public License, v 2.0
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
Apache License
|
||||||
Version 3, 29 June 2007
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
other entities that control, are controlled by, or are under common
|
||||||
General Public License.
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
other than an Application or a Combined Work as defined below.
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
by the Library, but which is not otherwise based on the Library.
|
including but not limited to software source code, documentation
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
source, and configuration files.
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
"Object" form shall mean any form resulting from mechanical
|
||||||
Application with the Library. The particular version of the Library
|
transformation or translation of a Source form, including but
|
||||||
with which the Combined Work was made is also called the "Linked
|
not limited to compiled object code, generated documentation,
|
||||||
Version".
|
and conversions to other media types.
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
Object form, made available under the License, as indicated by a
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
copyright notice that is included in or attached to the work
|
||||||
based on the Application, and not on the Linked Version.
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
object code and/or source code for the Application, including any data
|
form, that is based on (or derived from) the Work and for which the
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
without being bound by section 3 of the GNU GPL.
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
facility refers to a function or data to be supplied by an Application
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
that uses the facility (other than as an argument passed when the
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
facility is invoked), then you may convey a copy of the modified
|
(except as stated in this section) patent license to make, have made,
|
||||||
version:
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
ensure that, in the event an Application does not supply the
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
function or data, the facility still operates, and performs
|
modifications, and in Source or Object form, provided that You
|
||||||
whatever part of its purpose remains meaningful, or
|
meet the following conditions:
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
(a) You must give any other recipients of the Work or
|
||||||
this License applicable to that copy.
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
a header file that is part of the Library. You may convey such object
|
that You distribute, all copyright, patent, trademark, and
|
||||||
code under terms of your choice, provided that, if the incorporated
|
attribution notices from the Source form of the Work,
|
||||||
material is not limited to numerical parameters, data structure
|
excluding those notices that do not pertain to any part of
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
the Derivative Works; and
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
Library is used in it and that the Library and its use are
|
distribution, then any Derivative Works that You distribute must
|
||||||
covered by this License.
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
You may add Your own copyright statement to Your modifications and
|
||||||
document.
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
4. Combined Works.
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
taken together, effectively do not restrict modification of the
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
portions of the Library contained in the Combined Work and reverse
|
except as required for reasonable and customary use in describing the
|
||||||
engineering for debugging such modifications, if you also do each of
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
the Library is used in it and that the Library and its use are
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
covered by this License.
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
document.
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
execution, include the copyright notice for the Library among
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
these notices, as well as a reference directing the user to the
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
copies of the GNU GPL and this license document.
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
d) Do one of the following:
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
To apply the Apache License to your work, attach the following
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
a copy of the Library already present on the user's computer
|
replaced with your own identifying information. (Don't include
|
||||||
system, and (b) will operate properly with a modified version
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
of the Library that is interface-compatible with the Linked
|
comment syntax for the file format. We also recommend that a
|
||||||
Version.
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
Copyright [yyyy] [Parametric Products Intellectual Holdings, LLC]
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
Unless required by applicable law or agreed to in writing, software
|
||||||
on the Library, uncombined with any other library facilities,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
conveyed under the terms of this License.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
b) Give prominent notice with the combined library that part of it
|
limitations under the License.
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -1,11 +1,11 @@
|
||||||
README.txt
|
README.txt
|
||||||
setup.cfg
|
setup.cfg
|
||||||
setup.py
|
setup.py
|
||||||
cadquery\CQ.py
|
cadquery\cq.py
|
||||||
cadquery\__init__.py
|
cadquery\__init__.py
|
||||||
cadquery\cq_directive.py
|
cadquery\cq_directive.py
|
||||||
cadquery\selectors.py
|
cadquery\selectors.py
|
||||||
cadquery\workplane.py
|
cadquery\cqgi.py
|
||||||
cadquery\contrib\__init__.py
|
cadquery\contrib\__init__.py
|
||||||
cadquery\freecad_impl\__init__.py
|
cadquery\freecad_impl\__init__.py
|
||||||
cadquery\freecad_impl\exporters.py
|
cadquery\freecad_impl\exporters.py
|
||||||
|
@ -19,4 +19,5 @@ tests\TestCadQuery.py
|
||||||
tests\TestExporters.py
|
tests\TestExporters.py
|
||||||
tests\TestImporters.py
|
tests\TestImporters.py
|
||||||
tests\TestWorkplanes.py
|
tests\TestWorkplanes.py
|
||||||
|
tests\TestCQGI.py
|
||||||
tests\__init__.py
|
tests\__init__.py
|
||||||
|
|
|
@ -4,7 +4,7 @@ What is a CadQuery?
|
||||||
[](https://travis-ci.org/dcowden/cadquery)
|
[](https://travis-ci.org/dcowden/cadquery)
|
||||||
[](https://coveralls.io/r/dcowden/cadquery)
|
[](https://coveralls.io/r/dcowden/cadquery)
|
||||||
[](https://github.com/dcowden/cadquery/releases/tag/v0.3.0)
|
[](https://github.com/dcowden/cadquery/releases/tag/v0.3.0)
|
||||||
[](https://github.com/dcowden/cadquery/blob/master/LICENSE)
|
[](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 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!
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ CadQuery has several goals:
|
||||||
|
|
||||||
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.
|
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
|
||||||
|
============================
|
||||||
|
You can find the full cadquery documentation at http://dcowden.github.io/cadquery
|
||||||
|
|
||||||
|
|
||||||
Getting Started With CadQuery
|
Getting Started With CadQuery
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
@ -30,6 +35,7 @@ It has tons of awesome features like integration with FreeCAD so you can see you
|
||||||
We also have a Google Group to make it easy to get help from other CadQuery users. Please join the group and introduce yourself, and we would also love to hear what you are doing with CadQuery. https://groups.google.com/forum/#!forum/cadquery
|
We also have a Google Group to make it easy to get help from other CadQuery users. Please join the group and introduce yourself, and we would also love to hear what you are doing with CadQuery. https://groups.google.com/forum/#!forum/cadquery
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Why CadQuery instead of OpenSCAD?
|
Why CadQuery instead of OpenSCAD?
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
@ -57,7 +63,8 @@ CadQuery scripts have several key advantages over OpenSCAD:
|
||||||
License
|
License
|
||||||
========
|
========
|
||||||
|
|
||||||
CadQuery is licensed under the terms of the LGPLv3. http://www.gnu.org/copyleft/lesser.html
|
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
|
||||||
|
|
||||||
Where is the GUI?
|
Where is the GUI?
|
||||||
==================
|
==================
|
||||||
|
|
2
CadQuery/Libs/cadquery-lib/build-docs.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
sphinx-build -b html doc target/docs
|
|
@ -1,14 +1,19 @@
|
||||||
Metadata-Version: 1.1
|
Metadata-Version: 1.1
|
||||||
Name: cadquery
|
Name: cadquery
|
||||||
Version: 0.3.0
|
Version: 0.4.0
|
||||||
Summary: CadQuery is a parametric scripting language for creating and traversing CAD models
|
Summary: CadQuery is a parametric scripting language for creating and traversing CAD models
|
||||||
Home-page: https://github.com/dcowden/cadquery
|
Home-page: https://github.com/dcowden/cadquery
|
||||||
Author: David Cowden
|
Author: David Cowden
|
||||||
Author-email: dave.cowden@gmail.com
|
Author-email: dave.cowden@gmail.com
|
||||||
License: LGPL
|
License: Apache Public License 2.0
|
||||||
Description: What is a CadQuery?
|
Description: What is a CadQuery?
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
[](https://travis-ci.org/dcowden/cadquery)
|
||||||
|
[](https://coveralls.io/r/dcowden/cadquery)
|
||||||
|
[](https://github.com/dcowden/cadquery/releases/tag/v0.3.0)
|
||||||
|
[](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 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:
|
CadQuery has several goals:
|
||||||
|
@ -20,18 +25,25 @@ Description: What is a CadQuery?
|
||||||
|
|
||||||
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.
|
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
|
||||||
|
============================
|
||||||
|
You can find the full cadquery documentation at http://dcowden.github.io/cadquery
|
||||||
|
|
||||||
|
|
||||||
Getting Started With CadQuery
|
Getting Started With CadQuery
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
The easiest way to get started with CadQuery is to Install FreeCAD ( version 14 recommended ) (http://www.freecadweb.org/) , and then to use our CadQuery-FreeCAD plugin here:
|
The easiest way to get started with CadQuery is to Install FreeCAD (version 14+) (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 alreadby bundled, and has super-easy installation on Mac, Windows, and Unix.
|
It includes the latest version of cadquery alreadby 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!
|
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!
|
||||||
|
|
||||||
|
We also have a Google Group to make it easy to get help from other CadQuery users. Please join the group and introduce yourself, and we would also love to hear what you are doing with CadQuery. https://groups.google.com/forum/#!forum/cadquery
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Why CadQuery instead of OpenSCAD?
|
Why CadQuery instead of OpenSCAD?
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
@ -59,7 +71,8 @@ Description: What is a CadQuery?
|
||||||
License
|
License
|
||||||
========
|
========
|
||||||
|
|
||||||
CadQuery is licensed under the terms of the LGPLv3. http://www.gnu.org/copyleft/lesser.html
|
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
|
||||||
|
|
||||||
Where is the GUI?
|
Where is the GUI?
|
||||||
==================
|
==================
|
||||||
|
@ -73,7 +86,7 @@ Description: What is a CadQuery?
|
||||||
|
|
||||||
Use these steps if you would like to write CadQuery scripts as a python API. In this case, FreeCAD is used only as a CAD kernel.
|
Use these steps if you would like to write CadQuery scripts as a python API. In this case, FreeCAD is used only as a CAD kernel.
|
||||||
|
|
||||||
1. install FreeCAD, version 0.14 or greater for your platform. http://sourceforge.net/projects/free-cad/.
|
1. install FreeCAD, version 0.12 or greater for your platform. http://sourceforge.net/projects/free-cad/.
|
||||||
|
|
||||||
2. adjust your path if necessary. FreeCAD bundles a python interpreter, but you'll probably want to use your own,
|
2. adjust your path if necessary. FreeCAD bundles a python interpreter, but you'll probably want to use your own,
|
||||||
preferably one that has virtualenv available. To use FreeCAD from any python interpreter, just append the FreeCAD
|
preferably one that has virtualenv available. To use FreeCAD from any python interpreter, just append the FreeCAD
|
||||||
|
@ -131,7 +144,7 @@ Classifier: Intended Audience :: End Users/Desktop
|
||||||
Classifier: Intended Audience :: Information Technology
|
Classifier: Intended Audience :: Information Technology
|
||||||
Classifier: Intended Audience :: Science/Research
|
Classifier: Intended Audience :: Science/Research
|
||||||
Classifier: Intended Audience :: System Administrators
|
Classifier: Intended Audience :: System Administrators
|
||||||
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
Classifier: License :: OSI Approved :: Apache Software License
|
||||||
Classifier: Operating System :: POSIX
|
Classifier: Operating System :: POSIX
|
||||||
Classifier: Operating System :: MacOS
|
Classifier: Operating System :: MacOS
|
||||||
Classifier: Operating System :: Unix
|
Classifier: Operating System :: Unix
|
||||||
|
|
|
@ -2,15 +2,15 @@ MANIFEST.in
|
||||||
README.txt
|
README.txt
|
||||||
setup.cfg
|
setup.cfg
|
||||||
setup.py
|
setup.py
|
||||||
cadquery/CQ.py
|
|
||||||
cadquery/__init__.py
|
cadquery/__init__.py
|
||||||
|
cadquery/cq.py
|
||||||
cadquery/cq_directive.py
|
cadquery/cq_directive.py
|
||||||
|
cadquery/cqgi.py
|
||||||
cadquery/selectors.py
|
cadquery/selectors.py
|
||||||
cadquery.egg-info/PKG-INFO
|
cadquery.egg-info/PKG-INFO
|
||||||
cadquery.egg-info/SOURCES.txt
|
cadquery.egg-info/SOURCES.txt
|
||||||
cadquery.egg-info/dependency_links.txt
|
cadquery.egg-info/dependency_links.txt
|
||||||
cadquery.egg-info/not-zip-safe
|
cadquery.egg-info/not-zip-safe
|
||||||
cadquery.egg-info/pbr.json
|
|
||||||
cadquery.egg-info/top_level.txt
|
cadquery.egg-info/top_level.txt
|
||||||
cadquery/contrib/__init__.py
|
cadquery/contrib/__init__.py
|
||||||
cadquery/freecad_impl/__init__.py
|
cadquery/freecad_impl/__init__.py
|
||||||
|
@ -19,6 +19,7 @@ cadquery/freecad_impl/geom.py
|
||||||
cadquery/freecad_impl/importers.py
|
cadquery/freecad_impl/importers.py
|
||||||
cadquery/freecad_impl/shapes.py
|
cadquery/freecad_impl/shapes.py
|
||||||
cadquery/plugins/__init__.py
|
cadquery/plugins/__init__.py
|
||||||
|
tests/TestCQGI.py
|
||||||
tests/TestCQSelectors.py
|
tests/TestCQSelectors.py
|
||||||
tests/TestCadObjects.py
|
tests/TestCadObjects.py
|
||||||
tests/TestCadQuery.py
|
tests/TestCadQuery.py
|
||||||
|
|
|
@ -7,13 +7,15 @@ from .freecad_impl import importers
|
||||||
#these items are the common implementation
|
#these items are the common implementation
|
||||||
|
|
||||||
#the order of these matter
|
#the order of these matter
|
||||||
from .selectors import NearestToPointSelector,ParallelDirSelector,DirectionSelector,PerpendicularDirSelector,TypeSelector,DirectionMinMaxSelector,StringSyntaxSelector,Selector
|
from .selectors import *
|
||||||
from .CQ import CQ,CQContext,Workplane
|
from .cq import *
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'CQ','Workplane','plugins','selectors','Plane','BoundBox','Matrix','Vector','sortWiresByBuildOrder',
|
'CQ','Workplane','plugins','selectors','Plane','BoundBox','Matrix','Vector','sortWiresByBuildOrder',
|
||||||
'Shape','Vertex','Edge','Wire','Solid','Shell','Compound','exporters', 'importers', 'NearestToPointSelector','ParallelDirSelector','DirectionSelector','PerpendicularDirSelector','TypeSelector','DirectionMinMaxSelector','StringSyntaxSelector','Selector','plugins'
|
'Shape','Vertex','Edge','Wire','Solid','Shell','Compound','exporters', 'importers',
|
||||||
|
'NearestToPointSelector','ParallelDirSelector','DirectionSelector','PerpendicularDirSelector',
|
||||||
|
'TypeSelector','DirectionMinMaxSelector','StringSyntaxSelector','Selector','plugins'
|
||||||
]
|
]
|
||||||
|
|
||||||
__version__ = "0.3.0"
|
__version__ = "0.3.0"
|
||||||
|
|
|
@ -1735,8 +1735,7 @@ class Workplane(CQ):
|
||||||
"""
|
"""
|
||||||
Evaluates the provided function at each point on the stack (ie, eachpoint)
|
Evaluates the provided function at each point on the stack (ie, eachpoint)
|
||||||
and then cuts the result from the context solid.
|
and then cuts the result from the context solid.
|
||||||
:param fcn: a function suitable for use in the eachpoint method: ie, that accepts
|
:param fcn: a function suitable for use in the eachpoint method: ie, that accepts a vector
|
||||||
a vector
|
|
||||||
:param useLocalCoords: same as for :py:meth:`eachpoint`
|
:param useLocalCoords: same as for :py:meth:`eachpoint`
|
||||||
: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
|
||||||
:return: a CQ object that contains the resulting solid
|
:return: a CQ object that contains the resulting solid
|
|
@ -3,19 +3,18 @@ A special directive for including a cq object.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, os, shutil, imp, warnings, cStringIO, re,traceback
|
import traceback
|
||||||
|
|
||||||
from cadquery import *
|
from cadquery import *
|
||||||
|
from cadquery import cqgi
|
||||||
import StringIO
|
import StringIO
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives
|
||||||
|
|
||||||
|
|
||||||
template = """
|
template = """
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<div class="cq" style="text-align:%(txtAlign)s;float:left;">
|
<div class="cq" style="text-align:%(txt_align)s;float:left;">
|
||||||
%(outSVG)s
|
%(out_svg)s
|
||||||
</div>
|
</div>
|
||||||
<div style="clear:both;">
|
<div style="clear:both;">
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,37 +24,39 @@ template_content_indent = ' '
|
||||||
|
|
||||||
|
|
||||||
def cq_directive(name, arguments, options, content, lineno,
|
def cq_directive(name, arguments, options, content, lineno,
|
||||||
content_offset, block_text, state, state_machine):
|
content_offset, block_text, state, state_machine):
|
||||||
|
# only consider inline snippets
|
||||||
#only consider inline snippets
|
|
||||||
plot_code = '\n'.join(content)
|
plot_code = '\n'.join(content)
|
||||||
|
|
||||||
# Since we don't have a filename, use a hash based on the content
|
# Since we don't have a filename, use a hash based on the content
|
||||||
#the script must define a variable called 'out', which is expected to
|
# the script must define a variable called 'out', which is expected to
|
||||||
#be a CQ object
|
# be a CQ object
|
||||||
outSVG = "Your Script Did not assign the 'result' variable!"
|
out_svg = "Your Script Did not assign call build_output() function!"
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_s = StringIO.StringIO()
|
_s = StringIO.StringIO()
|
||||||
exec(plot_code)
|
result = cqgi.parse(plot_code).build()
|
||||||
|
|
||||||
exporters.exportShape(result,"SVG",_s)
|
if result.success:
|
||||||
outSVG = _s.getvalue()
|
exporters.exportShape(result.first_result, "SVG", _s)
|
||||||
except:
|
out_svg = _s.getvalue()
|
||||||
|
else:
|
||||||
|
raise result.exception
|
||||||
|
|
||||||
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
outSVG = traceback.format_exc()
|
out_svg = traceback.format_exc()
|
||||||
|
|
||||||
#now out
|
# now out
|
||||||
# Now start generating the lines of output
|
# Now start generating the lines of output
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
#get rid of new lines
|
# get rid of new lines
|
||||||
outSVG = outSVG.replace('\n','')
|
out_svg = out_svg.replace('\n', '')
|
||||||
|
|
||||||
txtAlign = "left"
|
txt_align = "left"
|
||||||
if options.has_key("align"):
|
if "align" in options:
|
||||||
txtAlign = options['align']
|
txt_align = options['align']
|
||||||
|
|
||||||
lines.extend((template % locals()).split('\n'))
|
lines.extend((template % locals()).split('\n'))
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ def cq_directive(name, arguments, options, content, lineno,
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
setup.app = app
|
setup.app = app
|
||||||
setup.config = app.config
|
setup.config = app.config
|
||||||
|
@ -78,8 +80,6 @@ def setup(app):
|
||||||
options = {'height': directives.length_or_unitless,
|
options = {'height': directives.length_or_unitless,
|
||||||
'width': directives.length_or_percentage_or_unitless,
|
'width': directives.length_or_percentage_or_unitless,
|
||||||
'align': directives.unchanged
|
'align': directives.unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
app.add_directive('cq_plot', cq_directive, True, (0, 2, 0), **options)
|
app.add_directive('cq_plot', cq_directive, True, (0, 2, 0), **options)
|
||||||
|
|
||||||
|
|
||||||
|
|
425
CadQuery/Libs/cadquery-lib/cadquery/cqgi.py
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
"""
|
||||||
|
The CadQuery Gateway Interface.
|
||||||
|
Provides classes and tools for executing CadQuery scripts
|
||||||
|
"""
|
||||||
|
import ast
|
||||||
|
import traceback
|
||||||
|
import time
|
||||||
|
import cadquery
|
||||||
|
|
||||||
|
CQSCRIPT = "<cqscript>"
|
||||||
|
|
||||||
|
def parse(script_source):
|
||||||
|
"""
|
||||||
|
Parses the script as a model, and returns a model.
|
||||||
|
|
||||||
|
If you would prefer to access the underlying model without building it,
|
||||||
|
for example, to inspect its available parameters, construct a CQModel object.
|
||||||
|
|
||||||
|
:param script_source: the script to run. Must be a valid cadquery script
|
||||||
|
:return: a CQModel object that defines the script and allows execution
|
||||||
|
|
||||||
|
"""
|
||||||
|
model = CQModel(script_source)
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
class CQModel(object):
|
||||||
|
"""
|
||||||
|
Represents a Cadquery Script.
|
||||||
|
|
||||||
|
After construction, the metadata property contains
|
||||||
|
a ScriptMetaData object, which describes the model in more detail,
|
||||||
|
and can be used to retrive the parameters defined by the model.
|
||||||
|
|
||||||
|
the build method can be used to generate a 3d model
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, script_source):
|
||||||
|
"""
|
||||||
|
Create an object by parsing the supplied python script.
|
||||||
|
:param script_source: a python script to parse
|
||||||
|
"""
|
||||||
|
self.metadata = ScriptMetadata()
|
||||||
|
self.ast_tree = ast.parse(script_source, CQSCRIPT)
|
||||||
|
self.script_source = script_source
|
||||||
|
self._find_vars()
|
||||||
|
# TODO: pick up other scirpt metadata:
|
||||||
|
# describe
|
||||||
|
# pick up validation methods
|
||||||
|
|
||||||
|
def _find_vars(self):
|
||||||
|
"""
|
||||||
|
Parse the script, and populate variables that appear to be
|
||||||
|
overridable.
|
||||||
|
"""
|
||||||
|
#assumption here: we assume that variable declarations
|
||||||
|
#are only at the top level of the script. IE, we'll ignore any
|
||||||
|
#variable definitions at lower levels of the script
|
||||||
|
|
||||||
|
#we dont want to use the visit interface because here we excplicitly
|
||||||
|
#want to walk only the top level of the tree.
|
||||||
|
assignment_finder = ConstantAssignmentFinder(self.metadata)
|
||||||
|
|
||||||
|
for node in self.ast_tree.body:
|
||||||
|
if isinstance(node, ast.Assign):
|
||||||
|
assignment_finder.visit_Assign(node)
|
||||||
|
|
||||||
|
|
||||||
|
def validate(self, params):
|
||||||
|
"""
|
||||||
|
Determine if the supplied parameters are valid.
|
||||||
|
NOT IMPLEMENTED YET-- raises NotImplementedError
|
||||||
|
:param params: a dictionary of parameters
|
||||||
|
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("not yet implemented")
|
||||||
|
|
||||||
|
def build(self, build_parameters=None):
|
||||||
|
"""
|
||||||
|
Executes the script, using the optional parameters to override those in the model
|
||||||
|
:param build_parameters: a dictionary of variables. The variables must be
|
||||||
|
assignable to the underlying variable type.
|
||||||
|
:raises: Nothing. If there is an exception, it will be on the exception property of the result.
|
||||||
|
This is the interface so that we can return other information on the result, such as the build time
|
||||||
|
:return: a BuildResult object, which includes the status of the result, and either
|
||||||
|
a resulting shape or an exception
|
||||||
|
"""
|
||||||
|
if not build_parameters:
|
||||||
|
build_parameters = {}
|
||||||
|
|
||||||
|
start = time.clock()
|
||||||
|
result = BuildResult()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.set_param_values(build_parameters)
|
||||||
|
collector = ScriptCallback()
|
||||||
|
env = EnvironmentBuilder().with_real_builtins().with_cadquery_objects() \
|
||||||
|
.add_entry("build_object", collector.build_object).build()
|
||||||
|
|
||||||
|
c = compile(self.ast_tree, CQSCRIPT, 'exec')
|
||||||
|
exec (c, env)
|
||||||
|
if collector.has_results():
|
||||||
|
result.set_success_result(collector.outputObjects)
|
||||||
|
else:
|
||||||
|
raise NoOutputError("Script did not call build_object-- no output available.")
|
||||||
|
except Exception, ex:
|
||||||
|
print "Error Executing Script:"
|
||||||
|
result.set_failure_result(ex)
|
||||||
|
traceback.print_exc()
|
||||||
|
print "Full Text of Script:"
|
||||||
|
print self.script_source
|
||||||
|
|
||||||
|
end = time.clock()
|
||||||
|
result.buildTime = end - start
|
||||||
|
return result
|
||||||
|
|
||||||
|
def set_param_values(self, params):
|
||||||
|
model_parameters = self.metadata.parameters
|
||||||
|
|
||||||
|
for k, v in params.iteritems():
|
||||||
|
if k not in model_parameters:
|
||||||
|
raise InvalidParameterError("Cannot set value '%s': not a parameter of the model." % k)
|
||||||
|
|
||||||
|
p = model_parameters[k]
|
||||||
|
p.set_value(v)
|
||||||
|
|
||||||
|
|
||||||
|
class BuildResult(object):
|
||||||
|
"""
|
||||||
|
The result of executing a CadQuery script.
|
||||||
|
The success property contains whether the exeuction was successful.
|
||||||
|
|
||||||
|
If successful, the results property contains a list of all results,
|
||||||
|
and the first_result property contains the first result.
|
||||||
|
|
||||||
|
If unsuccessful, the exception property contains a reference to
|
||||||
|
the stack trace that occurred.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.buildTime = None
|
||||||
|
self.results = []
|
||||||
|
self.first_result = None
|
||||||
|
self.success = False
|
||||||
|
self.exception = None
|
||||||
|
|
||||||
|
def set_failure_result(self, ex):
|
||||||
|
self.exception = ex
|
||||||
|
self.success = False
|
||||||
|
|
||||||
|
def set_success_result(self, results):
|
||||||
|
self.results = results
|
||||||
|
self.first_result = self.results[0]
|
||||||
|
self.success = True
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptMetadata(object):
|
||||||
|
"""
|
||||||
|
Defines the metadata for a parsed CQ Script.
|
||||||
|
the parameters property is a dict of InputParameter objects.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.parameters = {}
|
||||||
|
|
||||||
|
def add_script_parameter(self, p):
|
||||||
|
self.parameters[p.name] = p
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterType(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NumberParameterType(ParameterType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class StringParameterType(ParameterType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BooleanParameterType(ParameterType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InputParameter:
|
||||||
|
"""
|
||||||
|
Defines a parameter that can be supplied when the model is executed.
|
||||||
|
|
||||||
|
Name, varType, and default_value are always available, because they are computed
|
||||||
|
from a variable assignment line of code:
|
||||||
|
|
||||||
|
The others are only available if the script has used define_parameter() to
|
||||||
|
provide additional metadata
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
#: the default value for the variable.
|
||||||
|
self.default_value = None
|
||||||
|
|
||||||
|
#: the name of the parameter.
|
||||||
|
self.name = None
|
||||||
|
|
||||||
|
#: type of the variable: BooleanParameter, StringParameter, NumericParameter
|
||||||
|
self.varType = None
|
||||||
|
|
||||||
|
#: help text describing the variable. Only available if the script used describe_parameter()
|
||||||
|
self.shortDesc = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#: valid values for the variable. Only available if the script used describe_parameter()
|
||||||
|
self.valid_values = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.ast_node = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create(ast_node, var_name, var_type, default_value, valid_values=None, short_desc=None):
|
||||||
|
|
||||||
|
if valid_values is None:
|
||||||
|
valid_values = []
|
||||||
|
|
||||||
|
p = InputParameter()
|
||||||
|
p.ast_node = ast_node
|
||||||
|
p.default_value = default_value
|
||||||
|
p.name = var_name
|
||||||
|
if short_desc is None:
|
||||||
|
p.shortDesc = var_name
|
||||||
|
else:
|
||||||
|
p.shortDesc = short_desc
|
||||||
|
p.varType = var_type
|
||||||
|
p.valid_values = valid_values
|
||||||
|
return p
|
||||||
|
|
||||||
|
def set_value(self, new_value):
|
||||||
|
|
||||||
|
if len(self.valid_values) > 0 and new_value not in self.valid_values:
|
||||||
|
raise InvalidParameterError(
|
||||||
|
"Cannot set value '{0:s}' for parameter '{1:s}': not a valid value. Valid values are {2:s} "
|
||||||
|
.format(str(new_value), self.name, str(self.valid_values)))
|
||||||
|
|
||||||
|
if self.varType == NumberParameterType:
|
||||||
|
try:
|
||||||
|
f = float(new_value)
|
||||||
|
self.ast_node.n = f
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidParameterError(
|
||||||
|
"Cannot set value '{0:s}' for parameter '{1:s}': parameter must be numeric."
|
||||||
|
.format(str(new_value), self.name))
|
||||||
|
|
||||||
|
elif self.varType == StringParameterType:
|
||||||
|
self.ast_node.s = str(new_value)
|
||||||
|
elif self.varType == BooleanParameterType:
|
||||||
|
if new_value:
|
||||||
|
self.ast_node.id = 'True'
|
||||||
|
else:
|
||||||
|
self.ast_node.id = 'False'
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown Type of var: ", str(self.varType))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "InputParameter: {name=%s, type=%s, defaultValue=%s" % (
|
||||||
|
self.name, str(self.varType), str(self.default_value))
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptCallback(object):
|
||||||
|
"""
|
||||||
|
Allows a script to communicate with the container
|
||||||
|
the build_object() method is exposed to CQ scripts, to allow them
|
||||||
|
to return objects to the execution environment
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.outputObjects = []
|
||||||
|
|
||||||
|
def build_object(self, shape):
|
||||||
|
"""
|
||||||
|
return an object to the executing environment
|
||||||
|
:param shape: a cadquery object
|
||||||
|
"""
|
||||||
|
self.outputObjects.append(shape)
|
||||||
|
|
||||||
|
def describe_parameter(self,var, valid_values, short_desc):
|
||||||
|
"""
|
||||||
|
Not yet implemented: allows a script to document
|
||||||
|
extra metadata about the parameters
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_error(self, param, field_list):
|
||||||
|
"""
|
||||||
|
Not implemented yet: allows scripts to indicate that there are problems with inputs
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def has_results(self):
|
||||||
|
return len(self.outputObjects) > 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidParameterError(Exception):
|
||||||
|
"""
|
||||||
|
Raised when an attempt is made to provide a new parameter value
|
||||||
|
that cannot be assigned to the model
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NoOutputError(Exception):
|
||||||
|
"""
|
||||||
|
Raised when the script does not execute the build_object() method to
|
||||||
|
return a solid
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptExecutionError(Exception):
|
||||||
|
"""
|
||||||
|
Represents a script syntax error.
|
||||||
|
Useful for helping clients pinpoint issues with the script
|
||||||
|
interactively
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, line=None, message=None):
|
||||||
|
if line is None:
|
||||||
|
self.line = 0
|
||||||
|
else:
|
||||||
|
self.line = line
|
||||||
|
|
||||||
|
if message is None:
|
||||||
|
self.message = "Unknown Script Error"
|
||||||
|
else:
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def full_message(self):
|
||||||
|
return self.__repr__()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.__repr__()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "ScriptError [Line %s]: %s" % (self.line, self.message)
|
||||||
|
|
||||||
|
|
||||||
|
class EnvironmentBuilder(object):
|
||||||
|
"""
|
||||||
|
Builds an execution environment for a cadquery script.
|
||||||
|
The environment includes the builtins, as well as
|
||||||
|
the other methods the script will need.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.env = {}
|
||||||
|
|
||||||
|
def with_real_builtins(self):
|
||||||
|
return self.with_builtins(__builtins__)
|
||||||
|
|
||||||
|
def with_builtins(self, env_dict):
|
||||||
|
self.env['__builtins__'] = env_dict
|
||||||
|
return self
|
||||||
|
|
||||||
|
def with_cadquery_objects(self):
|
||||||
|
self.env['cadquery'] = cadquery
|
||||||
|
self.env['cq'] = cadquery
|
||||||
|
return self
|
||||||
|
|
||||||
|
def add_entry(self, name, value):
|
||||||
|
self.env[name] = value
|
||||||
|
return self
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
return self.env
|
||||||
|
|
||||||
|
|
||||||
|
class ConstantAssignmentFinder(ast.NodeTransformer):
|
||||||
|
"""
|
||||||
|
Visits a parse tree, and adds script parameters to the cqModel
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cq_model):
|
||||||
|
self.cqModel = cq_model
|
||||||
|
|
||||||
|
def handle_assignment(self, var_name, value_node):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
if type(value_node) == ast.Num:
|
||||||
|
self.cqModel.add_script_parameter(
|
||||||
|
InputParameter.create(value_node, var_name, NumberParameterType, value_node.n))
|
||||||
|
elif type(value_node) == ast.Str:
|
||||||
|
self.cqModel.add_script_parameter(
|
||||||
|
InputParameter.create(value_node, var_name, StringParameterType, value_node.s))
|
||||||
|
elif type(value_node == ast.Name):
|
||||||
|
if value_node.id == 'True':
|
||||||
|
self.cqModel.add_script_parameter(
|
||||||
|
InputParameter.create(value_node, var_name, BooleanParameterType, True))
|
||||||
|
elif value_node.id == 'False':
|
||||||
|
self.cqModel.add_script_parameter(
|
||||||
|
InputParameter.create(value_node, var_name, BooleanParameterType, True))
|
||||||
|
except:
|
||||||
|
print "Unable to handle assignment for variable '%s'" % var_name
|
||||||
|
pass
|
||||||
|
|
||||||
|
def visit_Assign(self, node):
|
||||||
|
|
||||||
|
try:
|
||||||
|
left_side = node.targets[0]
|
||||||
|
|
||||||
|
#do not handle attribute assignments
|
||||||
|
if isinstance(left_side,ast.Attribute):
|
||||||
|
return
|
||||||
|
|
||||||
|
if type(node.value) in [ast.Num, ast.Str, ast.Name]:
|
||||||
|
self.handle_assignment(left_side.id, node.value)
|
||||||
|
elif type(node.value) == ast.Tuple:
|
||||||
|
# we have a multi-value assignment
|
||||||
|
for n, v in zip(left_side.elts, node.value.elts):
|
||||||
|
self.handle_assignment(n.id, v)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
print "Unable to handle assignment for node '%s'" % ast.dump(left_side)
|
||||||
|
|
||||||
|
return node
|
|
@ -1,24 +1,3 @@
|
||||||
"""
|
|
||||||
Copyright (C) 2011-2015 Parametric Products Intellectual Holdings, LLC
|
|
||||||
|
|
||||||
This file is part of CadQuery.
|
|
||||||
|
|
||||||
CadQuery is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
CadQuery is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; If not, see <http://www.gnu.org/licenses/>
|
|
||||||
|
|
||||||
An exporter should provide functionality to accept a shape, and return
|
|
||||||
a string containing the model content.
|
|
||||||
"""
|
|
||||||
import cadquery
|
import cadquery
|
||||||
|
|
||||||
import FreeCAD
|
import FreeCAD
|
||||||
|
|
|
@ -32,9 +32,11 @@ def sortWiresByBuildOrder(wireList, plane, result=[]):
|
||||||
there are no wires inside wires inside wires
|
there are no wires inside wires inside wires
|
||||||
( IE, islands -- we can deal with that later on )
|
( IE, islands -- we can deal with that later on )
|
||||||
none of the wires are construction wires
|
none of the wires are construction wires
|
||||||
|
|
||||||
Compute:
|
Compute:
|
||||||
one or more sets of wires, with the outer wire listed first, and inner
|
one or more sets of wires, with the outer wire listed first, and inner
|
||||||
ones
|
ones
|
||||||
|
|
||||||
Returns, list of lists.
|
Returns, list of lists.
|
||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
|
@ -56,7 +58,7 @@ def sortWiresByBuildOrder(wireList, plane, result=[]):
|
||||||
class Vector(object):
|
class Vector(object):
|
||||||
"""Create a 3-dimensional vector
|
"""Create a 3-dimensional vector
|
||||||
|
|
||||||
:param *args: a 3-d vector, with x-y-z parts.
|
:param args: a 3-d vector, with x-y-z parts.
|
||||||
|
|
||||||
you can either provide:
|
you can either provide:
|
||||||
* nothing (in which case the null vector is return)
|
* nothing (in which case the null vector is return)
|
||||||
|
@ -363,7 +365,8 @@ class Plane(object):
|
||||||
self._calcTransforms()
|
self._calcTransforms()
|
||||||
|
|
||||||
def setOrigin2d(self, x, y):
|
def setOrigin2d(self, x, y):
|
||||||
"""Set a new origin in the plane itself
|
"""
|
||||||
|
Set a new origin in the plane itself
|
||||||
|
|
||||||
Set a new origin in the plane itself. The plane's orientation and
|
Set a new origin in the plane itself. The plane's orientation and
|
||||||
xDrection are unaffected.
|
xDrection are unaffected.
|
||||||
|
@ -374,9 +377,11 @@ class Plane(object):
|
||||||
|
|
||||||
The new coordinates are specified in terms of the current 2-d system.
|
The new coordinates are specified in terms of the current 2-d system.
|
||||||
As an example:
|
As an example:
|
||||||
p = Plane.XY()
|
|
||||||
p.setOrigin2d(2, 2)
|
p = Plane.XY()
|
||||||
p.setOrigin2d(2, 2)
|
p.setOrigin2d(2, 2)
|
||||||
|
p.setOrigin2d(2, 2)
|
||||||
|
|
||||||
results in a plane with its origin at (x, y) = (4, 4) in global
|
results in a plane with its origin at (x, y) = (4, 4) in global
|
||||||
coordinates. Both operations were relative to local coordinates of the
|
coordinates. Both operations were relative to local coordinates of the
|
||||||
plane.
|
plane.
|
||||||
|
|
|
@ -1,29 +1,13 @@
|
||||||
"""
|
|
||||||
Copyright (C) 2011-2015 Parametric Products Intellectual Holdings, LLC
|
|
||||||
|
|
||||||
This file is part of CadQuery.
|
|
||||||
|
|
||||||
CadQuery is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
CadQuery is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; If not, see <http://www.gnu.org/licenses/>
|
|
||||||
|
|
||||||
An exporter should provide functionality to accept a shape, and return
|
|
||||||
a string containing the model content.
|
|
||||||
"""
|
|
||||||
import cadquery
|
import cadquery
|
||||||
from .shapes import Shape
|
from .shapes import Shape
|
||||||
|
|
||||||
import FreeCAD
|
import FreeCAD
|
||||||
import Part
|
import Part
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import urllib as urlreader
|
||||||
|
import tempfile
|
||||||
|
|
||||||
class ImportTypes:
|
class ImportTypes:
|
||||||
STEP = "STEP"
|
STEP = "STEP"
|
||||||
|
@ -51,10 +35,10 @@ def importStep(fileName):
|
||||||
Accepts a file name and loads the STEP file into a cadquery shape
|
Accepts a file name and loads the STEP file into a cadquery shape
|
||||||
:param fileName: The path and name of the STEP file to be imported
|
:param fileName: The path and name of the STEP file to be imported
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#Now read and return the shape
|
#Now read and return the shape
|
||||||
try:
|
try:
|
||||||
rshape = Part.read(fileName)
|
#print fileName
|
||||||
|
rshape = Part.read(fileName)
|
||||||
|
|
||||||
#Make sure that we extract all the solids
|
#Make sure that we extract all the solids
|
||||||
solids = []
|
solids = []
|
||||||
|
@ -64,3 +48,24 @@ def importStep(fileName):
|
||||||
return cadquery.Workplane("XY").newObject(solids)
|
return cadquery.Workplane("XY").newObject(solids)
|
||||||
except:
|
except:
|
||||||
raise ValueError("STEP File Could not be loaded")
|
raise ValueError("STEP File Could not be loaded")
|
||||||
|
|
||||||
|
#Loads a STEP file from an URL into a CQ.Workplane object
|
||||||
|
def importStepFromURL(url):
|
||||||
|
#Now read and return the shape
|
||||||
|
try:
|
||||||
|
webFile = urlreader.urlopen(url)
|
||||||
|
tempFile = tempfile.NamedTemporaryFile(suffix='.step', delete=False)
|
||||||
|
tempFile.write(webFile.read())
|
||||||
|
webFile.close()
|
||||||
|
tempFile.close()
|
||||||
|
|
||||||
|
rshape = Part.read(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:
|
||||||
|
raise ValueError("STEP File from the URL: " + url + " Could not be loaded")
|
||||||
|
|
|
@ -349,6 +349,10 @@ class Shape(object):
|
||||||
|
|
||||||
|
|
||||||
class Vertex(Shape):
|
class Vertex(Shape):
|
||||||
|
"""
|
||||||
|
A Single Point in Space
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, obj, forConstruction=False):
|
def __init__(self, obj, forConstruction=False):
|
||||||
"""
|
"""
|
||||||
Create a vertex from a FreeCAD Vertex
|
Create a vertex from a FreeCAD Vertex
|
||||||
|
@ -373,6 +377,10 @@ class Vertex(Shape):
|
||||||
|
|
||||||
|
|
||||||
class Edge(Shape):
|
class Edge(Shape):
|
||||||
|
"""
|
||||||
|
A trimmed curve that represents the border of a face
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
"""
|
"""
|
||||||
An Edge
|
An Edge
|
||||||
|
@ -425,7 +433,7 @@ class Edge(Shape):
|
||||||
|
|
||||||
def tangentAt(self, locationVector=None):
|
def tangentAt(self, locationVector=None):
|
||||||
"""
|
"""
|
||||||
Compute tangent vector at the specified location.
|
Compute tangent vector at the specified location.
|
||||||
:param locationVector: location to use. Use the center point if None
|
:param locationVector: location to use. Use the center point if None
|
||||||
:return: tangent vector
|
:return: tangent vector
|
||||||
"""
|
"""
|
||||||
|
@ -479,6 +487,10 @@ class Edge(Shape):
|
||||||
|
|
||||||
|
|
||||||
class Wire(Shape):
|
class Wire(Shape):
|
||||||
|
"""
|
||||||
|
A series of connected, ordered Edges, that typically bounds a Face
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
"""
|
"""
|
||||||
A Wire
|
A Wire
|
||||||
|
@ -545,10 +557,11 @@ class Wire(Shape):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Face(Shape):
|
class Face(Shape):
|
||||||
|
"""
|
||||||
|
a bounded surface that represents part of the boundary of a solid
|
||||||
|
"""
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
"""
|
|
||||||
A Face
|
|
||||||
"""
|
|
||||||
self.wrapped = obj
|
self.wrapped = obj
|
||||||
|
|
||||||
self.facetypes = {
|
self.facetypes = {
|
||||||
|
@ -611,6 +624,9 @@ class Face(Shape):
|
||||||
|
|
||||||
|
|
||||||
class Shell(Shape):
|
class Shell(Shape):
|
||||||
|
"""
|
||||||
|
the outer boundary of a surface
|
||||||
|
"""
|
||||||
def __init__(self, wrapped):
|
def __init__(self, wrapped):
|
||||||
"""
|
"""
|
||||||
A Shell
|
A Shell
|
||||||
|
@ -626,6 +642,9 @@ class Shell(Shape):
|
||||||
|
|
||||||
|
|
||||||
class Solid(Shape):
|
class Solid(Shape):
|
||||||
|
"""
|
||||||
|
a single solid
|
||||||
|
"""
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
"""
|
"""
|
||||||
A Solid
|
A Solid
|
||||||
|
@ -649,36 +668,36 @@ class Solid(Shape):
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeBox(cls, length, width, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1)):
|
def makeBox(cls, length, width, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1)):
|
||||||
"""
|
"""
|
||||||
makeBox(length,width,height,[pnt,dir]) -- Make a box located\nin pnt with the d
|
makeBox(length,width,height,[pnt,dir]) -- Make a box located in pnt with the dimensions (length,width,height)
|
||||||
imensions (length,width,height)\nBy default pnt=Vector(0,0,0) and dir=Vector(0,0,1)'
|
By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCADPart.makeBox(length, width, height, pnt.wrapped, dir.wrapped))
|
return Shape.cast(FreeCADPart.makeBox(length, width, height, pnt.wrapped, dir.wrapped))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeCone(cls, radius1, radius2, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360):
|
def makeCone(cls, radius1, radius2, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360):
|
||||||
"""
|
"""
|
||||||
'makeCone(radius1,radius2,height,[pnt,dir,angle]) --
|
Make a cone with given radii and height
|
||||||
Make a cone with given radii and height\nBy default pnt=Vector(0,0,0),
|
By default pnt=Vector(0,0,0),
|
||||||
dir=Vector(0,0,1) and angle=360'
|
dir=Vector(0,0,1) and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCADPart.makeCone(radius1, radius2, height, pnt.wrapped, dir.wrapped, angleDegrees))
|
return Shape.cast(FreeCADPart.makeCone(radius1, radius2, height, pnt.wrapped, dir.wrapped, angleDegrees))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeCylinder(cls, radius, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360):
|
def makeCylinder(cls, radius, height, pnt=Vector(0, 0, 0), dir=Vector(0, 0, 1), angleDegrees=360):
|
||||||
"""
|
"""
|
||||||
makeCylinder(radius,height,[pnt,dir,angle]) --
|
makeCylinder(radius,height,[pnt,dir,angle]) --
|
||||||
Make a cylinder with a given radius and height
|
Make a cylinder with a given radius and height
|
||||||
By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360'
|
By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCADPart.makeCylinder(radius, height, pnt.wrapped, dir.wrapped, angleDegrees))
|
return Shape.cast(FreeCADPart.makeCylinder(radius, height, pnt.wrapped, dir.wrapped, angleDegrees))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeTorus(cls, radius1, radius2, pnt=None, dir=None, angleDegrees1=None, angleDegrees2=None):
|
def makeTorus(cls, radius1, radius2, pnt=None, dir=None, angleDegrees1=None, angleDegrees2=None):
|
||||||
"""
|
"""
|
||||||
makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle]) --
|
makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle]) --
|
||||||
Make a torus with agiven radii and angles
|
Make a torus with agiven radii and angles
|
||||||
By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0
|
By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0
|
||||||
,angle1=360 and angle=360'
|
,angle1=360 and angle=360'
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCADPart.makeTorus(radius1, radius2, pnt, dir, angleDegrees1, angleDegrees2))
|
return Shape.cast(FreeCADPart.makeTorus(radius1, radius2, pnt, dir, angleDegrees1, angleDegrees2))
|
||||||
|
|
||||||
|
@ -708,10 +727,8 @@ class Solid(Shape):
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeWedge(cls, xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max, pnt=None, dir=None):
|
def makeWedge(cls, xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max, pnt=None, dir=None):
|
||||||
"""
|
"""
|
||||||
'makeWedge(xmin, ymin, zmin, z2min, x2min,
|
Make a wedge located in pnt
|
||||||
xmax, ymax, zmax, z2max, x2max,[pnt, dir])
|
By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)
|
||||||
Make a wedge located in pnt\nBy default pnt=Vector(0,0,0) and dir=Vec
|
|
||||||
tor(0,0,1)'
|
|
||||||
"""
|
"""
|
||||||
return Shape.cast(
|
return Shape.cast(
|
||||||
FreeCADPart.makeWedge(xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max, pnt, dir))
|
FreeCADPart.makeWedge(xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max, pnt, dir))
|
||||||
|
@ -719,9 +736,8 @@ class Solid(Shape):
|
||||||
@classmethod
|
@classmethod
|
||||||
def makeSphere(cls, radius, pnt=None, dir=None, angleDegrees1=None, angleDegrees2=None, angleDegrees3=None):
|
def makeSphere(cls, radius, pnt=None, dir=None, angleDegrees1=None, angleDegrees2=None, angleDegrees3=None):
|
||||||
"""
|
"""
|
||||||
'makeSphere(radius,[pnt, dir, angle1,angle2,angle3]) --
|
Make a sphere with a given radius
|
||||||
Make a sphere with a giv
|
By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360
|
||||||
en radius\nBy default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360'
|
|
||||||
"""
|
"""
|
||||||
return Shape.cast(FreeCADPart.makeSphere(radius, pnt.wrapped, dir.wrapped, angleDegrees1, angleDegrees2, angleDegrees3))
|
return Shape.cast(FreeCADPart.makeSphere(radius, pnt.wrapped, dir.wrapped, angleDegrees1, angleDegrees2, angleDegrees3))
|
||||||
|
|
||||||
|
@ -733,11 +749,11 @@ class Solid(Shape):
|
||||||
Though the signature may appear to be similar enough to extrudeLinear to merit combining them, the
|
Though the signature may appear to be similar enough to extrudeLinear to merit combining them, the
|
||||||
construction methods used here are different enough that they should be separate.
|
construction methods used here are different enough that they should be separate.
|
||||||
|
|
||||||
At a high level, the steps followed ar:
|
At a high level, the steps followed are:
|
||||||
(1) accept a set of wires
|
(1) accept a set of wires
|
||||||
(2) create another set of wires like this one, but which are transformed and rotated
|
(2) create another set of wires like this one, but which are transformed and rotated
|
||||||
(3) create a ruledSurface between the sets of wires
|
(3) create a ruledSurface between the sets of wires
|
||||||
(40 create a shell and compute the resulting object
|
(4) create a shell and compute the resulting object
|
||||||
|
|
||||||
:param outerWire: the outermost wire, a cad.Wire
|
:param outerWire: the outermost wire, a cad.Wire
|
||||||
:param innerWires: a list of inner wires, a list of cad.Wire
|
:param innerWires: a list of inner wires, a list of cad.Wire
|
||||||
|
@ -930,6 +946,10 @@ class Solid(Shape):
|
||||||
|
|
||||||
|
|
||||||
class Compound(Shape):
|
class Compound(Shape):
|
||||||
|
"""
|
||||||
|
a collection of disconnected solids
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
"""
|
"""
|
||||||
An Edge
|
An Edge
|
||||||
|
|
|
@ -65,3 +65,9 @@ v0.3.0
|
||||||
* Add the ability to find the center of the bounding box, rather than the center of mass (thanks @huskier) #122
|
* Add the ability to find the center of the bounding box, rather than the center of mass (thanks @huskier) #122
|
||||||
* Changed normalize function to normalized to match OCC/PythonOCC nomenclature #124
|
* Changed normalize function to normalized to match OCC/PythonOCC nomenclature #124
|
||||||
* Added a label attribute to all freecad_impl.shapes so that they can have IDs attached to them #124
|
* Added a label attribute to all freecad_impl.shapes so that they can have IDs attached to them #124
|
||||||
|
|
||||||
|
v0.4.0
|
||||||
|
------
|
||||||
|
* Added Documentation, which is available on dcowden.github.io/cadquery
|
||||||
|
* Added CQGI, an adapter API that standardizes use of cadquery from within structured execution environments
|
||||||
|
* Added ability to import STEP files from a web URL (thanks @huskier ) #128
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
# Makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
|
||||||
SPHINXOPTS =
|
|
||||||
SPHINXBUILD = sphinx-build
|
|
||||||
PAPER =
|
|
||||||
BUILDDIR = _build
|
|
||||||
|
|
||||||
# Internal variables.
|
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
|
||||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|
||||||
# the i18n builder cannot share the environment and doctrees with the others
|
|
||||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|
||||||
|
|
||||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
|
||||||
|
|
||||||
help:
|
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
|
||||||
@echo " html to make standalone HTML files"
|
|
||||||
@echo " dirhtml to make HTML files named index.html in directories"
|
|
||||||
@echo " singlehtml to make a single large HTML file"
|
|
||||||
@echo " pickle to make pickle files"
|
|
||||||
@echo " json to make JSON files"
|
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
|
||||||
@echo " qthelp to make HTML files and a qthelp project"
|
|
||||||
@echo " devhelp to make HTML files and a Devhelp project"
|
|
||||||
@echo " epub to make an epub"
|
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
|
||||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
|
||||||
@echo " text to make text files"
|
|
||||||
@echo " man to make manual pages"
|
|
||||||
@echo " texinfo to make Texinfo files"
|
|
||||||
@echo " info to make Texinfo files and run them through makeinfo"
|
|
||||||
@echo " gettext to make PO message catalogs"
|
|
||||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
|
||||||
@echo " linkcheck to check all external links for integrity"
|
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm -rf $(BUILDDIR)/*
|
|
||||||
|
|
||||||
html:
|
|
||||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
|
||||||
|
|
||||||
dirhtml:
|
|
||||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
|
||||||
|
|
||||||
singlehtml:
|
|
||||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
|
||||||
|
|
||||||
pickle:
|
|
||||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the pickle files."
|
|
||||||
|
|
||||||
json:
|
|
||||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the JSON files."
|
|
||||||
|
|
||||||
htmlhelp:
|
|
||||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
|
||||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
|
||||||
|
|
||||||
qthelp:
|
|
||||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
|
||||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
|
||||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CadQuery.qhcp"
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CadQuery.qhc"
|
|
||||||
|
|
||||||
devhelp:
|
|
||||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished."
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/CadQuery"
|
|
||||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CadQuery"
|
|
||||||
@echo "# devhelp"
|
|
||||||
|
|
||||||
epub:
|
|
||||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
|
||||||
|
|
||||||
latex:
|
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
|
||||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
|
||||||
"(use \`make latexpdf' here to do that automatically)."
|
|
||||||
|
|
||||||
latexpdf:
|
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo "Running LaTeX files through pdflatex..."
|
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
|
||||||
|
|
||||||
text:
|
|
||||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
|
||||||
|
|
||||||
man:
|
|
||||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
|
||||||
|
|
||||||
texinfo:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
|
||||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
|
||||||
"(use \`make info' here to do that automatically)."
|
|
||||||
|
|
||||||
info:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo "Running Texinfo files through makeinfo..."
|
|
||||||
make -C $(BUILDDIR)/texinfo info
|
|
||||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
|
||||||
|
|
||||||
gettext:
|
|
||||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
|
||||||
|
|
||||||
changes:
|
|
||||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
|
||||||
@echo
|
|
||||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
|
||||||
|
|
||||||
linkcheck:
|
|
||||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
|
||||||
@echo
|
|
||||||
@echo "Link check complete; look for any errors in the above output " \
|
|
||||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
|
||||||
|
|
||||||
doctest:
|
|
||||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
|
||||||
@echo "Testing of doctests in the sources finished, look at the " \
|
|
||||||
"results in $(BUILDDIR)/doctest/output.txt."
|
|
|
@ -1 +1,2 @@
|
||||||
This documentation should be generated with sphinxdoc
|
This documentation should be generated with sphinxdoc.
|
||||||
|
see ../build-docs.sh
|
||||||
|
|
BIN
CadQuery/Libs/cadquery-lib/doc/_static/block.png
vendored
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 9.2 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/cqlogo.png
vendored
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/pillowblock.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/000.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/001.png
vendored
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/002.png
vendored
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/003.png
vendored
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/004.png
vendored
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/quickstart/005.png
vendored
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
CadQuery/Libs/cadquery-lib/doc/_static/simpleblock.png
vendored
Normal file
After Width: | Height: | Size: 8.5 KiB |
|
@ -4,34 +4,29 @@
|
||||||
CadQuery API Reference
|
CadQuery API Reference
|
||||||
***********************
|
***********************
|
||||||
|
|
||||||
|
The CadQuery API is made up of 3 main objects:
|
||||||
|
|
||||||
|
* **CQ** - An object that wraps a topological entity.
|
||||||
|
* **Workplane** -- A subclass of CQ, that applies in a 2-D modelling context.
|
||||||
|
* **Selector** -- Filter and select things
|
||||||
|
|
||||||
|
This page lists methods of these objects grouped by **functional area**
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
This page lists api methods grouped by functional area.
|
This page lists api methods grouped by functional area.
|
||||||
Use :ref:`classreference` to see methods alphabetically by class.
|
Use :ref:`classreference` to see methods alphabetically by class.
|
||||||
|
|
||||||
Primary Objects
|
|
||||||
----------------
|
|
||||||
|
|
||||||
The CadQuery API is made up of 3 main objects:
|
|
||||||
|
|
||||||
* **CQ** - Basic Selection, and 3d operations
|
|
||||||
* **Workplane** -- Draw in 2-d to make 3d features
|
|
||||||
* **Selector** -- Filter and select things
|
|
||||||
|
|
||||||
The sections below list methods of these objects grouped by **functional area**
|
|
||||||
|
|
||||||
Initialization
|
Initialization
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
.. automodule:: cadquery
|
.. currentmodule:: cadquery
|
||||||
|
|
||||||
Creating new workplanes and object chains
|
Creating new workplanes and object chains
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
CQ
|
CQ
|
||||||
Workplane
|
Workplane
|
||||||
CQ.workplane
|
|
||||||
|
|
||||||
|
|
||||||
.. _2dOperations:
|
.. _2dOperations:
|
||||||
|
@ -39,10 +34,14 @@ Creating new workplanes and object chains
|
||||||
2-d Operations
|
2-d Operations
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Creating 2-d constructs that can be used to create 3 d features
|
Creating 2-d constructs that can be used to create 3 d features.
|
||||||
|
|
||||||
|
All 2-d operations require a **Workplane** object to be created.
|
||||||
|
|
||||||
|
.. currentmodule:: cadquery
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
Workplane.center
|
Workplane.center
|
||||||
Workplane.lineTo
|
Workplane.lineTo
|
||||||
Workplane.line
|
Workplane.line
|
||||||
Workplane.vLine
|
Workplane.vLine
|
||||||
|
@ -67,7 +66,9 @@ Creating 2-d constructs that can be used to create 3 d features
|
||||||
3-d Operations
|
3-d Operations
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Methods that create 3d features
|
Some 3-d operations also require an active 2-d workplane, but some do not.
|
||||||
|
|
||||||
|
3-d operations that require a 2-d workplane to be active:
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
Workplane.cboreHole
|
Workplane.cboreHole
|
||||||
|
@ -80,12 +81,29 @@ Methods that create 3d features
|
||||||
Workplane.box
|
Workplane.box
|
||||||
Workplane.union
|
Workplane.union
|
||||||
Workplane.combine
|
Workplane.combine
|
||||||
|
|
||||||
|
3-d operations that do NOT require a 2-d workplane to be active:
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
CQ.shell
|
CQ.shell
|
||||||
CQ.fillet
|
CQ.fillet
|
||||||
CQ.split
|
CQ.split
|
||||||
|
CQ.rotate
|
||||||
CQ.rotateAboutCenter
|
CQ.rotateAboutCenter
|
||||||
CQ.translate
|
CQ.translate
|
||||||
|
|
||||||
|
File Management and Export
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
CQ.toSvg
|
||||||
|
CQ.exportSvg
|
||||||
|
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
importers.importStep
|
||||||
|
exporters.exportShape
|
||||||
|
|
||||||
|
|
||||||
Iteration Methods
|
Iteration Methods
|
||||||
------------------
|
------------------
|
||||||
|
@ -99,8 +117,8 @@ Methods that allow iteration over the stack or objects
|
||||||
|
|
||||||
.. _stackMethods:
|
.. _stackMethods:
|
||||||
|
|
||||||
Stack Methods
|
Stack and Selector Methods
|
||||||
-----------------
|
------------------------------
|
||||||
|
|
||||||
CadQuery methods that operate on the stack
|
CadQuery methods that operate on the stack
|
||||||
|
|
||||||
|
@ -127,14 +145,24 @@ CadQuery methods that operate on the stack
|
||||||
Selectors
|
Selectors
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Objects that filter and select CAD objects
|
Objects that filter and select CAD objects. Selectors are used to select existing geometry
|
||||||
|
as a basis for futher operations.
|
||||||
|
|
||||||
|
.. currentmodule:: cadquery
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
NearestToPointSelector
|
|
||||||
ParallelDirSelector
|
NearestToPointSelector
|
||||||
DirectionSelector
|
BoxSelector
|
||||||
PerpendicularDirSelector
|
BaseDirSelector
|
||||||
TypeSelector
|
ParallelDirSelector
|
||||||
DirectionMinMaxSelector
|
DirectionSelector
|
||||||
StringSyntaxSelector
|
PerpendicularDirSelector
|
||||||
|
TypeSelector
|
||||||
|
DirectionMinMaxSelector
|
||||||
|
BinarySelector
|
||||||
|
AndSelector
|
||||||
|
SumSelector
|
||||||
|
SubtractSelector
|
||||||
|
InverseSelector
|
||||||
|
StringSyntaxSelector
|
||||||
|
|
|
@ -1,243 +0,0 @@
|
||||||
.. _cadquerybasics:
|
|
||||||
|
|
||||||
.. automodule:: cadquery
|
|
||||||
|
|
||||||
*************************
|
|
||||||
Introduction to CadQuery
|
|
||||||
*************************
|
|
||||||
|
|
||||||
This page describes basic CadQuery concepts and goals. CadQuery is still under development, but already offers a lot.
|
|
||||||
|
|
||||||
======================
|
|
||||||
Goals and Principles
|
|
||||||
======================
|
|
||||||
|
|
||||||
|
|
||||||
Principle 1: Intuitive Construction
|
|
||||||
====================================
|
|
||||||
|
|
||||||
CadQuery aims to make building models using python scripting easy and intuitive.
|
|
||||||
CadQuery strives to allow scripts to read roughly as a human would describe an object verbally.
|
|
||||||
|
|
||||||
For example, consider this object:
|
|
||||||
|
|
||||||
.. image:: _static/quickstart.png
|
|
||||||
|
|
||||||
A human would describe this as:
|
|
||||||
|
|
||||||
"A block 80mm square x 30mm thick , with countersunk holes for M2 socket head cap screws
|
|
||||||
at the corners, and a circular pocket 22mm in diameter in the middle for a bearing"
|
|
||||||
|
|
||||||
The goal is to have the CadQuery script that produces this object be as close as possible to the english phrase
|
|
||||||
a human would use.
|
|
||||||
|
|
||||||
|
|
||||||
Principle 2: Capture Design Intent
|
|
||||||
====================================
|
|
||||||
|
|
||||||
The features that are **not** part of the part description above are just as important as those that are. For example, most
|
|
||||||
humans will assume that:
|
|
||||||
|
|
||||||
* The countersunk holes are spaced a uniform distance from the edges
|
|
||||||
* The circular pocket is in the center of the block, no matter how big the block is
|
|
||||||
|
|
||||||
If you have experience with 3D CAD systems, you also know that there is a key design intent built into this object.
|
|
||||||
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.
|
|
||||||
|
|
||||||
Many scripting langauges to 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
|
|
||||||
the design intent just like a human would when creating a drawing or building an object.
|
|
||||||
|
|
||||||
In fact, though many people know how to use 3D CAD systems, few understand how important the way that an object is built
|
|
||||||
impact its maintainability and resiliency to design changes.
|
|
||||||
|
|
||||||
|
|
||||||
Principle 3: Plugins as first class citizens
|
|
||||||
============================================
|
|
||||||
|
|
||||||
Any system for building 3D models will evolve to contain an immense number of libraries and feature builders. It is
|
|
||||||
important that these can be seamlessly included into the core and used alongside the built in libraries. Plugins
|
|
||||||
should be easy to install and familiar to use.
|
|
||||||
|
|
||||||
|
|
||||||
Principle 4: CAD models as source code makes sense
|
|
||||||
==================================================================
|
|
||||||
|
|
||||||
It is surprising that the world of 3D CAD is primarily dominated by systems that create opaque binary files.
|
|
||||||
Just like the world of software, CAD models are very complex.
|
|
||||||
|
|
||||||
CAD models have many things in common with software, and would benefit greatly from the use of tools that are standard
|
|
||||||
in the software industry, such as:
|
|
||||||
|
|
||||||
1. Easily re-using features between objects
|
|
||||||
2. Storing objects using version control systems
|
|
||||||
3. Computing the differences between objects by using source control tools
|
|
||||||
4. Share objects on the internet
|
|
||||||
5. Automate testing and generation by allowing objects to be built from within libraries
|
|
||||||
|
|
||||||
CadQuery is designed to make 3D content creation easy enough that the above benefits can be attained without more work
|
|
||||||
than using existing 'opaque', 'point and click' solutions.
|
|
||||||
|
|
||||||
======================
|
|
||||||
3D Topology Primer
|
|
||||||
======================
|
|
||||||
|
|
||||||
Before talking about CadQuery, it makes sense to talk a little about 3D CAD Topology. CadQuery is based upon the
|
|
||||||
OpenCascade kernel, which is uses Boundary Representations ( BREP ) for objects. This just means that objects
|
|
||||||
are defined by their enclosing surfaces.
|
|
||||||
|
|
||||||
When working in a BREP system, these fundamental constructs exist to define a shape ( working up the food chain):
|
|
||||||
|
|
||||||
:vertex: a single point in space
|
|
||||||
:edge: a connection between two or more vertices along a particular path ( called a curve )
|
|
||||||
:wire: a collection of edges that are connected together.
|
|
||||||
:face: a set of edges or wires that enclose a surface
|
|
||||||
:shell: a collection of faces that are connected together along some of their edges
|
|
||||||
:solid: a shell that has a closed interior
|
|
||||||
:compound: a collection of solids
|
|
||||||
|
|
||||||
When using CadQuery, all of these objects are created, hopefully with the least possible work. In the actual CAD
|
|
||||||
kernel, there are another set of Geometrical constructs involved as well. For example, an arc-shaped edge will
|
|
||||||
hold a reference to an underlying curve that is a full cricle, and each linear edge holds underneath it the equation
|
|
||||||
for a line. CadQuery shields you from these constructs.
|
|
||||||
|
|
||||||
======================
|
|
||||||
CadQuery Concepts
|
|
||||||
======================
|
|
||||||
|
|
||||||
CadQuery provides functions in several key areas. As you would expect, many are devoted to easy creation of
|
|
||||||
2D and 3D features. But just as many, if not more, are for navigating and selecting objects.
|
|
||||||
|
|
||||||
* CQ, the CadQuery object
|
|
||||||
* Workplanes
|
|
||||||
* Selection
|
|
||||||
* 2D Construction
|
|
||||||
* 3D Construction
|
|
||||||
* construction geometry
|
|
||||||
* easy iteration
|
|
||||||
|
|
||||||
|
|
||||||
CQ, the CadQuery Object
|
|
||||||
========================
|
|
||||||
|
|
||||||
The CadQuery object wraps a BREP feature, and provides functionality around it. Typical examples include rotating,
|
|
||||||
transforming, combining objects, and creating workplanes.
|
|
||||||
|
|
||||||
See :ref:`apireference` to learn more.
|
|
||||||
|
|
||||||
|
|
||||||
Workplanes
|
|
||||||
======================
|
|
||||||
|
|
||||||
Workplanes represent a plane in space, from which other features can be located. They have a center point and a local
|
|
||||||
coordinate system.
|
|
||||||
|
|
||||||
The most common way to create a workplane is to locate one on the face of a solid. You can also create new workplanes
|
|
||||||
in space, or relative to other planes using offsets or rotations.
|
|
||||||
|
|
||||||
The most powerful feature of workplanes is that they allow you to work in 2D space in the coordinate system of the
|
|
||||||
workplane, and then build 3D features based on local coordinates. This makes scripts much easier to create and maintain.
|
|
||||||
|
|
||||||
See :py:class:`Workplane` to learn more
|
|
||||||
|
|
||||||
|
|
||||||
2D Construction
|
|
||||||
======================
|
|
||||||
|
|
||||||
Once you create a workplane, you can work in 2D, and then later use the features you create to make 3D objects.
|
|
||||||
You'll find all of the 2D constructs you expect-- circles, lines, arcs, mirroring, points, etc.
|
|
||||||
|
|
||||||
See :ref:`2dOperations` to learn more.
|
|
||||||
|
|
||||||
|
|
||||||
3D Construction
|
|
||||||
======================
|
|
||||||
|
|
||||||
You can construct 3D primatives 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.
|
|
||||||
|
|
||||||
See :ref:`3doperations` to learn more.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Selectors
|
|
||||||
======================
|
|
||||||
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
|
|
||||||
Think of selectors as the equivalent of your hand and mouse, were you to build an object using a conventional CAD system.
|
|
||||||
|
|
||||||
You can learn more about selectors :ref:`selectors`
|
|
||||||
|
|
||||||
|
|
||||||
Construction Geometry
|
|
||||||
======================
|
|
||||||
|
|
||||||
Construction geometry are features that are not part of the object, but are only defined to aid in building the object.
|
|
||||||
A common example might be to define a rectangle, and then use the corners to define a the location of a set of holes.
|
|
||||||
|
|
||||||
Most CadQuery construction methods provide a forConstruction keyword, which creates a feature that will only be used
|
|
||||||
to locate other features
|
|
||||||
|
|
||||||
|
|
||||||
The Stack
|
|
||||||
======================
|
|
||||||
|
|
||||||
As you work in CadQuery, each operation returns a new CadQuery object with the result of that operations. Each CadQuery
|
|
||||||
object has a list of objects, and a reference to its parent.
|
|
||||||
|
|
||||||
You can always go backwards to older operations by removing the current object from the stack. For example::
|
|
||||||
|
|
||||||
CQ(someObject).faces(">Z").first().vertices()
|
|
||||||
|
|
||||||
returns a CadQuery object that contains all of the vertices on highest face of someObject. But you can always move
|
|
||||||
backwards in the stack to get the face as well::
|
|
||||||
|
|
||||||
CQ(someObject).faces(">Z").first().vertices().end() #returns the same as CQ(someObject).faces(">Z").first()
|
|
||||||
|
|
||||||
You can browse stack access methods here :ref:`stackMethods`
|
|
||||||
|
|
||||||
|
|
||||||
Chaining
|
|
||||||
======================
|
|
||||||
|
|
||||||
All CadQuery methods return another CadQuery object, so that you can chain the methods together fluently. Use
|
|
||||||
the core CQ methods to get at the objects that were created.
|
|
||||||
|
|
||||||
|
|
||||||
The Context Solid
|
|
||||||
======================
|
|
||||||
|
|
||||||
Most of the time, you are building a single object, and adding features to that single object. CadQuery watches
|
|
||||||
your operations, and defines the first solid object created as the 'context solid'. After that, any features
|
|
||||||
you create are automatically combined ( unless you specify otherwise) with that solid. This happens even if the
|
|
||||||
solid was created a long way up in the stack. For example::
|
|
||||||
|
|
||||||
Workplane('XY').box(1,2,3).faces(">Z").circle(0.25).extrude()
|
|
||||||
|
|
||||||
Will create a 1x2x3 box, with a cylindrical boss extending from the top face. It was not necessary to manually
|
|
||||||
combine the cylinder created by extruding the circle with the box, because the default behavior for extrude is
|
|
||||||
to combine the result with the context solid. The hole() method works similarly-- CadQuery presumes that you want
|
|
||||||
to subtract the hole from the context solid.
|
|
||||||
|
|
||||||
If you want to avoid this, you can specified combine=False, and CadQuery will create the solid separately.
|
|
||||||
|
|
||||||
|
|
||||||
Iteration
|
|
||||||
======================
|
|
||||||
|
|
||||||
CAD models often have repeated geometry, and its really annoying to resort to for loops to construct features.
|
|
||||||
Many CadQuery methods operate automatically on each element on the stack, so that you don't have to write loops.
|
|
||||||
For example, this::
|
|
||||||
|
|
||||||
Workplane('XY').box(1,2,3).faces(">Z").vertices().circle(0.5)
|
|
||||||
|
|
||||||
Will actually create 4 circles, because vertices() selects 4 vertices of a rectangular face, and the circle() method
|
|
||||||
iterates on each member of the stack.
|
|
||||||
|
|
||||||
This is really useful to remember when you author your own plugins. :py:meth:`Workplane.each` is useful for this purpose.
|
|
|
@ -1,7 +1,7 @@
|
||||||
.. _classreference:
|
.. _classreference:
|
||||||
|
|
||||||
*************************
|
*************************
|
||||||
CadQuery Class Reference
|
CadQuery Class Summary
|
||||||
*************************
|
*************************
|
||||||
|
|
||||||
This page documents all of the methods and functions of the CadQuery classes, organized alphabatically.
|
This page documents all of the methods and functions of the CadQuery classes, organized alphabatically.
|
||||||
|
@ -10,120 +10,61 @@ This page documents all of the methods and functions of the CadQuery classes, or
|
||||||
|
|
||||||
For a listing organized by functional area, see the :ref:`apireference`
|
For a listing organized by functional area, see the :ref:`apireference`
|
||||||
|
|
||||||
.. automodule:: cadquery
|
.. currentmodule:: cadquery
|
||||||
|
|
||||||
Core Classes
|
Core Classes
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
CQ
|
CQ
|
||||||
Plane
|
Workplane
|
||||||
Workplane
|
|
||||||
|
|
||||||
Primitives
|
Topological Classes
|
||||||
-----------------
|
----------------------
|
||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
|
Shape
|
||||||
Plane
|
|
||||||
Vector
|
|
||||||
Solid
|
|
||||||
Shell
|
|
||||||
Wire
|
|
||||||
Edge
|
|
||||||
Vertex
|
Vertex
|
||||||
|
Edge
|
||||||
|
Wire
|
||||||
|
Face
|
||||||
Selectors
|
Shell
|
||||||
---------------------
|
Solid
|
||||||
|
Compound
|
||||||
.. autosummary::
|
|
||||||
NearestToPointSelector
|
|
||||||
ParallelDirSelector
|
|
||||||
DirectionSelector
|
|
||||||
PerpendicularDirSelector
|
|
||||||
TypeSelector
|
|
||||||
DirectionMinMaxSelector
|
|
||||||
StringSyntaxSelector
|
|
||||||
|
|
||||||
Geometry Classes
|
Geometry Classes
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. autoclass:: Vector
|
.. autosummary::
|
||||||
:members:
|
Vector
|
||||||
|
Matrix
|
||||||
.. autoclass:: Plane
|
Plane
|
||||||
:members:
|
|
||||||
|
|
||||||
Shape Base Class
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
All objects inherit from Shape, which as basic manipulation methods:
|
|
||||||
|
|
||||||
.. autoclass:: Shape
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Primitive Classes
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. autoclass:: Solid
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Shell
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Wire
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Edge
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Vertex
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
Core Classes
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. autoclass:: CQ
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: Plane
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: Workplane
|
|
||||||
:members:
|
|
||||||
:inherited-members:
|
|
||||||
|
|
||||||
|
|
||||||
Selector Classes
|
Selector Classes
|
||||||
------------------------
|
---------------------
|
||||||
|
|
||||||
.. autoclass:: Selector
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: NearestToPointSelector
|
.. autosummary::
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: ParallelDirSelector
|
Selector
|
||||||
:members:
|
NearestToPointSelector
|
||||||
|
BoxSelector
|
||||||
|
BaseDirSelector
|
||||||
|
ParallelDirSelector
|
||||||
|
DirectionSelector
|
||||||
|
PerpendicularDirSelector
|
||||||
|
TypeSelector
|
||||||
|
DirectionMinMaxSelector
|
||||||
|
BinarySelector
|
||||||
|
AndSelector
|
||||||
|
SumSelector
|
||||||
|
SubtractSelector
|
||||||
|
InverseSelector
|
||||||
|
StringSyntaxSelector
|
||||||
|
|
||||||
.. autoclass:: DirectionSelector
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: PerpendicularDirSelector
|
Class Details
|
||||||
:members:
|
---------------
|
||||||
|
|
||||||
.. autoclass:: TypeSelector
|
.. automodule:: cadquery
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: DirectionMinMaxSelector
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: StringSyntaxSelector
|
|
||||||
:members:
|
:members:
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
import os.path
|
import os.path
|
||||||
print "working path is %s" % os.getcwd()
|
#print "working path is %s" % os.getcwd()
|
||||||
sys.path.append("..")
|
#sys.path.append("../cadquery")
|
||||||
import cadquery
|
import cadquery
|
||||||
|
|
||||||
#settings._target = None
|
#settings._target = None
|
||||||
|
@ -55,9 +55,9 @@ copyright = u'Parametric Products Intellectual Holdings LLC, All Rights Reserved
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.1'
|
version = '0.3'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.1'
|
release = '0.3.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -81,7 +81,7 @@ exclude_patterns = ['_build']
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
|
@ -99,7 +99,8 @@ pygments_style = 'sphinx'
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#html_theme = 'timlinux-linfiniti-sphinx'
|
#html_theme = 'timlinux-linfiniti-sphinx'
|
||||||
html_theme = 'pparts'
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
@ -136,14 +137,14 @@ html_theme = 'pparts'
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
html_title = "Documentation"
|
html_title = "CadQuery Documentation"
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
#html_short_title = None
|
#html_short_title = None
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# of the sidebar.
|
||||||
html_logo = "logo.png"
|
html_logo = "_static/cqlogo.png"
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
@ -261,7 +262,7 @@ man_pages = [
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'CadQuery', u'CadQuery Documentation',
|
('index', 'CadQuery', u'CadQuery Documentation',
|
||||||
u'David Cowden', 'CadQuery', 'One line description of project.',
|
u'David Cowden', 'CadQuery', 'A Fluent CAD api',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
125
CadQuery/Libs/cadquery-lib/doc/cqgi.rst
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
.. _cqgi:
|
||||||
|
|
||||||
|
The CadQuery Gateway Interface
|
||||||
|
====================================
|
||||||
|
|
||||||
|
|
||||||
|
CadQuery is first and foremost designed as a library, which can be used as a part of any project.
|
||||||
|
In this context, there is no need for a standard script format or gateway api.
|
||||||
|
|
||||||
|
Though the embedded use case is the most common, several tools have been created which run
|
||||||
|
cadquery scripts on behalf of the user, and then render the result of the script visually.
|
||||||
|
|
||||||
|
These execution environments (EE) generally accept a script and user input values for
|
||||||
|
script parameters, and then display the resulting objects visually to the user.
|
||||||
|
|
||||||
|
Today, three execution environments exist:
|
||||||
|
|
||||||
|
* `The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_, which runs scripts
|
||||||
|
inside of the FreeCAD IDE, and displays objects in the display window
|
||||||
|
* the cq-directive, which is used to execute scripts inside of sphinx-doc,
|
||||||
|
producing documented examples that include both a script and an SVG representation of the object that results
|
||||||
|
* `ParametricParts.com <https://www.parametricparts.com>`_, which provides a web-based way to prompt user input for
|
||||||
|
variables, and then display the result output in a web page.
|
||||||
|
|
||||||
|
The CQGI is distributed with cadquery, and standardizes the interface between execution environments and cadquery scripts.
|
||||||
|
|
||||||
|
|
||||||
|
The Script Side
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
CQGI compliant containers provide an execution environment for scripts. The environment includes:
|
||||||
|
|
||||||
|
* the cadquery library is automatically imported as 'cq'.
|
||||||
|
* the :py:meth:`cadquery.cqgi.ScriptCallback.build_object()` method is defined that should be used to export a shape to the execution environment
|
||||||
|
|
||||||
|
Scripts must call build_output at least once. Invoking build_object more than once will send multiple objects to
|
||||||
|
the container. An error will occur if the script does not return an object using the build_object() method.
|
||||||
|
|
||||||
|
Future enhancements will include several other methods, used to provide more metadata for the execution environment:
|
||||||
|
* :py:meth:`cadquery.cqgi.ScriptCallback.add_error()`, indicates an error with an input parameter
|
||||||
|
* :py:meth:`cadquery.cqgi.ScriptCallback.describe_parameter()`, provides extra information about a parameter in the script,
|
||||||
|
|
||||||
|
|
||||||
|
The execution environment side
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
CQGI makes it easy to run cadquery scripts in a standard way. To run a script from an execution environment,
|
||||||
|
run code like this::
|
||||||
|
|
||||||
|
from cadquery import cqgi
|
||||||
|
|
||||||
|
user_script = ...
|
||||||
|
build_result = cqgi.parse(user_script).build()
|
||||||
|
|
||||||
|
The :py:meth:`cadquery.cqgi.parse()` method returns a :py:class:`cadquery.cqgi.CQModel` object.
|
||||||
|
|
||||||
|
Calling :py:meth:`cadquery.cqgi.CQModel.build()` returns a :py:class:`cadquery.cqgi.BuildResult` object,
|
||||||
|
,which includes the script execution time, and a success flag.
|
||||||
|
|
||||||
|
If the script was successful, the results property will include a list of results returned by the script.
|
||||||
|
|
||||||
|
If the script failed, the exception property contains the exception object.
|
||||||
|
|
||||||
|
If you have a way to get inputs from a user, you can override any of the constants defined in the user script
|
||||||
|
with new values::
|
||||||
|
|
||||||
|
from cadquery import cqgi
|
||||||
|
|
||||||
|
user_script = ...
|
||||||
|
build_result = cqgi.parse(user_script).build({ 'param': 2 } )
|
||||||
|
|
||||||
|
If a parameter called 'param' is defined in the model, it will be assigned the value 2 before the script runs.
|
||||||
|
An error will occur if a value is provided that is not defined in the model, or if the value provided cannot
|
||||||
|
be assigned to a variable with the given name.
|
||||||
|
|
||||||
|
More about script variables
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
CQGI uses the following rules to find input variables for a script:
|
||||||
|
|
||||||
|
* only top-level statements are considered
|
||||||
|
* only assignments of constant values to a local name are considered.
|
||||||
|
|
||||||
|
For example, in the following script::
|
||||||
|
|
||||||
|
h = 1.0
|
||||||
|
w = 2.0
|
||||||
|
foo = 'bar'
|
||||||
|
|
||||||
|
def some_function():
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
h, w, and foo will be overridable script variables, but x is not.
|
||||||
|
|
||||||
|
You can list the variables defined in the model by using the return value of the parse method::
|
||||||
|
|
||||||
|
model = cqgi.parse(user_script)
|
||||||
|
|
||||||
|
//a dictionary of InputParameter objects
|
||||||
|
parameters = model.metadata.parameters
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Future enhancments will include a safer sandbox to prevent malicious scripts.
|
||||||
|
|
||||||
|
Important CQGI Methods
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
These are the most important Methods and classes of the CQGI
|
||||||
|
|
||||||
|
.. currentmodule:: cadquery.cqgi
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
parse
|
||||||
|
CQModel.build
|
||||||
|
BuildResult
|
||||||
|
ScriptCallback.build_object
|
||||||
|
|
||||||
|
Complete CQGI api
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. automodule:: cadquery.cqgi
|
||||||
|
:members:
|
||||||
|
|
74
CadQuery/Libs/cadquery-lib/doc/designprinciples.rst
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
.. _designprinciples:
|
||||||
|
|
||||||
|
|
||||||
|
===========================
|
||||||
|
CadQuery Design Principles
|
||||||
|
===========================
|
||||||
|
|
||||||
|
|
||||||
|
Principle 1: Intuitive Construction
|
||||||
|
====================================
|
||||||
|
|
||||||
|
CadQuery aims to make building models using python scripting easy and intuitive.
|
||||||
|
CadQuery strives to allow scripts to read roughly as a human would describe an object verbally.
|
||||||
|
|
||||||
|
For example, consider this object:
|
||||||
|
|
||||||
|
.. image:: _static/quickstart.png
|
||||||
|
|
||||||
|
A human would describe this as:
|
||||||
|
|
||||||
|
"A block 80mm square x 30mm thick , with countersunk holes for M2 socket head cap screws
|
||||||
|
at the corners, and a circular pocket 22mm in diameter in the middle for a bearing"
|
||||||
|
|
||||||
|
The goal is to have the CadQuery script that produces this object be as close as possible to the english phrase
|
||||||
|
a human would use.
|
||||||
|
|
||||||
|
|
||||||
|
Principle 2: Capture Design Intent
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The features that are **not** part of the part description above are just as important as those that are. For example, most
|
||||||
|
humans will assume that:
|
||||||
|
|
||||||
|
* The countersunk holes are spaced a uniform distance from the edges
|
||||||
|
* The circular pocket is in the center of the block, no matter how big the block is
|
||||||
|
|
||||||
|
If you have experience with 3D CAD systems, you also know that there is a key design intent built into this object.
|
||||||
|
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.
|
||||||
|
|
||||||
|
Many scripting langauges 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
|
||||||
|
the design intent just like a human would when creating a drawing or building an object.
|
||||||
|
|
||||||
|
In fact, though many people know how to use 3D CAD systems, few understand how important the way that an object is built
|
||||||
|
impact its maintainability and resiliency to design changes.
|
||||||
|
|
||||||
|
|
||||||
|
Principle 3: Plugins as first class citizens
|
||||||
|
============================================
|
||||||
|
|
||||||
|
Any system for building 3D models will evolve to contain an immense number of libraries and feature builders. It is
|
||||||
|
important that these can be seamlessly included into the core and used alongside the built in libraries. Plugins
|
||||||
|
should be easy to install and familiar to use.
|
||||||
|
|
||||||
|
|
||||||
|
Principle 4: CAD models as source code makes sense
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
It is surprising that the world of 3D CAD is primarily dominated by systems that create opaque binary files.
|
||||||
|
Just like the world of software, CAD models are very complex.
|
||||||
|
|
||||||
|
CAD models have many things in common with software, and would benefit greatly from the use of tools that are standard
|
||||||
|
in the software industry, such as:
|
||||||
|
|
||||||
|
1. Easily re-using features between objects
|
||||||
|
2. Storing objects using version control systems
|
||||||
|
3. Computing the differences between objects by using source control tools
|
||||||
|
4. Share objects on the internet
|
||||||
|
5. Automate testing and generation by allowing objects to be built from within libraries
|
||||||
|
|
||||||
|
CadQuery is designed to make 3D content creation easy enough that the above benefits can be attained without more work
|
||||||
|
than using existing 'opaque', 'point and click' solutions.
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
CadQuery Examples
|
CadQuery Examples
|
||||||
*********************************
|
*********************************
|
||||||
|
|
||||||
.. automodule:: cadquery
|
|
||||||
|
|
||||||
|
|
||||||
The examples on this page can help you learn how to build objects with CadQuery.
|
The examples on this page can help you learn how to build objects with CadQuery.
|
||||||
|
@ -23,11 +22,14 @@ Items introduced in the example are marked with a **!**
|
||||||
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::
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
* You have to have an svg capable browser to view these!
|
* You have to have an svg capable browser to view these!
|
||||||
* For brevity, these examples do not include the MetaData and Header sections required for a
|
|
||||||
fully functional parametric part. See the :ref:`quickstart` for a guide that includes those portions
|
|
||||||
|
|
||||||
.. contents:: List of Examples
|
.. contents:: List of Examples
|
||||||
:backlinks: entry
|
:backlinks: entry
|
||||||
|
@ -40,7 +42,8 @@ Just about the simplest possible example, a rectangular box
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(2.0,2.0,0.5)
|
result = cadquery.Workplane("front").box(2.0, 2.0, 0.5)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -60,9 +63,18 @@ of a working plane is at the center of the face. The default hole depth is thro
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(2.0,2.0,0.5).faces(">Z").hole(0.5)
|
# The dimensions of the box. These can be modified rather than changing the
|
||||||
|
# object's code directly.
|
||||||
|
length = 80.0
|
||||||
|
height = 60.0
|
||||||
|
thickness = 10.0
|
||||||
|
center_hole_dia = 22.0
|
||||||
|
|
||||||
|
# Create a box based on the dimensions above and add a 22mm center hole
|
||||||
|
result = cq.Workplane("XY").box(length, height, thickness) \
|
||||||
|
.faces(">Z").workplane().hole(center_hole_dia)
|
||||||
|
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -84,7 +96,8 @@ By default, rectangles and circles are centered around the previous working poin
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").circle(2.0).rect(0.5,0.75).extrude(0.5)
|
result = cq.Workplane("front").circle(2.0).rect(0.5, 0.75).extrude(0.5)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -108,8 +121,9 @@ closed curve.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").lineTo(2.0,0).lineTo(2.0,1.0).threePointArc((1.0,1.5),(0.0,1.0))\
|
result = cq.Workplane("front").lineTo(2.0, 0).lineTo(2.0, 1.0).threePointArc((1.0, 1.5),(0.0, 1.0))\
|
||||||
.close().extrude(0.25)
|
.close().extrude(0.25)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
@ -134,13 +148,14 @@ A new work plane center can be established at any point.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").circle(3.0) #current point is the center of the circle, at (0,0)
|
result = cq.Workplane("front").circle(3.0) #current point is the center of the circle, at (0,0)
|
||||||
result = result.center(1.5,0.0).rect(0.5,0.5) # new work center is (1.5,0.0)
|
result = result.center(1.5, 0.0).rect(0.5, 0.5) # new work center is (1.5, 0.0)
|
||||||
|
|
||||||
result = result.center(-1.5,1.5).circle(0.25) # new work center is ( 0.0,1.5).
|
result = result.center(-1.5, 1.5).circle(0.25) # new work center is ( 0.0, 1.5).
|
||||||
#the new center is specified relative to the previous center, not global coordinates!
|
#the new center is specified relative to the previous center, not global coordinates!
|
||||||
|
|
||||||
result = result.extrude(0.25)
|
result = result.extrude(0.25)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
@ -165,10 +180,11 @@ like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
r = Workplane("front").circle(2.0) # make base
|
r = cq.Workplane("front").circle(2.0) # make base
|
||||||
r = r.pushPoints( [ (1.5,0),(0,1.5),(-1.5,0),(0,-1.5) ] ) # now four points are on the stack
|
r = r.pushPoints( [ (1.5, 0),(0, 1.5),(-1.5, 0),(0, -1.5) ] ) # now four points are on the stack
|
||||||
r = r.circle( 0.25 ) # circle will operate on all four points
|
r = r.circle( 0.25 ) # circle will operate on all four points
|
||||||
result = r.extrude(0.125 ) # make prism
|
result = r.extrude(0.125 ) # make prism
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -188,8 +204,9 @@ correct for small hole sizes.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(3.0,4.0,0.25).pushPoints ( [ ( 0,0.75 ),(0,-0.75) ]) \
|
result = cq.Workplane("front").box(3.0, 4.0, 0.25).pushPoints ( [ ( 0,0.75 ),(0, -0.75) ]) \
|
||||||
.polygon(6,1.0).cutThruAll()
|
.polygon(6, 1.0).cutThruAll()
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -209,7 +226,7 @@ This example uses a polyline to create one half of an i-beam shape, which is mir
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
(L,H,W,t) = ( 100.0,20.0,20.0,1.0)
|
(L,H,W,t) = ( 100.0, 20.0, 20.0, 1.0)
|
||||||
pts = [
|
pts = [
|
||||||
(0,H/2.0),
|
(0,H/2.0),
|
||||||
(W/2.0,H/2.0),
|
(W/2.0,H/2.0),
|
||||||
|
@ -220,7 +237,8 @@ This example uses a polyline to create one half of an i-beam shape, which is mir
|
||||||
(W/2.0,H/-2.0),
|
(W/2.0,H/-2.0),
|
||||||
(0,H/-2.0)
|
(0,H/-2.0)
|
||||||
]
|
]
|
||||||
result = Workplane("front").polyline(pts).mirrorY().extrude(L)
|
result = cq.Workplane("front").polyline(pts).mirrorY().extrude(L)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -242,18 +260,19 @@ needs a complex profile
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
s = Workplane("XY")
|
s = cq.Workplane("XY")
|
||||||
sPnts = [
|
sPnts = [
|
||||||
(2.75,1.5),
|
(2.75, 1.5),
|
||||||
(2.5,1.75),
|
(2.5, 1.75),
|
||||||
(2.0,1.5),
|
(2.0, 1.5),
|
||||||
(1.5,1.0),
|
(1.5, 1.0),
|
||||||
(1.0,1.25),
|
(1.0, 1.25),
|
||||||
(0.5,1.0),
|
(0.5, 1.0),
|
||||||
(0,1.0)
|
(0, 1.0)
|
||||||
]
|
]
|
||||||
r = s.lineTo(3.0,0).lineTo(3.0,1.0).spline(sPnts).close()
|
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts).close()
|
||||||
result = r.extrude(0.5)
|
result = r.extrude(0.5)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -275,9 +294,10 @@ introduce horizontal and vertical lines, which make for slightly easier coding.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
r = Workplane("front").hLine(1.0) # 1.0 is the distance, not coordinate
|
r = cq.Workplane("front").hLine(1.0) # 1.0 is the distance, not coordinate
|
||||||
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0) # hLineTo allows using xCoordinate not distance
|
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0) # hLineTo allows using xCoordinate not distance
|
||||||
result =r.mirrorY().extrude(0.25 ) # mirror the geometry and extrude
|
result =r.mirrorY().extrude(0.25 ) # mirror the geometry and extrude
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -311,8 +331,9 @@ Keep in mind that the origin of new workplanes are located at the center of a fa
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(2,3,0.5) #make a basic prism
|
result = cq.Workplane("front").box(2,3, 0.5) #make a basic prism
|
||||||
result = result.faces(">Z").workplane().hole(0.5) #find the top-most face and make a hole
|
result = result.faces(">Z").workplane().hole(0.5) #find the top-most face and make a hole
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -338,9 +359,10 @@ how deep the part is
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(3,2,0.5) #make a basic prism
|
result = cq.Workplane("front").box(3,2, 0.5) #make a basic prism
|
||||||
result = result.faces(">Z").vertices("<XY").workplane() #select the lower left vertex and make a workplane
|
result = result.faces(">Z").vertices("<XY").workplane() #select the lower left vertex and make a workplane
|
||||||
result = result.circle(1.0).cutThruAll() #cut the corner out
|
result = result.circle(1.0).cutThruAll() #cut the corner out
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -365,9 +387,10 @@ This example uses an offset workplane to make a compound object, which is perfec
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(3,2,0.5) #make a basic prism
|
result = cq.Workplane("front").box(3, 2, 0.5) #make a basic prism
|
||||||
result = result.faces("<X").workplane(offset=0.75) #workplane is offset from the object surface
|
result = result.faces("<X").workplane(offset=0.75) #workplane is offset from the object surface
|
||||||
result = result.circle(1.0).extrude(0.5) #disc
|
result = result.circle(1.0).extrude(0.5) #disc
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -386,9 +409,10 @@ You can create a rotated work plane by specifying angles of rotation relative to
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(4.0,4.0,0.25).faces(">Z").workplane() \
|
result = cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z").workplane() \
|
||||||
.transformed(offset=Vector(0,-1.5,1.0),rotate=Vector(60,0,0)) \
|
.transformed(offset=cq.Vector(0, -1.5, 1.0),rotate=cq.Vector(60, 0, 0)) \
|
||||||
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.25)
|
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.25)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -410,8 +434,9 @@ In the example below, a rectangle is drawn, and its vertices are used to locate
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(2,2,0.5).faces(">Z").workplane() \
|
result = cq.Workplane("front").box(2, 2, 0.5).faces(">Z").workplane() \
|
||||||
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.125 )
|
.rect(1.5, 1.5, forConstruction=True).vertices().hole(0.125 )
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -434,7 +459,8 @@ are removed, and then the inside of the solid is 'hollowed out' to make the shel
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(2,2,2).faces("+Z").shell(0.05)
|
result = cq.Workplane("front").box(2, 2, 2).faces("+Z").shell(0.05)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -454,8 +480,10 @@ and a circular section.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("front").box(4.0,4.0,0.25).faces(">Z").circle(1.5) \
|
result = cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z").circle(1.5) \
|
||||||
.workplane(offset=3.0).rect(0.75,0.5).loft(combine=True)
|
.workplane(offset=3.0).rect(0.75, 0.5).loft(combine=True)
|
||||||
|
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -477,8 +505,10 @@ Similar to :py:meth:`Workplane.hole` , these functions operate on a list of poin
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane(Plane.XY()).box(4,2,0.5).faces(">Z").workplane().rect(3.5,1.5,forConstruction=True)\
|
result = cq.Workplane(cq.Plane.XY()).box(4,2, 0.5).faces(">Z").workplane().rect(3.5, 1.5, forConstruction=True)\
|
||||||
.vertices().cboreHole(0.125, 0.25,0.125,depth=None)
|
.vertices().cboreHole(0.125, 0.25, 0.125, depth=None)
|
||||||
|
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -503,7 +533,8 @@ Here we fillet all of the edges of a simple plate.
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
result = Workplane("XY" ).box(3,3,0.5).edges("|Z").fillet(0.125)
|
result = cq.Workplane("XY" ).box(3, 3, 0.5).edges("|Z").fillet(0.125)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -515,6 +546,24 @@ 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 Parametric Bearing Pillow Block
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Combining a few basic functions, its possible to make a very good parametric bearing pillow block,
|
||||||
|
with just a few lines of code.
|
||||||
|
|
||||||
|
.. cq_plot::
|
||||||
|
|
||||||
|
(length,height,bearing_diam, thickness,padding) = ( 30.0, 40.0, 22.0, 10.0, 8.0)
|
||||||
|
|
||||||
|
result = cq.Workplane("XY").box(length,height,thickness).faces(">Z").workplane().hole(bearing_diam) \
|
||||||
|
.faces(">Z").workplane() \
|
||||||
|
.rect(length-padding,height-padding,forConstruction=True) \
|
||||||
|
.vertices().cboreHole(2.4, 4.4, 2.1)
|
||||||
|
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
|
||||||
Splitting an Object
|
Splitting an Object
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
@ -522,10 +571,11 @@ You can split an object using a workplane, and retain either or both halves
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
c = Workplane("XY").box(1,1,1).faces(">Z").workplane().circle(0.25).cutThruAll()
|
c = cq.Workplane("XY").box(1,1,1).faces(">Z").workplane().circle(0.25).cutThruAll()
|
||||||
|
|
||||||
#now cut it in half sideways
|
#now cut it in half sideways
|
||||||
result = c.faces(">Y").workplane(-0.5).split(keepTop=True)
|
result = c.faces(">Y").workplane(-0.5).split(keepTop=True)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -554,12 +604,12 @@ ones at 13 lines, but that's very short compared to the pythonOCC version, which
|
||||||
|
|
||||||
.. cq_plot::
|
.. cq_plot::
|
||||||
|
|
||||||
(L,w,t) = (20.0,6.0,3.0)
|
(L,w,t) = (20.0, 6.0, 3.0)
|
||||||
s = Workplane("XY")
|
s = cq.Workplane("XY")
|
||||||
|
|
||||||
#draw half the profile of the bottle and extrude it
|
#draw half the profile of the bottle and extrude it
|
||||||
p = s.center(-L/2.0,0).vLine(w/2.0) \
|
p = s.center(-L/2.0, 0).vLine(w/2.0) \
|
||||||
.threePointArc((L/2.0, w/2.0 + t),(L,w/2.0)).vLine(-w/2.0) \
|
.threePointArc((L/2.0, w/2.0 + t),(L, w/2.0)).vLine(-w/2.0) \
|
||||||
.mirrorX().extrude(30.0,True)
|
.mirrorX().extrude(30.0,True)
|
||||||
|
|
||||||
#make the neck
|
#make the neck
|
||||||
|
@ -567,6 +617,7 @@ ones at 13 lines, but that's very short compared to the pythonOCC version, which
|
||||||
|
|
||||||
#make a shell
|
#make a shell
|
||||||
result = p.faces(">Z").shell(0.3)
|
result = p.faces(">Z").shell(0.3)
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
|
@ -609,7 +660,7 @@ A Parametric Enclosure
|
||||||
p_lipHeight = 1.0 #Height of lip on the underside of the lid.\nSits inside the box body for a snug fit.
|
p_lipHeight = 1.0 #Height of lip on the underside of the lid.\nSits inside the box body for a snug fit.
|
||||||
|
|
||||||
#outer shell
|
#outer shell
|
||||||
oshell = Workplane("XY").rect(p_outerWidth,p_outerLength).extrude(p_outerHeight + p_lipHeight)
|
oshell = cq.Workplane("XY").rect(p_outerWidth,p_outerLength).extrude(p_outerHeight + p_lipHeight)
|
||||||
|
|
||||||
#weird geometry happens if we make the fillets in the wrong order
|
#weird geometry happens if we make the fillets in the wrong order
|
||||||
if p_sideRadius > p_topAndBottomRadius:
|
if p_sideRadius > p_topAndBottomRadius:
|
||||||
|
@ -665,6 +716,8 @@ A Parametric Enclosure
|
||||||
#return the combined result
|
#return the combined result
|
||||||
result =topOfLid.combineSolids(bottom)
|
result =topOfLid.combineSolids(bottom)
|
||||||
|
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
.. topic:: Api References
|
.. topic:: Api References
|
||||||
|
|
||||||
.. hlist::
|
.. hlist::
|
||||||
|
@ -686,3 +739,300 @@ A Parametric Enclosure
|
||||||
* :py:meth:`Workplane.cboreHole`
|
* :py:meth:`Workplane.cboreHole`
|
||||||
* :py:meth:`Workplane.cskHole`
|
* :py:meth:`Workplane.cskHole`
|
||||||
* :py:meth:`Workplane.hole`
|
* :py:meth:`Workplane.hole`
|
||||||
|
|
||||||
|
Lego Brick
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
This script will produce any size regular rectangular Lego(TM) brick. Its only tricky because of the logic
|
||||||
|
regarding the underside of the brick.
|
||||||
|
|
||||||
|
.. cq_plot::
|
||||||
|
:height: 400
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Inputs
|
||||||
|
######
|
||||||
|
lbumps = 6 # number of bumps long
|
||||||
|
wbumps = 2 # number of bumps wide
|
||||||
|
thin = True # True for thin, False for thick
|
||||||
|
|
||||||
|
#
|
||||||
|
# Lego Brick Constants-- these make a lego brick a lego :)
|
||||||
|
#
|
||||||
|
pitch = 8.0
|
||||||
|
clearance = 0.1
|
||||||
|
bumpDiam = 4.8
|
||||||
|
bumpHeight = 1.8
|
||||||
|
if thin:
|
||||||
|
height = 3.2
|
||||||
|
else:
|
||||||
|
height = 9.6
|
||||||
|
|
||||||
|
t = (pitch - (2 * clearance) - bumpDiam) / 2.0
|
||||||
|
postDiam = pitch - t # works out to 6.5
|
||||||
|
total_length = lbumps*pitch - 2.0*clearance
|
||||||
|
total_width = wbumps*pitch - 2.0*clearance
|
||||||
|
|
||||||
|
# make the base
|
||||||
|
s = cq.Workplane("XY").box(total_length, total_width, height)
|
||||||
|
|
||||||
|
# shell inwards not outwards
|
||||||
|
s = s.faces("<Z").shell(-1.0 * t)
|
||||||
|
|
||||||
|
# make the bumps on the top
|
||||||
|
s = s.faces(">Z").workplane(). \
|
||||||
|
rarray(pitch, pitch, lbumps, wbumps, True).circle(bumpDiam / 2.0) \
|
||||||
|
.extrude(bumpHeight)
|
||||||
|
|
||||||
|
# add posts on the bottom. posts are different diameter depending on geometry
|
||||||
|
# solid studs for 1 bump, tubes for multiple, none for 1x1
|
||||||
|
tmp = s.faces("<Z").workplane(invert=True)
|
||||||
|
|
||||||
|
if lbumps > 1 and wbumps > 1:
|
||||||
|
tmp = tmp.rarray(pitch, pitch, lbumps - 1, wbumps - 1, center=True). \
|
||||||
|
circle(postDiam / 2.0).circle(bumpDiam / 2.0).extrude(height - t)
|
||||||
|
elif lbumps > 1:
|
||||||
|
tmp = tmp.rarray(pitch, pitch, lbumps - 1, 1, center=True). \
|
||||||
|
circle(t).extrude(height - t)
|
||||||
|
elif wbumps > 1:
|
||||||
|
tmp = tmp.rarray(pitch, pitch, 1, wbumps - 1, center=True). \
|
||||||
|
circle(t).extrude(height - t)
|
||||||
|
else:
|
||||||
|
tmp = s
|
||||||
|
|
||||||
|
# Render the solid
|
||||||
|
build_object(tmp)
|
||||||
|
|
||||||
|
|
||||||
|
Braille Example
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
.. cq_plot::
|
||||||
|
:height: 400
|
||||||
|
|
||||||
|
from __future__ import unicode_literals, division
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
|
# text_lines is a list of text lines.
|
||||||
|
# FreeCAD in braille (converted with braille-converter:
|
||||||
|
# https://github.com/jpaugh/braille-converter.git).
|
||||||
|
text_lines = ['⠠ ⠋ ⠗ ⠑ ⠑ ⠠ ⠉ ⠠ ⠁ ⠠ ⠙']
|
||||||
|
# See http://www.tiresias.org/research/reports/braille_cell.htm for examples
|
||||||
|
# of braille cell geometry.
|
||||||
|
horizontal_interdot = 2.5
|
||||||
|
vertical_interdot = 2.5
|
||||||
|
horizontal_intercell = 6
|
||||||
|
vertical_interline = 10
|
||||||
|
dot_height = 0.5
|
||||||
|
dot_diameter = 1.3
|
||||||
|
|
||||||
|
base_thickness = 1.5
|
||||||
|
|
||||||
|
# End of configuration.
|
||||||
|
BrailleCellGeometry = namedtuple('BrailleCellGeometry',
|
||||||
|
('horizontal_interdot',
|
||||||
|
'vertical_interdot',
|
||||||
|
'intercell',
|
||||||
|
'interline',
|
||||||
|
'dot_height',
|
||||||
|
'dot_diameter'))
|
||||||
|
|
||||||
|
|
||||||
|
class Point(object):
|
||||||
|
def __init__(self, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
return Point(self.x + other.x, self.y + other.y)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return (self.x, self.y)[index]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '({}, {})'.format(self.x, self.y)
|
||||||
|
|
||||||
|
|
||||||
|
def brailleToPoints(text, cell_geometry):
|
||||||
|
# Unicode bit pattern (cf. https://en.wikipedia.org/wiki/Braille_Patterns).
|
||||||
|
mask1 = 0b00000001
|
||||||
|
mask2 = 0b00000010
|
||||||
|
mask3 = 0b00000100
|
||||||
|
mask4 = 0b00001000
|
||||||
|
mask5 = 0b00010000
|
||||||
|
mask6 = 0b00100000
|
||||||
|
mask7 = 0b01000000
|
||||||
|
mask8 = 0b10000000
|
||||||
|
masks = (mask1, mask2, mask3, mask4, mask5, mask6, mask7, mask8)
|
||||||
|
|
||||||
|
# Corresponding dot position
|
||||||
|
w = cell_geometry.horizontal_interdot
|
||||||
|
h = cell_geometry.vertical_interdot
|
||||||
|
pos1 = Point(0, 2 * h)
|
||||||
|
pos2 = Point(0, h)
|
||||||
|
pos3 = Point(0, 0)
|
||||||
|
pos4 = Point(w, 2 * h)
|
||||||
|
pos5 = Point(w, h)
|
||||||
|
pos6 = Point(w, 0)
|
||||||
|
pos7 = Point(0, -h)
|
||||||
|
pos8 = Point(w, -h)
|
||||||
|
pos = (pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8)
|
||||||
|
|
||||||
|
# Braille blank pattern (u'\u2800').
|
||||||
|
blank = '⠀'
|
||||||
|
points = []
|
||||||
|
# Position of dot1 along the x-axis (horizontal).
|
||||||
|
character_origin = 0
|
||||||
|
for c in text:
|
||||||
|
for m, p in zip(masks, pos):
|
||||||
|
delta_to_blank = ord(c) - ord(blank)
|
||||||
|
if (m & delta_to_blank):
|
||||||
|
points.append(p + Point(character_origin, 0))
|
||||||
|
character_origin += cell_geometry.intercell
|
||||||
|
return points
|
||||||
|
|
||||||
|
|
||||||
|
def get_plate_height(text_lines, cell_geometry):
|
||||||
|
# cell_geometry.vertical_interdot is also used as space between base
|
||||||
|
# borders and characters.
|
||||||
|
return (2 * cell_geometry.vertical_interdot +
|
||||||
|
2 * cell_geometry.vertical_interdot +
|
||||||
|
(len(text_lines) - 1) * cell_geometry.interline)
|
||||||
|
|
||||||
|
|
||||||
|
def get_plate_width(text_lines, cell_geometry):
|
||||||
|
# cell_geometry.horizontal_interdot is also used as space between base
|
||||||
|
# borders and characters.
|
||||||
|
max_len = max([len(t) for t in text_lines])
|
||||||
|
return (2 * cell_geometry.horizontal_interdot +
|
||||||
|
cell_geometry.horizontal_interdot +
|
||||||
|
(max_len - 1) * cell_geometry.intercell)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cylinder_radius(cell_geometry):
|
||||||
|
"""Return the radius the cylinder should have
|
||||||
|
The cylinder have the same radius as the half-sphere make the dots (the
|
||||||
|
hidden and the shown part of the dots).
|
||||||
|
The radius is such that the spherical cap with diameter
|
||||||
|
cell_geometry.dot_diameter has a height of cell_geometry.dot_height.
|
||||||
|
"""
|
||||||
|
h = cell_geometry.dot_height
|
||||||
|
r = cell_geometry.dot_diameter / 2
|
||||||
|
return (r ** 2 + h ** 2) / 2 / h
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_plate_thickness(plate_thickness, cell_geometry):
|
||||||
|
"""Return the height on which the half spheres will sit"""
|
||||||
|
return (plate_thickness +
|
||||||
|
get_cylinder_radius(cell_geometry) -
|
||||||
|
cell_geometry.dot_height)
|
||||||
|
|
||||||
|
|
||||||
|
def make_base(text_lines, cell_geometry, plate_thickness):
|
||||||
|
base_width = get_plate_width(text_lines, cell_geometry)
|
||||||
|
base_height = get_plate_height(text_lines, cell_geometry)
|
||||||
|
base_thickness = get_base_plate_thickness(plate_thickness, cell_geometry)
|
||||||
|
base = cq.Workplane('XY').box(base_width, base_height, base_thickness,
|
||||||
|
centered=(False, False, False))
|
||||||
|
return base
|
||||||
|
|
||||||
|
|
||||||
|
def make_embossed_plate(text_lines, cell_geometry):
|
||||||
|
"""Make an embossed plate with dots as spherical caps
|
||||||
|
Method:
|
||||||
|
- make a thin plate on which sit cylinders
|
||||||
|
- fillet the upper edge of the cylinders so to get pseudo half-spheres
|
||||||
|
- make the union with a thicker plate so that only the sphere caps stay
|
||||||
|
"visible".
|
||||||
|
"""
|
||||||
|
base = make_base(text_lines, cell_geometry, base_thickness)
|
||||||
|
|
||||||
|
dot_pos = []
|
||||||
|
base_width = get_plate_width(text_lines, cell_geometry)
|
||||||
|
base_height = get_plate_height(text_lines, cell_geometry)
|
||||||
|
y = base_height - 3 * cell_geometry.vertical_interdot
|
||||||
|
line_start_pos = Point(cell_geometry.horizontal_interdot, y)
|
||||||
|
for text in text_lines:
|
||||||
|
dots = brailleToPoints(text, cell_geometry)
|
||||||
|
dots = [p + line_start_pos for p in dots]
|
||||||
|
dot_pos += dots
|
||||||
|
line_start_pos += Point(0, -cell_geometry.interline)
|
||||||
|
|
||||||
|
r = get_cylinder_radius(cell_geometry)
|
||||||
|
base = base.faces('>Z').vertices('<XY').workplane() \
|
||||||
|
.pushPoints(dot_pos).circle(r) \
|
||||||
|
.extrude(r)
|
||||||
|
# Make a fillet almost the same radius to get a pseudo spherical cap.
|
||||||
|
base = base.faces('>Z').edges() \
|
||||||
|
.fillet(r - 0.001)
|
||||||
|
hidding_box = cq.Workplane('XY').box(
|
||||||
|
base_width, base_height, base_thickness, centered=(False, False, False))
|
||||||
|
result = hidding_box.union(base)
|
||||||
|
return result
|
||||||
|
|
||||||
|
_cell_geometry = BrailleCellGeometry(
|
||||||
|
horizontal_interdot,
|
||||||
|
vertical_interdot,
|
||||||
|
horizontal_intercell,
|
||||||
|
vertical_interline,
|
||||||
|
dot_height,
|
||||||
|
dot_diameter)
|
||||||
|
|
||||||
|
if base_thickness < get_cylinder_radius(_cell_geometry):
|
||||||
|
raise ValueError('Base thickness should be at least {}'.format(dot_height))
|
||||||
|
|
||||||
|
build_object(make_embossed_plate(text_lines, _cell_geometry))
|
||||||
|
|
||||||
|
Panel With Various Connector Holes
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. cq_plot::
|
||||||
|
:height: 400
|
||||||
|
|
||||||
|
# The dimensions of the model. These can be modified rather than changing the
|
||||||
|
# object's code directly.
|
||||||
|
width = 400
|
||||||
|
height = 500
|
||||||
|
thickness = 2
|
||||||
|
|
||||||
|
# Create a plate with two polygons cut through it
|
||||||
|
result = cq.Workplane("front").box(width, height, thickness)
|
||||||
|
|
||||||
|
h_sep = 60
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(157,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
h_sep4DB9 = 30
|
||||||
|
for idx in range(8):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(91,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(25,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(8):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-41,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-107,-30-idx*h_sep).circle(14).rect(24.7487,24.7487, forConstruction=True).vertices().hole(3.2).cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(8):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
|
||||||
|
|
||||||
|
for idx in range(4):
|
||||||
|
result = result.workplane(offset=1, centerOption='CenterOfBoundBox').center(-173,-30-idx*h_sep).moveTo(-2.9176,-5.3).threePointArc((-6.05,0),(-2.9176,5.3)).lineTo(2.9176,5.3).threePointArc((6.05,0),(2.9176,-5.3)).close().cutThruAll()
|
||||||
|
|
||||||
|
# Render the solid
|
||||||
|
build_object(result)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
.. _extending:
|
.. _extending:
|
||||||
|
|
||||||
******************
|
|
||||||
Extending CadQuery
|
Extending CadQuery
|
||||||
******************
|
======================
|
||||||
|
|
||||||
.. automodule:: cadfile.cadutils.cadquery
|
|
||||||
|
|
||||||
If you find that CadQuery doesnt suit your needs, you can easily extend it. CadQuery provides several extension
|
If you find that CadQuery doesnt suit your needs, you can easily extend it. CadQuery provides several extension
|
||||||
methods:
|
methods:
|
||||||
|
@ -13,18 +11,14 @@ methods:
|
||||||
* you can define your own plugins.
|
* you can define your own plugins.
|
||||||
* you can use FreeCAD script directly
|
* you can use FreeCAD script directly
|
||||||
|
|
||||||
Loading external Plugins
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
You can load a plugin using the tools.loadScript(*URL*) directive in your script.
|
|
||||||
|
|
||||||
Using FreeCAD Script
|
Using FreeCAD Script
|
||||||
--------------------
|
-----------------------
|
||||||
|
|
||||||
The easiest way to extend CadQuery is to simply use FreeCAD script inside of your build method. Just about
|
The easiest way to extend CadQuery is to simply use FreeCAD script inside of your build method. Just about
|
||||||
any valid FreeCAD script will execute just fine. For example, this simple CadQuery script::
|
any valid FreeCAD script will execute just fine. For example, this simple CadQuery script::
|
||||||
|
|
||||||
return Workplane("XY").box(1.0,2.0,3.0).val()
|
return cq.Workplane("XY").box(1.0,2.0,3.0).val()
|
||||||
|
|
||||||
is actually equivalent to::
|
is actually equivalent to::
|
||||||
|
|
||||||
|
@ -45,19 +39,20 @@ a lot of the complexity of the FreeCAD api.
|
||||||
|
|
||||||
You can get the best of both worlds by wrapping your freecad script into a CadQuery plugin.
|
You can get the best of both worlds by wrapping your freecad script into a CadQuery plugin.
|
||||||
|
|
||||||
A CadQuery plugin is simply a function that is attached to the CadQuery :py:meth:`CQ` or :py:meth:`Workplane` class.
|
A CadQuery plugin is simply a function that is attached to the CadQuery :py:meth:`cadquery.CQ` or :py:meth:`cadquery.Workplane` class.
|
||||||
When connected, your plugin can be used in the chain just like the built-in functions.
|
When connected, your plugin can be used in the chain just like the built-in functions.
|
||||||
|
|
||||||
There are a few key concepts important to understand when building a plugin
|
There are a few key concepts important to understand when building a plugin
|
||||||
|
|
||||||
|
|
||||||
The Stack
|
The Stack
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-------------------
|
||||||
|
|
||||||
Every CadQuery object has a local stack, which contains a list of items. The items on the stack will be
|
Every CadQuery object has a local stack, which contains a list of items. The items on the stack will be
|
||||||
one of these types:
|
one of these types:
|
||||||
* **A CadQuery SolidReference object**, which holds a reference to a FreeCAD solid
|
|
||||||
* **A FreeCAD object**, a Vertex, Edge, Wire, Face, Shell, Solid, or Compound
|
* **A CadQuery SolidReference object**, which holds a reference to a FreeCAD solid
|
||||||
|
* **A FreeCAD object**, a Vertex, Edge, Wire, Face, Shell, Solid, or Compound
|
||||||
|
|
||||||
The stack is available by using self.objects, and will always contain at least one object.
|
The stack is available by using self.objects, and will always contain at least one object.
|
||||||
|
|
||||||
|
@ -68,58 +63,55 @@ The stack is available by using self.objects, and will always contain at least o
|
||||||
|
|
||||||
|
|
||||||
Preserving the Chain
|
Preserving the Chain
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
-----------------------
|
||||||
|
|
||||||
CadQuery's fluent api relies on the ability to chain calls together one after another. For this to work,
|
CadQuery's fluent api relies on the ability to chain calls together one after another. For this to work,
|
||||||
you must return a valid CadQuery object as a return value. If you choose not to return a CadQuery object,
|
you must return a valid CadQuery object as a return value. If you choose not to return a CadQuery object,
|
||||||
then your plugin will end the chain. Sometimes this is desired for example :py:meth:`CQ.size`
|
then your plugin will end the chain. Sometimes this is desired for example :py:meth:`cadquery.CQ.size`
|
||||||
|
|
||||||
There are two ways you can safely continue the chain:
|
There are two ways you can safely continue the chain:
|
||||||
|
|
||||||
1. **return self** If you simply wish to modify the stack contents, you can simply return a reference to
|
1. **return self** If you simply wish to modify the stack contents, you can simply return a reference to
|
||||||
self. This approach is destructive, because the contents of the stack are modified, but it is also the
|
self. This approach is destructive, because the contents of the stack are modified, but it is also the
|
||||||
simplest.
|
simplest.
|
||||||
2. :py:meth:`CQ.newObject` Most of the time, you will want to return a new object. Using newObject will
|
2. :py:meth:`cadquery.CQ.newObject` Most of the time, you will want to return a new object. Using newObject will
|
||||||
return a new CQ or Workplane object having the stack you specify, and will link this object to the
|
return a new CQ or Workplane object having the stack you specify, and will link this object to the
|
||||||
previous one. This preserves the original object and its stack.
|
previous one. This preserves the original object and its stack.
|
||||||
|
|
||||||
|
|
||||||
Helper Methods
|
Helper Methods
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
-----------------------
|
||||||
|
|
||||||
When you implement a CadQuery plugin, you are extending CadQuery's base objects. As a result, you can call any
|
When you implement a CadQuery plugin, you are extending CadQuery's base objects. As a result, you can call any
|
||||||
CadQuery or Workplane methods from inside of your extension. You can also call a number of internal methods that
|
CadQuery or Workplane methods from inside of your extension. You can also call a number of internal methods that
|
||||||
are designed to aid in plugin creation:
|
are designed to aid in plugin creation:
|
||||||
|
|
||||||
* :py:meth:`Workplane._pointsOnStack` returns a FreeCAD Vector ( a point ) for each item on the stack. Useful if you
|
|
||||||
are writing a plugin that you'd like to operate on all values on the stack, like :py:meth:`Workplane.circle` and
|
|
||||||
most other built-ins do
|
|
||||||
|
|
||||||
* :py:meth:`Workplane._makeWireAtPoints` will invoke a factory function you supply for all points on the stack,
|
* :py:meth:`cadquery.Workplane._makeWireAtPoints` will invoke a factory function you supply for all points on the stack,
|
||||||
and return a properly constructed cadquery object. This function takes care of registering wires for you
|
and return a properly constructed cadquery object. This function takes care of registering wires for you
|
||||||
and everything like that
|
and everything like that
|
||||||
|
|
||||||
* :py:meth:`Workplane.newObject` returns a new Workplane object with the provided stack, and with its parent set
|
* :py:meth:`cadquery.Workplane.newObject` returns a new Workplane object with the provided stack, and with its parent set
|
||||||
to the current object. The preferred way to continue the chain
|
to the current object. The preferred way to continue the chain
|
||||||
|
|
||||||
* :py:meth:`Workplane.findSolid` returns the first Solid found in the chain, working from the current object upwards
|
* :py:meth:`cadquery.CQ.findSolid` returns the first Solid found in the chain, working from the current object upwards
|
||||||
in the chain. commonly used when your plugin will modify an existing solid, or needs to create objects and
|
in the chain. commonly used when your plugin will modify an existing solid, or needs to create objects and
|
||||||
then combine them onto the 'main' part that is in progress
|
then combine them onto the 'main' part that is in progress
|
||||||
|
|
||||||
* :py:meth:`Workplane._addWire` must be called if you add a wire. This allows the base class to track all the wires
|
* :py:meth:`cadquery.Workplane._addPendingWire` must be called if you add a wire. This allows the base class to track all the wires
|
||||||
that are created, so that they can be managed when extrusion occurs.
|
that are created, so that they can be managed when extrusion occurs.
|
||||||
|
|
||||||
* :py:meth:`Workplane.wire` gathers up all of the edges that have been drawn ( eg, by line, vline, etc ), and
|
* :py:meth:`cadquery.Workplane.wire` gathers up all of the edges that have been drawn ( eg, by line, vline, etc ), and
|
||||||
attempts to combine them into a single wire, which is returned. This should be used when your plugin creates
|
attempts to combine them into a single wire, which is returned. This should be used when your plugin creates
|
||||||
2-d edges, and you know it is time to collect them into a single wire.
|
2-d edges, and you know it is time to collect them into a single wire.
|
||||||
|
|
||||||
* :py:meth:`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:`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:`Plane.toLocalCoords` will convet from global coordinates to local coordinates
|
* :py:meth:`cadquery.freecad_impl.geom.Plane.toLocalCoords` will convet from global coordinates to local coordinates
|
||||||
|
|
||||||
Coordinate Systems
|
Coordinate Systems
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
-----------------------
|
||||||
|
|
||||||
Keep in mind that the user may be using a work plane that has created a local coordinate system. Consequently,
|
Keep in mind that the user may be using a work plane that has created a local coordinate system. Consequently,
|
||||||
the orientation of shapes that you create are often implicitly defined by the user's workplane.
|
the orientation of shapes that you create are often implicitly defined by the user's workplane.
|
||||||
|
@ -129,7 +121,7 @@ inputs may be defined in terms of local coordinates.
|
||||||
|
|
||||||
|
|
||||||
Linking in your plugin
|
Linking in your plugin
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
-----------------------
|
||||||
|
|
||||||
Your plugin is a single method, which is attached to the main Workplane or CadQuery object.
|
Your plugin is a single method, which is attached to the main Workplane or CadQuery object.
|
||||||
|
|
||||||
|
@ -142,12 +134,21 @@ To install it, simply attach it to the CadQuery or Workplane object, like this::
|
||||||
do stuff
|
do stuff
|
||||||
return whatever_you_want
|
return whatever_you_want
|
||||||
|
|
||||||
Workplane.yourPlugin = _yourFunction
|
cq.Workplane.yourPlugin = _yourFunction
|
||||||
|
|
||||||
That's it!
|
That's it!
|
||||||
|
|
||||||
|
CadQueryExample Plugins
|
||||||
|
-----------------------
|
||||||
|
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:
|
||||||
|
|
||||||
|
* :py:meth:`cadquery.Workplane.polygon`
|
||||||
|
* :py:meth:`cadquery.Workplane.cboreHole`
|
||||||
|
|
||||||
|
|
||||||
Plugin Example
|
Plugin Example
|
||||||
^^^^^^^^^^^^^^^
|
-----------------------
|
||||||
|
|
||||||
This ultra simple plugin makes cubes of the specified size for each stack point.
|
This ultra simple plugin makes cubes of the specified size for each stack point.
|
||||||
|
|
||||||
|
@ -162,17 +163,18 @@ This ultra simple plugin makes cubes of the specified size for each stack point.
|
||||||
def _singleCube(pnt):
|
def _singleCube(pnt):
|
||||||
#pnt is a location in local coordinates
|
#pnt is a location in local coordinates
|
||||||
#since we're using eachpoint with useLocalCoordinates=True
|
#since we're using eachpoint with useLocalCoordinates=True
|
||||||
return Solid.makeBox(length,length,length,pnt)
|
return cq.Solid.makeBox(length,length,length,pnt)
|
||||||
|
|
||||||
#use CQ utility method to iterate over the stack, call our
|
#use CQ utility method to iterate over the stack, call our
|
||||||
#method, and convert to/from local coordinates.
|
#method, and convert to/from local coordinates.
|
||||||
return self.eachpoint(_singleCube,True)
|
return self.eachpoint(_singleCube,True)
|
||||||
|
|
||||||
#link the plugin into cadQuery
|
#link the plugin into cadQuery
|
||||||
Workplane.makeCubes = makeCubes
|
cq.Workplane.makeCubes = makeCubes
|
||||||
|
|
||||||
#use the plugin
|
#use the plugin
|
||||||
result = Workplane("XY").box(6.0,8.0,0.5).faces(">Z").rect(4.0,4.0,forConstruction=True).vertices() \
|
result = cq.Workplane("XY").box(6.0,8.0,0.5).faces(">Z")\
|
||||||
|
.rect(4.0,4.0,forConstruction=True).vertices() \
|
||||||
.makeCubes(1.0).combineSolids()
|
.makeCubes(1.0).combineSolids()
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
|
|
@ -1,202 +1,24 @@
|
||||||
.. _cadquery_reference:
|
.. _cadquery_reference:
|
||||||
|
|
||||||
********************************
|
CadQuery Scripts and Object Output
|
||||||
ModelScript Format Reference
|
======================================
|
||||||
********************************
|
|
||||||
|
|
||||||
ParametricParts ModelScripts define a parametric 3D model that can be executed and customized by an end user.
|
CadQuery scripts are pure python scripts, that may follow a few conventions.
|
||||||
CadQuery scripts are pure python scripts that follow a standard format. Each script contains these main components:
|
|
||||||
|
|
||||||
:MetaData:
|
If you are using cadquery as a library, there are no constraints.
|
||||||
*(Mandatory)* Defines the attributes that describe the model, such as version and unit of measure
|
|
||||||
|
|
||||||
:Parameters:
|
If you are using cadquery scripts inside of a cadquery execution environment,
|
||||||
*(Optional)* Defines parameters and their default values, which can be
|
like `The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_ or
|
||||||
manipulated by users to customize the object. Parameters are defined by creating local variables
|
`parametricParts.com <https://www.parametricparts.com>`_, there are a few conventions you need to be aware of:
|
||||||
of a particular class type. Presets and groups organize parameters to make them easier to use
|
|
||||||
|
|
||||||
:build script:
|
* cadquery is already imported as 'cq'
|
||||||
*(Mandatory)* Constructs the model once parameter values are collected and the model is validated.
|
* to return an object to the container, you need to call the build_object() method.
|
||||||
The script must return a solid object, or a cadquery solid
|
|
||||||
|
|
||||||
The Script Life-cycle
|
Each script generally has three sections:
|
||||||
----------------------
|
|
||||||
|
|
||||||
CadQuery scripts have the following lifecycle when they are executed by a user via the web interface:
|
* Variable Assignments and metadata definitions
|
||||||
|
* cadquery and other python code
|
||||||
|
* object exports, via the export_object() function
|
||||||
|
|
||||||
1. **Load Script** If it is valid, the parameters and MetaData
|
|
||||||
are loaded. A number of special objects are automatically available to your script
|
|
||||||
|
|
||||||
2. **Display Model to User** The parameters and default values are displayed to the user.
|
|
||||||
The model is rendered and displayed to the user using the default values
|
|
||||||
|
|
||||||
3. **User selects new parameter values** , either by selecting
|
|
||||||
preset combinations, or by providing values for each parameter
|
|
||||||
|
|
||||||
4. **Build the model** If validation is successful, the model is re-built, and the preview window is updated
|
|
||||||
|
|
||||||
5. **User downloads** If the user chooses to download the model as STL, STEP, or AMF, the model is re-built
|
|
||||||
again for download.
|
|
||||||
|
|
||||||
|
|
||||||
A Full Example Script
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
This script demonstrates all of the model elements available. Each is briefly introduced in the sample text,
|
|
||||||
and then described in more detail after the sample::
|
|
||||||
|
|
||||||
"""
|
|
||||||
Comments and Copyright Statement
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
|
||||||
# metadata describes your model
|
|
||||||
#
|
|
||||||
UOM = "mm"
|
|
||||||
VERSION = 1.0
|
|
||||||
|
|
||||||
#
|
|
||||||
# parameter definitions. Valid parameter types are FloatParam,IntParam,and BooleanParam
|
|
||||||
# each paraemter can have min and max values, a description, and a set of named preset values
|
|
||||||
#
|
|
||||||
p_diam = FloatParam(min=1.0,max=500.0,presets={'default':40.0,'small':2.0,'big':200.0},group="Basics", desc="Diameter");
|
|
||||||
|
|
||||||
#
|
|
||||||
# build the model based on user selected parameter values.
|
|
||||||
# Must return a FreeCAD solid before exiting.
|
|
||||||
#
|
|
||||||
def build():
|
|
||||||
return Part.makeSphere(p_diam.value);
|
|
||||||
|
|
||||||
|
|
||||||
Each section of the script is described in more detail below
|
|
||||||
|
|
||||||
Metadata
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Model metadata is provided by setting a dictionary variable called METADATA in the script. You can provide
|
|
||||||
any metadata you choose, but only these values are currently used:
|
|
||||||
|
|
||||||
:UOM:
|
|
||||||
The unit of measure of your model. in and mm are common values, but others are allowed.
|
|
||||||
Some model formats like AMF can accept units of measure, which streamlines the printing process. **[OPTIONAL]**
|
|
||||||
|
|
||||||
:VERSION:
|
|
||||||
The script format version. Valid versions are established by ParametricParts, currently only version 1.0 is
|
|
||||||
valid. If omitted, the latest version is assumed. **[OPTIONAL]**
|
|
||||||
|
|
||||||
|
|
||||||
Other metadata fields may be added in the future.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Model parameters provide the flexibility users need to customize your model. Parameters are optional, but most
|
|
||||||
users will expect at least a couple of parameters for your model to qualify as 'parametric'.
|
|
||||||
|
|
||||||
|
|
||||||
Parameters can be named whatever you would like. By convention, it is common to name them *p_<name>*, indicating
|
|
||||||
"parameter".
|
|
||||||
|
|
||||||
|
|
||||||
Each parameter has a particular type ( Float, Integer, Boolean ). Parameters also have optional attributes, which are
|
|
||||||
provided as keyword arguments:
|
|
||||||
|
|
||||||
:desc:
|
|
||||||
A description of the parameter, displayed to the user if help is needed [Optional]
|
|
||||||
|
|
||||||
:min:
|
|
||||||
The minimum value ( not applicable to Boolean ) [Optional]
|
|
||||||
|
|
||||||
:max:
|
|
||||||
The maximum value ( not applicable to Boolean ) [Optional]
|
|
||||||
|
|
||||||
:presets:
|
|
||||||
A dictionary containing key-value pairs. Each key is the name of a preset, and the value is the value the
|
|
||||||
parameter will take when the preset is selected by the user.
|
|
||||||
|
|
||||||
|
|
||||||
When a model defines presets, the user is presented with a choice of available presets in a drop-down-list.
|
|
||||||
Selecting a preset changes the values of all parameters to their associated values.
|
|
||||||
|
|
||||||
If it exists, the special preset named 'default' will be used to populate the default values when the user
|
|
||||||
is initially presented with the model.
|
|
||||||
|
|
||||||
When the model is built, the parameters are checked to ensure they meet the constraints. If they do not,
|
|
||||||
an error occurs.
|
|
||||||
|
|
||||||
:group:
|
|
||||||
If provided, parameters will be grouped together when displayed to the user. Any ungrouped parameters
|
|
||||||
will display in a special group named `default`. Groups help divide a long list of parameters to make
|
|
||||||
them easier to understand. Examples might include 'basics' and 'advanced'
|
|
||||||
|
|
||||||
|
|
||||||
Build Method
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
The heart of your model is the build method. Your build method must be called 'build'::
|
|
||||||
|
|
||||||
def build():
|
|
||||||
return Workplane("XY").box(1,1,1)
|
|
||||||
|
|
||||||
Your build method use any combination of FreeCAD, python, and CadQuery to construct objects.
|
|
||||||
You must return one of two things:
|
|
||||||
|
|
||||||
1. A CadQuery object, or
|
|
||||||
2. A FreeCAD object
|
|
||||||
|
|
||||||
In your build script,you retrieve the values of the parameters by using ``<parameter_name>.value``.
|
|
||||||
|
|
||||||
The following modules are available when your script runs:
|
|
||||||
|
|
||||||
Scripts Using CadQuery Syntax
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
:python syntax:
|
|
||||||
Python loops, dictionaries, lists, and other standard language structures are available.
|
|
||||||
|
|
||||||
:math:
|
|
||||||
Python's math package is imported for you to use
|
|
||||||
|
|
||||||
:FloatParam,IntegerParam,BooleanParam:
|
|
||||||
Parameter types used to declare parameters
|
|
||||||
|
|
||||||
:Workplane:
|
|
||||||
The CadQuery workplane object, which is the typical starting point for most scripts
|
|
||||||
|
|
||||||
:CQ:
|
|
||||||
The CadQuery object, in case you need to decorate a normal FreeCAD object
|
|
||||||
|
|
||||||
:Plane:
|
|
||||||
The CadQuery Plane object, in case you need to create non-standard planes
|
|
||||||
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
Though your script is a standard python script, it does **not** run in a standard python environment.
|
|
||||||
|
|
||||||
For security reasons, most python packages, like sys, os, import, and urllib are restricted.
|
|
||||||
|
|
||||||
|
|
||||||
FreeCAD Build Scripts
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
It is recommended that you use CadQuery for your model scripts-- the syntax is much shorter and more convienient.
|
|
||||||
|
|
||||||
But if you are willing to write more code, you can get access to all of the features that the FreeCAD library provides.
|
|
||||||
|
|
||||||
When your script executes, these FreeCAD objects are in scope as well:
|
|
||||||
|
|
||||||
:Part:
|
|
||||||
FreeCAD.Part
|
|
||||||
:Vector:
|
|
||||||
FreeCAD.Base.Vector
|
|
||||||
:Base:
|
|
||||||
FreeCAD.Base
|
|
||||||
|
|
||||||
**If you use a FreeCAD build script, your build method must return a FreeCAD shape object.**
|
|
||||||
|
|
||||||
Should you choose to write your model with the lower-level FreeCAD scripts, you may find this documentation useful:
|
|
||||||
|
|
||||||
http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=FreeCAD_API
|
|
||||||
|
|
||||||
|
see the :ref:`cqgi` section for more details.
|
|
@ -1,31 +1,56 @@
|
||||||
.. CadQuery documentation master file, created by
|
|
||||||
sphinx-quickstart on Sat Aug 25 21:10:53 2012.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
CadQuery Documentation Home
|
|
||||||
|
CadQuery Documentation
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
|
CadQuery is an intuitive, easy-to-use python library for building parametric 3D CAD models. It has several goals:
|
||||||
|
|
||||||
|
* Build models with scripts that are as close as possible to how you'd describe the object to a human,
|
||||||
|
using a standard, already established programming language
|
||||||
|
|
||||||
|
* Create parametric models that can be very easily customized by end users
|
||||||
|
|
||||||
|
* Output high quality 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
|
||||||
|
|
||||||
|
See CadQuery in Action
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
This `Getting Started Video <https://youtu.be/lxhBNOE7GVs>`_ will show you what CadQuery can do.
|
||||||
|
|
||||||
|
|
||||||
|
Quick Links
|
||||||
|
------------------
|
||||||
|
|
||||||
Contents
|
* :ref:`quickstart`
|
||||||
==================
|
* `CadQuery CheatSheet <_static/cadquery_cheatsheet.html>`_
|
||||||
|
* :ref:`apireference`
|
||||||
|
|
||||||
|
Table Of Contents
|
||||||
|
-------------------
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
intro.rst
|
intro.rst
|
||||||
|
installation.rst
|
||||||
quickstart.rst
|
quickstart.rst
|
||||||
cadquerybasics.rst
|
designprinciples.rst
|
||||||
|
primer.rst
|
||||||
|
fileformat.rst
|
||||||
examples.rst
|
examples.rst
|
||||||
apireference.rst
|
apireference.rst
|
||||||
selectors.rst
|
selectors.rst
|
||||||
classreference.rst
|
classreference.rst
|
||||||
|
cqgi.rst
|
||||||
|
extending.rst
|
||||||
|
roadmap.rst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
-------------------
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
|
|
63
CadQuery/Libs/cadquery-lib/doc/installation.rst
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
.. _installation:
|
||||||
|
|
||||||
|
Installing CadQuery
|
||||||
|
===================================
|
||||||
|
|
||||||
|
CadQuery is based on `FreeCAD <http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page>`_,
|
||||||
|
which is turn based on the open-source `OpenCascade <http://www.opencascade.com/>`_ modelling kernel.
|
||||||
|
|
||||||
|
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*
|
||||||
|
|
||||||
|
Ubuntu Command Line Installation
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
On Ubuntu, you can type::
|
||||||
|
|
||||||
|
sudo apt-get install -y freecad freecad-doc
|
||||||
|
pip install cadquery
|
||||||
|
|
||||||
|
This `Unix Installation Video <http://youtu.be/InZu8jgaYCA>`_ will walk you through the installation
|
||||||
|
|
||||||
|
|
||||||
|
Installation: Other Platforms
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
This `Windows Installation video <https://www.youtube.com/watch?v=dWw4Y_ah-8k>`_ will walk you through the installation on Windows
|
||||||
|
|
||||||
|
Test Your Installation
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
If all has gone well, you can open a command line/prompt, and type::
|
||||||
|
|
||||||
|
$python
|
||||||
|
$import cadquery
|
||||||
|
$cadquery.Workplane('XY').box(1,2,3).toSvg()
|
||||||
|
|
||||||
|
Adding a Nicer GUI via the cadquery-freecad-module
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
If you prefer to have a GUI available, your best option is to use
|
||||||
|
`The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_.
|
||||||
|
|
||||||
|
Simply extract cadquery-freecad-module into your FreeCAD installation. You'll end up
|
||||||
|
with a cadquery workbench that allows you to interactively run scripts, and then see the results in the FreeCAD GUI
|
||||||
|
|
||||||
|
If you are using Ubuntu, you can also install it via this ppa:
|
||||||
|
|
||||||
|
https://code.launchpad.net/~freecad-community/+archive/ubuntu/ppa/+packages
|
||||||
|
|
||||||
|
|
||||||
|
Zero Step Install
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
If you would like to use cadquery with no installation all, you can
|
||||||
|
use `ParametricParts.com <https://www.parametricparts.com>`_, a web-based platform that runs cadquery scripts
|
||||||
|
|
||||||
|
It is free, and allows running and viewing cadquery scripts in your web browser or mobile phone
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,10 @@ Introduction
|
||||||
What is CadQuery
|
What is CadQuery
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
CadQuery is an intuitive, easy-to-use language for building parametric 3D CAD models. It has several goals:
|
CadQuery is an intuitive, easy-to-use python library for building parametric 3D CAD models. It has several goals:
|
||||||
|
|
||||||
* Build models with scripts that are as close as possible to how you'd describe the object to a human.
|
* Build models with scripts that are as close as possible to how you'd describe the object to a human,
|
||||||
|
using a standard, already established programming language
|
||||||
|
|
||||||
* Create parametric models that can be very easily customized by end users
|
* Create parametric models that can be very easily customized by end users
|
||||||
|
|
||||||
|
@ -17,35 +18,49 @@ CadQuery is an intuitive, easy-to-use language for building parametric 3D CAD mo
|
||||||
|
|
||||||
* 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
|
||||||
|
`FreeCAD <http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page>`_,
|
||||||
|
which is turn based on the open-source `OpenCascade <http://www.opencascade.com/>`_ modelling kernel.
|
||||||
|
|
||||||
CadQuery is a Python module that provides a high-level wrapper around the
|
Using CadQuery, you can build fully parametric models with a very small amount of code. For example, this simple script
|
||||||
(`FreeCAD <http://sourceforge.net/apps/mediawiki/free-cad/index.php?title=Main_Page>`_) python libraries.
|
produces a flat plate with a hole in the middle::
|
||||||
|
|
||||||
Where does the name CadQuery come from?
|
thickness = 0.5
|
||||||
========================================
|
width=2.0
|
||||||
|
result = Workplane("front").box(width,width,thickness).faces(">Z").hole(thickness)
|
||||||
|
|
||||||
CadQuery is inspired by ( `jQuery <http://www.jquery.com>`_ ), a popular framework that
|
.. image:: _static/simpleblock.png
|
||||||
revolutionized web development involving javascript.
|
|
||||||
|
|
||||||
CadQuery is for 3D CAD what jQuery is for javascript.
|
That's a bit of a dixie-cup example. But it is pretty similar to a more useful part: a parametric pillow block for a
|
||||||
If you are familiar with how jQuery works, you will probably recognize several jQuery features that CadQuery uses:
|
standard 608-size ball bearing::
|
||||||
|
|
||||||
* A fluent api to create clean, easy to read code
|
(length,height,diam, thickness,padding) = ( 30.0,40.0,22.0,10.0,8.0)
|
||||||
|
|
||||||
* Ability to use the library along side other python libraries
|
result = Workplane("XY").box(length,height,thickness).faces(">Z").workplane().hole(diam)\
|
||||||
|
.faces(">Z").workplane() \
|
||||||
|
.rect(length-padding,height-padding,forConstruction=True) \
|
||||||
|
.vertices().cboreHole(2.4,4.4,2.1)
|
||||||
|
|
||||||
* Clear and complete documentation, with plenty of samples.
|
.. image:: _static/pillowblock.png
|
||||||
|
|
||||||
|
Lots more examples are available in the :ref:`examples`
|
||||||
|
|
||||||
|
CadQuery is a library, GUIs are separate
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
CadQuery is a library, that's intentionally designed to be usable as a GUI-less library. This enables
|
||||||
|
its use in a variety of engineering and scientific applications that create 3d models programmatically.
|
||||||
|
|
||||||
|
If you'd like a GUI, you have a couple of options:
|
||||||
|
|
||||||
|
* Install cadquery as a part of `The CadQuery Freecad Module <https://github.com/jmwright/cadquery-freecad-module>`_
|
||||||
|
* Use `ParametricParts.com <https://www.parametricparts.com>`_, a web-based platform that runs cadQuery scripts
|
||||||
|
|
||||||
|
|
||||||
Why ParametricParts instead of OpenSCAD?
|
Why CadQuery instead of OpenSCAD?
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
CadQuery is based on FreeCAD,which is in turn based on the OpenCascade modelling kernel. CadQuery/FreeCAD scripts
|
Like OpenSCAD, CadQuery is an open-source, script based, parametric model generator. But CadQuery has several key advantages:
|
||||||
share many features with OpenSCAD, another open source, script based, parametric model generator.
|
|
||||||
|
|
||||||
The primary advantage of OpenSCAD is the large number of model libaries that exist already. So why not simply use OpenSCAD?
|
|
||||||
|
|
||||||
CadQuery scripts run from ParametricParts.com have several key advantages over OpenSCAD ( including the various web-based SCAD solutions):
|
|
||||||
|
|
||||||
1. **The scripts use a standard programming language**, python, and thus can benefit from the associated infrastructure.
|
1. **The scripts use a standard programming language**, python, and thus can benefit from the associated infrastructure.
|
||||||
This includes many standard libraries and IDEs
|
This includes many standard libraries and IDEs
|
||||||
|
@ -62,3 +77,19 @@ CadQuery scripts run from ParametricParts.com have several key advantages over O
|
||||||
|
|
||||||
5. **Better Performance** CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD.
|
5. **Better Performance** CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD.
|
||||||
|
|
||||||
|
Where does the name CadQuery come from?
|
||||||
|
========================================
|
||||||
|
|
||||||
|
CadQuery is inspired by `jQuery <http://www.jquery.com>`_ , a popular framework that
|
||||||
|
revolutionized web development involving javascript.
|
||||||
|
|
||||||
|
CadQuery is for 3D CAD what jQuery is for javascript.
|
||||||
|
If you are familiar with how jQuery works, you will probably recognize several jQuery features that CadQuery uses:
|
||||||
|
|
||||||
|
* A fluent api to create clean, easy to read code
|
||||||
|
|
||||||
|
* Ability to use the library along side other python libraries
|
||||||
|
|
||||||
|
* Clear and complete documentation, with plenty of samples.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
@ECHO OFF
|
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
|
||||||
set SPHINXBUILD=sphinx-build
|
|
||||||
)
|
|
||||||
set BUILDDIR=_build
|
|
||||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
|
||||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
|
||||||
if NOT "%PAPER%" == "" (
|
|
||||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
|
||||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
|
||||||
|
|
||||||
if "%1" == "help" (
|
|
||||||
:help
|
|
||||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
|
||||||
echo. html to make standalone HTML files
|
|
||||||
echo. dirhtml to make HTML files named index.html in directories
|
|
||||||
echo. singlehtml to make a single large HTML file
|
|
||||||
echo. pickle to make pickle files
|
|
||||||
echo. json to make JSON files
|
|
||||||
echo. htmlhelp to make HTML files and a HTML help project
|
|
||||||
echo. qthelp to make HTML files and a qthelp project
|
|
||||||
echo. devhelp to make HTML files and a Devhelp project
|
|
||||||
echo. epub to make an epub
|
|
||||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
|
||||||
echo. text to make text files
|
|
||||||
echo. man to make manual pages
|
|
||||||
echo. texinfo to make Texinfo files
|
|
||||||
echo. gettext to make PO message catalogs
|
|
||||||
echo. changes to make an overview over all changed/added/deprecated items
|
|
||||||
echo. linkcheck to check all external links for integrity
|
|
||||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "clean" (
|
|
||||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
|
||||||
del /q /s %BUILDDIR%\*
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "html" (
|
|
||||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "dirhtml" (
|
|
||||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "singlehtml" (
|
|
||||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "pickle" (
|
|
||||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can process the pickle files.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "json" (
|
|
||||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can process the JSON files.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "htmlhelp" (
|
|
||||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
|
||||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "qthelp" (
|
|
||||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
|
||||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
|
||||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\CadQuery.qhcp
|
|
||||||
echo.To view the help file:
|
|
||||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\CadQuery.ghc
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "devhelp" (
|
|
||||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "epub" (
|
|
||||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "latex" (
|
|
||||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "text" (
|
|
||||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "man" (
|
|
||||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "texinfo" (
|
|
||||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "gettext" (
|
|
||||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "changes" (
|
|
||||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.The overview file is in %BUILDDIR%/changes.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "linkcheck" (
|
|
||||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Link check complete; look for any errors in the above output ^
|
|
||||||
or in %BUILDDIR%/linkcheck/output.txt.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "doctest" (
|
|
||||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
|
||||||
if errorlevel 1 exit /b 1
|
|
||||||
echo.
|
|
||||||
echo.Testing of doctests in the sources finished, look at the ^
|
|
||||||
results in %BUILDDIR%/doctest/output.txt.
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
|
|
||||||
:end
|
|
|
@ -1,9 +1,153 @@
|
||||||
.. _3d_cad_primer:
|
.. _3d_cad_primer:
|
||||||
|
|
||||||
***********************
|
|
||||||
3D CAD Primer
|
|
||||||
***********************
|
|
||||||
|
|
||||||
This section provides a basic introduction to 3D modeling. It will get you started with the basics. After that,
|
CadQuery Concepts
|
||||||
you may want to do some heavier reading on the subject (PUT LINKS HERE )
|
===================================
|
||||||
|
|
||||||
|
|
||||||
|
3D BREP Topology Concepts
|
||||||
|
---------------------------
|
||||||
|
Before talking about CadQuery, it makes sense to talk a little about 3D CAD Topology. CadQuery is based upon the
|
||||||
|
OpenCascade kernel, which is uses Boundary Representations ( BREP ) for objects. This just means that objects
|
||||||
|
are defined by their enclosing surfaces.
|
||||||
|
|
||||||
|
When working in a BREP system, these fundamental constructs exist to define a shape ( working up the food chain):
|
||||||
|
|
||||||
|
:vertex: a single point in space
|
||||||
|
:edge: a connection between two or more vertices along a particular path ( called a curve )
|
||||||
|
:wire: a collection of edges that are connected together.
|
||||||
|
:face: a set of edges or wires that enclose a surface
|
||||||
|
:shell: a collection of faces that are connected together along some of their edges
|
||||||
|
:solid: a shell that has a closed interior
|
||||||
|
:compound: a collection of solids
|
||||||
|
|
||||||
|
When using CadQuery, all of these objects are created, hopefully with the least possible work. In the actual CAD
|
||||||
|
kernel, there are another set of Geometrical constructs involved as well. For example, an arc-shaped edge will
|
||||||
|
hold a reference to an underlying curve that is a full cricle, and each linear edge holds underneath it the equation
|
||||||
|
for a line. CadQuery shields you from these constructs.
|
||||||
|
|
||||||
|
|
||||||
|
CQ, the CadQuery Object
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The CadQuery object wraps a BREP feature, and provides functionality around it. Typical examples include rotating,
|
||||||
|
transforming, combining objects, and creating workplanes.
|
||||||
|
|
||||||
|
See :ref:`apireference` to learn more.
|
||||||
|
|
||||||
|
|
||||||
|
Workplanes
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Workplanes represent a plane in space, from which other features can be located. They have a center point and a local
|
||||||
|
coordinate system.
|
||||||
|
|
||||||
|
The most common way to create a workplane is to locate one on the face of a solid. You can also create new workplanes
|
||||||
|
in space, or relative to other planes using offsets or rotations.
|
||||||
|
|
||||||
|
The most powerful feature of workplanes is that they allow you to work in 2D space in the coordinate system of the
|
||||||
|
workplane, and then build 3D features based on local coordinates. This makes scripts much easier to create and maintain.
|
||||||
|
|
||||||
|
See :py:class:`cadquery.Workplane` to learn more
|
||||||
|
|
||||||
|
|
||||||
|
2D Construction
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Once you create a workplane, you can work in 2D, and then later use the features you create to make 3D objects.
|
||||||
|
You'll find all of the 2D constructs you expect-- circles, lines, arcs, mirroring, points, etc.
|
||||||
|
|
||||||
|
See :ref:`2dOperations` to learn more.
|
||||||
|
|
||||||
|
|
||||||
|
3D Construction
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
You can construct 3D primatives 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.
|
||||||
|
|
||||||
|
See :ref:`3doperations` to learn more.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Selectors
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
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.
|
||||||
|
|
||||||
|
Think of selectors as the equivalent of your hand and mouse, were you to build an object using a conventional CAD system.
|
||||||
|
|
||||||
|
You can learn more about selectors :ref:`selectors`
|
||||||
|
|
||||||
|
|
||||||
|
Construction Geometry
|
||||||
|
---------------------------
|
||||||
|
Construction geometry are features that are not part of the object, but are only defined to aid in building the object.
|
||||||
|
A common example might be to define a rectangle, and then use the corners to define a the location of a set of holes.
|
||||||
|
|
||||||
|
Most CadQuery construction methods provide a forConstruction keyword, which creates a feature that will only be used
|
||||||
|
to locate other features
|
||||||
|
|
||||||
|
|
||||||
|
The Stack
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
As you work in CadQuery, each operation returns a new CadQuery object with the result of that operations. Each CadQuery
|
||||||
|
object has a list of objects, and a reference to its parent.
|
||||||
|
|
||||||
|
You can always go backwards to older operations by removing the current object from the stack. For example::
|
||||||
|
|
||||||
|
CQ(someObject).faces(">Z").first().vertices()
|
||||||
|
|
||||||
|
returns a CadQuery object that contains all of the vertices on highest face of someObject. But you can always move
|
||||||
|
backwards in the stack to get the face as well::
|
||||||
|
|
||||||
|
CQ(someObject).faces(">Z").first().vertices().end() #returns the same as CQ(someObject).faces(">Z").first()
|
||||||
|
|
||||||
|
You can browse stack access methods here :ref:`stackMethods`
|
||||||
|
|
||||||
|
|
||||||
|
Chaining
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
All CadQuery methods return another CadQuery object, so that you can chain the methods together fluently. Use
|
||||||
|
the core CQ methods to get at the objects that were created.
|
||||||
|
|
||||||
|
|
||||||
|
The Context Solid
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Most of the time, you are building a single object, and adding features to that single object. CadQuery watches
|
||||||
|
your operations, and defines the first solid object created as the 'context solid'. After that, any features
|
||||||
|
you create are automatically combined ( unless you specify otherwise) with that solid. This happens even if the
|
||||||
|
solid was created a long way up in the stack. For example::
|
||||||
|
|
||||||
|
Workplane('XY').box(1,2,3).faces(">Z").circle(0.25).extrude()
|
||||||
|
|
||||||
|
Will create a 1x2x3 box, with a cylindrical boss extending from the top face. It was not necessary to manually
|
||||||
|
combine the cylinder created by extruding the circle with the box, because the default behavior for extrude is
|
||||||
|
to combine the result with the context solid. The hole() method works similarly-- CadQuery presumes that you want
|
||||||
|
to subtract the hole from the context solid.
|
||||||
|
|
||||||
|
If you want to avoid this, you can specified combine=False, and CadQuery will create the solid separately.
|
||||||
|
|
||||||
|
|
||||||
|
Iteration
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
CAD models often have repeated geometry, and its really annoying to resort to for loops to construct features.
|
||||||
|
Many CadQuery methods operate automatically on each element on the stack, so that you don't have to write loops.
|
||||||
|
For example, this::
|
||||||
|
|
||||||
|
Workplane('XY').box(1,2,3).faces(">Z").vertices().circle(0.5)
|
||||||
|
|
||||||
|
Will actually create 4 circles, because vertices() selects 4 vertices of a rectangular face, and the circle() method
|
||||||
|
iterates on each member of the stack.
|
||||||
|
|
||||||
|
This is really useful to remember when you author your own plugins. :py:meth:`cadquery.CQ.Workplane.each` is useful for this purpose.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
.. _primreference:
|
|
||||||
|
|
||||||
***********************
|
|
||||||
Primitive Class Reference
|
|
||||||
***********************
|
|
||||||
|
|
||||||
.. automodule:: cadfile.cadutils.cad
|
|
||||||
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
|
|
||||||
Plane
|
|
||||||
Vector
|
|
||||||
Solid
|
|
||||||
Shell
|
|
||||||
Wire
|
|
||||||
Edge
|
|
||||||
Vertex
|
|
||||||
|
|
||||||
Geometry Classes
|
|
||||||
------------------
|
|
||||||
|
|
||||||
.. autoclass:: Vector
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: Plane
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Shape Base Class
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
All objects inherit from Shape, which as basic manipulation methods:
|
|
||||||
|
|
||||||
.. autoclass:: Shape
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Primitive Classes
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. autoclass:: Solid
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Shell
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Wire
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Edge
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: Vertex
|
|
||||||
:members:
|
|
|
@ -1,31 +1,33 @@
|
||||||
|
|
||||||
.. module:: cadquery
|
|
||||||
|
|
||||||
.. _quickstart:
|
.. _quickstart:
|
||||||
|
|
||||||
***********************
|
***********************
|
||||||
CadQuery QuickStart
|
CadQuery QuickStart
|
||||||
***********************
|
***********************
|
||||||
|
|
||||||
Want a quick glimpse of Parametric Parts ModelScripts? You're at the right place!
|
.. module:: cadquery
|
||||||
This quickstart will demonstrate the basics of ModelScripts using a simple example
|
|
||||||
|
|
||||||
Prerequisites
|
Want a quick glimpse of what CadQuery can do? This quickstart will demonstrate the basics of cadQuery using a simple example
|
||||||
=============
|
|
||||||
|
|
||||||
**WebGL Capable Browser**
|
Prerequisites: FreeCAD + cadQuery-freeCAD-module in FreeCAD
|
||||||
|
==============================================================
|
||||||
|
|
||||||
CadQuery renders models in your browser using WebGL-- which is supported by most browsers *except for IE*
|
If you have not already done so, follow the :ref:`installation`, and to install cadquery, FreeCAD,
|
||||||
You can follow along without IE, but you will not be able to see the model dynamically rendered
|
and the cadquery-freecad-module
|
||||||
|
|
||||||
|
After installation, open the CadQuery workbench:
|
||||||
|
|
||||||
|
.. 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.
|
||||||
|
|
||||||
|
If you want check out a couple of the examples in the CadQuery->Examples menu.
|
||||||
|
|
||||||
What we'll accomplish
|
What we'll accomplish
|
||||||
=====================
|
========================
|
||||||
|
|
||||||
Our finished object will look like this:
|
We will build a fully parametric bearing pillow block in this quickstart. Our finished object will look like this:
|
||||||
|
|
||||||
.. image:: quickstart.png
|
|
||||||
|
|
||||||
|
.. image:: _static/quickstart/000.png
|
||||||
|
|
||||||
**We would like our block to have these features:**
|
**We would like our block to have these features:**
|
||||||
|
|
||||||
|
@ -43,80 +45,30 @@ Hopefully our finished script will not be too much more complex than this human-
|
||||||
|
|
||||||
Let's see how we do.
|
Let's see how we do.
|
||||||
|
|
||||||
Start a new Model
|
Start With A single, simple Plate
|
||||||
==================================
|
======================================
|
||||||
|
|
||||||
CadQuery comes with an online, interactive default model as a starting point. Lets open up that tool
|
Lets start with a simple model that makes nothing but a rectangular block, but
|
||||||
`here <http://www.parametricparts.com/parts/create>`_
|
with place-holders for the dimensions. Paste this into the CodeWindow:
|
||||||
|
|
||||||
You should see the dynamic model creator page, which will display a sample model:
|
|
||||||
|
|
||||||
.. image:: _static/quickstart-1.png
|
|
||||||
|
|
||||||
Take a minute to play with this model. Here are a few things to try:
|
|
||||||
|
|
||||||
1. Use the mouse to rotate the block
|
|
||||||
2. Play with the view controls under the image
|
|
||||||
3. change the length ( the only available parameter),
|
|
||||||
and use the preview button to re-display the updated model
|
|
||||||
4. Change the preset value to `short`
|
|
||||||
5. Edit the model script itself. Change the hard-coded width and thickness values and click 'update script'
|
|
||||||
to re-display the model.
|
|
||||||
|
|
||||||
At this point, you should have some idea how to interact with the sample model, so lets get to work on the project.
|
|
||||||
|
|
||||||
Modify MetaData and Parameters
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Each model has metadata that describes the model's properties. The default Unit of Measure (UOM) will work:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
:emphasize-lines: 1
|
|
||||||
|
|
||||||
UOM = "mm"
|
height = 60.0
|
||||||
|
width = 80.0
|
||||||
|
|
||||||
Next, lets set up the parameters. Parameters are `placeholders` that users can modify separately from the script itself.
|
|
||||||
The default model has a single parameter, ``length``. Lets add a ``height`` parameter too
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
:emphasize-lines: 4
|
|
||||||
|
|
||||||
UOM = "mm"
|
|
||||||
|
|
||||||
length = FloatParam(min=30.0,max=200.0,presets={'default':80.0,'short':30.0},desc="Length of the block")
|
|
||||||
height = FloatParam(min=30.0,max=200.0,presets={'default':60.0,'short':30.0},desc="Height of the block")
|
|
||||||
thickness = 10.0
|
thickness = 10.0
|
||||||
|
|
||||||
def build():
|
# make the base
|
||||||
return Workplane("XY").box(length.value,height.value,thickness)
|
result = cq.Workplane("XY").box(height, width, thickness)
|
||||||
|
|
||||||
We've set the minimum values to 30 mm, since that's about as small as it could be while having room for a bearing 22mm
|
# Render the solid
|
||||||
in diameter. We've also set the default values to be those we'd like to start with: 80mm for the length and 60mm for the
|
build_object(result)
|
||||||
height.
|
|
||||||
|
|
||||||
Now, modify the build script to use your width value to make the block by changing ``height`` to
|
Press F2 to run the script. You should see Our basic base.
|
||||||
``height.value``
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. image:: _static/quickstart/002.png
|
||||||
:linenos:
|
|
||||||
:emphasize-lines: 3
|
|
||||||
|
|
||||||
...
|
|
||||||
def build():
|
|
||||||
return Workplane("XY").box(length.value,height.value,thickness)
|
|
||||||
|
|
||||||
The value property always returns the ``user-adjusted`` value of the parameter. That's good enough for now.
|
|
||||||
Click "Save Changes" and you should see your 80x60x10mm base plate, like this:
|
|
||||||
|
|
||||||
.. image:: _static/quickstart-2.png
|
|
||||||
|
|
||||||
If you'd like to come back to this model later, the url bar links to the newly created part.
|
|
||||||
|
|
||||||
Now lets move on and make this boring plate into a pillow block.
|
|
||||||
|
|
||||||
|
Nothing special, but its a start!
|
||||||
|
|
||||||
Add the Holes
|
Add the Holes
|
||||||
================
|
================
|
||||||
|
@ -127,21 +79,34 @@ This modification will do the trick:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
:emphasize-lines: 3
|
:emphasize-lines: 4,8
|
||||||
|
|
||||||
...
|
height = 60.0
|
||||||
def build():
|
width = 80.0
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0)
|
thickness = 10.0
|
||||||
|
diameter = 22.0
|
||||||
|
|
||||||
Rebuild your model by clicking "Save Model" at the bottom. Your block should look like this:
|
# make the base
|
||||||
|
result = cq.Workplane("XY").box(height, width, thickness)\
|
||||||
|
.faces(">Z").workplane().hole(diameter)
|
||||||
|
|
||||||
.. image:: _static/quickstart-3.png
|
# Render the solid
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
Rebuild your model by pressing F2. Your block should look like this:
|
||||||
|
|
||||||
|
.. image:: _static/quickstart/003.png
|
||||||
|
|
||||||
|
|
||||||
The code is pretty compact, and works like this:
|
The code is pretty compact, lets step through it.
|
||||||
* :py:meth:`Workplane.faces` selects the top-most face in the Z direction, and
|
|
||||||
* :py:meth:`Workplane.workplane` begins a new workplane located on this face
|
**Line 4** adds a new parameter, diameter, for the diamter of the hole
|
||||||
* :py:meth:`Workplane.hole` drills a hole through the part 22mm in diamter
|
|
||||||
|
**Line 8**, we're adding the hole.
|
||||||
|
:py:meth:`cadquery.CQ.faces` selects the top-most face in the Z direction, and then
|
||||||
|
:py:meth:`cadquery.CQ.workplane` begins a new workplane located on this face. The center of this workplane
|
||||||
|
is located at the geometric center of the shape, which in this case is the center of the plate.
|
||||||
|
Finally, :py:meth:`cadquery.Workplane.hole` drills a hole through the part 22mm in diamter
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -163,60 +128,45 @@ The centers of these holes should be 4mm from the edges of the block. And,
|
||||||
we want the block to work correctly even when the block is re-sized by the user.
|
we want the block to work correctly even when the block is re-sized by the user.
|
||||||
|
|
||||||
**Don't tell me** we'll have to repeat the steps above 8 times to get counter-bored holes?
|
**Don't tell me** we'll have to repeat the steps above 8 times to get counter-bored holes?
|
||||||
|
|
||||||
Good news!-- we can get the job done with just two lines of code. Here's the code we need:
|
Good news!-- we can get the job done with just two lines of code. Here's the code we need:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
:emphasize-lines: 4-5
|
:emphasize-lines: 5,10-13
|
||||||
|
|
||||||
...
|
height = 60.0
|
||||||
def build():
|
width = 80.0
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) \
|
thickness = 10.0
|
||||||
.faces(">Z").workplane() \
|
diameter = 22.0
|
||||||
.rect(length.value-8.0,height.value-8.0,forConstruction=True) \
|
padding = 12.0
|
||||||
.vertices().cboreHole(2.4,4.4,2.1)
|
|
||||||
|
|
||||||
You should see something like this:
|
# make the base
|
||||||
|
result = cq.Workplane("XY").box(height, width, thickness)\
|
||||||
|
.faces(">Z").workplane().hole(diameter)\
|
||||||
|
.faces(">Z").workplane() \
|
||||||
|
.rect(height - padding,width - padding,forConstruction=True)\
|
||||||
|
.vertices()\
|
||||||
|
.cboreHole(2.4, 4.4, 2.1)
|
||||||
|
|
||||||
.. image:: _static/quickstart-4.png
|
# Render the solid
|
||||||
|
build_object(result)
|
||||||
Lets Break that down a bit
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
|
|
||||||
**Line 4** selects the top-most face of the block, and creates a workplane on the top that face, which we'll use to
|
After pressing F2 to re-execute the model, you should see something like this:
|
||||||
define the centers of the holes in the corners:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. image:: _static/quickstart/004.png
|
||||||
:linenos:
|
|
||||||
:emphasize-lines: 4
|
|
||||||
|
|
||||||
...
|
|
||||||
def build():
|
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) \
|
|
||||||
.faces(">Z").workplane() \
|
|
||||||
.rect(length.value-8.0,width.value-8.0,forConstruction=True) \
|
|
||||||
.vertices().cboreHole(2.4,4.4,2.1)
|
|
||||||
|
|
||||||
|
|
||||||
**Line 5** draws a rectangle 8mm smaller than the overall length and width of the block,which we will use to
|
There is quite a bit going on here, so lets break it down a bit.
|
||||||
locate the corner holes:
|
|
||||||
|
|
||||||
.. code-block:: python
|
**Line 5** creates a new padding parameter that decides how far the holes are from the edges of the plate.
|
||||||
:linenos:
|
|
||||||
:emphasize-lines: 5
|
|
||||||
|
|
||||||
...
|
**Line 10** selects the top-most face of the block, and creates a workplane on the top of that face, which we'll use to
|
||||||
def build():
|
define the centers of the holes in the corners.
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) \
|
|
||||||
.faces(">Z").workplane() \
|
|
||||||
.rect(length.value-8.0,width.value-8.0,forConstruction=True) \
|
|
||||||
.vertices().cboreHole(2.4,4.4,2.1)
|
|
||||||
|
|
||||||
There are a couple of things to note about this line:
|
There are a couple of things to note about this line:
|
||||||
|
|
||||||
1. The :py:meth:`Workplane.rect` function draws a rectangle. **forConstruction=True**
|
1. The :py:meth:`cadquery.Workplane.rect` function draws a rectangle. **forConstruction=True**
|
||||||
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
|
||||||
|
@ -224,81 +174,69 @@ There are a couple of things to note about this line:
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
**Line 6** selects the corners of the rectangle, and makes the holes:
|
**Line 11** draws a rectangle 8mm smaller than the overall length and width of the block,which we will use to
|
||||||
|
locate the corner holes. We'll use the vertices ( corners ) of this rectangle to locate the holes. The rectangle's
|
||||||
|
center is at the center of the workplane, which in this case co-incides with the center of the bearing hole.
|
||||||
|
|
||||||
.. code-block:: python
|
**Line 12** selects the vertices of the rectangle, which we will use for the centers of the holes.
|
||||||
:linenos:
|
The :py:meth:`cadquery.CQ.vertices` function selects the corners of the rectangle
|
||||||
:emphasize-lines: 6
|
|
||||||
|
|
||||||
...
|
**Line 13** uses the cboreHole function to draw the holes.
|
||||||
def build():
|
The :py:meth:`cadquery.Workplane.cboreHole` function is a handy CadQuery function that makes a counterbored hole,
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) \
|
like most other CadQuery functions, operate on the values on the stack. In this case, since we
|
||||||
.faces(">Z").workplane() \
|
selected the four vertices before calling the function, the function operates on each of the four points--
|
||||||
.rect(length.value-8.0,width.value-8.0,forConstruction=True) \
|
which results in a counterbore hole at the corners.
|
||||||
.vertices().cboreHole(2.4,4.4,2.1)
|
|
||||||
|
|
||||||
Notes about this line:
|
|
||||||
|
|
||||||
1. The :py:meth:`CQ.vertices` function selects the corners of the rectangle
|
Filleting
|
||||||
2. The :py:meth:`Workplane.cboreHole` function is a handy CadQuery function that makes a counterbored hole
|
|
||||||
3. ``cboreHole``, like most other CadQuery functions, operate on the values on the stack. In this case, since
|
|
||||||
selected the four vertices before calling the function, the function operates on each of the four points--
|
|
||||||
which results in a counterbore hole at the corners.
|
|
||||||
|
|
||||||
Presets
|
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Almost done. This model is pretty easy to configure, but we can make it even easier by providing users with a few
|
Almost done. Let's just round the corners of the block a bit. That's easy, we just need to select the edges
|
||||||
'out of the box' options to choose from. Lets provide two preset options:
|
and then fillet them:
|
||||||
|
|
||||||
* **Small** : 30 mm x 40mm
|
|
||||||
* **Square-Medium** : 50 mm x 50mm
|
|
||||||
|
|
||||||
We can do that using the preset dictionaries in the parameter definition:
|
We can do that using the preset dictionaries in the parameter definition:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
:emphasize-lines: 2-3
|
:emphasize-lines: 13
|
||||||
|
|
||||||
...
|
height = 60.0
|
||||||
length = FloatParam(min=10.0,max=500.0,presets={'default':100.0,'small':30.0,'square-medium':50},desc="Length of the box")
|
width = 80.0
|
||||||
height = FloatParam(min=30.0,max=200.0,presets={'default':60.0,'small':40.0,'square-medium':50},desc="Height of the block")
|
thickness = 10.0
|
||||||
|
diameter = 22.0
|
||||||
|
padding = 12.0
|
||||||
|
|
||||||
Now save the model and have a look at the preset DDLB-- you'll see that you can easily switch between these
|
# make the base
|
||||||
configurations:
|
result = cq.Workplane("XY").box(height, width, thickness)\
|
||||||
|
.faces(">Z").workplane().hole(diameter)\
|
||||||
|
.faces(">Z").workplane() \
|
||||||
|
.rect(height - padding, width - padding, forConstruction=True)\
|
||||||
|
.vertices().cboreHole(2.4, 4.4, 2.1)\
|
||||||
|
.edges("|Z").fillet(2.0)
|
||||||
|
|
||||||
.. image:: _static/quickstart-5.png
|
# Render the solid
|
||||||
|
build_object(result)
|
||||||
|
|
||||||
|
**Line 13** fillets the edges using the :py:meth:`cadquery.CQ.fillet` method.
|
||||||
|
|
||||||
|
To grab the right edges, the :py:meth:`cadquery.CQ.edges` selects all of the
|
||||||
|
edges that are parallel to the Z axis ("\|Z"),
|
||||||
|
|
||||||
|
The finished product looks like this:
|
||||||
|
|
||||||
|
.. image:: _static/quickstart/005.png
|
||||||
|
|
||||||
|
|
||||||
Done!
|
Done!
|
||||||
============
|
============
|
||||||
|
|
||||||
And... We're done! Congratulations, you just made a parametric, 3d model with 15 lines of code.Users can use this
|
You just made a parametric, model that can generate pretty much any bearing pillow block
|
||||||
model to generate pillow blocks in any size they would like
|
with < 20 lines of code.
|
||||||
|
|
||||||
For completeness, Here's a copy of the finished model:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
:linenos:
|
|
||||||
|
|
||||||
UOM = "mm"
|
|
||||||
|
|
||||||
length = FloatParam(min=10.0,max=500.0,presets={'default':100.0,'small':30.0,'square-medium':50},desc="Length of the box")
|
|
||||||
height = FloatParam(min=30.0,max=200.0,presets={'default':60.0,'small':40.0,'square-medium':50},desc="Height of the block")
|
|
||||||
|
|
||||||
width = 40.0
|
|
||||||
thickness = 10.0
|
|
||||||
|
|
||||||
def build():
|
|
||||||
return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) \
|
|
||||||
.faces(">Z").workplane() \
|
|
||||||
.rect(length.value-8.0,height.value-8.0,forConstruction=True) \
|
|
||||||
.vertices().cboreHole(2.4,4.4,2.1)
|
|
||||||
|
|
||||||
|
|
||||||
Want to learn more?
|
Want to learn more?
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
* 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.
|
|
@ -1,114 +0,0 @@
|
||||||
.. _buildservice:
|
|
||||||
|
|
||||||
******************************************
|
|
||||||
The Parametric Parts Build Service
|
|
||||||
******************************************
|
|
||||||
|
|
||||||
|
|
||||||
If you have registered for an account, you can use the REST api to build models from your website or platform.
|
|
||||||
Each request to the service will construct a model in the format you choose.
|
|
||||||
|
|
||||||
|
|
||||||
Using the Build Service
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
The Build Service endpoint is `<https://parametricparts.com/parts/build>`_
|
|
||||||
|
|
||||||
In each request, you provide four main things via either a GET or a POST :
|
|
||||||
|
|
||||||
1. **An API Key**, to identify yourself.
|
|
||||||
2. **A ModelScript to build**, either by providing the entire script, or the id of a model stored on
|
|
||||||
parametricparts.com,
|
|
||||||
3. **The type of output** you want,
|
|
||||||
4. **The Model parameters** that should be supplied to the model.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
GET or POSTs are allowed, but be aware that URLs for GET requests are limited to 4K,
|
|
||||||
so POSTs are advised if you are sending your modelScript via the URL
|
|
||||||
|
|
||||||
The output streamed in the format you have requested.
|
|
||||||
|
|
||||||
Errors are provided using standard HTTP error codes:
|
|
||||||
|
|
||||||
:200: if the build is a success
|
|
||||||
:403: if the APIKey is invalid, or if your account cannot execute any more downloads
|
|
||||||
:404: if the requested model cannot be found
|
|
||||||
:50X: if there is a problem generating the model
|
|
||||||
|
|
||||||
Build Service Parameters
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
All parameters must be URL encoded:
|
|
||||||
|
|
||||||
:key:
|
|
||||||
(Required) Your API Key. See :ref:`gettingakey` If you do not have one.
|
|
||||||
|
|
||||||
:id:
|
|
||||||
(Either id or s is Required) The id of the ParametricParts.com ModelScript to build. The id is the last part of the url
|
|
||||||
when viewing the model: http://parametricparts.com/parts/<modelId>. Model ids are between 7 and 9
|
|
||||||
characters, for example '4hskpb69'.
|
|
||||||
|
|
||||||
:s:
|
|
||||||
(Either id or s is Required) The ModelScript to build. This should be a valid parametricparts.com ModelScript.
|
|
||||||
If both id and s are provided, s takes precedence.
|
|
||||||
|
|
||||||
:type:
|
|
||||||
(Required) ("STL" | "STEP" | "AMF" | "TJS" ). The type of output you want to receive. STL, STEP,
|
|
||||||
and AMF return the corresponding industry standard format.
|
|
||||||
TJS will return JSON content suitable for display in a Three.js scene.
|
|
||||||
|
|
||||||
:preset:
|
|
||||||
(Optional) The name of a preset defined in the ModelScript. If omitted, other parameters are used.
|
|
||||||
If a preset is provided in addition to parameters, then the preset is applied first, and then
|
|
||||||
parameters are set afterwards.
|
|
||||||
|
|
||||||
:<params>:
|
|
||||||
(Optional) Remaining URL parameters are mapped onto ModelScript parameters of the same name. Each
|
|
||||||
parameter value must have the datatype corresponding to the parameter in the ModelScript. To supply multiple
|
|
||||||
parameters, send an HTTP parameter for each desired value, having name matching the name of the ModelScript
|
|
||||||
parameter, and value having the value for that parameter. If no
|
|
||||||
parameters are provided, output is generated using ModelScript defaults.
|
|
||||||
|
|
||||||
Example
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
This example builds STEP for a trivial model, without supplying any model parameters or presets::
|
|
||||||
|
|
||||||
POST https://parametricparts.com/parts/build HTTP/1.1
|
|
||||||
key:259cd575c9a2998420ac65f21b2d6b2a
|
|
||||||
s:def+build%28%29%3A%0D%0A++++return+Part.makeBox%281%2C2%2C3%29%0D%0A++++++++
|
|
||||||
type:AMF
|
|
||||||
|
|
||||||
|
|
||||||
This example selects an existing model (2qus7a32 ) on the server, and requests
|
|
||||||
preset 'short', as well as adjusting parameter 'p_length' to value 120::
|
|
||||||
|
|
||||||
POST https://parametricparts.com/parts/build HTTP/1.1
|
|
||||||
key:259cd575c9a2998420ac65f21b2d6b2a
|
|
||||||
id:2qus7a32
|
|
||||||
type:STL
|
|
||||||
preset:short
|
|
||||||
p_length:120
|
|
||||||
|
|
||||||
|
|
||||||
.. _gettingakey:
|
|
||||||
|
|
||||||
Signing Up
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
In order to use the API, you first need to have an API key. To get one:
|
|
||||||
|
|
||||||
1. `Sign Up <https://parametricparts.com/account/signup>`_ for a ParametricParts account
|
|
||||||
2. `Contact ParametricParts Support <http://support.parametricparts.com/customer/portal/emails/new>`_ to request API key access.
|
|
||||||
API keys usually require an enterprise license, but are available for free evaluation if you request access
|
|
||||||
3. Log onto your ParametricParts account, and generate an API Key using the `API Keys <https://localhost:8080/key/keys>`_ link.
|
|
||||||
4. Test your api key using the api key tester `Here <https://parametricparts.com/apitester>`_
|
|
||||||
If the test goes well, you'll see STL output from the sample script.
|
|
||||||
|
|
||||||
Now you are ready to make REST requests to build models.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
Make sure to keep your API Key secret, as any requests that use your key will be charged to your account.
|
|
||||||
You can disable or generate a new API Key from your account page.
|
|
|
@ -1,8 +1,8 @@
|
||||||
.. _roadmap:
|
.. _roadmap:
|
||||||
|
|
||||||
**************************
|
|
||||||
RoadMap: Planned Features
|
RoadMap: Planned Features
|
||||||
**************************
|
==============================
|
||||||
|
|
||||||
**CadQuery is not even close to finished!!!**
|
**CadQuery is not even close to finished!!!**
|
||||||
|
|
||||||
|
@ -139,17 +139,11 @@ primitive creation
|
||||||
* wedge
|
* wedge
|
||||||
|
|
||||||
extrude/cut up to surface
|
extrude/cut up to surface
|
||||||
allow a cut or extrude to terminate at another surface ,rather than either through all or a fixed distance
|
allow a cut or extrude to terminate at another surface, rather than either through all or a fixed distance
|
||||||
|
|
||||||
extrude along a path
|
extrude along a path
|
||||||
rather than just normal to the plane. This would include
|
rather than just normal to the plane. This would include
|
||||||
|
|
||||||
loft
|
|
||||||
create a feature between two or more wire sections
|
|
||||||
|
|
||||||
revolve
|
|
||||||
revolve a wire around an axis to create a solid
|
|
||||||
|
|
||||||
STEP import
|
STEP import
|
||||||
allow embedding and importing step solids created in other tools, which
|
allow embedding and importing step solids created in other tools, which
|
||||||
can then be further manipulated parametrically
|
can then be further manipulated parametrically
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
.. _selector_reference:
|
.. _selector_reference:
|
||||||
|
|
||||||
*************************
|
String Selectors Reference
|
||||||
CadQuery String Selectors
|
=============================
|
||||||
*************************
|
|
||||||
|
|
||||||
.. automodule:: cadquery
|
|
||||||
|
|
||||||
CadQuery selector strings allow filtering various types of object lists. Most commonly, Edges, Faces, and Vertices are
|
CadQuery selector strings allow filtering various types of object lists. Most commonly, Edges, Faces, and Vertices are
|
||||||
used, but all objects types can be filtered.
|
used, but all objects types can be filtered.
|
||||||
|
|
||||||
String selectors are used as arguments to the various selection methods:
|
String selectors are simply shortcuts for using the full object equivalents. If you pass one of the
|
||||||
|
string patterns in, CadQuery will automatically use the associated selector object.
|
||||||
|
|
||||||
* :py:meth:`CQ.faces`
|
* :py:meth:`cadquery.CQ.faces`
|
||||||
* :py:meth:`CQ.edges`
|
* :py:meth:`cadquery.CQ.edges`
|
||||||
* :py:meth:`CQ.vertices`
|
* :py:meth:`cadquery.CQ.vertices`
|
||||||
* :py:meth:`CQ.solids`
|
* :py:meth:`cadquery.CQ.solids`
|
||||||
* :py:meth:`CQ.shells`
|
* :py:meth:`cadquery.CQ.shells`
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -26,6 +25,29 @@ String selectors are used as arguments to the various selection methods:
|
||||||
See :ref:`extending` to see how.
|
See :ref:`extending` to see how.
|
||||||
|
|
||||||
|
|
||||||
|
Combining Selectors
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Selectors can be combined arithmetically and logically, so that it is possible to do intersection, union, and other
|
||||||
|
combinations. For example::
|
||||||
|
|
||||||
|
box = cadquery.Workplane("XY").box(10,10,10)
|
||||||
|
|
||||||
|
s = selectors.StringSyntaxSelector
|
||||||
|
|
||||||
|
### select all edges on right and left faces
|
||||||
|
#box = box.edges((s("|Z") + s("|Y"))).fillet(1)
|
||||||
|
|
||||||
|
### select all edges on top and bottom
|
||||||
|
#box = box.edges(-s("|Z")).fillet(1)
|
||||||
|
#box = box.edges(s('|X')+s('Y')).fillet(1)
|
||||||
|
box = box.faces(s('>Z')+s('<Z')).fillet(1)
|
||||||
|
|
||||||
|
|
||||||
|
or for another example::
|
||||||
|
|
||||||
|
# select diagonal edges
|
||||||
|
box = box.faces(s('>Z')+s('<Z')).edges(-s('|X')-s('Y')).fillet(1)
|
||||||
|
|
||||||
.. _filteringfaces:
|
.. _filteringfaces:
|
||||||
|
|
||||||
|
@ -42,17 +64,17 @@ of the face.
|
||||||
|
|
||||||
The axis used in the listing below are for illustration: any axis would work similarly in each case.
|
The axis used in the listing below are for illustration: any axis would work similarly in each case.
|
||||||
|
|
||||||
========= ==================================== ====================================== ==========================
|
========= ====================================== ======================================================= ==========================
|
||||||
Selector Selector Class Selects # objects returned
|
Selector Selects Selector Class # objects returned
|
||||||
========= ==================================== ====================================== ==========================
|
========= ====================================== ======================================================= ==========================
|
||||||
+Z :py:class:`DirectionSelector` Faces with normal in +z direction 0 or 1
|
+Z Faces with normal in +z direction :py:class:`cadquery.DirectionSelector` 0 or 1
|
||||||
\|Z :py:class:`ParallelDirSelector` Faces parallel to xy plane 0..many
|
\|Z Faces parallel to xy plane :py:class:`cadquery.ParallelDirSelector` 0..many
|
||||||
-X :py:class:`DirectionSelector` Faces with normal in neg x direction 0..many
|
-X Faces with normal in neg x direction :py:class:`cadquery.DirectionSelector` 0..many
|
||||||
#Z :py:class:`PerpendicularDirSelector` Faces perpendicular to z direction 0..many
|
#Z Faces perpendicular to z direction :py:class:`cadquery.PerpendicularDirSelector` 0..many
|
||||||
%Plane :py:class:`TypeSelector` Faces of type plane 0..many
|
%Plane Faces of type plane :py:class:`cadquery.TypeSelector` 0..many
|
||||||
>Y :py:class:`DirectionMinMaxSelector` Face farthest in the positive y dir 0 or 1
|
>Y Face farthest in the positive y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
<Y :py:class:`DirectionMinMaxSelector` Face farthest in the negative y dir 0 or 1
|
<Y Face farthest in the negative y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
========= ==================================== ====================================== ==========================
|
========= ====================================== ======================================================= ==========================
|
||||||
|
|
||||||
|
|
||||||
.. _filteringedges:
|
.. _filteringedges:
|
||||||
|
@ -70,18 +92,17 @@ Some filter types are not supported for edges. The selector usually refers to t
|
||||||
The axis used in the listing below are for illustration: any axis would work similarly in each case.
|
The axis used in the listing below are for illustration: any axis would work similarly in each case.
|
||||||
|
|
||||||
|
|
||||||
|
========= ==================================== ======================================================= ==========================
|
||||||
========= ==================================== ===================================== ==========================
|
Selector Selects Selector Class # objects returned
|
||||||
Selector Selector Class Selects # objects returned
|
========= ==================================== ======================================================= ==========================
|
||||||
========= ==================================== ===================================== ==========================
|
+Z Edges aligned in the Z direction :py:class:`cadquery.DirectionSelector` 0..many
|
||||||
+Z :py:class:`DirectionSelector` Edges aligned in the Z direction 0..many
|
\|Z Edges parallel to z direction :py:class:`cadquery.ParallelDirSelector` 0..many
|
||||||
\|Z :py:class:`ParallelDirSelector` Edges parallel to z direction 0..many
|
-X Edges aligned in neg x direction :py:class:`cadquery.DirectionSelector` 0..many
|
||||||
-X :py:class:`DirectionSelector` Edges aligned in neg x direction 0..many
|
#Z Edges perpendicular to z direction :py:class:`cadquery.PerpendicularDirSelector` 0..many
|
||||||
#Z :py:class:`PerpendicularDirSelector` Edges perpendicular to z direction 0..many
|
%Line Edges of type line :py:class:`cadquery.TypeSelector` 0..many
|
||||||
%Line :py:class:`TypeSelector` Edges of type line 0..many
|
>Y Edges farthest in the positive y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
>Y :py:class:`DirectionMinMaxSelector` Edges farthest in the positive y dir 0 or 1
|
<Y Edges farthest in the negative y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
<Y :py:class:`DirectionMinMaxSelector` Edges farthest in the negative y dir 0 or 1
|
========= ==================================== ======================================================= ==========================
|
||||||
========= ==================================== ===================================== ==========================
|
|
||||||
|
|
||||||
|
|
||||||
.. _filteringvertices:
|
.. _filteringvertices:
|
||||||
|
@ -91,12 +112,12 @@ Filtering Vertices
|
||||||
|
|
||||||
Only a few of the filter types apply to vertices. The location of the vertex is the subject of the filter
|
Only a few of the filter types apply to vertices. The location of the vertex is the subject of the filter
|
||||||
|
|
||||||
========= ==================================== ===================================== ==========================
|
========= ======================================= ======================================================= ==========================
|
||||||
Selector Selector Class Selects # objects returned
|
Selector Selects Selector Class # objects returned
|
||||||
========= ==================================== ===================================== ==========================
|
========= ======================================= ======================================================= ==========================
|
||||||
>Y :py:class:`DirectionMinMaxSelector` Vertices farthest in the positive y dir 0 or 1
|
>Y Vertices farthest in the positive y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
<Y :py:class:`DirectionMinMaxSelector` Vertices farthest in the negative y dir 0 or 1
|
<Y Vertices farthest in the negative y dir :py:class:`cadquery.DirectionMinMaxSelector` 0 or 1
|
||||||
========= ==================================== ===================================== ==========================
|
========= ======================================= ======================================================= ==========================
|
||||||
|
|
||||||
Future Enhancements
|
Future Enhancements
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
{% extends "basic/layout.html" %}
|
|
||||||
|
|
||||||
{%- block extrahead %}
|
|
||||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
|
||||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&subset=latin" type="text/css" media="screen" charset="utf-8" />
|
|
||||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,800">
|
|
||||||
<!--[if lte IE 6]>
|
|
||||||
<link rel="stylesheet" href="{{ pathto('_static/ie6.css', 1) }}" type="text/css" media="screen" charset="utf-8" />
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
var _gaq = _gaq || [];
|
|
||||||
_gaq.push(['_setAccount', 'UA-37657197-1']);
|
|
||||||
_gaq.push(['_setDomainName', 'none']);
|
|
||||||
_gaq.push(['_setAllowLinker', 'true']);
|
|
||||||
_gaq.push(['_trackPageview']);
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
||||||
})();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<![endif]-->
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block header %}
|
|
||||||
{%- if logo %}
|
|
||||||
<div class="header">
|
|
||||||
<a href="{{ pathto(master_doc) }}">
|
|
||||||
<div class="logo">
|
|
||||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{%- block sidebarlogo %}{%- endblock %}
|
|
||||||
{%- block sidebarsourcelink %}{%- endblock %}
|
|
Before Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,310 +0,0 @@
|
||||||
/*
|
|
||||||
* default.css_t
|
|
||||||
* ~~~~~~~~~~~~~
|
|
||||||
*
|
|
||||||
* Sphinx stylesheet -- default theme.
|
|
||||||
*
|
|
||||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
|
||||||
* :license: BSD, see LICENSE for details.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import url("basic.css");
|
|
||||||
|
|
||||||
/* -- page layout ----------------------------------------------------------- */
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: {{ theme_bodyfont }};
|
|
||||||
font-size: 100%;
|
|
||||||
background-color: {{ theme_footerbgcolor }};
|
|
||||||
color: #000;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.document {
|
|
||||||
background-color: {{ theme_sidebarbgcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.documentwrapper {
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.bodywrapper {
|
|
||||||
margin: 0 0 0 230px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body {
|
|
||||||
background-color: {{ theme_bgcolor }};
|
|
||||||
color: {{ theme_textcolor }};
|
|
||||||
padding: 0 20px 30px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
{%- if theme_rightsidebar|tobool %}
|
|
||||||
div.bodywrapper {
|
|
||||||
margin: 0 230px 0 0;
|
|
||||||
}
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
div.footer {
|
|
||||||
color: {{ theme_footertextcolor }};
|
|
||||||
width: 100%;
|
|
||||||
padding: 9px 0 9px 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer a {
|
|
||||||
color: {{ theme_footertextcolor }};
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related {
|
|
||||||
background-color: {{ theme_relbarbgcolor }};
|
|
||||||
line-height: 30px;
|
|
||||||
color: {{ theme_relbartextcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related a {
|
|
||||||
color: {{ theme_relbarlinkcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar {
|
|
||||||
{%- if theme_stickysidebar|tobool %}
|
|
||||||
top: 30px;
|
|
||||||
bottom: 0;
|
|
||||||
margin: 0;
|
|
||||||
position: fixed;
|
|
||||||
overflow: auto;
|
|
||||||
height: auto;
|
|
||||||
{%- endif %}
|
|
||||||
{%- if theme_rightsidebar|tobool %}
|
|
||||||
float: right;
|
|
||||||
{%- if theme_stickysidebar|tobool %}
|
|
||||||
right: 0;
|
|
||||||
{%- endif %}
|
|
||||||
{%- endif %}
|
|
||||||
}
|
|
||||||
|
|
||||||
{%- if theme_stickysidebar|tobool %}
|
|
||||||
/* this is nice, but it it leads to hidden headings when jumping
|
|
||||||
to an anchor */
|
|
||||||
/*
|
|
||||||
div.related {
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.documentwrapper {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3 {
|
|
||||||
font-family: {{ theme_headfont }};
|
|
||||||
color: {{ theme_sidebartextcolor }};
|
|
||||||
font-size: 1.4em;
|
|
||||||
font-weight: normal;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3 a {
|
|
||||||
color: {{ theme_sidebartextcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h4 {
|
|
||||||
font-family: {{ theme_headfont }};
|
|
||||||
color: {{ theme_sidebartextcolor }};
|
|
||||||
font-size: 1.3em;
|
|
||||||
font-weight: normal;
|
|
||||||
margin: 5px 0 0 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar p {
|
|
||||||
color: {{ theme_sidebartextcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar p.topless {
|
|
||||||
margin: 5px 10px 10px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar ul {
|
|
||||||
margin: 10px;
|
|
||||||
padding: 0;
|
|
||||||
color: {{ theme_sidebartextcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar a {
|
|
||||||
color: {{ theme_sidebarlinkcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar input {
|
|
||||||
border: 1px solid {{ theme_sidebarlinkcolor }};
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
{% if theme_collapsiblesidebar|tobool %}
|
|
||||||
/* for collapsible sidebar */
|
|
||||||
div#sidebarbutton {
|
|
||||||
background-color: {{ theme_sidebarbtncolor }};
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
/* -- hyperlink styles ------------------------------------------------------ */
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: {{ theme_linkcolor }};
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: {{ theme_visitedlinkcolor }};
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
{% if theme_externalrefs|tobool %}
|
|
||||||
a.external {
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: 1px dashed {{ theme_linkcolor }};
|
|
||||||
}
|
|
||||||
|
|
||||||
a.external:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.external:visited {
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: 1px dashed {{ theme_visitedlinkcolor }};
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
/* -- body styles ----------------------------------------------------------- */
|
|
||||||
|
|
||||||
div.body h1,
|
|
||||||
div.body h2,
|
|
||||||
div.body h3,
|
|
||||||
div.body h4,
|
|
||||||
div.body h5,
|
|
||||||
div.body h6 {
|
|
||||||
font-family: {{ theme_headfont }};
|
|
||||||
background-color: {{ theme_headbgcolor }};
|
|
||||||
font-weight: normal;
|
|
||||||
color: {{ theme_headtextcolor }};
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
margin: 20px -20px 10px -20px;
|
|
||||||
padding: 3px 0 3px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body h1 { margin-top: 0; font-size: 200%; }
|
|
||||||
div.body h2 { font-size: 160%; }
|
|
||||||
div.body h3 { font-size: 140%; }
|
|
||||||
div.body h4 { font-size: 120%; }
|
|
||||||
div.body h5 { font-size: 110%; }
|
|
||||||
div.body h6 { font-size: 100%; }
|
|
||||||
|
|
||||||
a.headerlink {
|
|
||||||
color: {{ theme_headlinkcolor }};
|
|
||||||
font-size: 0.8em;
|
|
||||||
padding: 0 4px 0 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.headerlink:hover {
|
|
||||||
background-color: {{ theme_headlinkcolor }};
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body p, div.body dd, div.body li {
|
|
||||||
text-align: justify;
|
|
||||||
line-height: 130%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.admonition p.admonition-title + p {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.admonition p {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.admonition pre {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.admonition ul, div.admonition ol {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.note {
|
|
||||||
background-color: #eee;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.seealso {
|
|
||||||
background-color: #ffc;
|
|
||||||
border: 1px solid #ff6;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.topic {
|
|
||||||
background-color: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.warning {
|
|
||||||
background-color: #ffe4e4;
|
|
||||||
border: 1px solid #f66;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.admonition-title {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.admonition-title:after {
|
|
||||||
content: ":";
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
padding: 5px;
|
|
||||||
background-color: {{ theme_codebgcolor }};
|
|
||||||
color: {{ theme_codetextcolor }};
|
|
||||||
line-height: 120%;
|
|
||||||
border: 1px solid #ac9;
|
|
||||||
border-left: none;
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt {
|
|
||||||
background-color: #ecf0f3;
|
|
||||||
padding: 0 1px 0 1px;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
background-color: #ede;
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning tt {
|
|
||||||
background: #efc2c2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note tt {
|
|
||||||
background: #d6d6d6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewcode-back {
|
|
||||||
font-family: {{ theme_bodyfont }};
|
|
||||||
}
|
|
||||||
|
|
||||||
div.viewcode-block:target {
|
|
||||||
background-color: #f4debf;
|
|
||||||
border-top: 1px solid #ac9;
|
|
||||||
border-bottom: 1px solid #ac9;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 333 B |
Before Width: | Height: | Size: 203 B |
|
@ -1,7 +0,0 @@
|
||||||
* html img,
|
|
||||||
* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
|
|
||||||
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
|
|
||||||
this.src = "_static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
|
|
||||||
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
|
|
||||||
this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
|
|
||||||
);}
|
|
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,387 +0,0 @@
|
||||||
/*
|
|
||||||
* pylons.css_t
|
|
||||||
* ~~~~~~~~~~~~
|
|
||||||
*
|
|
||||||
* Sphinx stylesheet -- pylons theme.
|
|
||||||
*
|
|
||||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
|
||||||
* :license: BSD, see LICENSE for details.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
@import url("basic.css");
|
|
||||||
|
|
||||||
/* -- page layout ----------------------------------------------------------- */
|
|
||||||
|
|
||||||
html {background-image:url(../img/bg/html.png);}
|
|
||||||
body {color:#333;background-position:50% -400px;background-repeat:repeat-x;}
|
|
||||||
#home {background-position:50% 0;}
|
|
||||||
body, input, textarea, button {font:13px/20px Arial,sans-serif;}
|
|
||||||
|
|
||||||
/* Color for the links */
|
|
||||||
a {color:#84B51E; text-decoration:none;}
|
|
||||||
|
|
||||||
* {margin:0;}
|
|
||||||
p, ul, ol, table, form, pre {margin-bottom:20px;}
|
|
||||||
img {border:none;max-width:100%;}
|
|
||||||
ul {list-style:none;}
|
|
||||||
:focus {outline:0;}
|
|
||||||
.clear {clear:both;}
|
|
||||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {display:block;}
|
|
||||||
.wrapper:after, #login:after {content:".";display:block;height:0;clear:both;visibility:hidden;}
|
|
||||||
|
|
||||||
/* Overall background color and image */
|
|
||||||
html, #login {background-color:#f5f5f5;}
|
|
||||||
body {background-image:url('../img/bg/body.jpg');}
|
|
||||||
|
|
||||||
/* Background and border color for drop-down navigation */
|
|
||||||
nav ul ul {background-color:#13171A;border-color:#84B51E;}
|
|
||||||
|
|
||||||
/* Footer background color */
|
|
||||||
footer, footer h3 span {background-color:#13171A;}
|
|
||||||
|
|
||||||
/* Primary navigation color */
|
|
||||||
nav>ul>li>a {color:#ddd;}
|
|
||||||
|
|
||||||
/* Header colors */
|
|
||||||
h1, h1 a {color:#13171A;}
|
|
||||||
h2, h2 a, h3, h4, .pricing thead th {color:#444;}
|
|
||||||
|
|
||||||
|
|
||||||
/* Color for the links */
|
|
||||||
p a, .wrapper ul li a {color:#84B51E;}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Open Sans',Arial,sans-serif;
|
|
||||||
font-size: 100%;
|
|
||||||
background-color: #333;
|
|
||||||
color: #ffffff;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.documentwrapper {
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.bodywrapper {
|
|
||||||
margin: 0 0 0 {{ theme_sidebarwidth }}px;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: 1px solid #B1B4B6;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.document {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.header {
|
|
||||||
width:100%;
|
|
||||||
height:142px;
|
|
||||||
background: #eaad32 url(body.jpg) bottom;
|
|
||||||
position:relative;
|
|
||||||
}
|
|
||||||
div.header ul > li > a{
|
|
||||||
text-decoration:none;
|
|
||||||
line-height:30px;
|
|
||||||
font-size:15px;
|
|
||||||
padding: 0 12p 0 13px;
|
|
||||||
}
|
|
||||||
div.header ul {
|
|
||||||
background:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.logo {
|
|
||||||
text-align: left;
|
|
||||||
padding: 15px 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body {
|
|
||||||
background-color: #ffffff;
|
|
||||||
color: #3E4349;
|
|
||||||
padding: 0 30px 30px 30px;
|
|
||||||
font-size: 1em;
|
|
||||||
border-left: 1px solid #333;
|
|
||||||
border-right-style: none;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer {
|
|
||||||
color: #ffffff;
|
|
||||||
background-color:#13171A;
|
|
||||||
width: 100%;
|
|
||||||
padding: 13px 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 75%;
|
|
||||||
background: transparent;
|
|
||||||
clear:both;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer a {
|
|
||||||
color: #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer a:hover {
|
|
||||||
color: #e88f00;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related {
|
|
||||||
position:absolute;
|
|
||||||
top: 52px;
|
|
||||||
width:100%;
|
|
||||||
margin:0;
|
|
||||||
list-style:none;
|
|
||||||
line-height: 30px;
|
|
||||||
color: #373839;
|
|
||||||
font-size: 15px;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related a {
|
|
||||||
color: #1b61d6;
|
|
||||||
}
|
|
||||||
div.related h3{
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related ul {
|
|
||||||
padding-left: 450px;
|
|
||||||
}
|
|
||||||
div.related li{
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
div.related li.right{
|
|
||||||
display:inline;
|
|
||||||
}
|
|
||||||
div.related ul > li a{
|
|
||||||
font-size: 30px;
|
|
||||||
text-decoration: none;
|
|
||||||
line-height:30px;
|
|
||||||
color: #ddd;
|
|
||||||
font-weight:bold;
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
div.related ul > li.right a{
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight:normal;
|
|
||||||
display:inline;
|
|
||||||
}
|
|
||||||
div.sphinxsidebar {
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebarwrapper{
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3,
|
|
||||||
div.sphinxsidebar h4 {
|
|
||||||
color: #373839;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #444;
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px 10px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3{
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3 a {
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div.sphinxsidebar p {
|
|
||||||
color: #888;
|
|
||||||
padding: 5px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar p.topless {
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar ul {
|
|
||||||
margin: 10px 20px;
|
|
||||||
padding: 0;
|
|
||||||
color: #373839;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div.sphinxsidebar input {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar input[type=text]{
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- sidebars -------------------------------------------------------------- */
|
|
||||||
|
|
||||||
div.sidebar {
|
|
||||||
margin: 0 0 0.5em 1em;
|
|
||||||
border: 2px solid #c6d880;
|
|
||||||
background-color: #e6efc2;
|
|
||||||
width: 40%;
|
|
||||||
float: right;
|
|
||||||
border-right-style: none;
|
|
||||||
border-left-style: none;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.sidebar-title {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- body styles ----------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
div.body h1,
|
|
||||||
div.body h2,
|
|
||||||
div.body h3,
|
|
||||||
div.body h4,
|
|
||||||
div.body h5,
|
|
||||||
div.body h6 {
|
|
||||||
font-family: 'Open Sans',Arial,sans-serif;
|
|
||||||
background-color: #ffffff;
|
|
||||||
font-weight: normal;
|
|
||||||
color: #444;
|
|
||||||
margin: 30px 0px 10px 0px;
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
|
||||||
div.body h2 { font-size: 150%; background-color: #ffffff; }
|
|
||||||
div.body h3 { font-size: 120%; background-color: #ffffff; }
|
|
||||||
div.body h4 { font-size: 110%; background-color: #ffffff; }
|
|
||||||
div.body h5 { font-size: 100%; background-color: #ffffff; }
|
|
||||||
div.body h6 { font-size: 100%; background-color: #ffffff; }
|
|
||||||
|
|
||||||
a.headerlink {
|
|
||||||
color: #1b61d6;
|
|
||||||
font-size: 0.8em;
|
|
||||||
padding: 0 4px 0 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.headerlink:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body p, div.body dd, div.body li {
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.admonition p.admonition-title + p {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.highlight{
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.note {
|
|
||||||
border: 2px solid #7a9eec;
|
|
||||||
border-right-style: none;
|
|
||||||
border-left-style: none;
|
|
||||||
padding: 10px 20px 10px 60px;
|
|
||||||
background: #e1ecfe url(dialog-note.png) no-repeat 10px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.seealso {
|
|
||||||
background: #fff6bf url(dialog-seealso.png) no-repeat 10px 8px;
|
|
||||||
border: 2px solid #ffd324;
|
|
||||||
border-left-style: none;
|
|
||||||
border-right-style: none;
|
|
||||||
padding: 10px 20px 10px 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.topic {
|
|
||||||
background: #eeeeee;
|
|
||||||
border: 2px solid #C6C9CB;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-right-style: none;
|
|
||||||
border-left-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.warning {
|
|
||||||
background: #fbe3e4 url(dialog-warning.png) no-repeat 10px 8px;
|
|
||||||
border: 2px solid #fbc2c4;
|
|
||||||
border-right-style: none;
|
|
||||||
border-left-style: none;
|
|
||||||
padding: 10px 20px 10px 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.admonition-title {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.admonition-title:after {
|
|
||||||
content: ":";
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
padding: 10px;
|
|
||||||
background-color: #fafafa;
|
|
||||||
color: #222;
|
|
||||||
line-height: 1.2em;
|
|
||||||
border: 2px solid #C6C9CB;
|
|
||||||
font-size: 1.1em;
|
|
||||||
margin: 1.5em 0 1.5em 0;
|
|
||||||
border-right-style: none;
|
|
||||||
border-left-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt {
|
|
||||||
background-color: transparent;
|
|
||||||
color: #222;
|
|
||||||
font-size: 1.1em;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewcode-back {
|
|
||||||
font-family: "Nobile", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.viewcode-block:target {
|
|
||||||
background-color: #fff6bf;
|
|
||||||
border: 2px solid #ffd324;
|
|
||||||
border-left-style: none;
|
|
||||||
border-right-style: none;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.highlighttable {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.highlighttable td {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
a em.std-term {
|
|
||||||
color: #007f00;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover em.std-term {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download {
|
|
||||||
font-family: "Nobile", sans-serif;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt.xref {
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 49 B |
|
@ -1,4 +0,0 @@
|
||||||
[theme]
|
|
||||||
inherit = basic
|
|
||||||
stylesheet = pparts.css
|
|
||||||
pygments_style = friendly
|
|
3
CadQuery/Libs/cadquery-lib/requirements-dev.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
sphinx-rtd-theme==0.1.9
|
||||||
|
travis-sphinx==1.1.0
|
||||||
|
Sphinx==1.3.1
|
|
@ -14,4 +14,5 @@ suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQSelectors.TestC
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
|
||||||
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQGI.TestCQGI))
|
||||||
unittest.TextTestRunner().run(suite)
|
unittest.TextTestRunner().run(suite)
|
||||||
|
|
|
@ -1,14 +1,28 @@
|
||||||
|
# Copyright 2015 Parametric Products Intellectual Holdings, LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='cadquery',
|
name='cadquery',
|
||||||
version='0.3.0',
|
version='0.4.0',
|
||||||
url='https://github.com/dcowden/cadquery',
|
url='https://github.com/dcowden/cadquery',
|
||||||
license='LGPL',
|
license='Apache Public License 2.0',
|
||||||
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=open('README.txt').read(),
|
long_description=open('README.md').read(),
|
||||||
packages=['cadquery','cadquery.contrib','cadquery.freecad_impl','cadquery.plugins','tests'],
|
packages=['cadquery','cadquery.contrib','cadquery.freecad_impl','cadquery.plugins','tests'],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
@ -16,11 +30,6 @@ setup(
|
||||||
test_suite='tests',
|
test_suite='tests',
|
||||||
|
|
||||||
classifiers=[
|
classifiers=[
|
||||||
# As from http://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
||||||
#'Development Status :: 1 - Planning',
|
|
||||||
#'Development Status :: 2 - Pre-Alpha',
|
|
||||||
#'Development Status :: 3 - Alpha',
|
|
||||||
#'Development Status :: 4 - Beta',
|
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
#'Development Status :: 6 - Mature',
|
#'Development Status :: 6 - Mature',
|
||||||
#'Development Status :: 7 - Inactive',
|
#'Development Status :: 7 - Inactive',
|
||||||
|
@ -29,7 +38,7 @@ setup(
|
||||||
'Intended Audience :: Information Technology',
|
'Intended Audience :: Information Technology',
|
||||||
'Intended Audience :: Science/Research',
|
'Intended Audience :: Science/Research',
|
||||||
'Intended Audience :: System Administrators',
|
'Intended Audience :: System Administrators',
|
||||||
'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
|
'License :: OSI Approved :: Apache Software License',
|
||||||
'Operating System :: POSIX',
|
'Operating System :: POSIX',
|
||||||
'Operating System :: MacOS',
|
'Operating System :: MacOS',
|
||||||
'Operating System :: Unix',
|
'Operating System :: Unix',
|
||||||
|
|
170
CadQuery/Libs/cadquery-lib/tests/TestCQGI.py
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
"""
|
||||||
|
Tests CQGI functionality
|
||||||
|
|
||||||
|
Currently, this includes:
|
||||||
|
Parsing a script, and detecting its available variables
|
||||||
|
Altering the values at runtime
|
||||||
|
defining a build_object function to return results
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cadquery import cqgi
|
||||||
|
from tests import BaseTest
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
TESTSCRIPT = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
height=2.0
|
||||||
|
width=3.0
|
||||||
|
(a,b) = (1.0,1.0)
|
||||||
|
foo="bar"
|
||||||
|
|
||||||
|
result = "%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) )
|
||||||
|
build_object(result)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCQGI(BaseTest):
|
||||||
|
def test_parser(self):
|
||||||
|
model = cqgi.CQModel(TESTSCRIPT)
|
||||||
|
metadata = model.metadata
|
||||||
|
|
||||||
|
self.assertEquals(set(metadata.parameters.keys()), {'height', 'width', 'a', 'b', 'foo'})
|
||||||
|
|
||||||
|
def test_build_with_empty_params(self):
|
||||||
|
model = cqgi.CQModel(TESTSCRIPT)
|
||||||
|
result = model.build()
|
||||||
|
|
||||||
|
self.assertTrue(result.success)
|
||||||
|
self.assertTrue(len(result.results) == 1)
|
||||||
|
self.assertTrue(result.results[0] == "2.0|3.0|bar|1.0")
|
||||||
|
|
||||||
|
def test_build_with_different_params(self):
|
||||||
|
model = cqgi.CQModel(TESTSCRIPT)
|
||||||
|
result = model.build({'height': 3.0})
|
||||||
|
self.assertTrue(result.results[0] == "3.0|3.0|bar|1.0")
|
||||||
|
|
||||||
|
def test_build_with_exception(self):
|
||||||
|
badscript = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
raise ValueError("ERROR")
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
model = cqgi.CQModel(badscript)
|
||||||
|
result = model.build({})
|
||||||
|
self.assertFalse(result.success)
|
||||||
|
self.assertIsNotNone(result.exception)
|
||||||
|
self.assertTrue(result.exception.message == "ERROR")
|
||||||
|
|
||||||
|
def test_that_invalid_syntax_in_script_fails_immediately(self):
|
||||||
|
badscript = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
this doesnt even compile
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(Exception) as context:
|
||||||
|
model = cqgi.CQModel(badscript)
|
||||||
|
|
||||||
|
self.assertTrue('invalid syntax' in context.exception)
|
||||||
|
|
||||||
|
def test_that_two_results_are_returned(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = 1
|
||||||
|
build_object(h)
|
||||||
|
h = 2
|
||||||
|
build_object(h)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
model = cqgi.CQModel(script)
|
||||||
|
result = model.build({})
|
||||||
|
self.assertEquals(2, len(result.results))
|
||||||
|
self.assertEquals(1, result.results[0])
|
||||||
|
self.assertEquals(2, result.results[1])
|
||||||
|
|
||||||
|
def test_that_assinging_number_to_string_works(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = "this is a string"
|
||||||
|
build_object(h)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = cqgi.parse(script).build( {'h': 33.33})
|
||||||
|
self.assertEquals(result.results[0], "33.33")
|
||||||
|
|
||||||
|
def test_that_assigning_string_to_number_fails(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = 20.0
|
||||||
|
build_object(h)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = cqgi.parse(script).build( {'h': "a string"})
|
||||||
|
self.assertTrue(isinstance(result.exception, cqgi.InvalidParameterError))
|
||||||
|
|
||||||
|
def test_that_assigning_unknown_var_fails(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = 20.0
|
||||||
|
build_object(h)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
result = cqgi.parse(script).build( {'w': "var is not there"})
|
||||||
|
self.assertTrue(isinstance(result.exception, cqgi.InvalidParameterError))
|
||||||
|
|
||||||
|
def test_that_not_calling_build_object_raises_error(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = 20.0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = cqgi.parse(script).build()
|
||||||
|
self.assertTrue(isinstance(result.exception, cqgi.NoOutputError))
|
||||||
|
|
||||||
|
def test_that_cq_objects_are_visible(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
r = cadquery.Workplane('XY').box(1,2,3)
|
||||||
|
build_object(r)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
result = cqgi.parse(script).build()
|
||||||
|
self.assertTrue(result.success)
|
||||||
|
self.assertIsNotNone(result.first_result)
|
||||||
|
|
||||||
|
def test_setting_boolean_variable(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = True
|
||||||
|
build_object( "*%s*" % str(h) )
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
#result = cqgi.execute(script)
|
||||||
|
result = cqgi.parse(script).build({'h': False})
|
||||||
|
|
||||||
|
self.assertTrue(result.success)
|
||||||
|
self.assertEquals(result.first_result,'*False*')
|
||||||
|
|
||||||
|
def test_that_only_top_level_vars_are_detected(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
h = 1.0
|
||||||
|
w = 2.0
|
||||||
|
|
||||||
|
def do_stuff():
|
||||||
|
x = 1
|
||||||
|
y = 2
|
||||||
|
|
||||||
|
build_object( "result" )
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
model = cqgi.parse(script)
|
||||||
|
|
||||||
|
self.assertEquals(2, len(model.metadata.parameters))
|
|
@ -51,4 +51,4 @@ class BaseTest(unittest.TestCase):
|
||||||
for i, j in zip(actual, expected):
|
for i, j in zip(actual, expected):
|
||||||
self.assertAlmostEquals(i, j, places)
|
self.assertAlmostEquals(i, j, places)
|
||||||
|
|
||||||
__all__ = ['TestCadObjects', 'TestCadQuery', 'TestCQSelectors', 'TestWorkplanes', 'TestExporters', 'TestCQSelectors', 'TestImporters']
|
__all__ = ['TestCadObjects', 'TestCadQuery', 'TestCQSelectors', 'TestWorkplanes', 'TestExporters', 'TestCQSelectors', 'TestImporters','TestCQGI']
|
||||||
|
|