Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions cadquery/occ_impl/exporters/dxf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,28 @@ class DxfDocument:
.. rubric:: Example usage

.. code-block:: python
:caption: Single layer DXF document
:caption: Single layer DXF document

rectangle = cq.Workplane().rect(10, 20)
rectangle = cq.Workplane().rect(10, 20)

dxf = DxfDocument()
dxf.add_shape(rectangle)
dxf.document.saveas("rectangle.dxf")
dxf = DxfDocument()
dxf.add_shape(rectangle)
dxf.document.saveas("rectangle.dxf")

.. code-block:: python
:caption: Multilayer DXF document

rectangle = cq.Workplane().rect(10, 20)
circle = cq.Workplane().circle(3)

dxf = DxfDocument()
dxf = (
dxf.add_layer("layer_1", color=2)
.add_layer("layer_2", color=3)
.add_shape(rectangle, "layer_1")
.add_shape(circle, "layer_2")
)
dxf.document.saveas("rectangle-with-hole.dxf")
:caption: Multilayer DXF document

rectangle = cq.Workplane().rect(10, 20)
circle = cq.Workplane().circle(3)

dxf = DxfDocument()
dxf = (
dxf.add_layer("layer_1", color=2)
.add_layer("layer_2", color=3)
.add_shape(rectangle, "layer_1")
.add_shape(circle, "layer_2")
)
dxf.document.saveas("rectangle-with-hole.dxf")
"""

CURVE_TOLERANCE = 1e-9
Expand Down
197 changes: 99 additions & 98 deletions doc/assy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ We want to start with defining the model parameters to allow for easy dimension

.. code-block:: python

import cadquery as cq
import cadquery as cq

# Parameters
H = 400
W = 200
D = 350
# Parameters
H = 400
W = 200
D = 350

PROFILE = cq.importers.importDXF("vslot-2020_1.dxf").wires()
PROFILE = cq.importers.importDXF("vslot-2020_1.dxf").wires()

SLOT_D = 5
PANEL_T = 3
SLOT_D = 5
PANEL_T = 3

HANDLE_D = 20
HANDLE_L = 50
HANDLE_W = 4
HANDLE_D = 20
HANDLE_L = 50
HANDLE_W = 4

It is interesting to note that the v-slot profile is imported from a DXF file.
This way it is very easy to change to other aluminum extrusion type, e.g. Item or Bosch.
Expand All @@ -45,72 +45,72 @@ Next we want to define functions generating the assembly components based on the

.. code-block:: python

def make_vslot(l):
return PROFILE.toPending().extrude(l)
def make_vslot(l):
return PROFILE.toPending().extrude(l)


def make_connector():
rv = (
cq.Workplane()
.box(20, 20, 20)
.faces("<X")
.workplane()
.cboreHole(6, 15, 18)
.faces("<Z")
.workplane(centerOption="CenterOfMass")
.cboreHole(6, 15, 18)
)

# tag mating faces
rv.faces(">X").tag("X").end()
rv.faces(">Z").tag("Z").end()
def make_connector():
rv = (
cq.Workplane()
.box(20, 20, 20)
.faces("<X")
.workplane()
.cboreHole(6, 15, 18)
.faces("<Z")
.workplane(centerOption="CenterOfMass")
.cboreHole(6, 15, 18)
)

return rv
# tag mating faces
rv.faces(">X").tag("X").end()
rv.faces(">Z").tag("Z").end()

return rv


def make_panel(w, h, t, cutout):
rv = (
cq.Workplane("XZ")
.rect(w, h)
.extrude(t)
.faces(">Y")
.vertices()
.rect(2 * cutout, 2 * cutout)
.cutThruAll()
.faces("<Y")
.workplane()
.pushPoints([(-w / 3, HANDLE_L / 2), (-w / 3, -HANDLE_L / 2)])
.hole(3)
)

# tag mating edges
rv.faces(">Y").edges("%CIRCLE").edges(">Z").tag("hole1")
rv.faces(">Y").edges("%CIRCLE").edges("<Z").tag("hole2")

def make_panel(w, h, t, cutout):
rv = (
cq.Workplane("XZ")
.rect(w, h)
.extrude(t)
.faces(">Y")
.vertices()
.rect(2 * cutout, 2 * cutout)
.cutThruAll()
.faces("<Y")
.workplane()
.pushPoints([(-w / 3, HANDLE_L / 2), (-w / 3, -HANDLE_L / 2)])
.hole(3)
)
return rv

# tag mating edges
rv.faces(">Y").edges("%CIRCLE").edges(">Z").tag("hole1")
rv.faces(">Y").edges("%CIRCLE").edges("<Z").tag("hole2")

return rv
def make_handle(w, h, r):
pts = ((0, 0), (w, 0), (w, h), (0, h))

path = cq.Workplane().polyline(pts)

def make_handle(w, h, r):
pts = ((0, 0), (w, 0), (w, h), (0, h))

path = cq.Workplane().polyline(pts)

rv = (
cq.Workplane("YZ")
.rect(r, r)
.sweep(path, transition="round")
.tag("solid")
.faces("<X")
.workplane()
.faces("<X", tag="solid")
.hole(r / 1.5)
)
rv = (
cq.Workplane("YZ")
.rect(r, r)
.sweep(path, transition="round")
.tag("solid")
.faces("<X")
.workplane()
.faces("<X", tag="solid")
.hole(r / 1.5)
)

# tag mating faces
rv.faces("<X").faces(">Y").tag("mate1")
rv.faces("<X").faces("<Y").tag("mate2")
# tag mating faces
rv.faces("<X").faces(">Y").tag("mate1")
rv.faces("<X").faces("<Y").tag("mate2")

return rv
return rv

Initial assembly
================
Expand Down Expand Up @@ -149,35 +149,35 @@ Then we want to define all the constraints

.. code-block:: python

# define the constraints
(
door
# left profile
.constrain("left@faces@<Z", "con_bl?Z", "Plane")
.constrain("left@faces@<X", "con_bl?X", "Axis")
.constrain("left@faces@>Z", "con_tl?Z", "Plane")
.constrain("left@faces@<X", "con_tl?X", "Axis")
# top
.constrain("top@faces@<Z", "con_tl?X", "Plane")
.constrain("top@faces@<Y", "con_tl@faces@>Y", "Axis")
# bottom
.constrain("bottom@faces@<Y", "con_bl@faces@>Y", "Axis")
.constrain("bottom@faces@>Z", "con_bl?X", "Plane")
# right connectors
.constrain("top@faces@>Z", "con_tr@faces@>X", "Plane")
.constrain("bottom@faces@<Z", "con_br@faces@>X", "Plane")
.constrain("left@faces@>Z", "con_tr?Z", "Axis")
.constrain("left@faces@<Z", "con_br?Z", "Axis")
# right profile
.constrain("right@faces@>Z", "con_tr@faces@>Z", "Plane")
.constrain("right@faces@<X", "left@faces@<X", "Axis")
# panel
.constrain("left@faces@>X[-4]", "panel@faces@<X", "Plane")
.constrain("left@faces@>Z", "panel@faces@>Z", "Axis")
# handle
.constrain("panel?hole1", "handle?mate1", "Plane")
.constrain("panel?hole2", "handle?mate2", "Point")
)
# define the constraints
(
door
# left profile
.constrain("left@faces@<Z", "con_bl?Z", "Plane")
.constrain("left@faces@<X", "con_bl?X", "Axis")
.constrain("left@faces@>Z", "con_tl?Z", "Plane")
.constrain("left@faces@<X", "con_tl?X", "Axis")
# top
.constrain("top@faces@<Z", "con_tl?X", "Plane")
.constrain("top@faces@<Y", "con_tl@faces@>Y", "Axis")
# bottom
.constrain("bottom@faces@<Y", "con_bl@faces@>Y", "Axis")
.constrain("bottom@faces@>Z", "con_bl?X", "Plane")
# right connectors
.constrain("top@faces@>Z", "con_tr@faces@>X", "Plane")
.constrain("bottom@faces@<Z", "con_br@faces@>X", "Plane")
.constrain("left@faces@>Z", "con_tr?Z", "Axis")
.constrain("left@faces@<Z", "con_br?Z", "Axis")
# right profile
.constrain("right@faces@>Z", "con_tr@faces@>Z", "Plane")
.constrain("right@faces@<X", "left@faces@<X", "Axis")
# panel
.constrain("left@faces@>X[-4]", "panel@faces@<X", "Plane")
.constrain("left@faces@>Z", "panel@faces@>Z", "Axis")
# handle
.constrain("panel?hole1", "handle?mate1", "Plane")
.constrain("panel?hole2", "handle?mate2", "Point")
)

Should you need to do something unusual that is not possible with the string
based selectors (e.g. use :py:class:`cadquery.selectors.BoxSelector` or a user-defined selector class),
Expand Down Expand Up @@ -359,9 +359,10 @@ STEP can be loaded in all CAD tool, e.g. in FreeCAD and the XML be used in other
.. code-block:: python
:linenos:

door.export("door.step")
door.export("door.xml")
.. image:: _static/door_assy_freecad.png
door.export("door.step")
door.export("door.xml")

.. image:: _static/door_assy_freecad.png


Object locations
Expand Down
2 changes: 1 addition & 1 deletion doc/designprinciples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ CadQuery strives to allow scripts to read roughly as a human would describe an o

For example, consider this object:

.. image:: _static/quickstart.png
.. image:: _static/quickstart.png

A human would describe this as:

Expand Down
20 changes: 10 additions & 10 deletions doc/free-func.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,39 +53,39 @@ It begins with defining few edges.

.. code-block:: python

edge1 = circle(r)
edge2 = circle(2*r).moved(z=dh)
edge3 = circle(r).moved(z=1.5*dh)
edge1 = circle(r)
edge2 = circle(2*r).moved(z=dh)
edge3 = circle(r).moved(z=1.5*dh)


Those edges are used to create the side faces of the final solid using :meth:`~cadquery.occ_impl.shapes.loft`.

.. code-block:: python

side = loft(edge1, edge2, edge3)
side = loft(edge1, edge2, edge3)

Once the side is there, :meth:`~cadquery.occ_impl.shapes.cap` and :meth:`~cadquery.occ_impl.shapes.fill` are used to define the top and bottom faces.
Note that :meth:`~cadquery.occ_impl.shapes.cap` tries to maintain curvature continuity with respect to the context shape. This is not the case for :meth:`~cadquery.occ_impl.shapes.fill`.

.. code-block:: python

# bottom face
bottom = fill(side.edges('<Z'))
# bottom face
bottom = fill(side.edges('<Z'))

# top face with continuous curvature
top = cap(side.edges('>Z'), side, [(0,0,1.75*dh)])
# top face with continuous curvature
top = cap(side.edges('>Z'), side, [(0,0,1.75*dh)])

Next, all the faces are assembled into a solid.

.. code-block:: python

s = solid(side, bottom, top)
s = solid(side, bottom, top)

Finally, the solid is duplicated and placed in the desired locations creating the final compound object. Note various usages of :meth:`~cadquery.Shape.moved`.

.. code-block:: python

result = s.moved((-3*r, 0, 0), (3*r, 0, 0))
result = s.moved((-3*r, 0, 0), (3*r, 0, 0))

In general all the operations are implemented as free functions, with the exception of placement and selection which are strictly related to a specific shape.

Expand Down
Loading