diff --git a/cadquery/freecad_impl/exporters.py b/cadquery/freecad_impl/exporters.py index 5d8d321..efb174f 100644 --- a/cadquery/freecad_impl/exporters.py +++ b/cadquery/freecad_impl/exporters.py @@ -21,8 +21,48 @@ try: import xml.etree.cElementTree as ET except ImportError: import xml.etree.ElementTree as ET + +class ExportFormats: + STL = "STL" + BREP = "BREP" + STEP = "STEP" + AMF = "AMF" + IGES = "IGES" -class AMFWriter(object): +class UNITS: + MM = "mm" + IN = "in" + +def guessUnitOfMeasure(shape): + """ + Guess the unit of measure of a shape. + """ + bb = shape.BoundBox + + dimList = [ bb.XLength, bb.YLength,bb.ZLength ] + #no real part would likely be bigger than 10 inches on any side + if max(dimList) > 10: + return UNITS.MM + + #no real part would likely be smaller than 0.1 mm on all dimensions + if min(dimList) < 0.1: + return UNITS.IN + + #no real part would have the sum of its dimensions less than about 5mm + if sum(dimList) < 10: + return UNITS.IN + + return UNITS.MM + +class Exporter(object): + + def export(self): + """ + return a string representing the model exported in the specified format + """ + raise NotImplementedError() + +class AMFExporter(Exporter): def __init__(self,tessellation): self.units = "mm" @@ -65,7 +105,7 @@ class AMFWriter(object): three.js JSON object notation https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.0 """ -class JsonMesh(object): +class JsonExporter(Exporter): def __init__(self): self.vertices = []; @@ -95,31 +135,8 @@ class JsonMesh(object): 'nFaces' : self.nFaces }; +class SVGExporter(Exporter): -class UNITS: - MM = "mm" - IN = "in" - -def guessUnitOfMeasure(shape): - """ - Guess the unit of measure of a shape. - """ - bb = shape.BoundBox - - dimList = [ bb.XLength, bb.YLength,bb.ZLength ] - #no real part would likely be bigger than 10 inches on any side - if max(dimList) > 10: - return UNITS.MM - - #no real part would likely be smaller than 0.1 mm on all dimensions - if min(dimList) < 0.1: - return UNITS.IN - - #no real part would have the sum of its dimensions less than about 5mm - if sum(dimList) < 10: - return UNITS.IN - - return UNITS.MM def getPaths(freeCadSVG): """ diff --git a/cadquery/freecad_impl/shapes.py b/cadquery/freecad_impl/shapes.py index 887a625..0221bde 100644 --- a/cadquery/freecad_impl/shapes.py +++ b/cadquery/freecad_impl/shapes.py @@ -49,14 +49,6 @@ """ -class ExportFormats: - STL = "STL" - BREP = "BREP" - STEP = "STEP" - AMF = "AMF" - IGES = "IGES" - - class Shape(object): """ Represents a shape in the system. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..ed35aa2 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,153 @@ +# 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 ' where 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." diff --git a/doc/_static/ParametricPulley.PNG b/doc/_static/ParametricPulley.PNG new file mode 100644 index 0000000..c5e6e87 Binary files /dev/null and b/doc/_static/ParametricPulley.PNG differ diff --git a/doc/_static/PillowBlock.PNG b/doc/_static/PillowBlock.PNG new file mode 100644 index 0000000..76d5e38 Binary files /dev/null and b/doc/_static/PillowBlock.PNG differ diff --git a/doc/_static/block.png b/doc/_static/block.png new file mode 100644 index 0000000..1ab7ec7 Binary files /dev/null and b/doc/_static/block.png differ diff --git a/doc/_static/new_badge.png b/doc/_static/new_badge.png new file mode 100644 index 0000000..7a2a1fe Binary files /dev/null and b/doc/_static/new_badge.png differ diff --git a/doc/_static/parametric-cup-screencap.PNG b/doc/_static/parametric-cup-screencap.PNG new file mode 100644 index 0000000..b9ee082 Binary files /dev/null and b/doc/_static/parametric-cup-screencap.PNG differ diff --git a/doc/_static/quickstart-1.png b/doc/_static/quickstart-1.png new file mode 100644 index 0000000..6dd6e9a Binary files /dev/null and b/doc/_static/quickstart-1.png differ diff --git a/doc/_static/quickstart-2.png b/doc/_static/quickstart-2.png new file mode 100644 index 0000000..6dd6e9a Binary files /dev/null and b/doc/_static/quickstart-2.png differ diff --git a/doc/_static/quickstart-3.png b/doc/_static/quickstart-3.png new file mode 100644 index 0000000..e4997f0 Binary files /dev/null and b/doc/_static/quickstart-3.png differ diff --git a/doc/_static/quickstart-4.png b/doc/_static/quickstart-4.png new file mode 100644 index 0000000..e3d7568 Binary files /dev/null and b/doc/_static/quickstart-4.png differ diff --git a/doc/_static/quickstart-5.png b/doc/_static/quickstart-5.png new file mode 100644 index 0000000..45430d9 Binary files /dev/null and b/doc/_static/quickstart-5.png differ diff --git a/doc/_static/quickstart.png b/doc/_static/quickstart.png new file mode 100644 index 0000000..467b9c7 Binary files /dev/null and b/doc/_static/quickstart.png differ diff --git a/doc/apireference.rst b/doc/apireference.rst new file mode 100644 index 0000000..ba948aa --- /dev/null +++ b/doc/apireference.rst @@ -0,0 +1,139 @@ +.. _apireference: + +*********************** +CadQuery API Reference +*********************** + +.. automodule:: cadfile.cadutils.cadquery + +.. seealso:: + This page lists api methods grouped by functional area. + Use :ref:`classreference` to see methods alphabetically by class. + Don't see a method you want? see :ref:`extending` + +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 +---------------- + +Creating new workplanes and object chains + +.. autosummary:: + CQ + Workplane + CQ.workplane + + +.. _2dOperations: + +2-d Operations +----------------- + +Creating 2-d constructs that can be used to create 3 d features + +.. autosummary:: + Workplane.center + Workplane.lineTo + Workplane.line + Workplane.vLine + Workplane.vLineTo + Workplane.hLine + Workplane.moveTo + Workplane.move + Workplane.spline + Workplane.threePointArc + Workplane.rotateAndCopy + Workplane.mirrorY + Workplane.mirrorX + Workplane.wire + Workplane.rect + Workplane.circle + Workplane.polyline + Workplane.close + Workplane.rarray + +.. _3doperations: + +3-d Operations +----------------- + +Methods that create 3d features + +.. autosummary:: + + Workplane.cboreHole + Workplane.cskHole + Workplane.hole + Workplane.extrude + Workplane.cut + Workplane.cutBlind + Workplane.cutThruAll + Workplane.box + Workplane.union + Workplane.combine + CQ.shell + CQ.fillet + CQ.split + CQ.rotateAboutCenter + CQ.translate + + +Iteration Methods +------------------ + +Methods that allow iteration over the stack or objects + +.. autosummary:: + Workplane.each + Workplane.eachpoint + + +.. _stackMethods: + +Stack Methods +----------------- + +CadQuery methods that operate on the stack + +.. autosummary:: + CQ.all + CQ.size + CQ.vals + CQ.add + CQ.val + CQ.first + CQ.item + CQ.last + CQ.end + CQ.vertices + CQ.faces + CQ.edges + CQ.wires + CQ.solids + CQ.shells + CQ.compounds + +.. _selectors: + +Selectors +------------------------ + +Objects that filter and select CAD objects + +.. autosummary:: + NearestToPointSelector + ParallelDirSelector + DirectionSelector + PerpendicularDirSelector + TypeSelector + DirectionMinMaxSelector + StringSyntaxSelector diff --git a/doc/cadquerybasics.rst b/doc/cadquerybasics.rst new file mode 100644 index 0000000..91188c2 --- /dev/null +++ b/doc/cadquerybasics.rst @@ -0,0 +1,243 @@ +.. _cadquerybasics: + +.. automodule:: cadfile.cadutils.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:: 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 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. diff --git a/doc/classreference.rst b/doc/classreference.rst new file mode 100644 index 0000000..8fcb76a --- /dev/null +++ b/doc/classreference.rst @@ -0,0 +1,71 @@ +.. _classreference: + +************************* +CadQuery Class Reference +************************* + +This page documents all of the methods and functions of the CadQuery classes, organized alphabatically. + +.. seealso:: + + For a listing organized by functional area, see the :ref:`apireference` + +.. automodule:: cadfile.cadutils.cadquery + +Core Classes +--------------------- + +.. autosummary:: + CQ + Plane + Workplane + + +Selectors +--------------------- + +.. autosummary:: + NearestToPointSelector + ParallelDirSelector + DirectionSelector + PerpendicularDirSelector + TypeSelector + DirectionMinMaxSelector + StringSyntaxSelector + +Classes +------------------------ + +.. autoclass:: CQ + :members: + +.. autoclass:: Plane + :members: + +.. autoclass:: Workplane + :members: + :inherited-members: + +.. autoclass:: Selector + :members: + +.. autoclass:: NearestToPointSelector + :members: + +.. autoclass:: ParallelDirSelector + :members: + +.. autoclass:: DirectionSelector + :members: + +.. autoclass:: PerpendicularDirSelector + :members: + +.. autoclass:: TypeSelector + :members: + +.. autoclass:: DirectionMinMaxSelector + :members: + +.. autoclass:: StringSyntaxSelector + :members: \ No newline at end of file diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..0912e6b --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,272 @@ +# -*- coding: utf-8 -*- +# +# CadQuery documentation build configuration file, created by +# sphinx-quickstart on Sat Aug 25 21:10:53 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +import cadquery + +settings._target = None + + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary','cadfile.cadutils.cq_directive'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CadQuery' +copyright = u'Parametric Products Intellectual Holdings LLC, All Rights Reserved' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'timlinux-linfiniti-sphinx' +html_theme = 'pparts' + +# 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 +# documentation. +#html_theme_options = { +# "headerfont": "'Open Sans',Arial,sans-serif", +# #"bodyfont:": "'Open Sans',Arial,sans-serif", +# #"headerbg" : "{image: url('/img/bg/body.jpg');color:#000000;}", +# "headerbg" : "color:black;", +# "footerbg" : "{color:#13171A;}", +# "linkcolor": "#84B51E;", +## "headercolor1": "#13171A;", +# "headercolor2": "#444;", +# "headerlinkcolor" : "#13171A;", +#} + +#agogo options +""" + bodyfont (CSS font family): Font for normal text. + headerfont (CSS font family): Font for headings. + pagewidth (CSS length): Width of the page content, default 70em. + documentwidth (CSS length): Width of the document (without sidebar), default 50em. + sidebarwidth (CSS length): Width of the sidebar, default 20em. + bgcolor (CSS color): Background color. + headerbg (CSS value for “background”): background for the header area, default a grayish gradient. + footerbg (CSS value for “background”): background for the footer area, default a light gray gradient. + linkcolor (CSS color): Body link color. + headercolor1, headercolor2 (CSS color): colors for

and

headings. + headerlinkcolor (CSS color): Color for the backreference link in headings. + textalign (CSS text-align value): Text alignment for the body, default is justify. +""" +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = "Documentation" + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = "logo.png" + +# 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 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CadQuerydoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'CadQuery.tex', u'CadQuery Documentation', + u'David Cowden', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'cadquery', u'CadQuery Documentation', + [u'David Cowden'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'CadQuery', u'CadQuery Documentation', + u'David Cowden', 'CadQuery', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/doc/examples.rst b/doc/examples.rst new file mode 100644 index 0000000..b4c51d2 --- /dev/null +++ b/doc/examples.rst @@ -0,0 +1,688 @@ +.. _examples: + +********************************* +CadQuery Examples +********************************* + +.. automodule:: cadfile.cadutils.cadquery +.. automodule:: cadfile.cadutils.cad + +The examples on this page can help you learn how to build objects with CadQuery. + +They are organized from simple to complex, so working through them in order is the best way to absorb them. + +Each example lists the api elements used in the example for easy reference. +Items introduced in the example are marked with a **!** + +.. note:: + + You may want to work through these examples by pasting the text into a scratchpad on the live website. + If you do, make sure to take these steps so that they work: + + 1. paste the content into the build() method, properly intented, and + 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. + +.. warning:: + + * 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 + :backlinks: entry + + +Simple Rectangular Plate +------------------------ + +Just about the simplest possible example, a rectangular box + +.. cq_plot:: + + result = Workplane("front").box(2.0,2.0,0.5) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane` **!** + * :py:meth:`Workplane.box` **!** + +Plate with Hole +------------------------ + +A rectangular box, but with a hole added. + +"\>Z" selects the top most face of the resulting box. The hole is located in the center because the default origin +of a working plane is at the center of the face. The default hole depth is through the entire part. + +.. cq_plot:: + + result = Workplane("front").box(2.0,2.0,0.5).faces(">Z").hole(0.5) + + + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.hole` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.box` + +An extruded prismatic solid +------------------------------- + +Build a prismatic solid using extrusion. After a drawing operation, the center of the previous object +is placed on the stack, and is the reference for the next operation. So in this case, the rect() is drawn +centered on the previously draw circle. + +By default, rectangles and circles are centered around the previous working point. + +.. cq_plot:: + + result = Workplane("front").circle(2.0).rect(0.5,0.75).extrude(0.5) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.circle` **!** + * :py:meth:`Workplane.rect` **!** + * :py:meth:`Workplane.extrude` **!** + * :py:meth:`Workplane` + +Building Profiles using lines and arcs +-------------------------------------- + +Sometimes you need to build complex profiles using lines and arcs. This example builds a prismatic +solid from 2-d operations. + +2-d operations maintain a current point, which is initially at the origin. Use close() to finish a +closed curve. + + +.. cq_plot:: + + result = Workplane("front").lineTo(2.0,0).lineTo(2.0,1.0).threePointArc((1.0,1.5),(0.0,1.0))\ + .close().extrude(0.25) + + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.threePointArc` **!** + * :py:meth:`Workplane.lineTo` **!** + * :py:meth:`Workplane.extrude` + * :py:meth:`Workplane` + +Moving The Current working point +--------------------------------- + +In this example, a closed profile is required, with some interior features as well. + +This example also demonstrates using multiple lines of code instead of longer chained commands, +though of course in this case it was possible to do it in one long line as well. + +A new work plane center can be established at any point. + +.. cq_plot:: + + result = 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,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! + + result = result.extrude(0.25) + + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.center` **!** + * :py:meth:`Workplane` + * :py:meth:`Workplane.circle` + * :py:meth:`Workplane.rect` + * :py:meth:`Workplane.extrude` + +Using Point Lists +--------------------------- + +Sometimes you need to create a number of features at various locations, and using :py:meth:`Workplane.center` +is too cumbersome. + +You can use a list of points to construct multiple objects at once. Most construction methods, +like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on multiple points if they are on the stack + +.. cq_plot:: + + r = 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.circle( 0.25 ) # circle will operate on all four points + result = r.extrude(0.125 ) # make prism + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.points` **!** + * :py:meth:`Workplane` + * :py:meth:`Workplane.circle` + * :py:meth:`Workplane.extrude` + +Polygons +------------------------- + +You can create polygons for each stack point if you would like. Useful in 3d printers whos firmware does not +correct for small hole sizes. + +.. cq_plot:: + + result = Workplane("front").box(3.0,4.0,0.25).pushPoints ( [ ( 0,0.75 ),(0,-0.75) ]) \ + .polygon(6,1.0).cutThruAll() + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.polygon` **!** + * :py:meth:`Workplane.pushPoints` + * :py:meth:`Workplane.box` + +Polylines +------------------------- + +:py:meth:`Workplane.polyline` allows creating a shape from a large number of chained points connected by lines. + +This example uses a polyline to create one half of an i-beam shape, which is mirrored to create the final profile. + +.. cq_plot:: + + (L,H,W,t) = ( 100.0,20.0,20.0,1.0) + pts = [ + (0,H/2.0), + (W/2.0,H/2.0), + (W/2.0,(H/2.0 - t)), + (t/2.0,(H/2.0-t)), + (t/2.0,(t - H/2.0)), + (W/2.0,(t -H/2.0)), + (W/2.0,H/-2.0), + (0,H/-2.0) + ] + result = Workplane("front").polyline(pts).mirrorY().extrude(L) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.polyline` **!** + * :py:meth:`Workplane` + * :py:meth:`Workplane.mirrorY` + * :py:meth:`Workplane.extrude` + + + +Defining an Edge with a Spline +------------------------------ + +This example defines a side using a spline curve through a collection of points. Useful when you have an edge that +needs a complex profile + +.. cq_plot:: + + s = Workplane("XY") + sPnts = [ + (2.75,1.5), + (2.5,1.75), + (2.0,1.5), + (1.5,1.0), + (1.0,1.25), + (0.5,1.0), + (0,1.0) + ] + r = s.lineTo(3.0,0).lineTo(3.0,1.0).spline(sPnts).close() + result = r.extrude(0.5) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.spline` **!** + * :py:meth:`Workplane` + * :py:meth:`Workplane.close` + * :py:meth:`Workplane.lineTo` + * :py:meth:`Workplane.extrude` + +Mirroring Symmetric Geometry +----------------------------- + +You can mirror 2-d geometry when your shape is symmetric. In this example we also +introduce horizontal and vertical lines, which make for slightly easier coding. + + +.. cq_plot:: + + r = 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 + result =r.mirrorY().extrude(0.25 ) # mirror the geometry and extrude + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.hLine` **!** + * :py:meth:`Workplane.vLine` **!** + * :py:meth:`Workplane.hLineTo` **!** + * :py:meth:`Workplane.mirrorY` **!** + * :py:meth:`Workplane.mirrorX` **!** + * :py:meth:`Workplane` + * :py:meth:`Workplane.extrude` + + +Creating Workplanes on Faces +----------------------------- + +This example shows how to locate a new workplane on the face of a previously created feature. + +.. note:: + Using workplanes in this way are a key feature of CadQuery. Unlike typical 3d scripting language, + using work planes frees you from tracking the position of various features in variables, and + allows the model to adjust itself with removing redundant dimensions + +The :py:meth:`Workplane.faces()` method allows you to select the faces of a resulting solid. It accepts +a selector string or object, that allows you to target a single face, and make a workplane oriented on that +face. + +Keep in mind that the origin of new workplanes are located at the center of a face by default. + +.. cq_plot:: + + result = 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 + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.faces` **!** + * :py:meth:`StringSyntaxSelector` **!** + * :ref:`selector_reference` **!** + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane.box` + * :py:meth:`Workplane` + +Locating a Workplane on a vertex +--------------------------------- + +Normally, the :py:meth:`Workplane.workplane` method requires a face to be selected. But if a vertex is selected +**immediately after a face**, :py:meth:`Workplane.workplane` will locate the workplane on the face, with the origin at the vertex instead +of at the center of the face + +The example also introduces :py:meth:`Workplane.cutThruAll`, which makes a cut through the entire part, no matter +how deep the part is + +.. cq_plot:: + + result = Workplane("front").box(3,2,0.5) #make a basic prism + result = result.faces(">Z").vertices("Z").workplane() \ + .transformed(offset=cad.Vector(0,-1.5,1.0),rotate=cad.Vector(60,0,0)) \ + .rect(1.5,1.5,forConstruction=True).vertices().hole(0.25) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.transformed` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.rect` + * :py:meth:`Workplane.faces` + +Using construction Geometry +--------------------------- + +You can draw shapes to use the vertices as points to locate other features. Features that are used to +locate other features, rather than to create them, are called ``Construction Geometry`` + +In the example below, a rectangle is drawn, and its vertices are used to locate a set of holes. + +.. cq_plot:: + + result = Workplane("front").box(2,2,0.5).faces(">Z").workplane() \ + .rect(1.5,1.5,forConstruction=True).vertices().hole(0.125 ) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.rect` (forConstruction=True) + * :ref:`selector_reference` + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.hole` + * :py:meth:`Workplane` + +Shelling To Create Thin features +-------------------------------- + +Shelling converts a solid object into a shell of uniform thickness. To shell an object, one or more faces +are removed, and then the inside of the solid is 'hollowed out' to make the shell. + + +.. cq_plot:: + + result = Workplane("front").box(2,2,2).faces("+Z").shell(0.05) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.shell` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.faces` + * :py:meth:`Workplane` + +Making Lofts +-------------------------------------------- + +A loft is a solid swept through a set of wires. This example creates lofted section between a rectangle +and a circular section. + +.. cq_plot:: + + result = 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) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.loft` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.faces` + * :py:meth:`Workplane.circle` + * :py:meth:`Workplane.rect` + +Making Counter-bored and counter-sunk holes +---------------------------------------------- + +Counterbored and countersunk holes are so common that CadQuery creates macros to create them in a single step. + +Similar to :py:meth:`Workplane.hole` , these functions operate on a list of points as well as a single point. + +.. cq_plot:: + + result = Workplane(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) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.cboreHole` **!** + * :py:meth:`Workplane.cskHole` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.rect` + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane.vertices` + * :py:meth:`Workplane.faces` + * :py:meth:`Workplane` + +Rounding Corners with Fillet +----------------------------- + +Filleting is done by selecting the edges of a solid, and using the fillet function. + +Here we fillet all of the edges of a simple plate. + +.. cq_plot:: + + result = Workplane("XY" ).box(3,3,0.5).edges("|Z").fillet(0.125) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.fillet` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.edges` + * :py:meth:`Workplane` + +Splitting an Object +--------------------- + +You can split an object using a workplane, and retain either or both halves + +.. cq_plot:: + + c = Workplane("XY").box(1,1,1).faces(">Z").workplane().circle(0.25).cutThruAll() + + #now cut it in half sideways + result = c.faces(">Y").workplane(-0.5).split(keepTop=True) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.split` **!** + * :py:meth:`Workplane.box` + * :py:meth:`Workplane.circle` + * :py:meth:`Workplane.cutThruAll` + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane` + +The Classic OCC Bottle +---------------------- + +CadQuery is based on the OpenCascade.org (OCC) modeling Kernel. Those who are familiar with OCC know about the +famous 'bottle' example. http://www.opencascade.org/org/gettingstarted/appli/ + +A pythonOCC version is listed here + http://code.google.com/p/pythonocc/source/browse/trunk/src/examples/Tools/InteractiveViewer/scripts/Bottle.py?r=1046 + +Of course one difference between this sample and the OCC version is the length. This sample is one of the longer +ones at 13 lines, but that's very short compared to the pythonOCC version, which is 10x longer! + + +.. cq_plot:: + + (L,w,t) = (20.0,6.0,3.0) + s = Workplane("XY") + + #draw half the profile of the bottle and extrude it + 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) \ + .mirrorX().extrude(30.0,True) + + #make the neck + p.faces(">Z").workplane().circle(3.0).extrude(2.0,True) + + #make a shell + result = p.faces(">Z").shell(0.3) + +.. topic:: Api References + + .. hlist:: + :columns: 2 + + * :py:meth:`Workplane.extrude` + * :py:meth:`Workplane.mirrorX` + * :py:meth:`Workplane.threePointArc` + * :py:meth:`Workplane.workplane` + * :py:meth:`Workplane.vertices` + * :py:meth:`Workplane.vLine` + * :py:meth:`Workplane.faces` + * :py:meth:`Workplane` + +A Parametric Enclosure +----------------------- + +.. cq_plot:: + :height: 400 + + #parameter definitions + p_outerWidth = 100.0 #Outer width of box enclosure + p_outerLength = 150.0 #Outer length of box enclosure + p_outerHeight = 50.0 #Outer height of box enclosure + + p_thickness = 3.0 #Thickness of the box walls + p_sideRadius = 10.0 #Radius for the curves around the sides of the bo + p_topAndBottomRadius = 2.0 #Radius for the curves on the top and bottom edges of the box + + p_screwpostInset = 12.0 #How far in from the edges the screwposts should be place. + p_screwpostID = 4.0 #nner Diameter of the screwpost holes, should be roughly screw diameter not including threads + p_screwpostOD = 10.0 #Outer Diameter of the screwposts.\nDetermines overall thickness of the posts + + p_boreDiameter = 8.0 #Diameter of the counterbore hole, if any + p_boreDepth = 1.0 #Depth of the counterbore hole, if + p_countersinkDiameter = 0.0 #Outer diameter of countersink. Should roughly match the outer diameter of the screw head + p_countersinkAngle = 90.0 #Countersink angle (complete angle between opposite sides, not from center to one side) + p_flipLid = True #Whether to place the lid with the top facing down or not. + p_lipHeight = 1.0 #Height of lip on the underside of the lid.\nSits inside the box body for a snug fit. + + #outer shell + oshell = Workplane("XY").rect(p_outerWidth,p_outerLength).extrude(p_outerHeight + p_lipHeight) + + #weird geometry happens if we make the fillets in the wrong order + if p_sideRadius > p_topAndBottomRadius: + oshell.edges("|Z").fillet(p_sideRadius) + oshell.edges("#Z").fillet(p_topAndBottomRadius) + else: + oshell.edges("#Z").fillet(p_topAndBottomRadius) + oshell.edges("|Z").fillet(p_sideRadius) + + #inner shell + ishell = oshell.faces("Z").workplane(-p_thickness)\ + .rect(POSTWIDTH,POSTLENGTH,forConstruction=True)\ + .vertices() + + for v in postCenters.all(): + v.circle(p_screwpostOD/2.0).circle(p_screwpostID/2.0)\ + .extrude((-1.0)*(p_outerHeight + p_lipHeight -p_thickness ),True) + + #split lid into top and bottom parts + (lid,bottom) = box.faces(">Z").workplane(-p_thickness -p_lipHeight ).split(keepTop=True,keepBottom=True).all() #splits into two solids + + #translate the lid, and subtract the bottom from it to produce the lid inset + lowerLid = lid.translate((0,0,-p_lipHeight)) + cutlip = lowerLid.cut(bottom).translate((p_outerWidth + p_thickness ,0,p_thickness - p_outerHeight + p_lipHeight)) + + #compute centers for counterbore/countersink or counterbore + topOfLidCenters = cutlip.faces(">Z").workplane().rect(POSTWIDTH,POSTLENGTH,forConstruction=True).vertices() + + #add holes of the desired type + if p_boreDiameter > 0 and p_boreDepth > 0: + topOfLid = topOfLidCenters.cboreHole(p_screwpostID,p_boreDiameter,p_boreDepth,(2.0)*p_thickness) + elif p_countersinkDiameter > 0 and p_countersinkAngle > 0: + topOfLid = topOfLidCenters.cskHole(p_screwpostID,p_countersinkDiameter,p_countersinkAngle,(2.0)*p_thickness) + else: + topOfLid= topOfLidCenters.hole(p_screwpostID,(2.0)*p_thickness) + + #flip lid upside down if desired + if p_flipLid: + topOfLid.rotateAboutCenter((1,0,0),180) + + #return the combined result + result =topOfLid.combineSolids(bottom) + +.. topic:: Api References + + .. hlist:: + :columns: 3 + + * :py:meth:`Workplane.circle` + * :py:meth:`Workplane.rect` + * :py:meth:`Workplane.extrude` + * :py:meth:`Workplane.box` + * :py:meth:`CQ.all` + * :py:meth:`CQ.faces` + * :py:meth:`CQ.vertices` + * :py:meth:`CQ.edges` + * :py:meth:`CQ.workplane` + * :py:meth:`Workplane.fillet` + * :py:meth:`Workplane.cut` + * :py:meth:`Workplane.combineSolids` + * :py:meth:`Workplane.rotateAboutCenter` + * :py:meth:`Workplane.cboreHole` + * :py:meth:`Workplane.cskHole` + * :py:meth:`Workplane.hole` \ No newline at end of file diff --git a/doc/extending.rst b/doc/extending.rst new file mode 100644 index 0000000..e126c06 --- /dev/null +++ b/doc/extending.rst @@ -0,0 +1,178 @@ +.. _extending: + +****************** +Extending CadQuery +****************** + +.. automodule:: cadfile.cadutils.cadquery + +If you find that CadQuery doesnt suit your needs, you can easily extend it. CadQuery provides several extension +methods: + + * You can load plugins others have developed. This is by far the easiest way to access other code + * you can define your own plugins. + * 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 +-------------------- + +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:: + + return Workplane("XY").box(1.0,2.0,3.0).val() + +is actually equivalent to:: + + return Part.makeBox(1.0,2.0,3.0) + +As long as you return a valid FreeCAD Shape, you can use any FreeCAD methods you like. You can even mix and match the +two. For example, consider this script, which creates a FreeCAD box, but then uses cadquery to select its faces:: + + box = Part.makeBox(1.0,2.0,3.0) + cq = CQ(box).faces(">Z").size() # returns 6 + + +Extending CadQuery: Plugins +---------------------------- + +Though you can get a lot done with FreeCAD, the code gets pretty nasty in a hurry. CadQuery shields you from +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. + +A CadQuery plugin is simply a function that is attached to the CadQuery :py:meth:`CQ` or :py:meth:`Workplane` class. +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 + + +The Stack +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Every CadQuery object has a local stack, which contains a list of items. The items on the stack will be +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 + +The stack is available by using self.objects, and will always contain at least one object. + +.. note:: + + Objects and points on the stack are **always** in global coordinates. Similarly, any objects you + create must be created in terms of global coordinates as well! + + +Preserving the Chain +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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, +then your plugin will end the chain. Sometimes this is desired for example :py:meth:`CQ.size` + +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 + self. This approach is destructive, because the contents of the stack are modified, but it is also the + simplest. + 2. :py:meth:`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 + previous one. This preserves the original object and its stack. + + +Helper Methods +^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 +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, + and return a properly constructed cadquery object. This function takes care of registering wires for you + and everything like that + + * :py:meth:`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 + + * :py:meth:`Workplane.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 + 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 + 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 + 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. + + * :py:meth:`Workplane.plane` provides a reference to the workplane, which allows you to convert between workplane + coordinates and global coordinates: + * :py:meth:`Plane.toWorldCoords` will convert local coordinates to global ones + * :py:meth:`Plane.toLocalCoords` will convet from global coordinates to local coordinates + +Coordinate Systems +^^^^^^^^^^^^^^^^^^^^^^ + +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. + +Any objects that you create must be fully defined in *global coordinates*, even though some or all of the users' +inputs may be defined in terms of local coordinates. + + +Linking in your plugin +^^^^^^^^^^^^^^^^^^^^^^^ + +Your plugin is a single method, which is attached to the main Workplane or CadQuery object. + +Your plugin method's first parameter should be 'self', which will provide a reference to base class functionality. +You can also accept other arguments. + +To install it, simply attach it to the CadQuery or Workplane object, like this:: + + def _yourFunction(self,arg1,arg): + do stuff + return whatever_you_want + + Workplane.yourPlugin = _yourFunction + +That's it! + +Plugin Example +^^^^^^^^^^^^^^^ + +This ultra simple plugin makes cubes of the specified size for each stack point. + +(The cubes are off-center because the boxes have their lower left corner at the reference points.) + +.. cq_plot:: + + def makeCubes(self,length): + #self refers to the CQ or Workplane object + + #inner method that creates a cube + def _singleCube(pnt): + #pnt is a location in local coordinates + #since we're using eachpoint with useLocalCoordinates=True + return Solid.makeBox(length,length,length,pnt) + + #use CQ utility method to iterate over the stack, call our + #method, and convert to/from local coordinates. + return self.eachpoint(_singleCube,True) + + #link the plugin into cadQuery + Workplane.makeCubes = makeCubes + + #use the plugin + result = Workplane("XY").box(6.0,8.0,0.5).faces(">Z").rect(4.0,4.0,forConstruction=True).vertices() \ + .makeCubes(1.0).combineSolids() + + diff --git a/doc/fileformat.rst b/doc/fileformat.rst new file mode 100644 index 0000000..13733f8 --- /dev/null +++ b/doc/fileformat.rst @@ -0,0 +1,202 @@ +.. _cadquery_reference: + +******************************** +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 follow a standard format. Each script contains these main components: + + :MetaData: + *(Mandatory)* Defines the attributes that describe the model, such as version and unit of measure + + :Parameters: + *(Optional)* Defines parameters and their default values, which can be + manipulated by users to customize the object. Parameters are defined by creating local variables + of a particular class type. Presets and groups organize parameters to make them easier to use + + :build script: + *(Mandatory)* Constructs the model once parameter values are collected and the model is validated. + The script must return a solid object, or a cadquery solid + +The Script Life-cycle +---------------------- + +CadQuery scripts have the following lifecycle when they are executed by a user via the web interface: + + 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_*, 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 ``.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 + diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..2454e9d --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,43 @@ +.. 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. + +Parametric Parts Documentation Home +=================================== + +Parametric Parts is a technology platform that offers: + + * **For Users**: Customize, download, and print models easily using only a web browser. Every model is parametric. + * **For Designers**: Create models with an easy to use, fluent API called CadQuery. ( See :ref:`examples` ) + * **For Developers**: :ref:`buildservice` allows other technology platforms to build models while controlling the user + experience + + +Contents +================== + +.. toctree:: + :maxdepth: 2 + + intro.rst + quickstart.rst + fileformat.rst + cadquerybasics.rst + examples.rst + apireference.rst + primitiveref.rst + selectors.rst + classreference.rst + + restservice.rst + + roadmap.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/intro.rst b/doc/intro.rst new file mode 100644 index 0000000..57fdf26 --- /dev/null +++ b/doc/intro.rst @@ -0,0 +1,70 @@ +.. _what_is_cadquery: + +********************* +Introduction +********************* + +What is a ParametricParts Model Script? +======================================== + +A Model Script is a python script that builds a 3d model in response to user inputs. + +Model Scripts are written in python. They can use two different APIs: + 1. FreeCAD Scripts, or + 2. a new, fluent-api called CadQuery. + +CadQuery is an intuitive, easy-to-use language 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. + + * 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 + + +CadQuery is a Python module that provides a high-level wrapper around the +(`FreeCAD `_) python libraries. + +Where does the name CadQuery come from? +=============================== + +CadQuery is inspired by ( `jQuery `_ ), 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, 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. + + +Why ParametricParts instead of OpenSCAD? +================================== + +CadQuery is based on FreeCAD,which is in turn based on the OpenCascade modelling kernel. CadQuery/FreeCAD scripts +share many features with OpenSCAD, another open source, script based, parametric model generator. + +The primary advantage of OpenSCAD is the large number of already existing model 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. + This includes many standard libraries and IDEs + + 2. **More powerful CAD kernel** OpenCascade is much more powerful than CGAL. Features supported natively + by OCC include NURBS, splines, surface sewing, STL repair, STEP import/export, and other complex operations, + in addition to the standard CSG operations supported by CGAL + + 3. **Ability to import/export STEP** We think the ability to begin with a STEP model, created in a CAD package, + and then add parametric features is key. This is possible in OpenSCAD using STL, but STL is a lossy format + + 4. **Less Code and easier scripting** CadQuery scripts require less code to create most objects, because it is possible to locate + features based on the position of other features, workplanes, vertices, etc. + + 5. **Better Performance** CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD. + diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000..0217e3f --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,190 @@ +@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 ^` where ^ 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 diff --git a/doc/primer.rst b/doc/primer.rst new file mode 100644 index 0000000..c10e52e --- /dev/null +++ b/doc/primer.rst @@ -0,0 +1,9 @@ +.. _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, +you may want to do some heavier reading on the subject (PUT LINKS HERE ) + diff --git a/doc/primitiveref.rst b/doc/primitiveref.rst new file mode 100644 index 0000000..480752c --- /dev/null +++ b/doc/primitiveref.rst @@ -0,0 +1,57 @@ +.. _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: diff --git a/doc/quickstart.rst b/doc/quickstart.rst new file mode 100644 index 0000000..c51d55b --- /dev/null +++ b/doc/quickstart.rst @@ -0,0 +1,305 @@ + +.. module:: cadfile.cadutils.cadquery + +.. _quickstart: + +*********************** +ModelScript QuickStart +*********************** + +Want a quick glimpse of Parametric Parts ModelScripts? You're at the right place! +This quickstart will demonstrate the basics of ModelScripts using a simple example + +Prerequisites +============= + +**WebGL Capable Browser** + + CadQuery renders models in your browser using WebGL-- which is supported by most browsers *except for IE* + You can follow along without IE, but you will not be able to see the model dynamically rendered + + +What we'll accomplish +===================== + +Our finished object will look like this: + +.. image:: quickstart.png + + +**We would like our block to have these features:** + + 1. It should be sized to hold a single 608 ( 'skate' ) bearing, in the center of the block. + 2. It should have counter sunk holes for M2 socket head cap screws at the corners + 3. The length and width of the block should be configurable by the user to any reasonable size. + +A human would describe this as: + + "A rectangular block 80mm x 60mm x 30mm , 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" + +Human descriptions are very elegant, right? +Hopefully our finished script will not be too much more complex than this human-oriented description. + +Let's see how we do. + +Start a new Model +================================== + +CadQuery comes with an online, interactive default model as a starting point. Lets open up that tool +`here `_ + +You should see the dynamic model creator page, which will display a sample model: + + .. image:: 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 + :linenos: + :emphasize-lines: 1 + + UOM = "mm" + + +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 + + def build(): + return Workplane("XY").box(length.value,height.value,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 +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 +height. + +Now, modify the build script to use your width value to make the block by changing ``height`` to +``height.value`` + +.. code-block:: python + :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:: 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. + + +Add the Holes +================ + +Our pillow block needs to have a 22mm diameter hole in the center of this block to hold the bearing. + +This modification will do the trick: + +.. code-block:: python + :linenos: + :emphasize-lines: 3 + + ... + def build(): + return Workplane("XY").box(length.value,height.value,thickness).faces(">Z").workplane().hole(22.0) + +Rebuild your model by clicking "Save Model" at the bottom. Your block should look like this: + + .. image:: quickstart-3.png + + +The code is pretty compact, and works like this: + * :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 + * :py:meth:`Workplane.hole` drills a hole through the part 22mm in diamter + +.. note:: + + Don't worry about the CadQuery syntax now.. you can learn all about it in the :ref:`apireference` later. + +More Holes +============ + +Ok, that hole was not too hard, but what about the counter-bored holes in the corners? + +An M2 Socket head cap screw has these dimensions: + + * **Head Diameter** : 3.8 mm + * **Head height** : 2.0 mm + * **Clearance Hole** : 2.4 mm + * **CounterBore diameter** : 4.4 mm + +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. + +**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: + +.. code-block:: python + :linenos: + :emphasize-lines: 4-5 + + ... + 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) + +You should see something like this: + + .. image:: quickstart-4.png + +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 +define the centers of the holes in the corners: + +.. code-block:: python + :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 +locate the corner holes: + +.. code-block:: python + :linenos: + :emphasize-lines: 5 + + ... + 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) + +There are a couple of things to note about this line: + + 1. The :py:meth:`Workplane.rect` function draws a rectangle. **forConstruction=True** + 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. + 2. The center point of a workplane on a face is always at the center of the face, which works well here + 3. Unless you specifiy otherwise, a rectangle is drawn with its center on the current workplane center-- in + 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: + +.. code-block:: python + :linenos: + :emphasize-lines: 6 + + ... + 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) + +Notes about this line: + + 1. The :py:meth:`CQ.vertices` function selects the corners of the rectangle + 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 +'out of the box' options to choose from. Lets provide two preset options: + + * **Small** : 30 mm x 40mm + * **Square-Medium** : 50 mm x 50mm + +We can do that using the preset dictionaries in the parameter definition: + +.. code-block:: python + :linenos: + :emphasize-lines: 2-3 + + ... + 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") + +Now save the model and have a look at the preset DDLB-- you'll see that you can easily switch between these +configurations: + + .. image:: quickstart-5.png + + +Done! +============ + +And... We're done! Congratulations, you just made a parametric, 3d model with 15 lines of code.Users can use this +model to generate pillow blocks in any size they would like + +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? +==================== + + * The :ref:`examples` contains lots of examples demonstrating cadquery features + * The :ref:`cadquery_reference` describes the file format in detail + * 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. \ No newline at end of file diff --git a/doc/restservice.rst b/doc/restservice.rst new file mode 100644 index 0000000..6a9139b --- /dev/null +++ b/doc/restservice.rst @@ -0,0 +1,114 @@ +.. _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 ``_ + +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/. 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. + + :: + (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 `_ for a ParametricParts account + 2. `Contact ParametricParts Support `_ 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 `_ link. + 4. Test your api key using the api key tester `Here `_ + 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. \ No newline at end of file diff --git a/doc/roadmap.rst b/doc/roadmap.rst new file mode 100644 index 0000000..12865d1 --- /dev/null +++ b/doc/roadmap.rst @@ -0,0 +1,172 @@ +.. _roadmap: + +************************** +RoadMap: Planned Features +************************** + +**CadQuery is not even close to finished!!!** + +Many features are planned for later versions. This page tracks them. If you find that you need features +not listed here, let us know! + +Core +-------------------- + +end(n) + allows moving backwards a fixed number of parents in the chain, eg end(3) is same as end().end().end() + +FreeCAD object wrappers + return CQ wrappers for FreeCAD shapes instead of the native FreeCAD objects. + +Improved iteration tools for plugin developers + make it easier to iterate over points and wires for plugins + +More parameter types (String? ) + +face.outerWire + allow selecting the outerWire of a face, so that it can be used for reference geometry or offsets + +Selectors +-------------------- + +Chained Selectors + Space delimited selectors should be unioned to allow multiple selections. For example ">Z >X" + +Ad-hoc axes + for example, >(1,2,1) would select a face with normal in the 1,2,1 direction + +logic inversion + ! or not to invert logic, such as "!(>Z)" to select faces _other_ than the most z facing + +closest to point + support faces, points, or edges closest to a provided point + +tagged entities + support tagging entities when they are created, so they can be selected later on using that tag. + ideally, tags are propagated to features that are created from these features ( ie, an edge tagged with 'foo' + that is later extruded into a face means that face would be tagged with 'foo' as well ) + + +Workplanes +-------------------- + +rotated workplanes + support creation of workplanes at an angle to another plane or face + +workplane local rotations + rotate the coordinate system of a workplane by an angle. + +make a workplane from a wire + useful to select outer wire and then operate from there, to allow offsets + +2-d operations +------------------- + +offsets + offset profiles, including circles, rects, and other profiles. + +ellipses + create elipses and portions of elipses + +regular polygons + several construction methods: + * number of sides and side length + * number of sides inscribed in circle + * number of sides circumscribed by circle + +arc construction using relative measures + instead of forcing use of absolute workplane coordinates + +tangent arcs + after a line + +centerpoint arcs + including portions of arcs as well as with end points specified + +trimming + ability to use construction geometry to trim other entities + +construction lines + especially centerlines + +2-d fillets + for a rectangle, or for consecutive selected lines + +2-d chamfers + based on rectangles, polygons, polylines, or adjacent selected lines + +mirror around centerline + using centerline construction geometry + +rectangular array + automate creation of equally spread points + +polar array + create equally spaced copies of a feature around a circle + perhaps based on a construction circle? + +midpoint selection + select midpoints of lines, arcs + +face center + explicit selection of face center + +manipulate spline control points + so that the shape of a spline can be more accurately controlled + +feature snap + project geometry in the rest of the part into the work plane, so that + they can be selected and used as references for other features. + +polyline edges + allow polyline to be combined with other edges/curves + +create text + ideally, in various fonts. + +3-d operations +--------------------- + +rotation/transform that return a copy + The current rotateAboutCenter and translate method modify the object, rather than returning a copy + +primitive creation + Need primitive creation for: + * cone + * sphere + * cylinder + * torus + * wedge + +extrude/cut up to surface + allow a cut or extrude to terminate at another surface ,rather than either through all or a fixed distance + +extrude along a path + 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 + allow embedding and importing step solids created in other tools, which + can then be further manipulated parametrically + +Dome + very difficult to do otherwise + +primitive boolean operations + * intersect + * union + * subtract + + +Algorithms +--------------------- + +Wire Discretization + Sample wires at point interval to improve closet wire computations + + diff --git a/doc/selectors.rst b/doc/selectors.rst new file mode 100644 index 0000000..178d12e --- /dev/null +++ b/doc/selectors.rst @@ -0,0 +1,103 @@ +.. _selector_reference: + +************************* +CadQuery String Selectors +************************* + +.. automodule:: cadfile.cadutils.cadquery + +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. + +String selectors are used as arguments to the various selection methods: + + * :py:meth:`CQ.faces` + * :py:meth:`CQ.edges` + * :py:meth:`CQ.vertices` + * :py:meth:`CQ.solids` + * :py:meth:`CQ.shells` + +.. note:: + + String selectors are shortcuts to concrete selector classes, which you can use or extend. See + :ref:`classreference` for more details + + If you find that the built-in selectors are not sufficient, you can easily plug in your own. + See :ref:`extending` to see how. + + + +.. _filteringfaces: + +Filtering Faces +---------------- + +All types of filters work on faces. In most cases, the selector refers to the direction of the **normal vector** +of the face. + +.. warning:: + + If a face is not planar, selectors are evaluated at the center of mass of the face. This can lead + to results that are quite unexpected. + +The axis used in the listing below are for illustration: any axis would work similarly in each case. + +========= ==================================== ====================================== ========================== +Selector Selector Class Selects # objects returned +========= ==================================== ====================================== ========================== ++Z :py:class:`DirectionSelector` Faces with normal in +z direction 0 or 1 +\|Z :py:class:`ParallelDirSelector` Faces parallel to xy plane 0..many +-X :py:class:`DirectionSelector` Faces with normal in neg x direction 0..many +#Z :py:class:`PerpendicularDirSelector` Faces perpendicular to z direction 0..many +%Plane :py:class:`TypeSelector` Faces of type plane 0..many +>Y :py:class:`DirectionMinMaxSelector` Face farthest in the positive y dir 0 or 1 +Y :py:class:`DirectionMinMaxSelector` Edges farthest in the positive y dir 0 or 1 +Y :py:class:`DirectionMinMaxSelector` Edges farthest in the positive y dir 0 or 1 + + + + +{% endblock %} + +{% block header %} +{%- if logo %} + +{%- endif %} + +{% endblock %} + +{%- block sidebarlogo %}{%- endblock %} +{%- block sidebarsourcelink %}{%- endblock %} diff --git a/doc/themes/pparts/static/body.jpg b/doc/themes/pparts/static/body.jpg new file mode 100644 index 0000000..f10460c Binary files /dev/null and b/doc/themes/pparts/static/body.jpg differ diff --git a/doc/themes/pparts/static/dialog-note.png b/doc/themes/pparts/static/dialog-note.png new file mode 100644 index 0000000..263fbd5 Binary files /dev/null and b/doc/themes/pparts/static/dialog-note.png differ diff --git a/doc/themes/pparts/static/dialog-seealso.png b/doc/themes/pparts/static/dialog-seealso.png new file mode 100644 index 0000000..3eb7b05 Binary files /dev/null and b/doc/themes/pparts/static/dialog-seealso.png differ diff --git a/doc/themes/pparts/static/dialog-topic.png b/doc/themes/pparts/static/dialog-topic.png new file mode 100644 index 0000000..2ac5747 Binary files /dev/null and b/doc/themes/pparts/static/dialog-topic.png differ diff --git a/doc/themes/pparts/static/dialog-warning.png b/doc/themes/pparts/static/dialog-warning.png new file mode 100644 index 0000000..7233d45 Binary files /dev/null and b/doc/themes/pparts/static/dialog-warning.png differ diff --git a/doc/themes/pparts/static/epub.css b/doc/themes/pparts/static/epub.css new file mode 100644 index 0000000..28dff73 --- /dev/null +++ b/doc/themes/pparts/static/epub.css @@ -0,0 +1,310 @@ +/* + * 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; +} diff --git a/doc/themes/pparts/static/footerbg.png b/doc/themes/pparts/static/footerbg.png new file mode 100644 index 0000000..1fbc873 Binary files /dev/null and b/doc/themes/pparts/static/footerbg.png differ diff --git a/doc/themes/pparts/static/headerbg.png b/doc/themes/pparts/static/headerbg.png new file mode 100644 index 0000000..0596f20 Binary files /dev/null and b/doc/themes/pparts/static/headerbg.png differ diff --git a/doc/themes/pparts/static/ie6.css b/doc/themes/pparts/static/ie6.css new file mode 100644 index 0000000..74baa5d --- /dev/null +++ b/doc/themes/pparts/static/ie6.css @@ -0,0 +1,7 @@ +* 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) +);} diff --git a/doc/themes/pparts/static/logo.png b/doc/themes/pparts/static/logo.png new file mode 100644 index 0000000..fa68e82 Binary files /dev/null and b/doc/themes/pparts/static/logo.png differ diff --git a/doc/themes/pparts/static/middlebg.png b/doc/themes/pparts/static/middlebg.png new file mode 100644 index 0000000..2369cfb Binary files /dev/null and b/doc/themes/pparts/static/middlebg.png differ diff --git a/doc/themes/pparts/static/pparts.css_t b/doc/themes/pparts/static/pparts.css_t new file mode 100644 index 0000000..64229c1 --- /dev/null +++ b/doc/themes/pparts/static/pparts.css_t @@ -0,0 +1,387 @@ +/* + * 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; +} diff --git a/doc/themes/pparts/static/transparent.gif b/doc/themes/pparts/static/transparent.gif new file mode 100644 index 0000000..0341802 Binary files /dev/null and b/doc/themes/pparts/static/transparent.gif differ diff --git a/doc/themes/pparts/theme.conf b/doc/themes/pparts/theme.conf new file mode 100644 index 0000000..11043fe --- /dev/null +++ b/doc/themes/pparts/theme.conf @@ -0,0 +1,4 @@ +[theme] +inherit = basic +stylesheet = pparts.css +pygments_style = friendly