Lines and loops
Solid and planar primitives are not always enough to build the geometry you need. The more advanced operations in this manual can construct bodies from arbitrary curves.
ZenCad and the OpenCascade kernel have two classes of one-dimensional geometry: Edge and Wire. An Edge is a simple primitive; joining several edges into a composite curve produces a Wire. They can often be used interchangeably, but the distinction matters when inspecting a model's topology.
A collection of Wire and/or Edge objects can be joined with sew (described below).
Closed curves are called loops. If a loop and all its constituent curves lie in one plane, fill can turn it into a face (see "Planar primitives").
Additional operations are described in "Curve analysis".
Segment
An ordinary line segment, specified by two points.
Signature:
segment(pnt1, pnt2)

Polysegment
A polysegment is a polyline specified by an array of points, pnts. Setting closed adds a segment from the final point back to the first.
Signature:
polysegment(pnts, closed=False)

Interpolation through points
Builds an interpolated curve through pnts. The optional tangs parameter specifies a tangent direction at each point (None leaves it unconstrained). Setting closed adds a closing curve segment.
Signature:
interpolate(pnts, tangs=None, closed=False)

Circular arc through three points
An alternative to circle (see Planar primitives) for creating a circular arc, using three points.
Signature:
circle_arc(p1, p2, p3)

Helix
An ascending helix specified by radius r, height h and pitch step. Setting left changes right-handed winding to left-handed winding. The optional angle makes the radius vary with height along a cone.
Signature:
helix(r, h, step, angle=angle, left=False)

Bézier curve
A Bézier curve (wiki), specified by control points and optional weights. Omitted weights are all one.
Signature:
bezier(pnts)
bezier(pnts, weights)

BSpline
Creates a BSpline by specifying its parameters directly.
Signature:
bspline(pnts, knots, muls, degree, periodic=False)
bspline(pnts, knots, muls, degree, weights=weights, check_rational=True)
knots gives parameter values; muls gives their multiplicities. For example, a cubic curve with four control points and clamped endpoints:
from zencad import *
curve = bspline(
[(0, 0, 0), (10, 20, 0), (20, -10, 0), (30, 0, 0)],
knots=[0, 1], muls=[4, 4], degree=3,
)
display(curve)
show()
Rounded polysegment
Adds circular arcs at the joins between line segments. r sets the fillet radius. It can be used with pipe_shell (see sweep surfaces). Setting closed closes the curve with a rounded join.
Signature:
rounded_polysegment(pnts, r, closed=False)
Example:
rounded_polysegment(
pnts=[(0,0,0), (20,0,0), (20,20,40), (-40,20,40), (-40,20,0)],
r=10)

Creating a composite curve
sew assembles a composite curve from the parts in wires.
The parts can be Edge and Wire objects (geometric types).
Parts must meet at their endpoints and follow the correct order. If sort is set, the algorithm attempts to order them automatically.
Signature:
sew(wires, True) # sort is positional; default: True
Example:
sew([
segment((0,0,0), (0,10,0)),
circle_arc((0,10,0),(10,15,0),(20,10,0)),
segment((20,0,0), (20,10,0)),
segment((20,0,0), (0,0,0))
])

Wire builder
Builds a curve one section at a time, starting each edge at the previous edge's endpoint. Operations accept absolute or relative coordinates. In relative mode, control-point coordinates are added to the builder's current position. rel selects the mode: False for absolute, True for relative. If omitted, defrel is used.
Constructor arguments:
start — starting point
defrel — default coordinate mode
wb = wire_builder(start=(0,0,0), defrel=False)
Restarting
Restarts at a new point and clears the edge list.
wb.restart(pnt, y=None, z=None)
wb.restart(point3(10,15,0))
wb.restart(10,15)
Adding a segment
Builds a segment to pnt.
wb.segment(pnt, y=None, z=None, rel=None)
wb.line(b, y=None, z=None, rel=None)
wb.l(b, y=None, z=None, rel=None)
wire_builder(defrel=True).restart((0,10)).l(10,0).l(0,-10).close().doit() # draw a square

Adding a circular arc through points
wb.arc_by_points(a,b,rel=None)
Adding an interpolated curve
curtang sets the curve direction at the starting point. Setting approx derives curtang from the direction at the end of the preceding section.
wb.interpolate(pnts, tangs=None, curtang=(0,0,0), approx=False, rel=None)
Closing
close builds a section back to the starting point. approx_a and approx_b enable interpolation at the closing joins.
wb.close(approx_a=False, approx_b=False)
The finished contour
.doit() returns the constructed Wire. The contour can be filled and extruded into a body:
from zencad import *
contour = (wire_builder(start=(0, 0, 0))
.segment((30, 0, 0))
.arc_by_points((40, 10, 0), (30, 20, 0))
.segment((0, 20, 0))
.close()
.doit())
body = fill(contour).extrude(5)
display(body)
show()