Merge branch 'master' into master

This commit is contained in:
AU
2021-09-08 08:17:06 +02:00
committed by GitHub
30 changed files with 1576 additions and 270 deletions

View File

@ -18,7 +18,7 @@ are appreciated.
If you want to discuss something in a more casual environment, we have other options under [Getting help in the README.md](https://github.com/CadQuery/cadquery#getting-help). There are also additional examples in the [cadquery-contrib repository](https://github.com/CadQuery/cadquery-contrib).
-->
<!-- We are all volunteers here, you can help us help you by making this question quick to answer. Minimal examples, trimmed of all unreleated code are appreciated. It also helps if you provide code that can be cut and pasted into CQ-Editor. ie. instead of:
<!-- We are all volunteers here, you can help us help you by making this question quick to answer. Minimal examples, trimmed of all unrelated code are appreciated. It also helps if you provide code that can be cut and pasted into CQ-Editor. ie. instead of:
> I have a box, how to I fillet a top corner?

10
.gitignore vendored
View File

@ -9,3 +9,13 @@ target/*
MANIFEST
out.*
res?.dxf
.~*
assy.wrl
assy.xml
assy.zip
nested.step
simple.caf
simple.step
simple.stp
simple.xml
test.brep

View File

@ -15,8 +15,8 @@ CadQuery is an intuitive, easy-to-use Python module for building parametric 3D C
CadQuery is often compared to [OpenSCAD](http://www.openscad.org/). Like OpenSCAD, CadQuery is an open-source, script based, parametric model generator. However, CadQuery stands out in many ways and has several key advantages:
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. CadQuery's CAD kernel Open CASCADE Technology (OCCT) is much more powerful than CGAL. Features supported natively by OCCT 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 and the ability to begin with a STEP model, created in a CAD package, and then add parametric features. This is possible in OpenSCAD using STL, but STL is a lossy format.
2. CadQuery's CAD kernel Open CASCADE Technology ([OCCT](https://en.wikipedia.org/wiki/Open_Cascade_Technology)) is much more powerful than the [CGAL](https://en.wikipedia.org/wiki/CGAL) used by OpenSCAD. Features supported natively by OCCT 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](https://en.wikipedia.org/wiki/ISO_10303) and the ability to begin with a STEP model, created in a CAD package, and then add parametric features. This is possible in OpenSCAD using STL, but STL is a lossy format.
4. 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. CadQuery scripts can build STL, STEP, and AMF faster than OpenSCAD.
@ -25,7 +25,7 @@ CadQuery is often compared to [OpenSCAD](http://www.openscad.org/). Like OpenSCA
* Create parametric models that can be very easily customized by end users.
* Output high quality (loss-less) CAD formats like STEP and DXF in addition to STL, VRML and AMF.
* Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser.
* Offer advanced modeling capabilities such as fillets, curvelinear extrudes, parametric curves and lofts.
* Offer advanced modeling capabilities such as fillets, curvilinear extrudes, parametric curves and lofts.
* Build nested assemblies out of individual parts and other assemblies.
### Why this fork
@ -175,7 +175,7 @@ If you are going to contribute code, make sure to follow this steps:
start working on your changes
- Create a conda development environment with something like:
- `conda env create -n cq-dev -f environment.yml`
- Activate the new conda enviornment:
- Activate the new conda environment:
- `conda activate cq-dev`
- If desired, install the master branch of cq-editor (Note; a release version may not be compatible with the master branch of cadquery):
- `conda install -c cadquery -c conda-forge cq-editor=master`

View File

@ -26,7 +26,7 @@ ExportLiterals = Literal["STEP", "XML"]
PATH_DELIM = "/"
# enitity selector grammar definiiton
# entity selector grammar definiiton
def _define_grammar():
from pyparsing import (
@ -83,11 +83,11 @@ class Constraint(object):
"""
Construct a constraint.
:param objects: object names refernced in the constraint
:param objects: object names referenced in the constraint
:param args: subshapes (e.g. faces or edges) of the objects
:param sublocs: locations of the objects (only relevant if the objects are nested in a sub-assembly)
:param kind: constraint kind
:param param: optional arbitrary paramter passed to the solver
:param param: optional arbitrary parameter passed to the solver
"""
self.objects = objects
@ -357,7 +357,7 @@ class Assembly(object):
"""
Calculate relative location of an object in a subassembly.
Returns the relative posiitons as well as the name of the top assembly.
Returns the relative positions as well as the name of the top assembly.
"""
rv = Location()
@ -411,7 +411,7 @@ class Assembly(object):
elif len(args) == 6:
id1, s1, id2, s2, kind, param = args
else:
raise ValueError(f"Incompatibile arguments: {args}")
raise ValueError(f"Incompatible arguments: {args}")
loc1, id1_top = self._subloc(id1)
loc2, id2_top = self._subloc(id2)

View File

@ -130,7 +130,7 @@ class CQContext(object):
class Workplane(object):
"""
Defines a coordinate system in space, in which 2-d coordinates can be used.
Defines a coordinate system in space, in which 2D coordinates can be used.
:param plane: the plane in which the workplane will be done
:type plane: a Plane object, or a string in (XY|YZ|XZ|front|back|top|bottom|left|right)
@ -305,7 +305,7 @@ class Workplane(object):
)
rv = [solid.split(*tools)]
# split using the current wokrplane
# split using the current workplane
else:
# boilerplate for arg/kwarg parsing
@ -501,7 +501,7 @@ class Workplane(object):
origin: Optional[VectorLike] = None,
) -> T:
"""
Creates a new 2-D workplane, located relative to the first face on the stack.
Creates a new 2D workplane, located relative to the first face on the stack.
:param offset: offset for the work plane in the Z direction. Default
:param invert: invert the Z direction from that of the face.
@ -518,7 +518,7 @@ class Workplane(object):
item on the chain immediately before the vertex must be a
face.
The result will be a 2-d working plane
The result will be a 2D working plane
with a new coordinate system set up as follows:
* The centerOption parameter sets how the center is defined.
@ -1087,7 +1087,7 @@ class Workplane(object):
Future Enhancements:
* A version of this method that returns a transformed copy, rather than modifying
the originals
* This method doesnt expose a very good interface, because the axis of rotation
* This method doesn't expose a very good interface, because the axis of rotation
could be inconsistent between multiple objects. This is because the beginning
of the axis is variable, while the end is fixed. This is fine when operating on
one object, but is not cool for multiple.
@ -1212,7 +1212,7 @@ class Workplane(object):
:param thickness: a positive float, representing the thickness of the desired shell.
Negative values shell inwards, positive values shell outwards.
:param kind: kind of joints, intersetion or arc (default: arc).
:param kind: kind of joints, intersection or arc (default: arc).
:raises ValueError: if the current stack contains objects that are not faces of a solid
further up in the chain.
:returns: a CQ object with the resulting shelled solid selected.
@ -1531,7 +1531,7 @@ class Workplane(object):
def pushPoints(self: T, pntList: Iterable[Union[VectorLike, Location]]) -> T:
"""
Pushes a list of points onto the stack as vertices.
The points are in the 2-d coordinate space of the workplane face
The points are in the 2D coordinate space of the workplane face
:param pntList: a list of points to push onto the stack
:type pntList: list of 2-tuples, in *local* coordinates
@ -1687,7 +1687,7 @@ class Workplane(object):
self: T, distance: float, angle: float, forConstruction: bool = False
) -> T:
"""
Make a line from the current point to the given polar co-ordinates
Make a line from the current point to the given polar coordinates
Useful if it is more convenient to specify the end location rather than
the distance and angle from the current point
@ -1817,11 +1817,11 @@ class Workplane(object):
where a tangent constraint is specified.
:param periodic: creation of periodic curves
:param parameters: the value of the parameter at each interpolation point.
(The intepolated curve is represented as a vector-valued function of a
(The interpolated curve is represented as a vector-valued function of a
scalar parameter.)
If periodic == True, then len(parameters) must be
len(intepolation points) + 1, otherwise len(parameters) must be equal to
len(interpolation points) + 1, otherwise len(parameters) must be equal to
len(interpolation points).
:param scale: whether to scale the specified tangent vectors before
interpolating.
@ -2356,11 +2356,11 @@ class Workplane(object):
:param forConstruction: whether the wire should be used to make a solid, or if it is just
for reference
This method is primarily of use to plugin developers making utilities for 2-d construction.
This method should be called when a user operation implies that 2-d construction is
This method is primarily of use to plugin developers making utilities for 2D construction.
This method should be called when a user operation implies that 2D construction is
finished, and we are ready to begin working in 3d.
SEE '2-d construction concepts' for a more detailed explanation of how CadQuery handles
SEE '2D construction concepts' for a more detailed explanation of how CadQuery handles
edges, wires, etc.
Any non edges will still remain.
@ -2693,11 +2693,11 @@ class Workplane(object):
def close(self: T) -> T:
"""
End 2-d construction, and attempt to build a closed wire.
End 2D construction, and attempt to build a closed wire.
:return: a CQ object with a completed wire on the stack, if possible.
After 2-d drafting with methods such as lineTo, threePointArc,
After 2D drafting with methods such as lineTo, threePointArc,
tangentArcPoint and polyline, it is necessary to convert the edges
produced by these into one or more wires.
@ -2710,7 +2710,7 @@ class Workplane(object):
endPoint = self._findFromPoint(True)
if self.ctx.firstPoint is None:
raise ValueError("Not start point specified - cannot close")
raise ValueError("No start point specified - cannot close")
else:
startPoint = self.ctx.firstPoint
@ -2767,7 +2767,7 @@ class Workplane(object):
return self.newObject([s])
# but parameter list is different so a simple function pointer wont work
# but parameter list is different so a simple function pointer won't work
def cboreHole(
self: T,
diameter: float,
@ -2813,7 +2813,7 @@ class Workplane(object):
# first make the hole
hole = Solid.makeCylinder(
diameter / 2.0, depth, center, boreDir
) # local coordianates!
) # local coordinates!
# add the counter bore
cbore = Solid.makeCylinder(cboreDiameter / 2.0, cboreDepth, Vector(), boreDir)
@ -2822,7 +2822,7 @@ class Workplane(object):
return self.cutEach(lambda loc: r.moved(loc), True, clean)
# TODO: almost all code duplicated!
# but parameter list is different so a simple function pointer wont work
# but parameter list is different so a simple function pointer won't work
def cskHole(
self: T,
diameter: float,
@ -2879,7 +2879,7 @@ class Workplane(object):
return self.cutEach(lambda loc: res.moved(loc), True, clean)
# TODO: almost all code duplicated!
# but parameter list is different so a simple function pointer wont work
# but parameter list is different so a simple function pointer won't work
def hole(
self: T, diameter: float, depth: Optional[float] = None, clean: bool = True,
) -> T:
@ -3463,7 +3463,7 @@ class Workplane(object):
eDir = self.plane.zDir.multiply(distance)
# one would think that fusing faces into a compound and then extruding would work,
# but it doesnt-- the resulting compound appears to look right, ( right number of faces, etc)
# but it doesn't-- the resulting compound appears to look right, ( right number of faces, etc)
# but then cutting it from the main solid fails with BRep_NotDone.
# the work around is to extrude each and then join the resulting solids, which seems to work
@ -3589,7 +3589,7 @@ class Workplane(object):
maxSegments: int = 9,
) -> T:
"""
Returns a plate surface that is 'thickness' thick, enclosed by 'surf_edge_pts' points, and going through 'surf_pts' points. Using pushpoints directly with interpPlate and combine=True, can be very ressources intensive depending on the complexity of the shape. In this case set combine=False.
Returns a plate surface that is 'thickness' thick, enclosed by 'surf_edge_pts' points, and going through 'surf_pts' points. Using pushpoints directly with interpPlate and combine=True, can be very resources intensive depending on the complexity of the shape. In this case set combine=False.
:param surf_edges
:type 1 surf_edges: list of [x,y,z] float ordered coordinates
@ -3597,7 +3597,7 @@ class Workplane(object):
:param surf_pts = [] (uses only edges if [])
:type surf_pts: list of [x,y,z] float coordinates
:param thickness = 0 (returns 2D surface if 0)
:type thickness: float (may be negative or positive depending on thicknening direction)
:type thickness: float (may be negative or positive depending on thickening direction)
:param combine: should the results be combined with other solids on the stack
(and each other)?
:type combine: true to combine shapes, false otherwise.
@ -3608,8 +3608,8 @@ class Workplane(object):
:type: NbPtsOnCur Integer >= 15
:param NbIter = 2 (OCCT default)
:type: NbIterInteger >= 2
:param Anisotropie = False (OCCT default)
:type Anisotropie: Boolean
:param anisotropy = False (OCCT default)
:type anisotropy: Boolean
:param: Tol2d = 0.00001 (OCCT default)
:type Tol2d: float > 0
:param Tol3d = 0.0001 (OCCT default)
@ -3800,6 +3800,69 @@ class Workplane(object):
else:
return self.union(spheres, clean=clean)
def cylinder(
self: T,
height: float,
radius: float,
direct: Vector = Vector(0, 0, 1),
angle: float = 360,
centered: Union[bool, Tuple[bool, bool, bool]] = True,
combine: bool = True,
clean: bool = True,
) -> T:
"""
Returns a cylinder with the specified radius and height for each point on the stack
:param height: The height of the cylinder
:type height: float > 0
:param radius: The radius of the cylinder
:type radius: float > 0
:param direct: The direction axis for the creation of the cylinder
:type direct: A three-tuple
:param angle: The angle to sweep the cylinder arc through
:type angle: float > 0
:param centered: If True, the cylinder will be centered around the reference point. If False,
the corner of a bounding box around the cylinder will be on the reference point and it
will extend in the positive x, y and z directions. Can also use a 3-tuple to specify
centering along each axis.
:param combine: Whether the results should be combined with other solids on the stack
(and each other)
:type combine: true to combine shapes, false otherwise
:param clean: call :py:meth:`clean` afterwards to have a clean shape
:return: A cylinder object for each point on the stack
One cylinder is created for each item on the current stack. If no items are on the stack, one
cylinder is created using the current workplane center.
If combine is true, the result will be a single object on the stack. If a solid was found
in the chain, the result is that solid with all cylinders produced fused onto it otherwise,
the result is the combination of all the produced cylinders.
If combine is false, the result will be a list of the cylinders produced.
"""
if isinstance(centered, bool):
centered = (centered, centered, centered)
offset = Vector()
if not centered[0]:
offset += Vector(radius, 0, 0)
if not centered[1]:
offset += Vector(0, radius, 0)
if centered[2]:
offset += Vector(0, 0, -height / 2)
s = Solid.makeCylinder(radius, height, offset, direct, angle)
# We want a cylinder for each point on the workplane
cylinders = self.eachpoint(lambda loc: s.moved(loc), True)
# If we don't need to combine everything, just return the created cylinders
if not combine:
return cylinders
else:
return self.union(cylinders, clean=clean)
def wedge(
self: T,
dx: float,

View File

@ -153,7 +153,7 @@ class ShapeResult(object):
class BuildResult(object):
"""
The result of executing a CadQuery script.
The success property contains whether the exeuction was successful.
The success property contains whether the execution was successful.
If successful, the results property contains a list of all results,
and the first_result property contains the first result.

View File

@ -76,16 +76,23 @@ def _dxf_spline(e: Edge, msp: ezdxf.layouts.Modelspace, plane: Plane):
curve, adaptor.FirstParameter(), adaptor.LastParameter(), CURVE_TOLERANCE
)
# need to apply the transform on the geometry level
spline.Transform(plane.fG.wrapped.Trsf())
order = spline.Degree() + 1
knots = list(spline.KnotSequence())
poles = [(p.X(), p.Y(), p.Z()) for p in spline.Poles()]
weights = (
[spline.Weight(i) for i in range(1, spline.NbPoles() + 1)]
if spline.IsRational()
else None
)
weights = list(spline.Weights()) if spline.IsRational() else None
if spline.IsPeriodic():
pad = spline.NbKnots() - spline.LastUKnotIndex()
poles += poles[:pad]
if spline.IsClosed():
dxf_spline = ezdxf.math.BSplineClosed(poles, order, knots, weights)
else:
dxf_spline = ezdxf.math.BSpline(poles, order, knots, weights)
dxf_spline = ezdxf.math.BSpline(poles, order, knots, weights)
msp.add_spline().apply_construction_tool(dxf_spline)

View File

@ -223,7 +223,7 @@ def getSVG(shape, opts=None):
hidden = list(map(Shape, hidden))
(hiddenPaths, visiblePaths) = getPaths(visible, hidden)
# get bounding box -- these are all in 2-d space
# get bounding box -- these are all in 2D space
bb = Compound.makeCompound(hidden + visible).BoundingBox()
# width pixels for x, height pixels for y

View File

@ -27,7 +27,7 @@ TOL = 1e-2
class Vector(object):
"""Create a 3-dimensional vector
:param args: a 3-d vector, with x-y-z parts.
:param args: a 3D vector, with x-y-z parts.
you can either provide:
* nothing (in which case the null vector is return)
@ -166,7 +166,7 @@ class Vector(object):
"""Return the vector itself
The center of myself is myself.
Provided so that vectors, vertexes, and other shapes all support a
Provided so that vectors, vertices, and other shapes all support a
common interface, when Center() is requested for all objects on the
stack.
"""
@ -375,6 +375,14 @@ class Matrix:
else:
raise IndexError("Out of bounds access into 4x4 matrix: {!r}".format(rc))
def __repr__(self) -> str:
"""
Generate a valid python expression representing this Matrix
"""
matrix_transposed = self.transposed_list()
matrix_str = ",\n ".join(str(matrix_transposed[i::4]) for i in range(4))
return f"Matrix([{matrix_str}])"
class Plane(object):
"""A 2D coordinate system in space
@ -382,7 +390,7 @@ class Plane(object):
A 2D coordinate system in space, with the x-y axes on the plane, and a
particular point as the origin.
A plane allows the use of 2-d coordinates, which are later converted to
A plane allows the use of 2D coordinates, which are later converted to
global, 3d coordinates when the operations are complete.
Frequently, it is not necessary to create work planes, as they can be
@ -592,7 +600,7 @@ class Plane(object):
:param float y: offset in the y direction
:return: void
The new coordinates are specified in terms of the current 2-d system.
The new coordinates are specified in terms of the current 2D system.
As an example:
p = Plane.XY()
@ -614,9 +622,9 @@ class Plane(object):
Most of the time, the z-coordinate returned will be zero, because most
operations based on a plane are all 2-d. Occasionally, though, 3-d
operations based on a plane are all 2D. Occasionally, though, 3D
points outside of the current plane are transformed. One such example is
:py:meth:`Workplane.box`, where 3-d corners of a box are transformed to
:py:meth:`Workplane.box`, where 3D corners of a box are transformed to
orient the box in space correctly.
"""
@ -706,7 +714,7 @@ class Plane(object):
for w in listOfShapes:
mirrored = w.transformShape(Matrix(T))
# attemp stitching of the wires
# attempt stitching of the wires
resultWires.append(mirrored)
return resultWires

View File

@ -136,7 +136,7 @@ def _dxf_spline(el):
knots.SetValue(i + 1, k)
multiplicities.SetValue(i + 1, m)
# assemble wieghts if present:
# assemble weights if present:
if el.weights:
rational = True
@ -144,7 +144,7 @@ def _dxf_spline(el):
for i, w in enumerate(el.weights):
weights.SetValue(i + 1, w)
# assmeble conotrol points
# assemble control points
pts = TColgp_Array1OfPnt(1, len(el.control_points))
for i, p in enumerate(el.control_points):
pts.SetValue(i + 1, gp_Pnt(*p))

View File

@ -98,7 +98,7 @@ from OCP.BRepPrimAPI import (
from OCP.TopExp import TopExp_Explorer # Toplogy explorer
# used for getting underlying geoetry -- is this equvalent to brep adaptor?
# used for getting underlying geoetry -- is this equivalent to brep adaptor?
from OCP.BRep import BRep_Tool, BRep_Builder
from OCP.TopoDS import (
@ -420,7 +420,7 @@ class Shape(object):
}
t = shapetype(obj)
# NB downcast is nedded to handly TopoDS_Shape types
# NB downcast is needed to handly TopoDS_Shape types
tr = constructor_LUT[t](downcast(obj))
tr.forConstruction = forConstruction
@ -1045,7 +1045,7 @@ class Shape(object):
def mesh(self, tolerance: float, angularTolerance: float = 0.1):
"""
Generate traingulation if none exists.
Generate triangulation if none exists.
"""
if not BRepTools.Triangulation_s(self.wrapped, tolerance):
@ -1115,7 +1115,7 @@ class Shape(object):
rv = shape_data.getVtkPolyData()
# convert to traingles and split edges
# convert to triangles and split edges
t_filter = vtkTriangleFilter()
t_filter.SetInputData(rv)
t_filter.Update()
@ -1353,7 +1353,7 @@ class Mixin1D(object):
d: float,
mode: Literal["length", "parameter"] = "length",
) -> Vector:
"""Generate a postion along the underlying curve.
"""Generate a position along the underlying curve.
:param d: distance or parameter value
:param mode: position calculation mode (default: length)
:return: A Vector on the underlying curve located at the specified d value.
@ -1567,8 +1567,8 @@ class Edge(Shape, Mixin1D):
:param listOfVector: a list of Vectors that represent the points
:param tangents: tuple of Vectors specifying start and finish tangent
:param periodic: creation of peridic curves
:param parameters: the value of the parameter at each interpolation point. (The intepolated
:param periodic: creation of periodic curves
:param parameters: the value of the parameter at each interpolation point. (The interpolated
curve is represented as a vector-valued function of a scalar parameter.) If periodic ==
True, then len(parameters) must be len(intepolation points) + 1, otherwise len(parameters)
must be equal to len(interpolation points).
@ -1899,7 +1899,7 @@ class Wire(Shape, Mixin1D):
gp_Ax3(center.toPnt(), dir.toDir()), angle * DEG2RAD, radius
)
# 2. construct an semgent in the u,v domain
# 2. construct an segment in the u,v domain
if lefthand:
geom_line = Geom2d_Line(gp_Pnt2d(0.0, 0.0), gp_Dir2d(-2 * pi, pitch))
else:
@ -2415,7 +2415,7 @@ class Mixin3D(object):
object within the specified tolerance.
:param point: tuple or Vector representing 3D point to be tested
:param tolerance: tolerence for inside determination, default=1.0e-6
:param tolerance: tolerance for inside determination, default=1.0e-6
:return: bool indicating whether or not point is within solid
"""
if isinstance(point, Vector):
@ -2765,7 +2765,7 @@ class Solid(Shape, Mixin3D):
straight_spine_e = Edge.makeLine(vecCenter, vecCenter.add(vecNormal))
straight_spine_w = Wire.combine([straight_spine_e,])[0].wrapped
# make an auxliliary spine
# make an auxiliary spine
pitch = 360.0 / angleDegrees * vecNormal.Length
radius = 1
aux_spine_w = Wire.makeHelix(
@ -2783,7 +2783,7 @@ class Solid(Shape, Mixin3D):
for w in innerWires
]
# combine the inner solids into compund
# combine the inner solids into compound
inner_comp = Compound._makeCompound(inner_solids)
# subtract from the outer solid
@ -2933,7 +2933,7 @@ class Solid(Shape, Mixin3D):
:param outerWire: the outermost wire
:param innerWires: a list of inner wires
:param path: The wire to sweep the face resulting from the wires over
:param boolean makeSolid: return Solid or Shell (defualt True)
:param boolean makeSolid: return Solid or Shell (default True)
:param boolean isFrenet: Frenet mode (default False)
:param mode: additional sweep mode parameters.
:param transitionMode:
@ -3027,7 +3027,7 @@ class Solid(Shape, Mixin3D):
"""
Make a prismatic feature (additive or subtractive)
:param basis: face to perfrom the operation on
:param basis: face to perform the operation on
:param profiles: list of profiles
:param depth: depth of the cut or extrusion
:param thruAll: cut thruAll

View File

@ -214,7 +214,7 @@ class ParallelDirSelector(BaseDirSelector):
CQ(aCube).faces(ParallelDirSelector((0, 0, 1))
selects faces with a normals in the z direction, and is equivalent to::
selects faces with the normal parallel to the z direction, and is equivalent to::
CQ(aCube).faces("|Z")
"""
@ -237,7 +237,7 @@ class DirectionSelector(BaseDirSelector):
CQ(aCube).faces(DirectionSelector((0, 0, 1))
selects faces with a normals in the z direction, and is equivalent to::
selects faces with the normal in the z direction, and is equivalent to::
CQ(aCube).faces("+Z")
"""
@ -261,7 +261,7 @@ class PerpendicularDirSelector(BaseDirSelector):
CQ(aCube).faces(PerpendicularDirSelector((0, 0, 1))
selects faces with a normals perpendicular to the z direction, and is equivalent to::
selects faces with the normal perpendicular to the z direction, and is equivalent to::
CQ(aCube).faces("#Z")
"""
@ -586,7 +586,7 @@ class SumSelector(BinarySelector):
class SubtractSelector(BinarySelector):
"""
Difference selector. Substract results of a selector from another
Difference selector. Subtract results of a selector from another
selectors results.
"""
@ -842,7 +842,7 @@ class StringSyntaxSelector(Selector):
:return: objects that match the specified selector
***Modfiers*** are ``('|','+','-','<','>','%')``
***Modifiers*** are ``('|','+','-','<','>','%')``
:\|:
parallel to ( same as :py:class:`ParallelDirSelector` ). Can return multiple objects.
@ -862,7 +862,7 @@ class StringSyntaxSelector(Selector):
***axisStrings*** are: ``X,Y,Z,XY,YZ,XZ`` or ``(x,y,z)`` which defines an arbitrary direction
It is possible to combine simple selectors together using logical operations.
The following operations are suuported
The following operations are supported
:and:
Logical AND, e.g. >X and >Y

View File

@ -15,7 +15,7 @@ requirements:
- setuptools
run:
- python {{ environ.get('PYTHON_VERSION') }}
- ocp 7.5.1
- ocp 7.5.2
- pyparsing 2.*
- ezdxf
- ipython

View File

@ -153,7 +153,7 @@
</tr>
<tr>
<td>Workplane(inPlane[origin, obj])</td>
<td>Defines a coordinate system in space, in which 2-d coordinates can be used.</td>
<td>Defines a coordinate system in space, in which 2D coordinates can be used.</td>
</tr>
</table>
</div>

View File

@ -6,7 +6,7 @@ CadQuery API Reference
The CadQuery API is made up of 2 main objects:
* **Workplane** -- Wraps a topological entity and provides a 2-D modelling context.
* **Workplane** -- Wraps a topological entity and provides a 2D modelling context.
* **Selector** -- Filter and select things
This page lists methods of these objects grouped by **functional area**
@ -29,12 +29,12 @@ Creating new workplanes and object chains
.. _2dOperations:
2-d Operations
2D Operations
-----------------
Creating 2-d constructs that can be used to create 3 d features.
Creating 2D constructs that can be used to create 3D features.
All 2-d operations require a **Workplane** object to be created.
All 2D operations require a **Workplane** object to be created.
.. currentmodule:: cadquery
@ -73,12 +73,12 @@ All 2-d operations require a **Workplane** object to be created.
.. _3doperations:
3-d Operations
3D Operations
-----------------
Some 3-d operations also require an active 2-d workplane, but some do not.
Some 3D operations also require an active 2D workplane, but some do not.
3-d operations that require a 2-d workplane to be active:
3D operations that require a 2D workplane to be active:
.. autosummary::
Workplane.cboreHole
@ -90,6 +90,7 @@ Some 3-d operations also require an active 2-d workplane, but some do not.
Workplane.cutThruAll
Workplane.box
Workplane.sphere
Workplane.cylinder
Workplane.union
Workplane.combine
Workplane.intersect
@ -100,7 +101,7 @@ Some 3-d operations also require an active 2-d workplane, but some do not.
Workplane.text
3-d operations that do NOT require a 2-d workplane to be active:
3D operations that do NOT require a 2D workplane to be active:
.. autosummary::
Workplane.shell
@ -167,7 +168,7 @@ Selectors
------------------------
Objects that filter and select CAD objects. Selectors are used to select existing geometry
as a basis for futher operations.
as a basis for further operations.
.. currentmodule:: cadquery.selectors
.. autosummary::

View File

@ -1,11 +1,11 @@
.. _assytutorial:
***********************
Assembly Tutorial
***********************
**********
Assemblies
**********
Introduction
============
Assembly tutorial
-----------------
The purpose of this section is to demonstrate how to use the assembly and constraints
functionality to build a realistic model. It will be a enclosure door assembly made out of 20x20 v-slot profiles.
@ -373,3 +373,872 @@ STEP can be loaded in all CAD tool, e.g. in FreeCAD and the XML be used in other
In the case of STEP colors are preserved but not transparency.
.. image:: _static/door_assy_freecad.png
Object locations
----------------
Objects can be added to an assembly with initial locations supplied, such as:
.. cadquery::
import cadquery as cq
cone = cq.Solid.makeCone(1, 0, 2)
assy = cq.Assembly()
assy.add(
cone,
loc=cq.Location(cq.Vector(0, 0, 0), cq.Vector(1, 0, 0), 180),
name="cone0",
color=cq.Color("green")
)
assy.add(cone, name="cone1", color=cq.Color("blue"))
show_object(assy)
As an alternative to the user calculating locations, constraints and the method
:meth:`~cadquery.Assembly.solve` can be used to position objects in an assembly.
If initial locations and the method :meth:`~cadquery.Assembly.solve` are used the solver will
overwrite these initial locations with it's solution, however initial locations can still affect the
final solution. In an underconstrained system the solver may not move an object if it does not
contribute to the cost function, or if multiple solutions exist (ie. multiple instances
where the cost function is at a minimum) initial locations can cause the solver to converge on one
particular solution. For very complicated assemblies setting approximately correct initial locations
can also reduce the computational time requred.
Constraints
-----------
Constraints are often a better representation of the real world relationship the user wants to
model than directly supplying locations. In the above example the real world relationship is that
the bottom face of each cone should touch, which can be modelled with a Plane constraint. When the
user provides explicit locations (instead of constraints) then they are also reponsible for updating
them when, for example, the location of ``cone1`` changes.
When at least one constraint is supplied and the method :meth:`~cadquery.Assembly.solve` is run, an
optimization problem is set up. Each constraint provides a cost function that depends on the
position and orientation (represented by a :class:`~cadquery.Location`) of the two objects specified
when creating the constraint. The solver varies the location of the assembly's children and attempts
to minimize the sum of all cost functions. Hence by reading the formulae of the cost functions
below, you can understand exactly what each constraint does.
Point
=====
The Point constraint is a frequently used constraint that minimizes the distance between two points.
Some example uses are centering faces or aligning verticies, but it is also useful with dummy
vertices to create offsets between two parts.
The cost function is:
.. math::
( param - \lvert \vec{ c_1 } - \vec{ c_2 } \rvert ) ^2
Where:
- :math:`param` is the parameter of the constraint, which defaults to 0,
- :math:`\vec{ c_i }` is the center of the ith object, and
- :math:`\lvert \vec{ v } \rvert` is the modulus of :math:`\vec{ v }`, ie. the length of
:math:`\vec{ v }`.
When creating a Point constraint, the ``param`` argument can be used to specify a desired offset
between the two centers. This offset does not have a direction associated with it, if you want to
specify an offset in a specific direction then you should use a dummy :class:`~cadquery.Vertex`.
The Point constraint uses the :meth:`~cadquery.occ_impl.Shape.Center` to find the center of the
argument. Hence it will work with all subclasses of :class:`~caquery.occ_impl.Shape`.
.. cadquery::
import cadquery as cq
# Use the Point constraint to position boxes relative to an arc
line = cq.Edge.makeCircle(radius=10, angle1=0, angle2=90)
box = cq.Workplane().box(1, 1, 1)
assy = cq.Assembly()
assy.add(line, name="line")
# position the red box on the center of the arc
assy.add(box, name="box0", color=cq.Color("red"))
assy.constrain("line", "box0", "Point")
# position the green box at a normalized distance of 0.8 along the arc
position0 = line.positionAt(0.8)
assy.add(box, name="box1", color=cq.Color("green"))
assy.constrain(
"line", cq.Vertex.makeVertex(*position0.toTuple()), "box1", box.val(), "Point",
)
# position the orange box 2 units in any direction from the green box
assy.add(box, name="box2", color=cq.Color("orange"))
assy.constrain(
"line",
cq.Vertex.makeVertex(*position0.toTuple()),
"box2",
box.val(),
"Point",
param=2,
)
# position the blue box offset 2 units in the x direction from the green box
position1 = position0 + cq.Vector(2, 0, 0)
assy.add(box, name="box3", color=cq.Color("blue"))
assy.constrain(
"line", cq.Vertex.makeVertex(*position1.toTuple()), "box3", box.val(), "Point",
)
assy.solve()
show_object(assy)
Axis
====
The Axis constraint minimizes the angle between two vectors. It is frequently used to align faces
and control the rotation of an object.
The cost function is:
.. math::
( k_{ dir } \times ( param - \vec{ d_1 } \angle \vec{ d_2 } ) ^2
Where:
- :math:`k_{ dir }` is a scaling factor for directional constraints,
- :math:`param` is the parameter of the constraint, which defaults to :math:`\pi` radians,
- :math:`\vec{d_i}` is the direction created from the ith object argument as described below, and
- :math:`\vec{ d_1 } \angle \vec{ d_2 }` is the angle in radians between :math:`\vec{ d_1 }` and
:math:`\vec{ d_2 }`.
The argument ``param`` defaults to :math:`\pi` radians, which sets the two directions opposite
to each other. This represents what is often called a "mate" relationship, where the external faces
of two objects touch.
.. cadquery::
import cadquery as cq
cone = cq.Solid.makeCone(1, 0, 2)
assy = cq.Assembly()
assy.add(cone, name="cone0", color=cq.Color("green"))
assy.add(cone, name="cone1", color=cq.Color("blue"))
assy.constrain("cone0@faces@<Z", "cone1@faces@<Z", "Axis")
assy.solve()
show_object(assy)
If the ``param`` argument is set to zero, then the two objects will point in the same direction.
This is often used when one object goes through another, such as a pin going into a hole in a plate:
.. cadquery::
import cadquery as cq
plate = cq.Workplane().box(10, 10, 1).faces(">Z").workplane().hole(2)
cone = cq.Solid.makeCone(0.8, 0, 4)
assy = cq.Assembly()
assy.add(plate, name="plate", color=cq.Color("green"))
assy.add(cone, name="cone", color=cq.Color("blue"))
# place the center of the flat face of the cone in the center of the upper face of the plate
assy.constrain("plate@faces@>Z", "cone@faces@<Z", "Point")
# set both the flat face of the cone and the upper face of the plate to point in the same direction
assy.constrain("plate@faces@>Z", "cone@faces@<Z", "Axis", param=0)
assy.solve()
show_object(assy)
In creating an Axis constraint, a direction vector is extracted in one of three different ways,
depending on the object's type.
:class:`~cadquery.Face`:
Using :meth:`~cadquery.Face.normalAt`
:class:`~cadquery.Edge` and :meth:`~cadquery.Shape.geomType` is ``"CIRCLE"``:
Using :meth:`~cadquery.Mixin1D.normal`
:class:`~cadquery.Edge` and :meth:`~cadquery.Shape.geomType` is not ``"CIRCLE"``:
Using :meth:`~cadquery.Mixin1D.tangentAt`
Using any other type of object will raise a :exc:`ValueError`. By far the most common use case
is to define an Axis constraint from a :class:`~cadquery.Face`.
.. cadquery::
import cadquery as cq
from math import cos, sin, pi
# Create a sinusoidal surface:
surf = cq.Workplane().parametricSurface(
lambda u, v: (u, v, 5 * sin(pi * u / 10) * cos(pi * v / 10)),
N=40,
start=0,
stop=20,
)
# Create a cone with a small, flat tip:
cone = (
cq.Workplane()
.add(cq.Solid.makeCone(1, 0.1, 2))
# tag the tip for easy reference in the constraint:
.faces(">Z")
.tag("tip")
.end()
)
assy = cq.Assembly()
assy.add(surf, name="surf", color=cq.Color("lightgray"))
assy.add(cone, name="cone", color=cq.Color("green"))
# set the Face on the tip of the cone to point in
# the opposite direction of the center of the surface:
assy.constrain("surf", "cone?tip", "Axis")
# to make the example clearer, move the cone to the center of the face:
assy.constrain("surf", "cone?tip", "Point")
assy.solve()
show_object(assy)
Plane
=====
The Plane constraint is simply a combination of both the Point and Axis constraints. It is a
convienient shortcut for a commonly used combination of constraints. It can be used to shorten the
previous example from the two constraints to just one:
.. code-block:: diff
assy = cq.Assembly()
assy.add(surf, name="surf", color=cq.Color("lightgray"))
assy.add(cone, name="cone", color=cq.Color("green"))
-# set the Face on the tip of the cone to point in
-# the opposite direction of the center of the surface:
-assy.constrain("surf", "cone?tip", "Axis")
-# to make the example clearer, move the cone to the center of the face:
-assy.constrain("surf", "cone?tip", "Point")
+assy.constrain("surf", "cone?tip", "Plane")
assy.solve()
show_object(assy)
The result of this code is identical to the above two constraint example.
For the cost function of Plane, please see the Point and Axis sections. The ``param`` argument is
copied into both constraints and should be left as the default value of ``None`` for a "mate" style
constraint (two surfaces touching) or can be set to ``0`` for a through surface constraint (see
desciption in the Axis constraint section).
PointInPlane
============
PointInPlane positions the center of the first object within the plane defined by the second object.
The cost function is:
.. math::
\operatorname{dist}( \vec{ c }, p_\text{ offset } ) ^2
Where:
- :math:`\vec{ c }` is the center of the first argument,
- :math:`p_\text{ offset }` is a plane created from the second object, offset in the plane's normal
direction by ``param``, and
- :math:`\operatorname{dist}( \vec{ a }, b)` is the distance between point :math:`\vec{ a }` and
plane :math:`b`.
.. cadquery::
import cadquery as cq
# Create an L-shaped object:
bracket = (
cq.Workplane("YZ")
.hLine(1)
.vLine(0.1)
.hLineTo(0.2)
.vLineTo(1)
.hLineTo(0)
.close()
.extrude(1)
# tag some faces for easy reference:
.faces(">Y[1]")
.tag("inner_vert")
.end()
.faces(">Z[1]")
.tag("inner_horiz")
.end()
)
box = cq.Workplane().box(0.5, 0.5, 0.5)
assy = cq.Assembly()
assy.add(bracket, name="bracket", color=cq.Color("gray"))
assy.add(box, name="box", color=cq.Color("green"))
# lock bracket orientation:
assy.constrain("bracket@faces@>Z", "box@faces@>Z", "Axis", param=0)
assy.constrain("bracket@faces@>X", "box@faces@>X", "Axis", param=0)
# constrain the bottom of the box to be on the plane defined by inner_horiz:
assy.constrain("box@faces@<Z", "bracket?inner_horiz", "PointInPlane")
# constrain the side of the box to be 0.2 units from the plane defined by inner_vert
assy.constrain("box@faces@<Y", "bracket?inner_vert", "PointInPlane", param=0.2)
# constrain the end of the box to be 0.1 units inside the end of the bracket
assy.constrain("box@faces@>X", "bracket@faces@>X", "PointInPlane", param=-0.1)
assy.solve()
show_object(assy)
Assembly colors
---------------
Aside from RGBA values, the :class:`~cadquery.Color` class can be instantiated from a text name. Valid names are
listed along with a color sample below:
.. raw:: html
<div class="color-grid" style="display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill, minmax(200px,1fr));">
<div style="background-color:rgba(222,239,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">aliceblue</div>
<div style="background-color:rgba(243,211,173,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">antiquewhite</div>
<div style="background-color:rgba(255,220,180,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">antiquewhite1</div>
<div style="background-color:rgba(218,188,153,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">antiquewhite2</div>
<div style="background-color:rgba(155,134,110,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">antiquewhite3</div>
<div style="background-color:rgba(65,57,47,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">antiquewhite4</div>
<div style="background-color:rgba(54,255,167,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">aquamarine1</div>
<div style="background-color:rgba(46,218,144,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">aquamarine2</div>
<div style="background-color:rgba(15,65,44,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">aquamarine4</div>
<div style="background-color:rgba(222,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">azure</div>
<div style="background-color:rgba(190,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">azure2</div>
<div style="background-color:rgba(135,155,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">azure3</div>
<div style="background-color:rgba(57,65,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">azure4</div>
<div style="background-color:rgba(68,10,68,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">beet</div>
<div style="background-color:rgba(232,232,182,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">beige</div>
<div style="background-color:rgba(255,197,140,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">bisque</div>
<div style="background-color:rgba(218,169,120,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">bisque2</div>
<div style="background-color:rgba(155,120,87,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">bisque3</div>
<div style="background-color:rgba(65,52,37,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">bisque4</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">black</div>
<div style="background-color:rgba(255,211,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">blanchedalmond</div>
<div style="background-color:rgba(0,0,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blue</div>
<div style="background-color:rgba(0,0,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blue1</div>
<div style="background-color:rgba(0,0,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blue2</div>
<div style="background-color:rgba(0,0,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blue3</div>
<div style="background-color:rgba(0,0,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blue4</div>
<div style="background-color:rgba(64,6,193,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">blueviolet</div>
<div style="background-color:rgba(95,5,5,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">brown</div>
<div style="background-color:rgba(255,13,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">brown1</div>
<div style="background-color:rgba(218,11,11,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">brown2</div>
<div style="background-color:rgba(155,8,8,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">brown3</div>
<div style="background-color:rgba(65,4,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">brown4</div>
<div style="background-color:rgba(186,122,61,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">burlywood</div>
<div style="background-color:rgba(255,166,83,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">burlywood1</div>
<div style="background-color:rgba(218,142,72,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">burlywood2</div>
<div style="background-color:rgba(155,102,52,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">burlywood3</div>
<div style="background-color:rgba(65,43,23,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">burlywood4</div>
<div style="background-color:rgba(29,87,89,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cadetblue</div>
<div style="background-color:rgba(80,232,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cadetblue1</div>
<div style="background-color:rgba(68,199,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cadetblue2</div>
<div style="background-color:rgba(49,142,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cadetblue3</div>
<div style="background-color:rgba(22,60,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cadetblue4</div>
<div style="background-color:rgba(54,255,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chartreuse</div>
<div style="background-color:rgba(54,255,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chartreuse1</div>
<div style="background-color:rgba(46,218,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chartreuse2</div>
<div style="background-color:rgba(33,155,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chartreuse3</div>
<div style="background-color:rgba(15,65,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chartreuse4</div>
<div style="background-color:rgba(164,36,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chocolate</div>
<div style="background-color:rgba(255,54,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chocolate1</div>
<div style="background-color:rgba(218,46,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chocolate2</div>
<div style="background-color:rgba(155,33,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chocolate3</div>
<div style="background-color:rgba(65,15,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">chocolate4</div>
<div style="background-color:rgba(255,54,20,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">coral</div>
<div style="background-color:rgba(255,42,23,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">coral1</div>
<div style="background-color:rgba(218,36,20,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">coral2</div>
<div style="background-color:rgba(155,26,15,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">coral3</div>
<div style="background-color:rgba(65,12,7,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">coral4</div>
<div style="background-color:rgba(32,76,215,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cornflowerblue</div>
<div style="background-color:rgba(255,239,182,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cornsilk1</div>
<div style="background-color:rgba(218,205,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cornsilk2</div>
<div style="background-color:rgba(155,147,112,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cornsilk3</div>
<div style="background-color:rgba(65,62,47,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cornsilk4</div>
<div style="background-color:rgba(0,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cyan</div>
<div style="background-color:rgba(0,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cyan1</div>
<div style="background-color:rgba(0,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">cyan2</div>
<div style="background-color:rgba(0,155,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cyan3</div>
<div style="background-color:rgba(0,65,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">cyan4</div>
<div style="background-color:rgba(122,60,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgoldenrod</div>
<div style="background-color:rgba(255,123,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgoldenrod1</div>
<div style="background-color:rgba(218,106,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgoldenrod2</div>
<div style="background-color:rgba(155,76,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgoldenrod3</div>
<div style="background-color:rgba(65,33,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgoldenrod4</div>
<div style="background-color:rgba(0,32,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkgreen</div>
<div style="background-color:rgba(129,120,37,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkkhaki</div>
<div style="background-color:rgba(23,37,7,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkolivegreen</div>
<div style="background-color:rgba(150,255,41,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkolivegreen1</div>
<div style="background-color:rgba(128,218,35,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkolivegreen2</div>
<div style="background-color:rgba(92,155,26,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkolivegreen3</div>
<div style="background-color:rgba(39,65,11,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkolivegreen4</div>
<div style="background-color:rgba(255,66,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorange</div>
<div style="background-color:rgba(255,54,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorange1</div>
<div style="background-color:rgba(218,46,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorange2</div>
<div style="background-color:rgba(155,33,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorange3</div>
<div style="background-color:rgba(65,15,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorange4</div>
<div style="background-color:rgba(81,8,153,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorchid</div>
<div style="background-color:rgba(132,12,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkorchid1</div>
<div style="background-color:rgba(113,10,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorchid2</div>
<div style="background-color:rgba(82,8,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorchid3</div>
<div style="background-color:rgba(35,4,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkorchid4</div>
<div style="background-color:rgba(207,77,49,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darksalmon</div>
<div style="background-color:rgba(70,128,70,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkseagreen</div>
<div style="background-color:rgba(135,255,135,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkseagreen1</div>
<div style="background-color:rgba(116,218,116,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkseagreen2</div>
<div style="background-color:rgba(83,155,83,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkseagreen3</div>
<div style="background-color:rgba(36,65,36,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkseagreen4</div>
<div style="background-color:rgba(16,11,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkslateblue</div>
<div style="background-color:rgba(7,19,19,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkslategray</div>
<div style="background-color:rgba(78,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkslategray1</div>
<div style="background-color:rgba(67,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">darkslategray2</div>
<div style="background-color:rgba(48,155,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkslategray3</div>
<div style="background-color:rgba(21,65,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkslategray4</div>
<div style="background-color:rgba(0,157,162,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkturquoise</div>
<div style="background-color:rgba(75,0,166,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">darkviolet</div>
<div style="background-color:rgba(255,1,74,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deeppink</div>
<div style="background-color:rgba(218,1,63,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deeppink2</div>
<div style="background-color:rgba(155,1,46,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deeppink3</div>
<div style="background-color:rgba(65,0,20,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deeppink4</div>
<div style="background-color:rgba(0,132,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">deepskyblue1</div>
<div style="background-color:rgba(0,113,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deepskyblue2</div>
<div style="background-color:rgba(0,82,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deepskyblue3</div>
<div style="background-color:rgba(0,35,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">deepskyblue4</div>
<div style="background-color:rgba(3,71,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">dodgerblue1</div>
<div style="background-color:rgba(2,60,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">dodgerblue2</div>
<div style="background-color:rgba(2,44,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">dodgerblue3</div>
<div style="background-color:rgba(1,19,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">dodgerblue4</div>
<div style="background-color:rgba(113,4,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">firebrick</div>
<div style="background-color:rgba(255,7,7,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">firebrick1</div>
<div style="background-color:rgba(218,6,6,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">firebrick2</div>
<div style="background-color:rgba(155,4,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">firebrick3</div>
<div style="background-color:rgba(65,2,2,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">firebrick4</div>
<div style="background-color:rgba(255,243,222,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">floralwhite</div>
<div style="background-color:rgba(4,65,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">forestgreen</div>
<div style="background-color:rgba(182,182,182,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gainsboro</div>
<div style="background-color:rgba(239,239,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">ghostwhite</div>
<div style="background-color:rgba(255,173,0,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gold</div>
<div style="background-color:rgba(255,173,0,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gold1</div>
<div style="background-color:rgba(218,148,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gold2</div>
<div style="background-color:rgba(155,106,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gold3</div>
<div style="background-color:rgba(65,45,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gold4</div>
<div style="background-color:rgba(178,95,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">goldenrod</div>
<div style="background-color:rgba(255,135,4,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">goldenrod1</div>
<div style="background-color:rgba(218,116,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">goldenrod2</div>
<div style="background-color:rgba(155,83,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">goldenrod3</div>
<div style="background-color:rgba(65,36,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">goldenrod4</div>
<div style="background-color:rgba(134,134,134,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray0</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray1</div>
<div style="background-color:rgba(2,2,2,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray10</div>
<div style="background-color:rgba(2,2,2,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray11</div>
<div style="background-color:rgba(3,3,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray12</div>
<div style="background-color:rgba(3,3,3,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray13</div>
<div style="background-color:rgba(4,4,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray14</div>
<div style="background-color:rgba(4,4,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray15</div>
<div style="background-color:rgba(5,5,5,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray16</div>
<div style="background-color:rgba(6,6,6,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray17</div>
<div style="background-color:rgba(6,6,6,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray18</div>
<div style="background-color:rgba(7,7,7,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray19</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray2</div>
<div style="background-color:rgba(8,8,8,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray20</div>
<div style="background-color:rgba(9,9,9,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray21</div>
<div style="background-color:rgba(10,10,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray22</div>
<div style="background-color:rgba(11,11,11,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray23</div>
<div style="background-color:rgba(11,11,11,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray24</div>
<div style="background-color:rgba(13,13,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray25</div>
<div style="background-color:rgba(13,13,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray26</div>
<div style="background-color:rgba(15,15,15,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray27</div>
<div style="background-color:rgba(16,16,16,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray28</div>
<div style="background-color:rgba(17,17,17,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray29</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray3</div>
<div style="background-color:rgba(18,18,18,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray30</div>
<div style="background-color:rgba(19,19,19,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray31</div>
<div style="background-color:rgba(21,21,21,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray32</div>
<div style="background-color:rgba(22,22,22,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray33</div>
<div style="background-color:rgba(24,24,24,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray34</div>
<div style="background-color:rgba(25,25,25,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray35</div>
<div style="background-color:rgba(27,27,27,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray36</div>
<div style="background-color:rgba(28,28,28,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray37</div>
<div style="background-color:rgba(30,30,30,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray38</div>
<div style="background-color:rgba(31,31,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray39</div>
<div style="background-color:rgba(0,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray4</div>
<div style="background-color:rgba(33,33,33,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray40</div>
<div style="background-color:rgba(36,36,36,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray41</div>
<div style="background-color:rgba(37,37,37,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray42</div>
<div style="background-color:rgba(39,39,39,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray43</div>
<div style="background-color:rgba(41,41,41,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray44</div>
<div style="background-color:rgba(43,43,43,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray45</div>
<div style="background-color:rgba(45,45,45,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray46</div>
<div style="background-color:rgba(47,47,47,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray47</div>
<div style="background-color:rgba(49,49,49,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray48</div>
<div style="background-color:rgba(52,52,52,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray49</div>
<div style="background-color:rgba(1,1,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray5</div>
<div style="background-color:rgba(54,54,54,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray50</div>
<div style="background-color:rgba(56,56,56,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray51</div>
<div style="background-color:rgba(59,59,59,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray52</div>
<div style="background-color:rgba(61,61,61,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray53</div>
<div style="background-color:rgba(64,64,64,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray54</div>
<div style="background-color:rgba(66,66,66,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray55</div>
<div style="background-color:rgba(70,70,70,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray56</div>
<div style="background-color:rgba(72,72,72,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray57</div>
<div style="background-color:rgba(75,75,75,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray58</div>
<div style="background-color:rgba(77,77,77,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray59</div>
<div style="background-color:rgba(1,1,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray6</div>
<div style="background-color:rgba(81,81,81,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray60</div>
<div style="background-color:rgba(84,84,84,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray61</div>
<div style="background-color:rgba(87,87,87,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray62</div>
<div style="background-color:rgba(90,90,90,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray63</div>
<div style="background-color:rgba(93,93,93,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray64</div>
<div style="background-color:rgba(97,97,97,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray65</div>
<div style="background-color:rgba(99,99,99,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray66</div>
<div style="background-color:rgba(103,103,103,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray67</div>
<div style="background-color:rgba(106,106,106,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray68</div>
<div style="background-color:rgba(110,110,110,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray69</div>
<div style="background-color:rgba(1,1,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray7</div>
<div style="background-color:rgba(114,114,114,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray70</div>
<div style="background-color:rgba(117,117,117,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray71</div>
<div style="background-color:rgba(122,122,122,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray72</div>
<div style="background-color:rgba(125,125,125,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray73</div>
<div style="background-color:rgba(129,129,129,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray74</div>
<div style="background-color:rgba(132,132,132,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray75</div>
<div style="background-color:rgba(137,137,137,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray76</div>
<div style="background-color:rgba(140,140,140,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray77</div>
<div style="background-color:rgba(145,145,145,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray78</div>
<div style="background-color:rgba(148,148,148,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray79</div>
<div style="background-color:rgba(1,1,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray8</div>
<div style="background-color:rgba(153,153,153,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray80</div>
<div style="background-color:rgba(159,159,159,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray81</div>
<div style="background-color:rgba(162,162,162,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray82</div>
<div style="background-color:rgba(167,167,167,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray83</div>
<div style="background-color:rgba(176,176,176,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray85</div>
<div style="background-color:rgba(180,180,180,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray86</div>
<div style="background-color:rgba(186,186,186,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray87</div>
<div style="background-color:rgba(190,190,190,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray88</div>
<div style="background-color:rgba(195,195,195,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray89</div>
<div style="background-color:rgba(2,2,2,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">gray9</div>
<div style="background-color:rgba(199,199,199,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray90</div>
<div style="background-color:rgba(205,205,205,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray91</div>
<div style="background-color:rgba(211,211,211,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray92</div>
<div style="background-color:rgba(215,215,215,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray93</div>
<div style="background-color:rgba(222,222,222,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray94</div>
<div style="background-color:rgba(226,226,226,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray95</div>
<div style="background-color:rgba(237,237,237,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray97</div>
<div style="background-color:rgba(243,243,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray98</div>
<div style="background-color:rgba(248,248,248,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">gray99</div>
<div style="background-color:rgba(0,255,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">green</div>
<div style="background-color:rgba(0,255,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">green1</div>
<div style="background-color:rgba(0,218,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">green2</div>
<div style="background-color:rgba(0,155,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">green3</div>
<div style="background-color:rgba(0,65,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">green4</div>
<div style="background-color:rgba(106,255,7,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">greenyellow</div>
<div style="background-color:rgba(222,255,222,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">honeydew</div>
<div style="background-color:rgba(190,218,190,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">honeydew2</div>
<div style="background-color:rgba(135,155,135,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">honeydew3</div>
<div style="background-color:rgba(57,65,57,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">honeydew4</div>
<div style="background-color:rgba(255,36,116,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">hotpink</div>
<div style="background-color:rgba(255,39,116,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">hotpink1</div>
<div style="background-color:rgba(218,36,98,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">hotpink2</div>
<div style="background-color:rgba(155,29,71,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">hotpink3</div>
<div style="background-color:rgba(65,10,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">hotpink4</div>
<div style="background-color:rgba(155,27,27,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">indianred</div>
<div style="background-color:rgba(255,36,36,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">indianred1</div>
<div style="background-color:rgba(218,31,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">indianred2</div>
<div style="background-color:rgba(155,23,23,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">indianred3</div>
<div style="background-color:rgba(65,10,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">indianred4</div>
<div style="background-color:rgba(255,255,222,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">ivory</div>
<div style="background-color:rgba(218,218,190,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">ivory2</div>
<div style="background-color:rgba(155,155,135,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">ivory3</div>
<div style="background-color:rgba(65,65,57,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">ivory4</div>
<div style="background-color:rgba(222,201,66,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">khaki</div>
<div style="background-color:rgba(255,235,70,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">khaki1</div>
<div style="background-color:rgba(218,201,59,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">khaki2</div>
<div style="background-color:rgba(155,144,43,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">khaki3</div>
<div style="background-color:rgba(65,60,19,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">khaki4</div>
<div style="background-color:rgba(201,201,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lavender</div>
<div style="background-color:rgba(255,222,232,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lavenderblush1</div>
<div style="background-color:rgba(218,190,199,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lavenderblush2</div>
<div style="background-color:rgba(155,135,142,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lavenderblush3</div>
<div style="background-color:rgba(65,57,60,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lavenderblush4</div>
<div style="background-color:rgba(51,248,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lawngreen</div>
<div style="background-color:rgba(255,243,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lemonchiffon1</div>
<div style="background-color:rgba(218,207,132,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lemonchiffon2</div>
<div style="background-color:rgba(155,148,95,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lemonchiffon3</div>
<div style="background-color:rgba(65,63,41,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lemonchiffon4</div>
<div style="background-color:rgba(106,175,201,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightblue</div>
<div style="background-color:rgba(132,220,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightblue1</div>
<div style="background-color:rgba(113,188,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightblue2</div>
<div style="background-color:rgba(82,134,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightblue3</div>
<div style="background-color:rgba(35,57,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightblue4</div>
<div style="background-color:rgba(222,55,55,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightcoral</div>
<div style="background-color:rgba(190,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightcyan</div>
<div style="background-color:rgba(190,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightcyan1</div>
<div style="background-color:rgba(162,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightcyan2</div>
<div style="background-color:rgba(116,155,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightcyan3</div>
<div style="background-color:rgba(49,65,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightcyan4</div>
<div style="background-color:rgba(218,184,56,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightgoldenrod</div>
<div style="background-color:rgba(255,213,65,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightgoldenrod1</div>
<div style="background-color:rgba(218,182,56,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightgoldenrod2</div>
<div style="background-color:rgba(155,131,41,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightgoldenrod3</div>
<div style="background-color:rgba(65,55,18,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightgoldenrod4</div>
<div style="background-color:rgba(243,243,164,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightgoldenrodyellow</div>
<div style="background-color:rgba(166,166,166,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightgray</div>
<div style="background-color:rgba(255,119,135,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightpink</div>
<div style="background-color:rgba(255,107,123,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightpink1</div>
<div style="background-color:rgba(218,92,106,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightpink2</div>
<div style="background-color:rgba(155,66,76,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightpink3</div>
<div style="background-color:rgba(65,29,33,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightpink4</div>
<div style="background-color:rgba(255,89,49,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightsalmon1</div>
<div style="background-color:rgba(218,76,42,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightsalmon2</div>
<div style="background-color:rgba(155,55,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightsalmon3</div>
<div style="background-color:rgba(65,24,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightsalmon4</div>
<div style="background-color:rgba(3,113,102,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightseagreen</div>
<div style="background-color:rgba(61,157,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightskyblue</div>
<div style="background-color:rgba(110,193,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightskyblue1</div>
<div style="background-color:rgba(94,166,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightskyblue2</div>
<div style="background-color:rgba(67,119,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightskyblue3</div>
<div style="background-color:rgba(29,50,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightskyblue4</div>
<div style="background-color:rgba(58,41,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightslateblue</div>
<div style="background-color:rgba(47,62,81,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightslategray</div>
<div style="background-color:rgba(110,140,186,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightsteelblue</div>
<div style="background-color:rgba(150,192,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightsteelblue1</div>
<div style="background-color:rgba(128,164,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightsteelblue2</div>
<div style="background-color:rgba(92,117,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightsteelblue3</div>
<div style="background-color:rgba(39,50,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightsteelblue4</div>
<div style="background-color:rgba(255,255,190,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightyellow</div>
<div style="background-color:rgba(218,218,162,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightyellow2</div>
<div style="background-color:rgba(155,155,116,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">lightyellow3</div>
<div style="background-color:rgba(65,65,49,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">lightyellow4</div>
<div style="background-color:rgba(8,155,8,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">limegreen</div>
<div style="background-color:rgba(243,222,201,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">linen</div>
<div style="background-color:rgba(255,0,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">magenta</div>
<div style="background-color:rgba(255,0,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">magenta1</div>
<div style="background-color:rgba(218,0,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">magenta2</div>
<div style="background-color:rgba(155,0,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">magenta3</div>
<div style="background-color:rgba(65,0,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">magenta4</div>
<div style="background-color:rgba(110,7,29,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">maroon</div>
<div style="background-color:rgba(255,8,114,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">maroon1</div>
<div style="background-color:rgba(218,7,98,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">maroon2</div>
<div style="background-color:rgba(155,5,71,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">maroon3</div>
<div style="background-color:rgba(65,2,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">maroon4</div>
<div style="background-color:rgba(0,0,133,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">matrablue</div>
<div style="background-color:rgba(81,81,81,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">matragray</div>
<div style="background-color:rgba(33,155,102,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumaquamarine</div>
<div style="background-color:rgba(125,23,166,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumorchid</div>
<div style="background-color:rgba(190,33,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mediumorchid1</div>
<div style="background-color:rgba(162,29,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mediumorchid2</div>
<div style="background-color:rgba(116,21,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumorchid3</div>
<div style="background-color:rgba(49,9,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumorchid4</div>
<div style="background-color:rgba(74,41,180,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumpurple</div>
<div style="background-color:rgba(103,56,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mediumpurple1</div>
<div style="background-color:rgba(88,48,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumpurple2</div>
<div style="background-color:rgba(63,35,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumpurple3</div>
<div style="background-color:rgba(27,16,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumpurple4</div>
<div style="background-color:rgba(11,114,42,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumseagreen</div>
<div style="background-color:rgba(50,35,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumslateblue</div>
<div style="background-color:rgba(0,243,82,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumspringgreen</div>
<div style="background-color:rgba(16,162,153,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumturquoise</div>
<div style="background-color:rgba(145,1,59,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mediumvioletred</div>
<div style="background-color:rgba(2,2,41,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">midnightblue</div>
<div style="background-color:rgba(232,255,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mintcream</div>
<div style="background-color:rgba(255,197,192,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mistyrose</div>
<div style="background-color:rgba(218,169,164,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mistyrose2</div>
<div style="background-color:rgba(155,120,117,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">mistyrose3</div>
<div style="background-color:rgba(65,52,50,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">mistyrose4</div>
<div style="background-color:rgba(255,197,117,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">moccasin</div>
<div style="background-color:rgba(255,186,106,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">navajowhite1</div>
<div style="background-color:rgba(218,159,90,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">navajowhite2</div>
<div style="background-color:rgba(155,114,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">navajowhite3</div>
<div style="background-color:rgba(65,48,28,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">navajowhite4</div>
<div style="background-color:rgba(0,0,55,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">navyblue</div>
<div style="background-color:rgba(250,232,201,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">oldlace</div>
<div style="background-color:rgba(37,68,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">olivedrab</div>
<div style="background-color:rgba(134,255,12,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">olivedrab1</div>
<div style="background-color:rgba(114,218,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">olivedrab2</div>
<div style="background-color:rgba(82,155,8,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">olivedrab3</div>
<div style="background-color:rgba(36,65,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">olivedrab4</div>
<div style="background-color:rgba(255,95,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orange</div>
<div style="background-color:rgba(255,95,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orange1</div>
<div style="background-color:rgba(218,82,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orange2</div>
<div style="background-color:rgba(155,59,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orange3</div>
<div style="background-color:rgba(65,26,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orange4</div>
<div style="background-color:rgba(255,15,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orangered</div>
<div style="background-color:rgba(255,15,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orangered1</div>
<div style="background-color:rgba(218,13,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orangered2</div>
<div style="background-color:rgba(155,9,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orangered3</div>
<div style="background-color:rgba(65,4,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orangered4</div>
<div style="background-color:rgba(178,41,171,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">orchid</div>
<div style="background-color:rgba(255,57,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">orchid1</div>
<div style="background-color:rgba(218,49,207,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">orchid2</div>
<div style="background-color:rgba(155,36,148,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orchid3</div>
<div style="background-color:rgba(65,16,63,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">orchid4</div>
<div style="background-color:rgba(218,205,102,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">palegoldenrod</div>
<div style="background-color:rgba(80,245,80,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">palegreen</div>
<div style="background-color:rgba(82,255,82,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">palegreen1</div>
<div style="background-color:rgba(71,218,71,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palegreen2</div>
<div style="background-color:rgba(51,155,51,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palegreen3</div>
<div style="background-color:rgba(22,65,22,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palegreen4</div>
<div style="background-color:rgba(109,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">paleturquoise</div>
<div style="background-color:rgba(126,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">paleturquoise1</div>
<div style="background-color:rgba(107,218,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">paleturquoise2</div>
<div style="background-color:rgba(77,155,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">paleturquoise3</div>
<div style="background-color:rgba(33,65,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">paleturquoise4</div>
<div style="background-color:rgba(180,41,74,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palevioletred</div>
<div style="background-color:rgba(255,56,103,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">palevioletred1</div>
<div style="background-color:rgba(218,48,88,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palevioletred2</div>
<div style="background-color:rgba(155,35,63,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palevioletred3</div>
<div style="background-color:rgba(65,16,27,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">palevioletred4</div>
<div style="background-color:rgba(255,220,169,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">papayawhip</div>
<div style="background-color:rgba(255,178,123,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">peachpuff</div>
<div style="background-color:rgba(218,152,106,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">peachpuff2</div>
<div style="background-color:rgba(155,109,76,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">peachpuff3</div>
<div style="background-color:rgba(65,47,33,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">peachpuff4</div>
<div style="background-color:rgba(155,59,12,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">peru</div>
<div style="background-color:rgba(255,134,152,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">pink</div>
<div style="background-color:rgba(255,117,142,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">pink1</div>
<div style="background-color:rgba(218,101,122,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">pink2</div>
<div style="background-color:rgba(155,72,87,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">pink3</div>
<div style="background-color:rgba(65,31,38,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">pink4</div>
<div style="background-color:rgba(184,89,184,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">plum</div>
<div style="background-color:rgba(255,126,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">plum1</div>
<div style="background-color:rgba(218,107,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">plum2</div>
<div style="background-color:rgba(155,77,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">plum3</div>
<div style="background-color:rgba(65,33,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">plum4</div>
<div style="background-color:rgba(110,190,201,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">powderblue</div>
<div style="background-color:rgba(89,3,222,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">purple</div>
<div style="background-color:rgba(83,7,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">purple1</div>
<div style="background-color:rgba(72,6,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">purple2</div>
<div style="background-color:rgba(52,4,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">purple3</div>
<div style="background-color:rgba(23,2,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">purple4</div>
<div style="background-color:rgba(255,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">red</div>
<div style="background-color:rgba(255,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">red1</div>
<div style="background-color:rgba(218,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">red2</div>
<div style="background-color:rgba(155,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">red3</div>
<div style="background-color:rgba(65,0,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">red4</div>
<div style="background-color:rgba(128,70,70,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">rosybrown</div>
<div style="background-color:rgba(255,135,135,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">rosybrown1</div>
<div style="background-color:rgba(218,116,116,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">rosybrown2</div>
<div style="background-color:rgba(155,83,83,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">rosybrown3</div>
<div style="background-color:rgba(65,36,36,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">rosybrown4</div>
<div style="background-color:rgba(13,36,192,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">royalblue</div>
<div style="background-color:rgba(16,46,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">royalblue1</div>
<div style="background-color:rgba(14,39,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">royalblue2</div>
<div style="background-color:rgba(10,29,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">royalblue3</div>
<div style="background-color:rgba(5,13,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">royalblue4</div>
<div style="background-color:rgba(65,15,1,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">saddlebrown</div>
<div style="background-color:rgba(243,55,42,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">salmon</div>
<div style="background-color:rgba(255,66,36,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">salmon1</div>
<div style="background-color:rgba(218,56,31,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">salmon2</div>
<div style="background-color:rgba(155,41,22,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">salmon3</div>
<div style="background-color:rgba(65,18,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">salmon4</div>
<div style="background-color:rgba(230,94,29,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sandybrown</div>
<div style="background-color:rgba(6,65,24,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seagreen</div>
<div style="background-color:rgba(22,255,88,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seagreen1</div>
<div style="background-color:rgba(19,218,75,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seagreen2</div>
<div style="background-color:rgba(14,155,55,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seagreen3</div>
<div style="background-color:rgba(6,65,24,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seagreen4</div>
<div style="background-color:rgba(255,232,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">seashell</div>
<div style="background-color:rgba(218,199,186,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">seashell2</div>
<div style="background-color:rgba(155,142,132,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">seashell3</div>
<div style="background-color:rgba(65,60,56,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">seashell4</div>
<div style="background-color:rgba(89,21,6,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sienna</div>
<div style="background-color:rgba(255,56,16,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sienna1</div>
<div style="background-color:rgba(218,48,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sienna2</div>
<div style="background-color:rgba(155,35,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sienna3</div>
<div style="background-color:rgba(65,16,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">sienna4</div>
<div style="background-color:rgba(61,157,211,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">skyblue</div>
<div style="background-color:rgba(61,157,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">skyblue1</div>
<div style="background-color:rgba(53,134,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">skyblue2</div>
<div style="background-color:rgba(38,97,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">skyblue3</div>
<div style="background-color:rgba(17,41,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">skyblue4</div>
<div style="background-color:rgba(36,26,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slateblue</div>
<div style="background-color:rgba(57,40,255,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slateblue1</div>
<div style="background-color:rgba(49,34,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slateblue2</div>
<div style="background-color:rgba(36,25,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slateblue3</div>
<div style="background-color:rgba(16,11,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slateblue4</div>
<div style="background-color:rgba(41,55,71,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slategray</div>
<div style="background-color:rgba(144,193,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">slategray1</div>
<div style="background-color:rgba(123,166,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">slategray2</div>
<div style="background-color:rgba(88,119,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slategray3</div>
<div style="background-color:rgba(38,50,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">slategray4</div>
<div style="background-color:rgba(255,243,243,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">snow</div>
<div style="background-color:rgba(218,207,207,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">snow2</div>
<div style="background-color:rgba(155,148,148,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">snow3</div>
<div style="background-color:rgba(65,63,63,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">snow4</div>
<div style="background-color:rgba(0,255,54,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">springgreen</div>
<div style="background-color:rgba(0,218,46,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">springgreen2</div>
<div style="background-color:rgba(0,155,33,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">springgreen3</div>
<div style="background-color:rgba(0,65,15,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">springgreen4</div>
<div style="background-color:rgba(15,56,116,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">steelblue</div>
<div style="background-color:rgba(31,122,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">steelblue1</div>
<div style="background-color:rgba(27,105,218,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">steelblue2</div>
<div style="background-color:rgba(19,75,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">steelblue3</div>
<div style="background-color:rgba(9,32,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">steelblue4</div>
<div style="background-color:rgba(164,116,66,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tan</div>
<div style="background-color:rgba(255,95,19,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tan1</div>
<div style="background-color:rgba(218,82,16,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tan2</div>
<div style="background-color:rgba(155,59,12,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tan3</div>
<div style="background-color:rgba(65,26,6,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tan4</div>
<div style="background-color:rgba(10,68,68,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">teal</div>
<div style="background-color:rgba(175,132,175,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">thistle</div>
<div style="background-color:rgba(255,192,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">thistle1</div>
<div style="background-color:rgba(218,164,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">thistle2</div>
<div style="background-color:rgba(155,117,155,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">thistle3</div>
<div style="background-color:rgba(65,50,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">thistle4</div>
<div style="background-color:rgba(255,31,16,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tomato</div>
<div style="background-color:rgba(255,31,16,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tomato1</div>
<div style="background-color:rgba(218,27,13,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tomato2</div>
<div style="background-color:rgba(155,19,10,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tomato3</div>
<div style="background-color:rgba(65,9,4,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">tomato4</div>
<div style="background-color:rgba(13,190,160,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">turquoise</div>
<div style="background-color:rgba(0,232,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">turquoise1</div>
<div style="background-color:rgba(0,199,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">turquoise2</div>
<div style="background-color:rgba(0,142,155,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">turquoise3</div>
<div style="background-color:rgba(0,60,65,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">turquoise4</div>
<div style="background-color:rgba(218,56,218,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">violet</div>
<div style="background-color:rgba(160,3,71,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">violetred</div>
<div style="background-color:rgba(255,12,77,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">violetred1</div>
<div style="background-color:rgba(218,10,66,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">violetred2</div>
<div style="background-color:rgba(155,8,47,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">violetred3</div>
<div style="background-color:rgba(65,4,21,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">violetred4</div>
<div style="background-color:rgba(232,186,114,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">wheat</div>
<div style="background-color:rgba(255,203,125,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">wheat1</div>
<div style="background-color:rgba(218,175,107,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">wheat2</div>
<div style="background-color:rgba(155,125,77,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">wheat3</div>
<div style="background-color:rgba(65,53,33,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">wheat4</div>
<div style="background-color:rgba(255,255,255,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">white</div>
<div style="background-color:rgba(232,232,232,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">whitesmoke</div>
<div style="background-color:rgba(255,255,0,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">yellow</div>
<div style="background-color:rgba(255,255,0,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">yellow1</div>
<div style="background-color:rgba(218,218,0,1.0);padding:10px;border-radius:5px;color:rgba(0,0,0);">yellow2</div>
<div style="background-color:rgba(155,155,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">yellow3</div>
<div style="background-color:rgba(65,65,0,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">yellow4</div>
<div style="background-color:rgba(82,155,8,1.0);padding:10px;border-radius:5px;color:rgba(255,255,255);">yellowgreen</div>
</div>

View File

@ -4,7 +4,7 @@
CadQuery Class Summary
*************************
This page documents all of the methods and functions of the CadQuery classes, organized alphabatically.
This page documents all of the methods and functions of the CadQuery classes, organized alphabetically.
.. seealso::

View File

@ -44,6 +44,7 @@ extensions = [
"sphinx.ext.viewcode",
"sphinx.ext.autosummary",
"cadquery.cq_directive",
"sphinx.ext.mathjax",
]
always_document_param_types = True

View File

@ -58,8 +58,10 @@ 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.
"\>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 the projected origin of the last Workplane, the last Workplane having origin at (0,0,0) the
projection is at the center of the face. The default hole depth is through the entire part.
.. cadquery::
@ -109,16 +111,16 @@ By default, rectangles and circles are centered around the previous working poin
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.
Sometimes you need to build complex profiles using lines and arcs. This example builds a prismatic
solid from 2D operations.
2-d operations maintain a current point, which is initially at the origin. Use close() to finish a
2D operations maintain a current point, which is initially at the origin. Use close() to finish a
closed curve.
.. cadquery::
result = (cq.Workplane("front").lineTo(2.0, 0).lineTo(2.0, 1.0).threePointArc((1.0, 1.5),(0.0, 1.0))
result = (cq.Workplane("front").lineTo(2.0, 0).lineTo(2.0, 1.0).threePointArc((1.0, 1.5), (0.0, 1.0))
.close().extrude(0.25))
@ -144,10 +146,10 @@ A new work plane center can be established at any point.
.. cadquery::
result = cq.Workplane("front").circle(3.0) #current point is the center of the circle, at (0,0)
result = result.center(1.5, 0.0).rect(0.5, 0.5) # new work center is (1.5, 0.0)
result = cq.Workplane("front").circle(3.0) # current point is the center of the circle, at (0, 0)
result = result.center(1.5, 0.0).rect(0.5, 0.5) # new work center is (1.5, 0.0)
result = result.center(-1.5, 1.5).circle(0.25) # new work center is ( 0.0, 1.5).
result = result.center(-1.5, 1.5).circle(0.25) # new work center is (0.0, 1.5).
# The new center is specified relative to the previous center, not global coordinates!
result = result.extrude(0.25)
@ -175,10 +177,10 @@ like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on
.. cadquery::
r = cq.Workplane("front").circle(2.0) # make base
r = r.pushPoints( [ (1.5, 0),(0, 1.5),(-1.5, 0),(0, -1.5) ] ) # now four points are on the stack
r = r.circle( 0.25 ) # circle will operate on all four points
result = r.extrude(0.125 ) # make prism
r = cq.Workplane("front").circle(2.0) # make base
r = r.pushPoints([(1.5, 0), (0, 1.5), (-1.5, 0), (0, -1.5)]) # now four points are on the stack
r = r.circle(0.25) # circle will operate on all four points
result = r.extrude(0.125) # make prism
.. topic:: Api References
@ -193,12 +195,12 @@ like :py:meth:`Workplane.circle` and :py:meth:`Workplane.rect`, will operate on
Polygons
-------------------------
You can create polygons for each stack point if you would like. Useful in 3d printers whos firmware does not
You can create polygons for each stack point if you would like. Useful in 3d printers whose firmware does not
correct for small hole sizes.
.. cadquery::
result = (cq.Workplane("front").box(3.0, 4.0, 0.25).pushPoints ( [ ( 0,0.75 ),(0, -0.75) ])
result = (cq.Workplane("front").box(3.0, 4.0, 0.25).pushPoints([(0, 0.75), (0, -0.75)])
.polygon(6, 1.0).cutThruAll())
.. topic:: Api References
@ -219,16 +221,16 @@ This example uses a polyline to create one half of an i-beam shape, which is mir
.. cadquery::
(L,H,W,t) = ( 100.0, 20.0, 20.0, 1.0)
(L, H, W, t) = (100.0, 20.0, 20.0, 1.0)
pts = [
(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)
(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 = cq.Workplane("front").polyline(pts).mirrorY().extrude(L)
@ -262,7 +264,7 @@ needs a complex profile
(0.5, 1.0),
(0, 1.0)
]
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts,includeCurrent=True).close()
r = s.lineTo(3.0, 0).lineTo(3.0, 1.0).spline(sPnts, includeCurrent=True).close()
result = r.extrude(0.5)
.. topic:: Api References
@ -279,15 +281,15 @@ needs a complex profile
Mirroring Symmetric Geometry
-----------------------------
You can mirror 2-d geometry when your shape is symmetric. In this example we also
You can mirror 2D geometry when your shape is symmetric. In this example we also
introduce horizontal and vertical lines, which make for slightly easier coding.
.. cadquery::
r = cq.Workplane("front").hLine(1.0) # 1.0 is the distance, not coordinate
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0) # hLineTo allows using xCoordinate not distance
result =r.mirrorY().extrude(0.25 ) # mirror the geometry and extrude
r = cq.Workplane("front").hLine(1.0) # 1.0 is the distance, not coordinate
r = r.vLine(0.5).hLine(-0.25).vLine(-0.25).hLineTo(0.0) # hLineTo allows using xCoordinate not distance
result = r.mirrorY().extrude(0.25) # mirror the geometry and extrude
.. topic:: Api References
@ -308,34 +310,34 @@ Mirroring 3D Objects
.. cadquery::
result0 = (cadquery.Workplane("XY")
.moveTo(10,0)
.lineTo(5,0)
.threePointArc((3.9393,0.4393),(3.5,1.5))
.threePointArc((3.0607,2.5607),(2,3))
.lineTo(1.5,3)
.threePointArc((0.4393,3.4393),(0,4.5))
.lineTo(0,13.5)
.threePointArc((0.4393,14.5607),(1.5,15))
.lineTo(28,15)
.lineTo(28,13.5)
.lineTo(24,13.5)
.lineTo(24,11.5)
.lineTo(27,11.5)
.lineTo(27,10)
.lineTo(22,10)
.lineTo(22,13.2)
.lineTo(14.5,13.2)
.lineTo(14.5,10)
.lineTo(12.5,10 )
.lineTo(12.5,13.2)
.lineTo(5.5,13.2)
.lineTo(5.5,2)
.threePointArc((5.793,1.293),(6.5,1))
.lineTo(10,1)
.moveTo(10, 0)
.lineTo(5, 0)
.threePointArc((3.9393, 0.4393), (3.5, 1.5))
.threePointArc((3.0607, 2.5607), (2, 3))
.lineTo(1.5, 3)
.threePointArc((0.4393, 3.4393), (0, 4.5))
.lineTo(0, 13.5)
.threePointArc((0.4393, 14.5607), (1.5, 15))
.lineTo(28, 15)
.lineTo(28, 13.5)
.lineTo(24, 13.5)
.lineTo(24, 11.5)
.lineTo(27, 11.5)
.lineTo(27, 10)
.lineTo(22, 10)
.lineTo(22, 13.2)
.lineTo(14.5, 13.2)
.lineTo(14.5, 10)
.lineTo(12.5, 10)
.lineTo(12.5, 13.2)
.lineTo(5.5, 13.2)
.lineTo(5.5, 2)
.threePointArc((5.793, 1.293), (6.5, 1))
.lineTo(10, 1)
.close())
result = result0.extrude(100)
result = result.rotate((0, 0, 0),(1, 0, 0), 90)
result = result.rotate((0, 0, 0), (1, 0, 0), 90)
result = result.translate(result.val().BoundingBox().center.multiply(-1))
@ -364,7 +366,7 @@ Mirroring 3D Objects
Mirroring From Faces
-----------------------------
This example shows how you can mirror about a selected face. It also shows how the resulting mirrored object can be unioned immediately with the referenced mirror geometry.
This example shows how you can mirror about a selected face. It also shows how the resulting mirrored object can be unioned immediately with the referenced mirror geometry.
.. cadquery::
@ -396,7 +398,7 @@ 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 a typical 3d scripting
Using workplanes in this way are a key feature of CadQuery. Unlike a 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
@ -410,7 +412,7 @@ through the centerOption argument of :py:meth:`Workplane.workplane`.
.. cadquery::
result = cq.Workplane("front").box(2,3, 0.5) # make a basic prism
result = cq.Workplane("front").box(2, 3, 0.5) # make a basic prism
result = result.faces(">Z").workplane().hole(0.5) # find the top-most face and make a hole
.. topic:: Api References
@ -465,9 +467,9 @@ This example uses an offset workplane to make a compound object, which is perfec
.. cadquery::
result = cq.Workplane("front").box(3, 2, 0.5) #make a basic prism
result = result.faces("<X").workplane(offset=0.75) #workplane is offset from the object surface
result = result.circle(1.0).extrude(0.5) #disc
result = cq.Workplane("front").box(3, 2, 0.5) # make a basic prism
result = result.faces("<X").workplane(offset=0.75) # workplane is offset from the object surface
result = result.circle(1.0).extrude(0.5) # disc
.. topic:: Api References
@ -486,7 +488,7 @@ An existing CQ object can copy a workplane from another CQ object.
.. cadquery::
result = (cq.Workplane("front").circle(1).extrude(10) # make a cylinder
result = (cq.Workplane("front").circle(1).extrude(10) # make a cylinder
# We want to make a second cylinder perpendicular to the first,
# but we have no face to base the workplane off
.copyWorkplane(
@ -513,7 +515,7 @@ You can create a rotated work plane by specifying angles of rotation relative to
result = (cq.Workplane("front").box(4.0, 4.0, 0.25).faces(">Z").workplane()
.transformed(offset=cq.Vector(0, -1.5, 1.0),rotate=cq.Vector(60, 0, 0))
.rect(1.5,1.5,forConstruction=True).vertices().hole(0.25))
.rect(1.5, 1.5, forConstruction=True).vertices().hole(0.25))
.. topic:: Api References
@ -528,7 +530,7 @@ You can create a rotated work plane by specifying angles of rotation relative to
Using construction Geometry
---------------------------
You can draw shapes to use the vertices as points to locate other features. Features that are used to
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.
@ -536,7 +538,7 @@ In the example below, a rectangle is drawn, and its vertices are used to locate
.. cadquery::
result = (cq.Workplane("front").box(2, 2, 0.5).faces(">Z").workplane()
.rect(1.5, 1.5, forConstruction=True).vertices().hole(0.125 ))
.rect(1.5, 1.5, forConstruction=True).vertices().hole(0.125))
.. topic:: Api References
@ -724,7 +726,7 @@ Here we fillet all of the edges of a simple plate.
.. cadquery::
result = cq.Workplane("XY" ).box(3, 3, 0.5).edges("|Z").fillet(0.125)
result = cq.Workplane("XY").box(3, 3, 0.5).edges("|Z").fillet(0.125)
.. topic:: Api References
@ -739,7 +741,7 @@ Here we fillet all of the edges of a simple plate.
Tagging objects
----------------
The :py:meth:`Workplane.tag` method can be used to tag a particular object in the chain with a string, so that it can be refered to later in the chain.
The :py:meth:`Workplane.tag` method can be used to tag a particular object in the chain with a string, so that it can be referred to later in the chain.
The :py:meth:`Workplane.workplaneFromTagged` method applies :py:meth:`Workplane.copyWorkplane` to a tagged object. For example, when extruding two different solids from a surface, after the first solid is extruded it can become difficult to reselect the original surface with CadQuery's other selectors.
@ -791,11 +793,11 @@ with just a few lines of code.
.. cadquery::
(length,height,bearing_diam, thickness,padding) = ( 30.0, 40.0, 22.0, 10.0, 8.0)
(length, height, bearing_diam, thickness, padding) = (30.0, 40.0, 22.0, 10.0, 8.0)
result = (cq.Workplane("XY").box(length,height,thickness).faces(">Z").workplane().hole(bearing_diam)
result = (cq.Workplane("XY").box(length, height, thickness).faces(">Z").workplane().hole(bearing_diam)
.faces(">Z").workplane()
.rect(length-padding,height-padding,forConstruction=True)
.rect(length-padding, height-padding, forConstruction=True)
.vertices().cboreHole(2.4, 4.4, 2.1))
@ -806,9 +808,9 @@ You can split an object using a workplane, and retain either or both halves
.. cadquery::
c = cq.Workplane("XY").box(1,1,1).faces(">Z").workplane().circle(0.25).cutThruAll()
c = cq.Workplane("XY").box(1, 1, 1).faces(">Z").workplane().circle(0.25).cutThruAll()
#now cut it in half sideways
# now cut it in half sideways
result = c.faces(">Y").workplane(-0.5).split(keepTop=True)
.. topic:: Api References
@ -826,7 +828,7 @@ You can split an object using a workplane, and retain either or both halves
The Classic OCC Bottle
----------------------
CadQuery is based on the OpenCascade.org (OCC) modeling Kernel. Those who are familiar with OCC know about the
CadQuery is based on the OpenCascade.org (OCC) modeling Kernel. Those who are familiar with OCC know about the
famous 'bottle' example. `The bottle example in the OCCT online documentation <https://old.opencascade.com/doc/occt-7.5.0/overview/html/occt__tutorial.html>`_.
A pythonOCC version is listed `here <https://github.com/tpaviot/pythonocc-demos/blob/f3ea9b4f65a9dff482be04b153d4ce5ec2430e13/examples/core_classic_occ_bottle.py>`_.
@ -837,18 +839,18 @@ ones at 13 lines, but that's very short compared to the pythonOCC version, which
.. cadquery::
(L,w,t) = (20.0, 6.0, 3.0)
(L, w, t) = (20.0, 6.0, 3.0)
s = cq.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))
.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 = p.faces(">Z").workplane(centerOption="CenterOfMass").circle(3.0).extrude(2.0,True)
# Make the neck
p = p.faces(">Z").workplane(centerOption="CenterOfMass").circle(3.0).extrude(2.0, True)
#make a shell
# Make a shell
result = p.faces(">Z").shell(0.3)
.. topic:: Api References
@ -871,30 +873,30 @@ A Parametric Enclosure
.. cadquery::
:height: 400px
#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
# 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 box
p_topAndBottomRadius = 2.0 #Radius for the curves on the top and bottom edges of the box
p_thickness = 3.0 # Thickness of the box walls
p_sideRadius = 10.0 # Radius for the curves around the sides of the box
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 screw posts should be place.
p_screwpostID = 4.0 #Inner Diameter of the screw post holes, should be roughly screw diameter not including threads
p_screwpostOD = 10.0 #Outer Diameter of the screw posts.\nDetermines overall thickness of the posts
p_screwpostInset = 12.0 # How far in from the edges the screw posts should be place.
p_screwpostID = 4.0 # Inner Diameter of the screw post holes, should be roughly screw diameter not including threads
p_screwpostOD = 10.0 # Outer Diameter of the screw posts.\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.
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 = cq.Workplane("XY").rect(p_outerWidth,p_outerLength).extrude(p_outerHeight + p_lipHeight)
# outer shell
oshell = cq.Workplane("XY").rect(p_outerWidth, p_outerLength).extrude(p_outerHeight + p_lipHeight)
#weird geometry happens if we make the fillets in the wrong order
# weird geometry happens if we make the fillets in the wrong order
if p_sideRadius > p_topAndBottomRadius:
oshell = oshell.edges("|Z").fillet(p_sideRadius)
oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius)
@ -902,49 +904,49 @@ A Parametric Enclosure
oshell = oshell.edges("#Z").fillet(p_topAndBottomRadius)
oshell = oshell.edges("|Z").fillet(p_sideRadius)
#inner shell
ishell = (oshell.faces("<Z").workplane(p_thickness,True)
.rect((p_outerWidth - 2.0* p_thickness),(p_outerLength - 2.0*p_thickness))
.extrude((p_outerHeight - 2.0*p_thickness),False) #set combine false to produce just the new boss
# inner shell
ishell = (oshell.faces("<Z").workplane(p_thickness, True)
.rect((p_outerWidth - 2.0*p_thickness), (p_outerLength - 2.0*p_thickness))
.extrude((p_outerHeight - 2.0*p_thickness), False) # set combine false to produce just the new boss
)
ishell = ishell.edges("|Z").fillet(p_sideRadius - p_thickness)
#make the box outer box
# make the box outer box
box = oshell.cut(ishell)
#make the screw posts
# make the screw posts
POSTWIDTH = (p_outerWidth - 2.0*p_screwpostInset)
POSTLENGTH = (p_outerLength -2.0*p_screwpostInset)
POSTLENGTH = (p_outerLength - 2.0*p_screwpostInset)
box = (box.faces(">Z").workplane(-p_thickness)
.rect(POSTWIDTH,POSTLENGTH,forConstruction=True)
.rect(POSTWIDTH, POSTLENGTH, forConstruction=True)
.vertices().circle(p_screwpostOD/2.0).circle(p_screwpostID/2.0)
.extrude((-1.0)*(p_outerHeight + p_lipHeight -p_thickness ),True))
.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
# 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))
# 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()
# compute centers for counterbore/countersink or counterbore
topOfLidCenters = cutlip.faces(">Z").workplane().rect(POSTWIDTH, POSTLENGTH, forConstruction=True).vertices()
#add holes of the desired type
# 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)
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)
topOfLid = topOfLidCenters.cskHole(p_screwpostID, p_countersinkDiameter, p_countersinkAngle, 2.0*p_thickness)
else:
topOfLid= topOfLidCenters.hole(p_screwpostID,(2.0)*p_thickness)
topOfLid = topOfLidCenters.hole(p_screwpostID, 2.0*p_thickness)
#flip lid upside down if desired
# flip lid upside down if desired
if p_flipLid:
topOfLid = topOfLid.rotateAboutCenter((1,0,0),180)
topOfLid = topOfLid.rotateAboutCenter((1, 0, 0), 180)
#return the combined result
result =topOfLid.union(bottom)
# return the combined result
result = topOfLid.union(bottom)
.. topic:: Api References
@ -982,9 +984,9 @@ regarding the underside of the brick.
#####
# Inputs
######
lbumps = 6 # number of bumps long
wbumps = 2 # number of bumps wide
thin = True # True for thin, False for thick
lbumps = 6 # number of bumps long
wbumps = 2 # number of bumps wide
thin = True # True for thin, False for thick
#
# Lego Brick Constants-- these make a Lego brick a Lego :)
@ -1230,35 +1232,35 @@ Panel With Various Connector Holes
h_sep = 60
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(157,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(157, 210 - idx*h_sep).moveTo(-23.5, 0).circle(1.6).moveTo(23.5, 0).circle(1.6).moveTo(-17.038896, -5.7).threePointArc((-19.44306, -4.70416), (-20.438896, -2.3)).lineTo(-21.25, 2.3).threePointArc((-20.25416, 4.70416), (-17.85, 5.7)).lineTo(17.85, 5.7).threePointArc((20.25416, 4.70416), (21.25, 2.3)).lineTo(20.438896, -2.3).threePointArc((19.44306, -4.70416), (17.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(157,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(157, -30 - idx*h_sep).moveTo(-16.65, 0).circle(1.6).moveTo(16.65, 0).circle(1.6).moveTo(-10.1889, -5.7).threePointArc((-12.59306, -4.70416), (-13.5889, -2.3)).lineTo(-14.4, 2.3).threePointArc((-13.40416, 4.70416), (-11, 5.7)).lineTo(11, 5.7).threePointArc((13.40416, 4.70416), (14.4, 2.3)).lineTo(13.5889, -2.3).threePointArc((12.59306, -4.70416), (10.1889, -5.7)).close().cutThruAll()
h_sep4DB9 = 30
for idx in range(8):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(91,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(91, 225 - idx*h_sep4DB9).moveTo(-12.5, 0).circle(1.6).moveTo(12.5, 0).circle(1.6).moveTo(-6.038896, -5.7).threePointArc((-8.44306, -4.70416), (-9.438896, -2.3)).lineTo(-10.25, 2.3).threePointArc((-9.25416, 4.70416), (-6.85, 5.7)).lineTo(6.85, 5.7).threePointArc((9.25416, 4.70416), (10.25, 2.3)).lineTo(9.438896, -2.3).threePointArc((8.44306, -4.70416), (6.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(25,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(25, 210 - idx*h_sep).moveTo(-23.5, 0).circle(1.6).moveTo(23.5, 0).circle(1.6).moveTo(-17.038896, -5.7).threePointArc((-19.44306, -4.70416), (-20.438896, -2.3)).lineTo(-21.25, 2.3).threePointArc((-20.25416, 4.70416), (-17.85, 5.7)).lineTo(17.85, 5.7).threePointArc((20.25416, 4.70416), (21.25, 2.3)).lineTo(20.438896, -2.3).threePointArc((19.44306, -4.70416), (17.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(25,-30-idx*h_sep).moveTo(-16.65,0).circle(1.6).moveTo(16.65,0).circle(1.6).moveTo(-10.1889,-5.7).threePointArc((-12.59306,-4.70416),(-13.5889,-2.3)).lineTo(-14.4,2.3).threePointArc((-13.40416,4.70416),(-11,5.7)).lineTo(11,5.7).threePointArc((13.40416,4.70416),(14.4,2.3)).lineTo(13.5889,-2.3).threePointArc((12.59306,-4.70416),(10.1889,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(25, -30 - idx*h_sep).moveTo(-16.65, 0).circle(1.6).moveTo(16.65, 0).circle(1.6).moveTo(-10.1889, -5.7).threePointArc((-12.59306, -4.70416), (-13.5889, -2.3)).lineTo(-14.4, 2.3).threePointArc((-13.40416, 4.70416), (-11, 5.7)).lineTo(11, 5.7).threePointArc((13.40416, 4.70416), (14.4, 2.3)).lineTo(13.5889, -2.3).threePointArc((12.59306, -4.70416), (10.1889, -5.7)).close().cutThruAll()
for idx in range(8):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-41,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-41, 225 - idx*h_sep4DB9).moveTo(-12.5, 0).circle(1.6).moveTo(12.5, 0).circle(1.6).moveTo(-6.038896, -5.7).threePointArc((-8.44306, -4.70416), (-9.438896, -2.3)).lineTo(-10.25, 2.3).threePointArc((-9.25416, 4.70416), (-6.85, 5.7)).lineTo(6.85, 5.7).threePointArc((9.25416, 4.70416), (10.25, 2.3)).lineTo(9.438896, -2.3).threePointArc((8.44306, -4.70416), (6.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-107,210-idx*h_sep).moveTo(-23.5,0).circle(1.6).moveTo(23.5,0).circle(1.6).moveTo(-17.038896,-5.7).threePointArc((-19.44306,-4.70416),(-20.438896,-2.3)).lineTo(-21.25,2.3).threePointArc((-20.25416,4.70416),(-17.85,5.7)).lineTo(17.85,5.7).threePointArc((20.25416,4.70416),(21.25,2.3)).lineTo(20.438896,-2.3).threePointArc((19.44306,-4.70416),(17.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-107, 210 - idx*h_sep).moveTo(-23.5, 0).circle(1.6).moveTo(23.5, 0).circle(1.6).moveTo(-17.038896, -5.7).threePointArc((-19.44306, -4.70416), (-20.438896, -2.3)).lineTo(-21.25, 2.3).threePointArc((-20.25416, 4.70416), (-17.85, 5.7)).lineTo(17.85, 5.7).threePointArc((20.25416, 4.70416), (21.25, 2.3)).lineTo(20.438896, -2.3).threePointArc((19.44306, -4.70416), (17.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-107,-30-idx*h_sep).circle(14).rect(24.7487,24.7487, forConstruction=True).vertices().hole(3.2).cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-107, -30 - idx*h_sep).circle(14).rect(24.7487, 24.7487, forConstruction=True).vertices().hole(3.2).cutThruAll()
for idx in range(8):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-173,225-idx*h_sep4DB9).moveTo(-12.5,0).circle(1.6).moveTo(12.5,0).circle(1.6).moveTo(-6.038896,-5.7).threePointArc((-8.44306,-4.70416),(-9.438896,-2.3)).lineTo(-10.25,2.3).threePointArc((-9.25416,4.70416),(-6.85,5.7)).lineTo(6.85,5.7).threePointArc((9.25416,4.70416),(10.25,2.3)).lineTo(9.438896,-2.3).threePointArc((8.44306,-4.70416),(6.038896,-5.7)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-173, 225 - idx*h_sep4DB9).moveTo(-12.5, 0).circle(1.6).moveTo(12.5, 0).circle(1.6).moveTo(-6.038896, -5.7).threePointArc((-8.44306, -4.70416), (-9.438896, -2.3)).lineTo(-10.25, 2.3).threePointArc((-9.25416, 4.70416), (-6.85, 5.7)).lineTo(6.85, 5.7).threePointArc((9.25416, 4.70416), (10.25, 2.3)).lineTo(9.438896, -2.3).threePointArc((8.44306, -4.70416), (6.038896, -5.7)).close().cutThruAll()
for idx in range(4):
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-173,-30-idx*h_sep).moveTo(-2.9176,-5.3).threePointArc((-6.05,0),(-2.9176,5.3)).lineTo(2.9176,5.3).threePointArc((6.05,0),(2.9176,-5.3)).close().cutThruAll()
result = result.workplane(offset=1, centerOption="CenterOfBoundBox").center(-173, -30 - idx*h_sep).moveTo(-2.9176, -5.3).threePointArc((-6.05, 0), (-2.9176, 5.3)).lineTo(2.9176, 5.3).threePointArc((6.05, 0), (2.9176, -5.3)).close().cutThruAll()
Cycloidal gear
@ -1271,21 +1273,21 @@ This specific examples generates a helical cycloidal gear.
:height: 400px
import cadquery as cq
from math import sin, cos,pi,floor
from math import sin, cos, pi, floor
# define the generating function
def hypocycloid(t,r1,r2):
return ((r1-r2)*cos(t)+r2*cos(r1/r2*t-t),(r1-r2)*sin(t)+r2*sin(-(r1/r2*t-t)))
def hypocycloid(t, r1, r2):
return ((r1-r2)*cos(t)+r2*cos(r1/r2*t-t), (r1-r2)*sin(t)+r2*sin(-(r1/r2*t-t)))
def epicycloid(t,r1,r2):
return ((r1+r2)*cos(t)-r2*cos(r1/r2*t+t),(r1+r2)*sin(t)-r2*sin(r1/r2*t+t))
def epicycloid(t, r1, r2):
return ((r1+r2)*cos(t)-r2*cos(r1/r2*t+t), (r1+r2)*sin(t)-r2*sin(r1/r2*t+t))
def gear(t,r1=4,r2=1):
def gear(t, r1=4, r2=1):
if (-1)**(1+floor(t/2/pi*(r1/r2))) < 0:
return epicycloid(t,r1,r2)
return epicycloid(t, r1, r2)
else:
return hypocycloid(t,r1,r2)
return hypocycloid(t, r1, r2)
# create the gear profile and extrude it
result = (cq.Workplane('XY').parametricCurve(lambda t: gear(t*2*pi,6,1))
.twistExtrude(15,90).faces('>Z').workplane().circle(2).cutThruAll())
result = (cq.Workplane('XY').parametricCurve(lambda t: gear(t*2*pi, 6, 1))
.twistExtrude(15, 90).faces('>Z').workplane().circle(2).cutThruAll())

View File

@ -103,7 +103,7 @@ are designed to aid in plugin creation:
* :py:meth:`cadquery.Workplane.wire` gathers up all of the edges that have been drawn ( eg, by line, vline, etc ), and
attempts to combine them into a single wire, which is returned. This should be used when your plugin creates
2-d edges, and you know it is time to collect them into a single wire.
2D edges, and you know it is time to collect them into a single wire.
* :py:meth:`cadquery.Workplane.plane` provides a reference to the workplane, which allows you to convert between workplane
coordinates and global coordinates:

74
doc/gen_colors.py Normal file
View File

@ -0,0 +1,74 @@
"""
A script to generate RST (HTML only) for displaying all the colours supported
by OCP. Used in the file assy.rst.
"""
from OCP import Quantity
import cadquery as cq
from typing import Dict
from itertools import chain
OCP_COLOR_LEADER, SEP = "Quantity_NOC", "_"
TEMPLATE = """\
<div style="background-color:rgba({background_color});padding:10px;border-radius:5px;color:rgba({text_color});">{color_name}</div>\
"""
def color_to_rgba_str(c: cq.Color) -> str:
""" Convert a Color object to a string for the HTML/CSS template.
"""
t = c.toTuple()
vals = [int(v * 255) for v in t[:3]]
return ",".join([str(v) for v in chain(vals, [t[3]])])
def calc_text_color(c: cq.Color) -> str:
""" Calculate required overlay text color from background color.
"""
val = sum(c.toTuple()[:3]) / 3
if val < 0.5:
rv = "255,255,255"
else:
rv = "0,0,0"
return rv
def get_colors() -> Dict[str, cq.Color]:
""" Scan OCP for colors and output to a dict.
"""
colors = {}
for name in dir(Quantity):
splitted = name.rsplit(SEP, 1)
if splitted[0] == OCP_COLOR_LEADER:
colors.update({splitted[1].lower(): cq.Color(splitted[1])})
return colors
def rst():
""" Produce the text for a Sphinx directive.
"""
lines = [
".. raw:: html",
"",
' <div class="color-grid" style="display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill, minmax(200px,1fr));">',
]
colors = get_colors()
for name, c in colors.items():
lines += [
TEMPLATE.format(
background_color=color_to_rgba_str(c),
text_color=calc_text_color(c),
color_name=name,
)
]
lines.append(" </div>")
return "\n".join(lines)
if __name__ == "__main__":
print(rst())

View File

@ -19,7 +19,7 @@ CadQuery is an intuitive, easy-to-use Python library for building parametric 3D
* Provide a non-proprietary, plain text model format that can be edited and executed with only a web browser
CadQuery 2 is based on
`OCP https://github.com/CadQuery/OCP`_,
`OCP <https://github.com/CadQuery/OCP>`_,
which is a set of Python bindings for the open-source `OpenCascade <http://www.opencascade.com/>`_ modelling kernel.
Using CadQuery, you can build fully parametric models with a very small amount of code. For example, this simple script
@ -80,10 +80,10 @@ Like OpenSCAD, CadQuery is an open-source, script based, parametric model genera
Where does the name CadQuery come from?
========================================
CadQuery is inspired by `jQuery <http://www.jquery.com>`_ , a popular framework that
revolutionized web development involving javascript.
CadQuery is inspired by `jQuery <http://www.jquery.com>`_, a popular framework that
revolutionized web development involving JavaScript.
CadQuery is for 3D CAD what jQuery is for javascript.
CadQuery is for 3D CAD what jQuery is for JavaScript.
If you are familiar with how jQuery works, you will probably recognize several jQuery features that CadQuery uses:
* A fluent API to create clean, easy to read code

View File

@ -90,7 +90,7 @@ You can select Vertices, Edges, Faces, Solids, and Wires using selectors.
Think of selectors as the equivalent of your hand and mouse, if you were to build an object using a conventional CAD system.
You can learn more about selectors :ref:`selectors`
See :ref:`selectors` to learn more.
Construction Geometry
@ -99,7 +99,7 @@ Construction geometry are features that are not part of the object, but are only
A common example might be to define a rectangle, and then use the corners to define 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
to locate other features.
The Stack
@ -295,7 +295,7 @@ Which produces the output:
The first thing to note is that this is a different :class:`~cadquery.Workplane` object to the
previous one, and in the :attr:`~cadquery.Workplane.parent` attribute of this
:class:`~cadquery.Workplane` is our previous :class:`~cadquery.Workplane`. Returning a new instance
of :class:`~caduqery.Workplane` is the normal behaviour of most :class:`~cadquery.Workplane` methods
of :class:`~cadquery.Workplane` is the normal behaviour of most :class:`~cadquery.Workplane` methods
(with some exceptions, as will be shown below) and this is how the `chaining`_ concept is
implemented.
@ -387,7 +387,7 @@ The output is now:
tags: {'base': <cadquery.cq.Workplane object at 0xaa90>}
Modelling operations take their wires and edges from the modelling context's pending lists. In order
to use the :meth:`~cadquery.Workplane.loft` command futher down the chain, we need to push this wire
to use the :meth:`~cadquery.Workplane.loft` command further down the chain, we need to push this wire
to the modelling context with::
part = part.toPending()
@ -560,14 +560,14 @@ another :class:`~cadquery.Workplane` method).
The next step is to extrude this circle and create a cylindrical protrusion::
part = part.extrude(1)
part = part.extrude(1, clean=False)
Now:
.. code-block:: none
Workplane object at 0xafd0:
parent: Workplane object at 0x6df0
parent: Workplane object at 0xe790
plane: Plane object at 0x3e80:
origin: (0.5, 0.0, 0.0)
z direction: (1.0, 0.0, 0.0)
@ -582,6 +582,16 @@ The :meth:`~cadquery.Workplane.extrude` method has cleared all the pending wires
that is shown in the 3D view above.
.. note::
The :meth:`~cadquery.Workplane.extrude` has an argument for ``clean`` which defaults to ``True``.
This extrudes the pending wires (creating a new :class:`~cadquery.Workplane` object), then runs
the :meth:`~cadquery.Workplane.clean` method to refine the result, creating another
:class:`~cadquery.Workplane`. If you were to run the example with the default
``clean=True`` then you would see an intermediate
:class:`~cadquery.Workplane` object in :attr:`~cadquery.Workplane.parent`
rather than the object from the previous step.
Assemblies
----------

View File

@ -166,7 +166,7 @@ There are a couple of things to note about this line:
1. The :py:meth:`cadquery.Workplane.rect` function draws a rectangle. **forConstruction=True**
tells CadQuery that this rectangle will not form a part of the solid,
but we are just using it to help define some other geometry.
2. Unless you specifiy otherwise, a rectangle is drawn with its center on the current workplane center-- in
2. Unless you specify otherwise, a rectangle is drawn with its center on the current workplane center-- in
this case, the center of the top face of the block. So this rectangle will be centered on the face.

View File

@ -29,7 +29,7 @@ implement more constraints
in plane, on axis, parallel to vector
2-d operations
2D operations
-------------------
arc construction using relative measures
@ -47,10 +47,10 @@ trimming
construction lines
especially centerlines
2-d fillets
2D fillets
for a rectangle, or for consecutive selected lines
2-d chamfers
2D chamfers
based on rectangles, polygons, polylines, or adjacent selected lines
mirror around centerline
@ -72,7 +72,7 @@ feature snap
polyline edges
allow polyline to be combined with other edges/curves
3-d operations
3D operations
---------------------
rotation/transform that return a copy
@ -81,9 +81,8 @@ rotation/transform that return a copy
primitive creation
Need primitive creation for:
* cone
* 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
allow a cut or extrude to terminate at another surface, rather than either through all or a fixed distance

View File

@ -15,7 +15,7 @@ defaultSweep = (
.sweep(path, multisection=True)
)
# We can sweep thrue different shapes
# We can sweep through different shapes
recttocircleSweep = (
cq.Workplane("YZ")
.workplane(offset=-10.0)
@ -63,7 +63,7 @@ path = (
# Placement of different shapes should follow the path
# cylinder r=1.5 along first line
# then sweep allong arc from r=1.5 to r=1.0
# then sweep along arc from r=1.5 to r=1.0
# then cylinder r=1.0 along last line
arcSweep = (
cq.Workplane("YZ")

View File

@ -47,6 +47,11 @@ class TestCadObjects(BaseTest):
v9.z = 3.0
self.assertTupleAlmostEquals((1, 2, 3), (v9.x, v9.y, v9.z), 4)
with self.assertRaises(TypeError):
Vector("vector")
with self.assertRaises(TypeError):
Vector(1, 2, 3, 4)
def testVertex(self):
"""
Tests basic vertex functions
@ -66,6 +71,46 @@ class TestCadObjects(BaseTest):
# OCC uses some approximations
self.assertAlmostEqual(bb1.xlen, 1.0, 1)
# Test adding to an existing bounding box
v0 = Vertex.makeVertex(0, 0, 0)
bb2 = v0.BoundingBox().add(v.BoundingBox())
bb3 = bb1.add(bb2)
self.assertTupleAlmostEquals((2, 2, 2), (bb3.xlen, bb3.ylen, bb3.zlen), 7)
bb3 = bb2.add((3, 3, 3))
self.assertTupleAlmostEquals((3, 3, 3), (bb3.xlen, bb3.ylen, bb3.zlen), 7)
bb3 = bb2.add(Vector(3, 3, 3))
self.assertTupleAlmostEquals((3, 3, 3), (bb3.xlen, bb3.ylen, bb3.zlen), 7)
# Test 2D bounding boxes
bb1 = (
Vertex.makeVertex(1, 1, 0)
.BoundingBox()
.add(Vertex.makeVertex(2, 2, 0).BoundingBox())
)
bb2 = (
Vertex.makeVertex(0, 0, 0)
.BoundingBox()
.add(Vertex.makeVertex(3, 3, 0).BoundingBox())
)
bb3 = (
Vertex.makeVertex(0, 0, 0)
.BoundingBox()
.add(Vertex.makeVertex(1.5, 1.5, 0).BoundingBox())
)
# Test that bb2 contains bb1
self.assertEqual(bb2, BoundBox.findOutsideBox2D(bb1, bb2))
self.assertEqual(bb2, BoundBox.findOutsideBox2D(bb2, bb1))
# Test that neither bounding box contains the other
self.assertIsNone(BoundBox.findOutsideBox2D(bb1, bb3))
# Test creation of a bounding box from a shape - note the low accuracy comparison
# as the box is a little larger than the shape
bb1 = BoundBox._fromTopoDS(Solid.makeCylinder(1, 1).wrapped, optimal=False)
self.assertTupleAlmostEquals((2, 2, 1), (bb1.xlen, bb1.ylen, bb1.zlen), 1)
def testEdgeWrapperCenter(self):
e = self._make_circle()
@ -295,6 +340,18 @@ class TestCadObjects(BaseTest):
vec.Length * math.cos(angle), vecLineProjection.Length, decimal_places
)
def testVectorNotImplemented(self):
v = Vector(1, 2, 3)
with self.assertRaises(NotImplementedError):
v.distanceToLine()
with self.assertRaises(NotImplementedError):
v.distanceToPlane()
def testVectorSpecialMethods(self):
v = Vector(1, 2, 3)
self.assertEqual(repr(v), "Vector: (1.0, 2.0, 3.0)")
self.assertEqual(str(v), "Vector: (1.0, 2.0, 3.0)")
def testMatrixCreationAndAccess(self):
def matrix_vals(m):
return [[m[r, c] for c in range(4)] for r in range(4)]
@ -339,7 +396,9 @@ class TestCadObjects(BaseTest):
]
with self.assertRaises(ValueError):
Matrix(invalid)
# Test input with invalid type
with self.assertRaises(TypeError):
Matrix("invalid")
# Test input with invalid size / nested types
with self.assertRaises(TypeError):
Matrix([[1, 2, 3, 4], [1, 2, 3], [1, 2, 3, 4]])
@ -359,6 +418,77 @@ class TestCadObjects(BaseTest):
with self.assertRaises(IndexError):
m["ab"]
# test __repr__ methods
m = Matrix(vals4x4)
mRepr = "Matrix([[1.0, 0.0, 0.0, 1.0],\n [0.0, 1.0, 0.0, 2.0],\n [0.0, 0.0, 1.0, 3.0],\n [0.0, 0.0, 0.0, 1.0]])"
self.assertEqual(repr(m), mRepr)
self.assertEqual(str(eval(repr(m))), mRepr)
def testMatrixFunctionality(self):
# Test rotate methods
def matrix_almost_equal(m, target_matrix):
for r, row in enumerate(target_matrix):
for c, target_value in enumerate(row):
self.assertAlmostEqual(m[r, c], target_value)
root_3_over_2 = math.sqrt(3) / 2
m_rotate_x_30 = [
[1, 0, 0, 0],
[0, root_3_over_2, -1 / 2, 0],
[0, 1 / 2, root_3_over_2, 0],
[0, 0, 0, 1],
]
mx = Matrix()
mx.rotateX(30 * DEG2RAD)
matrix_almost_equal(mx, m_rotate_x_30)
m_rotate_y_30 = [
[root_3_over_2, 0, 1 / 2, 0],
[0, 1, 0, 0],
[-1 / 2, 0, root_3_over_2, 0],
[0, 0, 0, 1],
]
my = Matrix()
my.rotateY(30 * DEG2RAD)
matrix_almost_equal(my, m_rotate_y_30)
m_rotate_z_30 = [
[root_3_over_2, -1 / 2, 0, 0],
[1 / 2, root_3_over_2, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
]
mz = Matrix()
mz.rotateZ(30 * DEG2RAD)
matrix_almost_equal(mz, m_rotate_z_30)
# Test matrix multipy vector
v = Vector(1, 0, 0)
self.assertTupleAlmostEquals(
mz.multiply(v).toTuple(), (root_3_over_2, 1 / 2, 0), 7
)
# Test matrix multipy matrix
m_rotate_xy_30 = [
[root_3_over_2, 0, 1 / 2, 0],
[1 / 4, root_3_over_2, -root_3_over_2 / 2, 0],
[-root_3_over_2 / 2, 1 / 2, 3 / 4, 0],
[0, 0, 0, 1],
]
mxy = mx.multiply(my)
matrix_almost_equal(mxy, m_rotate_xy_30)
# Test matrix inverse
vals4x4 = [[1, 2, 3, 4], [5, 1, 6, 7], [8, 9, 1, 10], [0, 0, 0, 1]]
vals4x4_invert = [
[-53 / 144, 25 / 144, 1 / 16, -53 / 144],
[43 / 144, -23 / 144, 1 / 16, -101 / 144],
[37 / 144, 7 / 144, -1 / 16, -107 / 144],
[0, 0, 0, 1],
]
m = Matrix(vals4x4).inverse()
matrix_almost_equal(m, vals4x4_invert)
def testTranslate(self):
e = Edge.makeCircle(2, (1, 2, 3))
e2 = e.translate(Vector(0, 0, 1))
@ -413,6 +543,55 @@ class TestCadObjects(BaseTest):
Plane(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 1, 1)),
)
def testInvalidPlane(self):
# Test plane creation error handling
with self.assertRaises(ValueError):
Plane.named("XX", (0, 0, 0))
with self.assertRaises(ValueError):
Plane(origin=(0, 0, 0), xDir=(0, 0, 0), normal=(0, 1, 1))
with self.assertRaises(ValueError):
Plane(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 0, 0))
def testPlaneMethods(self):
# Test error checking
p = Plane(origin=(0, 0, 0), xDir=(1, 0, 0), normal=(0, 1, 0))
with self.assertRaises(ValueError):
p.toLocalCoords("box")
with self.assertRaises(NotImplementedError):
p.mirrorInPlane([Solid.makeBox(1, 1, 1)], "Z")
# Test translation to local coordinates
local_box = Workplane(p.toLocalCoords(Solid.makeBox(1, 1, 1)))
local_box_vertices = [(v.X, v.Y, v.Z) for v in local_box.vertices().vals()]
target_vertices = [
(0, -1, 0),
(0, 0, 0),
(0, -1, 1),
(0, 0, 1),
(1, -1, 0),
(1, 0, 0),
(1, -1, 1),
(1, 0, 1),
]
for i, target_point in enumerate(target_vertices):
self.assertTupleAlmostEquals(target_point, local_box_vertices[i], 7)
# Test mirrorInPlane
mirror_box = Workplane(p.mirrorInPlane([Solid.makeBox(1, 1, 1)], "Y")[0])
mirror_box_vertices = [(v.X, v.Y, v.Z) for v in mirror_box.vertices().vals()]
target_vertices = [
(0, 0, 1),
(0, 0, 0),
(0, -1, 1),
(0, -1, 0),
(-1, 0, 1),
(-1, 0, 0),
(-1, -1, 1),
(-1, -1, 0),
]
for i, target_point in enumerate(target_vertices):
self.assertTupleAlmostEquals(target_point, mirror_box_vertices[i], 7)
def testLocation(self):
# Vector
@ -437,6 +616,17 @@ class TestCadObjects(BaseTest):
== loc3.wrapped.Transformation().TranslationPart().Z()
)
# Test creation from the OCP.gp.gp_Trsf object
loc4 = Location(gp_Trsf())
self.assertTupleAlmostEquals(loc4.toTuple()[0], (0, 0, 0), 7)
self.assertTupleAlmostEquals(loc4.toTuple()[1], (0, 0, 0), 7)
# Test error handling on creation
with self.assertRaises(TypeError):
Location((0, 0, 1))
with self.assertRaises(TypeError):
Location("xy_plane")
def testEdgeWrapperRadius(self):
# get a radius from a simple circle

View File

@ -55,7 +55,7 @@ TEST_RESULT_TEMPLATE = """
"""
# clean up any summary file that is in the output directory.
# i know, this sux, but there is no other way to do this in 2.6, as we cannot do class fixutres till 2.7
# i know, this sux, but there is no other way to do this in 2.6, as we cannot do class fixtures till 2.7
writeStringToFile(SUMMARY_TEMPLATE, SUMMARY_FILE)
@ -63,7 +63,7 @@ class TestCadQuery(BaseTest):
def tearDown(self):
"""
Update summary with data from this test.
This is a really hackey way of doing it-- we get a startup event from module load,
This is a really hacky way of doing it-- we get a startup event from module load,
but there is no way in unittest to get a single shutdown event-- except for stuff in 2.7 and above
So what we do here is to read the existing file, stick in more content, and leave it
@ -187,7 +187,7 @@ class TestCadQuery(BaseTest):
"""
Tests a plugin to make regular polygons around points on the stack
Demonstratings using eachpoint to allow working in local coordinates
Demonstrations using eachpoint to allow working in local coordinates
to create geometry
"""
@ -716,7 +716,7 @@ class TestCadQuery(BaseTest):
.consolidateWires()
)
# Test point equivalence for parameter, and pamater multiplied by 10:
# Test point equivalence for parameter, and parameter multiplied by 10:
test_point1 = spline1.edges().val().positionAt(1.5, mode="parameter")
test_point2 = spline2.edges().val().positionAt(15, mode="parameter")
expected_test_point = Vector(1.625, 0.625, 0.0)
@ -880,7 +880,7 @@ class TestCadQuery(BaseTest):
start = ellipseArc3.vertices().objects[0]
end = ellipseArc3.vertices().objects[1]
# swap start and end points for coparison due to different sense
# swap start and end points for comparison due to different sense
self.assertTupleAlmostEquals(
(start.X, start.Y), (p0[0] + ex_rot, p0[1] + ey_rot), 3
)
@ -909,7 +909,7 @@ class TestCadQuery(BaseTest):
start = ellipseArc4.vertices().objects[0]
end = ellipseArc4.vertices().objects[1]
# swap start and end points for coparison due to different sense
# swap start and end points for comparison due to different sense
self.assertTupleAlmostEquals(
(start.X, start.Y), (p0[0] + ex_rot - ex_rot, p0[1] + ey_rot - ey_rot), 3
)
@ -1146,7 +1146,7 @@ class TestCadQuery(BaseTest):
.sweep(path, multisection=True)
)
# We can sweep thrue different shapes
# We can sweep through different shapes
recttocircleSweep = (
Workplane("YZ")
.workplane(offset=-10.0)
@ -1193,7 +1193,7 @@ class TestCadQuery(BaseTest):
# Placement of different shapes should follow the path
# cylinder r=1.5 along first line
# then sweep allong arc from r=1.5 to r=1.0
# then sweep along arc from r=1.5 to r=1.0
# then cylinder r=1.0 along last line
arcSweep = (
Workplane("YZ")
@ -1483,10 +1483,10 @@ class TestCadQuery(BaseTest):
self.assertEqual(0, s.faces().size())
t = r.faces(">Z").workplane().rect(0.25, 0.25).extrude(0.5, False)
# result has 6 faces, becuase it was not combined with the original
# result has 6 faces, because it was not combined with the original
self.assertEqual(6, t.faces().size())
self.assertEqual(6, r.faces().size()) # original is unmodified as well
# subseuent opertions use that context solid afterwards
# subsequent operations use that context solid afterwards
def testSimpleWorkplane(self):
"""
@ -1794,7 +1794,7 @@ class TestCadQuery(BaseTest):
self.saveModel(t)
def testBasicLines(self):
"Make a triangluar boss"
"Make a triangular boss"
global OUTDIR
s = Workplane(Plane.XY())
@ -2443,6 +2443,39 @@ class TestCadQuery(BaseTest):
self.assertEqual(1, s.solids().size())
self.assertEqual(4, s.faces().size())
def testCylinderDefaults(self):
s = Workplane("XY").cylinder(20, 10)
self.assertEqual(1, s.size())
self.assertEqual(1, s.solids().size())
self.assertEqual(3, s.faces().size())
self.assertEqual(2, s.vertices().size())
self.assertTupleAlmostEquals(s.val().Center().toTuple(), (0, 0, 0), 3)
def testCylinderCentering(self):
radius = 10
height = 40
b = (True, False)
expected_x = (0, radius)
expected_y = (0, radius)
expected_z = (0, height / 2)
for (xopt, xval), (yopt, yval), (zopt, zval) in product(
zip(b, expected_x), zip(b, expected_y), zip(b, expected_z)
):
s = Workplane("XY").cylinder(height, radius, centered=(xopt, yopt, zopt))
self.assertEqual(1, s.size())
self.assertTupleAlmostEquals(
s.val().Center().toTuple(), (xval, yval, zval), 3
)
# check centered=True produces the same result as centered=(True, True, True)
for val in b:
s0 = Workplane("XY").cylinder(height, radius, centered=val)
self.assertEqual(s0.size(), 1)
s1 = Workplane("XY").cylinder(height, radius, centered=(val, val, val))
self.assertEqual(s1.size(), 1)
self.assertTupleAlmostEquals(
s0.val().Center().toTuple(), s1.val().Center().toTuple(), 3
)
def testWedgeDefaults(self):
s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5)
self.saveModel(s)
@ -2954,7 +2987,7 @@ class TestCadQuery(BaseTest):
return cup
"""
# for some reason shell doesnt work on this simple shape. how disappointing!
# for some reason shell doesn't work on this simple shape. how disappointing!
td = 50.0
bd = 20.0
h = 10.0
@ -2990,7 +3023,7 @@ class TestCadQuery(BaseTest):
# How far in from the edges the screwposts should be place.
p_screwpostInset = 12.0
# nner Diameter of the screwpost holes, should be roughly screw diameter not including threads
# Inner Diameter of the screwpost holes, should be roughly screw diameter not including threads
p_screwpostID = 4.0
# Outer Diameter of the screwposts.\nDetermines overall thickness of the posts
p_screwpostOD = 10.0
@ -3427,7 +3460,7 @@ class TestCadQuery(BaseTest):
def testWorkplaneCenterOptions(self):
"""
Test options for specifiying origin of workplane
Test options for specifying origin of workplane
"""
decimal_places = 9
@ -3544,7 +3577,7 @@ class TestCadQuery(BaseTest):
self.assertEqual(len(r.objects), 2)
self.assertTrue(isinstance(r.val(), Solid))
# find solid should return a compund of two solids
# find solid should return a compound of two solids
s = r.findSolid()
self.assertEqual(len(s.Solids()), 2)
self.assertTrue(isinstance(s, Compound))
@ -3682,7 +3715,7 @@ class TestCadQuery(BaseTest):
def testWorkplaneFromTagged(self):
# create a flat, wide base. Extrude one object 4 units high, another
# object ontop of it 6 units high. Go back to base plane. Extrude an
# object on top of it 6 units high. Go back to base plane. Extrude an
# object 11 units high. Assert that top face is 11 units high.
result = (
Workplane("XY")
@ -3763,7 +3796,7 @@ class TestCadQuery(BaseTest):
def test_interpPlate(self):
"""
Tests the interpPlate() functionnalites
Tests the interpPlate() functionalities
Numerical values of Areas and Volumes were obtained with the Area() and Volume() functions on a Linux machine under Debian 10 with python 3.7.
"""

View File

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

View File

@ -9,6 +9,8 @@ import io
from cadquery import *
from cadquery import exporters, importers
from tests import BaseTest
from OCP.GeomConvert import GeomConvert
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
class TestExporters(BaseTest):
@ -168,6 +170,43 @@ class TestExporters(BaseTest):
self.assertAlmostEqual(s4.val().Area(), s4_i.val().Area(), 6)
self.assertAlmostEqual(s4.edges().size(), s4_i.edges().size())
# test periodic spline
w = Workplane().spline([(1, 1), (2, 2), (3, 2), (3, 1)], periodic=True)
exporters.dxf.exportDXF(w, "res5.dxf")
w_i = importers.importDXF("res5.dxf")
self.assertAlmostEqual(w.val().Length(), w_i.wires().val().Length(), 6)
# test rational spline
c = Edge.makeCircle(1)
adaptor = c._geomAdaptor()
curve = GeomConvert.CurveToBSplineCurve_s(adaptor.Curve().Curve())
e = Workplane().add(Edge(BRepBuilderAPI_MakeEdge(curve).Shape()))
exporters.dxf.exportDXF(e, "res6.dxf")
e_i = importers.importDXF("res6.dxf")
self.assertAlmostEqual(e.val().Length(), e_i.wires().val().Length(), 6)
# test non-planar section
s5 = (
Workplane()
.spline([(0, 0), (1, 0), (1, 1), (0, 1)])
.close()
.extrude(1, both=True)
.translate((-3, -4, 0))
)
s5.plane = Plane(origin=(0, 0.1, 0.5), normal=(0.05, 0.05, 1))
s5 = s5.section()
exporters.dxf.exportDXF(s5, "res7.dxf")
s5_i = importers.importDXF("res7.dxf")
self.assertAlmostEqual(s5.val().Area(), s5_i.val().Area(), 4)
def testTypeHandling(self):
with self.assertRaises(ValueError):