17. curve — Handling curves in pyFormex

This module defines classes and functions specialized for handling curves (one-dimensional geometrical objects) in pyFormex. They can be straight lines, polylines, higher order curves and collections thereof. In general, the curves are 3D, but special cases may be created for handling plane curves.

The most important curve type classes defined in this module are:

  • Curve: a virtual base class for all curve type classes. It can not be instantiated itself: always use one of the derived classes.

  • BezierSpline: curves consisting of a concatenation of Bezier polynomes of degree 1 to 3.

  • PolyLine: curves consisting of a concatenation of straight segments.

  • Arc: circles and arcs

Another important curve type, NurbsCurve, is defined in the plugins.nurbs module.

17.1. Classes defined in module curve

class curve.Curve[source]

Base class for curve type classes.

This is a virtual class that can not be instantiated. It defines the common definitions for all curve type subclasses. The subclasses define at least the following attributes:

coords

The coordinates of all the points needed to define the curve. These are not necessarily points on the curve.

Type:

Coords

nparts

The number of parts comprising the curve. Subsequent parts of a curve (e.g. straight segments of a polyline), have a local parameter with values in the range 0..1. Any point on the curve can thus be identified by a float number, where the integer part is the curve number and the fractional part is the parameter value. See localParam().

Type:

int

closed

Whether the curve is closed or not. A closed curve has coinciding begin and end points, making it a closed loop. An open curve with coinciding end points may look like a closed curve, but technically it is still open, and its behavior may be different from that of a closed curve.

Type:

bool

property ctype

Return the curve type

Returns:

str – A oneline string with the class name and important parameters.

See also

report

return a full report about the curve

Examples

>>> C = PolyLine(Coords('012'))
>>> print(C.ctype)
PolyLine: nparts=2, ncoords=3, open
>>> C = BezierSpline('012')
>>> print(C.ctype)
BezierSpline: degree=3, nparts=2, ncoords=7, open
>>> C = Arc(center=[0.,0.,0.], radius=1., angles=(-90., 90.))
>>> print(C.ctype)
Arc: nparts=1, ncoords=3, open
report()[source]

Return a report of the curve.

Returns:

str – A multiline string with the ctype() and the full set of control points. This is also what is printed by the print statement.

See also

ctype

return a one-line string with the curve type

sub_points(t, j)[source]

Return the points at parameter values t in part j

Parameters:
  • t (float or float array) – One or more parameter values at which to evaluate the point coordinates. Values are usually between 0.0 and 1.0.

  • j (int) – Curve part index for which to find points.

Returns:

Coords – The coordinates of the points on curve part j at parameter values t.

sub_directions(t, j)[source]

Return the directions at parameter values t in part j

Parameters:
  • t (float or float array) – One or more parameter values at which to evaluate the curve’s direction vector. Values are usually between 0.0 and 1.0.

  • j (int) – Curve part index for which to find directions.

Returns:

Coords – The direction vector(s) at parameter values t in curve part j.

pointsOn()[source]

Return the control points that are on the curve.

Returns:

Coords

pointsOff()[source]

Return the control points that are off the curve.

Returns:

Coords

ncoords()[source]

Return the total number of control points.

Returns:

int

endPoints()[source]

Return start and end points of an open curve.

Returns:

Coords – A Coords with two points (the begin and end of the open curve) or None if the curve is closed.

charLength()[source]

Return a characteristic length of the curve.

This value is used in some methods to make input tolerances dimensionless.

Returns:

float – The characteristic length of the curve. If the curve defines a lengths() method returning the lengths of its parts, this is the mean part length. Else, it is the dsize() of the curve’s bbox().

Examples

>>> PolyLine([[0.,0.,0.], [1.,0.,0.], [1.5,0.,0.]]).charLength()
0.75
localParam(u, disc=False)[source]

Split global parameter value in part number and local parameter

Each point along a Curve can be identified by a single float value varying from 0 at the begin point to nparts at the end point, where nparts is the number of parts in the curve. The integer part of the parameter is the part number, and the decimal part is the local parameter for that part, varying from 0 to 1. Input values outside the range [0..nparts] are allowed. Values < 0 return a negative local parameter on part 0, values above nparts return a value > 1 on the last part (nparts-1).

Parameters:
  • u (float array_like) – One or more global parameter values, usually in the range 0..nparts.

  • disc (bool) – If True, values input values which are (very nearly) integers will be reported twice: once in the previous part with local parameter value 1., and once with the next part with local parameter 0. This allows processing of discontinuities at the part boundaries.

Returns:

  • j (int array) – Array of the same length as u with the part numbers corresponding to the parameters t. Values are in the range 0 to nparts-1.

  • t (float array) – Array of the same length as u with the local parameter value in part i corresponding to global parameter u. Values are in the range [0.0, 1.0] if input was inside 0..nparts. It is however legal to extend parameters before the start and after the end of the curve.

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.nparts
2
>>> PL.localParam([0.0, 0.5, 1.0, 1.5, 2.0])
(array([0, 0, 1, 1, 1]), array([0. , 0.5, 0. , 0.5, 1. ]))
>>> PL.localParam([0.0, 0.5, 1.0, 1.5, 2.0], disc=True)
(array([0, 0, 0, 1, 1, 1]), array([0. , 0.5, 1. , 0. , 0.5, 1. ]))
>>> PL.localParam([-0.1, 1.000001, 1.999999, 2.1])
(array([0, 1, 1, 1]), array([-0.1,  0. ,  1. ,  1.1]))
>>> PL.localParam([-0.1, 1.000001, 1.999999, 2.1], disc=True)
(array([0, 0, 1, 1, 1]), array([-0.1,  1. ,  0. ,  1. ,  1.1]))
pointsAt(u, return_position=False)[source]

Return the points at parameter values t.

Parameters:
  • u (float array_like) – One or more global parameter values, usually in the range 0..nparts (see localParam())

  • return_position (bool, optional) – If True, also returns the values of localParam() for the given u.

Returns:

  • coords (Coords) – The coordinates of the points on the curve corresponding with the parameter values u.

  • j, t – The return values of localParam() for the given u. Only returned if return_position is True.

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.pointsAt([0.5, 1.5])
Coords([[0.5, 0. , 0. ],
        [1. , 0.5, 0. ]])
directionsAt(u)[source]

Return the directions at parameter values t.

Parameters:

u (float array_like) – One or more global parameter values, usually in the range 0..nparts (see localParam())

Returns:

Coords – The unit tangent vectors to the curve at the points with parameter values u.

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.directionsAt([0.5, 1.5])
Coords([[1., 0., 0.],
        [0., 1., 0.]])
approx(nseg=None, *, ndiv=None, chordal=0.01, equidistant=False, npre=None, atl=None)[source]

Approximate a Curve with a PolyLine

There are three strategies to define the positions of the PolyLine approximation:

  • nseg: specify the total number of segments along the curve,

  • ndiv: specify the number of segments over each part of the curve,

  • chordal: use an adaptive method limiting the chordal distance of the curve to the PolyLine segments.

Parameters:
  • nseg (int) – Total number of segments of the resulting PolyLine. The number of returned parameter values is nseg if the curve is closed, else nseg+1. If provided, the nseg method will be used and ndiv and chordal are ignored.

  • ndiv (int) – A single integer or a list of nparts integers. If a single integer, each part of the curve is divided in ndiv segments and the total number of segments is ndiv * self.nparts. A list of integers specifies the number of segments for each part, and the total is the sum of the list. If provided (and nseg is not), chordal is ignored.

  • chordal (float) – Maximum chordal error when using the chordal method (i.e. neither nseg nor ndiv are provided). The chordal error is the maximum chord to curve distance, relative to the curve’s charLength().

  • equidistant (bool) – Only used with the nseg method: if True, the nseg points are spread at (almost) equal distances along the curve, instead of at equal parameter distances.

  • npre (int:) – Only used if the chordal method is used or if nseg is used and equidistant is True: the number of segments per part of the curve (like ndiv) used in a pre-approximation. If not provided, the default value is set to the degree of the curve in case of the chordal method, and to 100 for the equidistant nseg method (which uses the pre-approximation to compute accurate curve lengths).

  • atl (float array_like) – Only used with the chordal method: a list of parameter values that need to be included in the result. The list should contain increasing values in the curve’s parameter range. It will be used as a start for the adaptive refining. If not provided, a default is used assuring that the curve is properly approximated. If you specify this yourself, you may end up with bad approximations due to bad choice of the initial values.

Returns:

PolyLine

See also

atApprox

return the parameter values yielding the PolyLine points

Examples

>>> C = BezierSpline([[1,0,0], [0,1,0], [-1,0,0]], degree=2)
>>> print(C.approx(4))
PolyLine: nparts=4, ncoords=5, open
  Control points:
[[ 1.    0.    0.  ]
 [ 0.5   0.75  0.  ]
 [ 0.    1.    0.  ]
 [-0.5   0.75  0.  ]
 [-1.    0.    0.  ]]
>>> print(C.approx(ndiv=2))
PolyLine: nparts=4, ncoords=5, open
  Control points:
[[ 1.    0.    0.  ]
 [ 0.5   0.75  0.  ]
 [ 0.    1.    0.  ]
 [-0.5   0.75  0.  ]
 [-1.    0.    0.  ]]
>>> print(C.approx(chordal=0.2))
PolyLine: nparts=4, ncoords=5, open
  Control points:
[[ 1.    0.    0.  ]
 [ 0.5   0.75  0.  ]
 [ 0.    1.    0.  ]
 [-0.5   0.75  0.  ]
 [-1.    0.    0.  ]]
atApprox(nseg=None, ndiv=None, chordal=0.02, equidistant=False, npre=None, atl=None)[source]

Return parameter values for approximating a Curve with a PolyLine.

The parameters are the same as for approx()

Returns:

array – A list of parameter values that define the positions of the point of the PolyLine approximation of the curve using the same parameter values.

See also

approx

return a PolyLine approximation of a Curve.

Examples

>>> PL = PolyLine([[0,0,0],[1,0,0],[1,1,0]])
>>> print(PL.atApprox(nseg=6))
[0.    0.333 0.667 1.    1.333 1.667 2.   ]
>>> print(PL.atApprox(ndiv=3))
[0.    0.333 0.667 1.    1.333 1.667 2.   ]
>>> print(PL.atApprox(ndiv=(2,4)))
[0.   0.5  1.   1.25 1.5  1.75 2.  ]
>>> print(PL.atApprox(ndiv=(2,)))
[0.  0.5 1. ]
approxAt(u)[source]

Create a PolyLine approximation with specified parameter values.

Parameters:

u (array_like) – A list of global parameter values for the curve, usually in the curve’s parameter range. Values outside the range will extend the curve.

Returns:

PolyLine – A PolyLine connecting the points on the curve at the specified parameter values.

See also

atApprox

convenient methods to compute the parameter values

approx

PolyLine approximation with parameter values from atApprox

Examples

>>> C = BezierSpline([[1,0,0], [0,1,0], [-1,0,0]], degree=2)
>>> PL = C.approxAt([0.0, 1.0, 2.0])
>>> print(PL)
PolyLine: nparts=2, ncoords=3, open
  Control points:
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [-1.  0.  0.]]
>>> C.approxAt([0.0, 0.5, 1.0]).coords
Coords([[1.  , 0.  , 0.  ],
        [0.5 , 0.75, 0.  ],
        [0.  , 1.  , 0.  ]])
length(u0=None, u1=None)[source]

Return the length of the curve between two parameter values.

Parameters:
  • u0 (float) – Global parameter value from where to measure length. If not provided, it is set to the start of the curve (0.).

  • u1 (float) – Global parameter value until where to measure length. If not provided, it is set to the end of the curve (self.nparts).

Returns:

float – The length of the curve between the specified parameter values. Without parameters, the full length of the curve.

Notes

This is only available for curves that implement the ‘lengths’ method.

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.length()
3.23...
>>> C.length(u1=1.5)
1.61...
>>> C.length(0.5, 2.5)
1.95...
frenet(ndiv=None, nseg=None, chordal=0.01, upvector=None, avgdir=True, compensate=False)[source]

Return points and Frenet frame along the curve.

First, a PolyLine approximation for the curve is constructed, using the Curve.approx() method with the arguments ndiv, nseg and chordal. Then Frenet frames are constructed with PolyLine._movingFrenet() using the remaining arguments. The resulting PolyLine points and Frenet frames are returned. The PolyLine polygon approximation,limits the accuracy. More accurate results can be obtained by converting the Curve to a NurbsCurve and using its plugins.nurbs.NurbsCurve.frenet() method. That one however has currently no discontinuity smoothing (discontinuous tangents at sharp corners, undetermined normals at zero curvature, binormal flips).

Parameters:
  • upvector (float (3,) vector) – A vector normal to the (tangent,normal) plane at the first point of the curve. It defines the binormal at the first point. If not provided it is set to the shortest distance through the set of 10 first points.

  • avgdir (bool | array.) – If True (default), the tangential vector is set to the average direction of the two segments ending at a node. If False, the tangent vectors will be those of the line segment starting at the points. The tangential vector can also be set by the user by specifying an array with the matching number of vectors.

  • compensate (bool) –

    If True, adds a compensation algorithm if the curve is closed. For a closed curve the moving Frenet algorithm can be continued back to the first point. If the resulting binormal does not coincide with the starting one, some torsion is added to the end portions of the curve to make the two binormals coincide.

    This feature is off by default because it is currently experimental and is likely to change in future. It may also form the base for setting the starting as well as the ending binormal.

Returns:

  • X (Coords (npts,3)) – The coordinates of npts points on the curve.

  • T (Coords (npts,3)) – The normalized tangent vectors to the curve at the points X.

  • N (Coords (npts,3)) – The normalized normal vectors to the curve at the points X.

  • B (Coords (npts,3)) – The normalized binormal vector to the curve at the points X.

Notes

position(geom, csys=None)[source]

Position a Geometry object along a path.

Creates copies of geom along a curve, orienting it according to the frenet() frame.

Parameters:
  • geom (Geometry | Coords) – The geometry to position

  • csys (CoordSys) – The coordinate system that will be positioned along the frenet axes. If not provided, the global axes are used.

Returns:

list – A list of Geometry/Coords objects properly positioned and oriented along the curve.

sweep(mesh, eltype=None, csys=None)[source]

Sweep a mesh along the curve, creating an extrusion.

Copies of the input mesh are position() -ed along the curve and then connect() -ing them into an extrusion.

Parameters:
  • mesh (Mesh) – The (usually planar) mesh that is to be swept along the curve. It should be a Mesh or an object having a toMesh method to transform it into a Mesh.

  • eltype (str) – The name of the target element type of the returned Mesh. If not provided, it is determined from extruding the mesh eltype.

  • csys (CoordSys) – The coordinate system that will be positioned along the frenet() axes. If not provided, the global axes are used.

Returns:

  • Mesh – The Mesh obtained by sweeping the input mesh along the curve. This involves position() -ing copies of the input Mesh along the curve,

    The returned Mesh has double plexitude of the original. If path is a closed Curve connect back to the first.

  • .. note:: Sweeping nonplanar objects and/or sweeping along very curly – curves may result in physically impossible geometries.

See also

sweep2

position2(objects, normal=0, upvector=2, avgdir=True, enddir=None)[source]

Position a sequence of Coords objects along a path.

At each point of the curve, a copy of the Coords object is created, with its origin in the curve’s point, and its normal along the curve’s direction. In case of a PolyLine, directions are pointing to the next point by default. If avgdir==True, average directions are taken at the intermediate points avgdir can also be an array like sequence of shape (N,3) to explicitely set the directions for ALL the points of the path

Missing end directions can explicitely be set by enddir, and are by default taken along the last segment. enddir is a list of 2 array like values of shape (3). one of the two can also be an empty list. If the curve is closed, endpoints are treated as any intermediate point, and the user should normally not specify enddir.

The return value is a sequence of the repositioned Coords objects.

sweep2(coords, origin=(0.0, 0.0, 0.0), scale=None, **kargs)[source]

Sweep a Coords object along a curve, returning a series of copies.

At each point of the curve a copy of the coords is created, possibly scaled, and rotated to keep same orientation with respect to the curve.

Parameters:
  • coords (Coords object) – The Coords object to be copied, possibly scaled and positioned at each point of the curve.

  • origin (float array_like (3,)) – The local origin in the Coords. This is the point that will be positioned at the curve’s points. It is also the center of scaling if scale is provided.

  • scale (float array_like, optional) – If provided, it should have the shape (npts,3). For each point of the curve, it specifies the three scaling factors to be used in the three coordinate directions on the coords for the copy that is to be plavced at that point.

  • **kargs (optional keyword arguments) – Extra keyword arguments that are passed to position2().

Returns:

A sequence of the transformed Coords objects.

See also

sweep

actor(**kargs)[source]

Create an actor to draw the Curve.

toNurbs()[source]

Convert a curve to a NurbsCurve.

Returns:

NurbsCurve – A plugins.nurbs.nurbscurve equivalent with the input Curve. This is currently only implemented for BezierSpline and PolyLine.

setProp(prop=None)[source]

Create or destroy the property number for the Curve.

A curve can have a single integer as property number. If it is set, derived curves and approximations will inherit it. Use this method to set or remove the property.

Parameters:

prop (int) – The int value to set as the curve’s prop number. If None, the prop is removed from the Curve.

Returns:

self – The curve itself with the property set or removed.

class curve.BezierSpline(coords=None, *, control=None, degree=3, closed=False, tol=None, tangents=None, curl=0.3333333333333333, **kargs)[source]

A class representing a Bezier spline curve of degree 1, 2, 3 or higher.

A BezierSpline of degree d is a continuous curve consisting of nparts successive Bezier curves of the same degree. Successive means that the end point of one curve is also the starting point of the next curve.

A Bezier curve of degree d is determined by d+1 control points, of which the first and the last are on the curve (the endpoints), and the intermediate d-1 points are not. Since the end point of one part is the starting point of the next part, a BezierSpline is described by ncontrol = d * nparts + 1 control points. The number of points on the curve is npoints = nparts + 1.

The above holds for open curves. The BezierSpline class however distinguishes between open and closed curves. In a closed curve, the last point coincides with the first, and is not stored. If the last point is needed, it is obtained by wrapping around back to the first point. An open curve however may also have a last point coinciding with the first, so that the curve looks closed, but technically it remains an open curve.

The BezierSpline class provides ways to create a full set of control points. Often the off-curve control points can be generated automatically. The default degree (3) generates them from the requirement that the curve should be smooth, i.e. have a continuous tangent vector when moving from one part to the next.

Therefore there are basically two ways to create a BezierSpline: by specifying all control points, or by specifying only the points through which the curve should pass (and possibly the tangents at those points). The difference is made clear by using either the control or the coords parameter. Because in most quick application cases the use of the coords option is the likely choice, that parameter is made the (only) positional one. The coords and control parameters are mutually exclusive, but at least one of them must be used. Historically, there was an option to use both coords and control parameters, with the latter then only specifying the off-curve points, but this use case is now prohibited. See Notes for how to work around it.

Parameters:
  • coords (coords_like (npoints, 3), optional) – A set of points through which the curve should pass. The number of points should at least be 2. An interpolation BezierSpline of the requested degree is then constructed. The result can be tuned by other parameters (tangents, curl). This is the only parameter that is allowed as a positional parameter It can not be combined with the control parameter. It can also not be used for degrees > 3 (which are seldomly used).

  • control (coords_like (ntrl, 3)) – The complete set of control points that define the BezierSpline. The number of points (nctrl) should be a multiple of degree, plus 1. This parameter can not be used if coords was provided.

  • degree (int) – The polynomial degree of the curve. The default value is 3. For curves of degree 1, the specialized PolyLine subclass may be more appropriate. For curves of degree 4 or higher the use of a NurbsCurve may be prefered.

  • closed (bool) – If True, a closed curve is created. If the distance from the last point to the first is less than tol, the last point is removed and the last segment is created between the penultimate point and the first point. Else, a segment is created between the last point and the first.

  • tol (float, optional) – Tolerance used in testing for end point coincidence when creating a closed curve. Only used if closed=True. If the distance between the end points is less than tol, they are considered coincident. Else, an extra curve segment is created between the last and the first point. A value 0.0 will force the creation of a extra segment. A value np.inf will never create an extra segment. If not provided, a default value 1.e-5 * coords.dsize() is used. This value ensures expected behavior in most use cases.

  • tangents (coords_like (npts, 3) or (2, 3), optional) – The imposed tangent vectors to the curve at the specified points coords. Can only be used with degree 2 or 3. The number of tangents should be equal to the number of points (after possibly removing one point for a closed curve). As a convenience, the tangents array may contain just two vectors if only the end tangents need to be specified. The provided vectors will get normalized, so their length is irrelevant. If not provided, tangents is set equal to PolyLine(coords).avgDirections(). The tangents array can contain np.nan values for points were the user does not want to prescribe a tangent direction. These will also be filled in with values from PolyLine(coords).avgDirections()

  • curl (float, optional) – The curl parameter can be set to influence the curliness of the curve between two subsequent curve endpoints. A value curl=0.0 results in straight segments. The higher the value, the more the curve becomes curled. Can only be used with degree 3.

  • kargs (deprecated keyword arguments) – For compatibility of legacy code, the ‘tangents’ parameter may also be called ‘deriv’.

Returns:

BezierSpline – A BezierSpline of the requested degree, passing through all points coords. If the degree is 3, or the degree is 2 and all points are lying in the same plane, the curve will have the provided (or computed) tangents at the given points. If the degree is 2 and the points are not coplanar, the curve may have discontinuities in the tangent at the points.

See also

PolyLine

a BezierSpline of degree 1 with more specialized methods

NurbsCurve

Industry standard curves with a finer control of smoothness.

Notes

The combined use of coords and control is no longer permitted. For such cases one can use the arraytools.interleave function to combine them into a single full set of control points. Thus, instead of:

BezierSpline(coords=Q, control=R, degree=2)
BezierSpline(coords=Q, control=R, degree=3)

use:

BezierSpline(control=at.interleave(Q, R[:,0]), degree=2)
BezierSpline(control=at.interleave(Q, R[:,0], R[:,1]), degree=3)

Examples

>>> B = BezierSpline('0123')
>>> print(B)
BezierSpline: degree=3, nparts=3, ncoords=10, open
  Control points:
[[ 0.     0.     0.   ]
 [ 0.316 -0.105  0.   ]
 [ 0.764 -0.236  0.   ]
 [ 1.     0.     0.   ]
 [ 1.236  0.236  0.   ]
 [ 1.236  0.764  0.   ]
 [ 1.     1.     0.   ]
 [ 0.764  1.236  0.   ]
 [ 0.316  1.105  0.   ]
 [ 0.     1.     0.   ]]
>>> print(B.pointsOn())
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> print(B.pointsOff())
[[[ 0.316 -0.105  0.   ]
  [ 0.764 -0.236  0.   ]]

 [[ 1.236  0.236  0.   ]
  [ 1.236  0.764  0.   ]]

 [[ 0.764  1.236  0.   ]
  [ 0.316  1.105  0.   ]]]
>>> print(B.points(1))
[[1.    0.    0.   ]
 [1.236 0.236 0.   ]
 [1.236 0.764 0.   ]
 [1.    1.    0.   ]]
>>> B = BezierSpline('0123', degree=1)
>>> print(B)
BezierSpline: degree=1, nparts=3, ncoords=4, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> B = BezierSpline('0123', degree=1, closed=True)
>>> print(B.ctype)
BezierSpline: degree=1, nparts=4, ncoords=4, closed
property nparts

The number of parts in the BezierSpline

property npoints

The number of oncurve points in the BezierSpline

This is equal to the number of parts if the curve is closed; else, it is one more.

pointsOn()[source]

Return the control points that are on the curve.

Returns:

Coords (nparts+1, 3) – The coordinates of the nparts+1 points on the curve. For a closed curve, the last point will be equal to the first.

pointsOff()[source]

Return the control points that are off the curve.

Returns:

Coords (nparts, degree-1, 3) – The coordinates of the intermediary control points for the nparts in dividual Bezier curves. For degree=1, an empty Coords is returned.

points(j=None, k=None)[source]

Return the point sequence defining parts j to k of the curve.

The returned points sequence can be used to create a curve identical to the parts j:k of the curve.

Parameters:
  • j (int) – The first (or only) part to return. The value should be in the range 0..nparts. If not provided, all points are returned.

  • k (int, optional) – One more than the last part to return. Its value should be in the range 1..nparts+1. For an open curve, k should be > j. For a closed curve, k <= j is allowed to take a points spanning the first/last point. If not provided, k is set to j+1, resulting in the points for a single part.

Returns:

Coords ((k-j)*degree+1, 3) – The sequence of points from self.coords that define parts j to k of the curve.

See also

part_points

return an array of single part points

parts

return a curve identical to parts j:k

Examples

>>> C = BezierSpline('1234', degree=2)
>>> print(C.coords)
[[ 1.    0.    0.  ]
 [ 1.25  0.75  0.  ]
 [ 1.    1.    0.  ]
 [ 0.5   1.5   0.  ]
 [ 0.    1.    0.  ]
 [-0.25  0.75  0.  ]
 [ 0.    0.    0.  ]]
>>> print(C.points(0))
[[1.   0.   0.  ]
 [1.25 0.75 0.  ]
 [1.   1.   0.  ]]
>>> print(C.points(1,3))
[[ 1.    1.    0.  ]
 [ 0.5   1.5   0.  ]
 [ 0.    1.    0.  ]
 [-0.25  0.75  0.  ]
 [ 0.    0.    0.  ]]

Notice the difference with part_points():

>>> print(C.part_points([1,2]))
[[[ 1.    1.    0.  ]
  [ 0.5   1.5   0.  ]
  [ 0.    1.    0.  ]]

 [[ 0.    1.    0.  ]
  [-0.25  0.75  0.  ]
  [ 0.    0.    0.  ]]]

Closed curve example:

>>> C = BezierSpline('1234', degree=2, closed=True)
>>> print(C.coords)
[[ 1.   0.   0. ]
 [ 1.5  0.5  0. ]
 [ 1.   1.   0. ]
 [ 0.5  1.5  0. ]
 [ 0.   1.   0. ]
 [-0.5  0.5  0. ]
 [ 0.   0.   0. ]
 [ 0.5 -0.5  0. ]]
>>> print(C.points(0))
[[1.  0.  0. ]
 [1.5 0.5 0. ]
 [1.  1.  0. ]]
>>> print(C.points(3,1))
[[ 0.   0.   0. ]
 [ 0.5 -0.5  0. ]
 [ 1.   0.   0. ]
 [ 1.5  0.5  0. ]
 [ 1.   1.   0. ]]
split(split=None)[source]

Split a curve into a list of partial curves

Parameters:

split (list(int)) – A list of integer values specifying the point numbers where the curve is to be split. As a convenience, a single int may be given if the curve is to be split only at a single point, or None, to split at all nodes.

Returns:

list – A list of open curves of the same type as the original. Together, the curves cover the original curve.

Notes

Only multipart curves can be split. Splitting a closed curve at a single point creates a single open curve with begin/end at the split point.

Examples

>>> PL = PolyLine(Coords('0123'))
>>> for PLi in PL.split(): print(PLi)
PolyLine: nparts=1, ncoords=2, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]]
PolyLine: nparts=1, ncoords=2, open
  Control points:
[[1. 0. 0.]
 [1. 1. 0.]]
PolyLine: nparts=1, ncoords=2, open
  Control points:
[[1. 1. 0.]
 [0. 1. 0.]]
parts(j, k)[source]

Return a curve containing only parts j to k.

Parameters:
  • j (int) – The first part to include in the new curve. The value should be in range(0,nparts).

  • k (int) – One more than the last part to include.

Returns:

BezierSpline – An open BezierSpline of the same degree as the input curve, containing only the parts j..k of it.

Examples

>>> PL = PolyLine(Coords('0123'))
>>> print(PL.ctype)
PolyLine: nparts=3, ncoords=4, open
>>> print(PL.parts(1,3))
PolyLine: nparts=2, ncoords=3, open
  Control points:
[[1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> PLC = PL.close()
>>> print(PLC)
PolyLine: nparts=4, ncoords=4, closed
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> print(PLC.ctype)
PolyLine: nparts=4, ncoords=4, closed
>>> print(PLC.parts(3,1))
PolyLine: nparts=2, ncoords=3, open
  Control points:
[[0. 1. 0.]
 [0. 0. 0.]
 [1. 0. 0.]]
>>> print(PLC.parts(0,1))
PolyLine: nparts=1, ncoords=2, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]]
part_points(j=None)[source]

Return the defining points for parts j.

Parameters:

j (int | int array_like) – The part number(s)for which to return the defining points. If not provided, all parts are returned.

Returns:

Coords – The coordinates of the points defining each of the parts j of the curve. If j is a single int, the shape of the Coords (degree+1, 3), else it is (len(j), degree+1, 3).

See also

points

return a single sequence of points for parts j to k

Examples

>>> C = BezierSpline('1234', degree=2)
>>> print(C.coords)
[[ 1.    0.    0.  ]
 [ 1.25  0.75  0.  ]
 [ 1.    1.    0.  ]
 [ 0.5   1.5   0.  ]
 [ 0.    1.    0.  ]
 [-0.25  0.75  0.  ]
 [ 0.    0.    0.  ]]
>>> print(C.part_points(0))
[[1.   0.   0.  ]
 [1.25 0.75 0.  ]
 [1.   1.   0.  ]]
>>> print(C.part_points([2,0]))
[[[ 0.    1.    0.  ]
  [-0.25  0.75  0.  ]
  [ 0.    0.    0.  ]]

 [[ 1.    0.    0.  ]
  [ 1.25  0.75  0.  ]
  [ 1.    1.    0.  ]]]
sub_points(t, j=None)[source]

Return points on the curve at parameter values t in part(s) j.

Parameters:
  • t (float array_like) – Local parameter values (usually in the range 0.0..1.0) of the points to return.

  • j (int or int array_like) – The part number(s)for which to return points. If not provided, points on all parts are returned.

Returns:

Coords – The coordinates of the points on the curve at local parameter values t of the parts j. The shape of the Coords is (len(t), 3) if j is a single int, else the shape is (len(j), len(t), 3).

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.sub_points([0.0, 0.2, 0.5])
Coords([[[ 1.   ,  0.   ,  0.   ],
         [ 1.08 ,  0.28 ,  0.   ],
         [ 1.125,  0.625,  0.   ]],

        [[ 1.   ,  1.   ,  0.   ],
         [ 0.8  ,  1.16 ,  0.   ],
         [ 0.5  ,  1.25 ,  0.   ]],

        [[ 0.   ,  1.   ,  0.   ],
         [-0.08 ,  0.88 ,  0.   ],
         [-0.125,  0.625,  0.   ]]])
>>> C.sub_points([0.0, 0.2, 0.5], 1)
Coords([[1.  , 1.  , 0.  ],
        [0.8 , 1.16, 0.  ],
        [0.5 , 1.25, 0.  ]])
>>> C.sub_points([0.0, 0.2, 0.5], [1, 0])
Coords([[[1.   , 1.   , 0.   ],
         [0.8  , 1.16 , 0.   ],
         [0.5  , 1.25 , 0.   ]],

        [[1.   , 0.   , 0.   ],
         [1.08 , 0.28 , 0.   ],
         [1.125, 0.625, 0.   ]]])
sub_directions(t, j=None)[source]

Return the unit direction vectors at values t in part j.

Parameters:
  • t (float array_like) – Local parameter values (usually in the range 0.0..1.0) of the points at which to find the direction vector.

  • j (int or int array_like) – The part number(s) for which to return directions. If not provided, directions for t on all parts are returned.

Returns:

array – The unit direction vectors of the curve at the points with local parameter values t on the parts j. The shape of the array is (len(t), 3) if j is a single int, else it is (len(j), len(t), 3).

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.sub_directions([0.0, 0.5, 1.0], 1)
array([[-0.707,  0.707,  0.   ],
       [-1.   ,  0.   ,  0.   ],
       [-0.707, -0.707,  0.   ]])
>>> C.sub_directions([0.0, 0.5, 1.0])
array([[[ 0.316,  0.949,  0.   ],
        [ 0.   ,  1.   ,  0.   ],
        [-0.707,  0.707,  0.   ]],

       [[-0.707,  0.707,  0.   ],
        [-1.   ,  0.   ,  0.   ],
        [-0.707, -0.707,  0.   ]],

       [[-0.707, -0.707,  0.   ],
        [ 0.   , -1.   ,  0.   ],
        [ 0.316, -0.949,  0.   ]]])
sub_curvature(t, j=None)[source]

Return the curvature at values t in part j.

Parameters:
  • t (float array_like) – Local parameter values (usually in the range 0.0..1.0) of the points at which to find the curvature.

  • j (int or int array_like) – The part number(s) for which to return curvatures. If not provided, curvatures for all parts are returned.

Returns:

array – The curvature of the curve at the points with local parameter values t on the parts j. The shape of the return array is (len(t),) if j is a single int, else it is (len(j), len(t)).

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.sub_curvature([0.0, 0.5, 1.0], 0)
array([0.253, 1.   , 2.828])
>>> C.sub_curvature([0.0, 0.5, 1.0], 1)
array([0.707, 2.   , 0.707])
>>> C.sub_curvature([0.0, 0.5, 1.0])
array([[0.253, 1.   , 2.828],
       [0.707, 2.   , 0.707],
       [2.828, 1.   , 0.253]])
directions()[source]

Return the direction vectors at the points on the curve

lengths(t=(0.0, 1.0), j=None)[source]

Return the length of the parts of the curve.

Parameters:
  • t (tuple of float) – The range of parameter values over which to integrate the length. Default is 0.0..1.0, to obtaind the full part length.

  • j (int or int array_like) – The part number(s) for which to return lengths. If not provided, lengths for all parts are returned.

Returns:

array – The lengths of the parts j of the curve between parameter values t.

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.lengths()
array([1.046, 1.148, 1.046])
>>> C.lengths((0.0, 0.5), [0,1])
array([0.64 , 0.574])
atLength(l, approx=20)[source]

Return the parameter values at given relative curve length.

Parameters:
  • l (array_like) – The list of relative curve lengths (ranging from 0.0 to 1.0 over the full length of the curve). As a convenience, a single integer value may be specified, in which case the relative curve lengths are found by dividing the interval [0.0,1.0] in the specified number of subintervals.

  • approx (int or None.) – If not None, an approximate result is returned obtained by approximating the curve first by a PolyLine with approx number of line segments per curve segment. This is currently the only implemented method, and specifying None will fail.

Returns:

list – A list with the parameter values for the points at the specified relative lengths.

Examples

>>> C = BezierSpline('1234', degree=2)
>>> C.atLength([0.0, 1/3, 0.5, 0.75, 1.0])
array([0.   , 1.025, 1.5  , 2.314, 3.   ])
insertPointsAt(t, return_indices=False)[source]

Insert new points on the curve at parameter values t.

Parameters:
  • t (float array_like) – A list of global parameter values where the new points will be inserted. ** Currently there is a maximum of one new point per segment. **

  • return_indices (bool) – If True, returns the indices of the new points in the BezierSpline.

Returns:

  • BezierSpline – The BezierSpline with extra points inserted at the specified parameter values.

  • indices (int array) – The indices in the new curve’s pointsOn() of the inserted oncurve points. Only returned if return_indices is True.

See also

PolyLine.insertPointsAt

allows multiple insertions on same segment

Examples

>>> C = BezierSpline('012', degree=2)
>>> print(C)
BezierSpline: degree=2, nparts=2, ncoords=5, open
  Control points:
[[ 0.    0.    0.  ]
 [ 0.75 -0.25  0.  ]
 [ 1.    0.    0.  ]
 [ 1.25  0.25  0.  ]
 [ 1.    1.    0.  ]]
>>> C1 = C.insertPointsAt([0.5, 1.5])
>>> print(C1)
BezierSpline: degree=2, nparts=4, ncoords=9, open
  Control points:
[[ 0.     0.     0.   ]
 [ 0.375 -0.125  0.   ]
 [ 0.625 -0.125  0.   ]
 [ 0.875 -0.125  0.   ]
 [ 1.     0.     0.   ]
 [ 1.125  0.125  0.   ]
 [ 1.125  0.375  0.   ]
 [ 1.125  0.625  0.   ]
 [ 1.     1.     0.   ]]
>>> C1 = C.insertPointsAt([-0.5])
>>> print(C1)
BezierSpline: degree=2, nparts=3, ncoords=7, open
  Control points:
[[-0.875  0.375  0.   ]
 [-0.375  0.125  0.   ]
 [ 0.     0.     0.   ]
 [ 0.75  -0.25   0.   ]
 [ 1.     0.     0.   ]
 [ 1.25   0.25   0.   ]
 [ 1.     1.     0.   ]]
splitAt(t)[source]

Split a BezierSpline at parameter values.

Parameters:

t (float array_like) – A list of global parameter values where the curve will be split. For a BezierSpline there is currently a maximum of one split point per segment. The PolyLine subclass however allows multiple split points per segment.

Returns:

list(BezierSpline) – A list of len(t)+1 open BezierSplines of the same degree as the input.

Examples

>>> C = BezierSpline('012', degree=2)
>>> CL = C.splitAt([0.5, 1.5])
>>> for Ci in CL: print(Ci)
BezierSpline: degree=2, nparts=1, ncoords=3, open
  Control points:
[[ 0.     0.     0.   ]
 [ 0.375 -0.125  0.   ]
 [ 0.625 -0.125  0.   ]]
BezierSpline: degree=2, nparts=2, ncoords=5, open
  Control points:
[[ 0.625 -0.125  0.   ]
 [ 0.875 -0.125  0.   ]
 [ 1.     0.     0.   ]
 [ 1.125  0.125  0.   ]
 [ 1.125  0.375  0.   ]]
BezierSpline: degree=2, nparts=1, ncoords=3, open
  Control points:
[[1.125 0.375 0.   ]
 [1.125 0.625 0.   ]
 [1.    1.    0.   ]]
splitAtLength(L)[source]

Split a BezierSpline at relative lenghts L.

This is a convenient shorthand for:

self.splitAt(self.atLength(L))

See also

splitAt

split a PolyLine at given parameter values

atLength

compute parameter values at given curve length

extend(start=None, end=None)[source]

Extend the curve beyond its endpoints.

Uses de Casteljau’s algorithm to add an extra curve part before the first and/or after the last part of the BezierSpline.

Parameters:
  • start (float) – Parameter values to extend the BezierSpline at the start. Values start with zero at the start of the curve and run in the direction opposite to that of segment 0. The new start point of the curve will thus become the point that would be inserted by self.insertPointsAt([-start]).

  • end (float) – Parameter value to extend BezierSpline at the end. Values start with zero at the end of the curve and run beyond thet point along the last segment. The new start point of the curve will thus become the point that would be inserted by self.insertPointsAt([self.nparts + end]).

Returns:

BezierSpline – A Curve of same type and degree as the input, extended at the start and/or the end.

Notes

Only open curves can be extended.

See also

PolyLine.extend

allows a list of values for start/end

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.extend(0.4, 0.5).coords
Coords([[-0.4,  0. ,  0. ],
        [ 0. ,  0. ,  0. ],
        [ 1. ,  0. ,  0. ],
        [ 1. ,  1. ,  0. ],
        [ 1. ,  1.5,  0. ]])
>>> C = BezierSpline('012', degree=1)
>>> C.extend(0.4, 0.5).coords
Coords([[-0.4,  0. ,  0. ],
        [ 0. ,  0. ,  0. ],
        [ 1. ,  0. ,  0. ],
        [ 1. ,  1. ,  0. ],
        [ 1. ,  1.5,  0. ]])
close(tangents=False, tol=None)[source]

Close a Curve

Creates a closed curve throught the oncurve points of the current, and possibly with the same tangents.

Parameters:
  • tangents (bool) – If True, the returned curve will have the same tangents at all internal points.

  • tol (float) – Tolerance for testing end point coincidence when creating closed curves. This parameter is passed to ipol().

Returns:

BezierSpline | PolyLine – A closed variant of the input curve. If that is already closed, just returns self.

reverse()[source]

Return the same curve with the parameter direction reversed.

roll(n)[source]

Roll the parts of a closed curve.

This rolls the start vertex of the curve n positions further.

Parameters:

n (int) – The number of vertex positions to roll over: part 0 then becomes part n.

Returns:

BezierSpline | PolyLine – The same curve as the input, but with the vertex numbers rolled over n positions.

Notes

This only works for a closed curve.

Examples

>>> C = BezierSpline('012', degree=2, closed=True)
>>> print(C.coords)
[[ 0.     0.     0.   ]
 [ 0.293 -0.707  0.   ]
 [ 1.     0.     0.   ]
 [ 1.707  0.707  0.   ]
 [ 1.     1.     0.   ]
 [-0.707  1.707  0.   ]]
>>> print(C.roll(1).coords)
[[ 1.     1.     0.   ]
 [-0.707  1.707  0.   ]
 [ 0.     0.     0.   ]
 [ 0.293 -0.707  0.   ]
 [ 1.     0.     0.   ]
 [ 1.707  0.707  0.   ]]
toMesh()[source]

Convert a BezierSpline to a Mesh.

Returns:

Mesh – A Mesh of eltype ‘line2’, ‘line3’ or ‘line4’, where each element corresponds with a part of the BezierSpline. This gives an exact representation of a BezierSpline of degree 1, 2, or 3 or a PolyLine.

Notes

Currently, only BezierSplines of degree <= 3 can be converted to a Mesh. For higher degrees, create an approximation of degree <= 3 first.

Examples

>>> M = PolyLine('0123').toMesh()
>>> print(M.coords)
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> print(M.elems)
[[0 1]
 [1 2]
 [2 3]]
>>> M = BezierSpline('0123',degree=2,closed=True).toMesh()
>>> print(M.coords)
[[ 0.    0.    0.  ]
 [ 0.5  -0.25  0.  ]
 [ 1.    0.    0.  ]
 [ 1.25  0.5   0.  ]
 [ 1.    1.    0.  ]
 [ 0.5   1.25  0.  ]
 [ 0.    1.    0.  ]
 [-0.25  0.5   0.  ]]
>>> print(M.elems)
[[0 1 2]
 [2 3 4]
 [4 5 6]
 [6 7 0]]
toFormex()[source]

Convert the BezierSpline to a Formex.

This is notational convenience for::

self.toMesh().toFormex()

pzf_dict()[source]

Construct common part of all Geometry pzf dicts

class curve.PolyLine(control=None, *, closed=False, tol=None, **kargs)[source]

A Curve consisting of a sequence of straight line segments.

This is implemented as a BezierSpline of degree 1, and in many cases one can just use that super class. The PolyLine class however provides a lot of extra functionality, which is only available for curves of degree 1.

Parameters:
  • coords (coords_like) – An (npts,3) shaped array with the coordinates of the subsequent vertices of the PolyLine, or any other data accepted by the Coords initialization. Each vertex is connected to the next to form a PolyLine segment. For compatibility with the BezierSpline class, this argument can also be named control, and takes precedent if both are used.

  • closed (bool, optional) – If True, the PolyLine is closed by connecting the last vertex back to the first. The closed PolyLine thus has npts segments. The default (False) leaves the curve open with npts-1 segments.

  • control (optional) – This is an alias for the coords parameter. It exists only for symmetry with the BezierSpline class. If specified, control overrides the value of coords.

Examples

>>> P = PolyLine('0123')
>>> print(P)
PolyLine: nparts=3, ncoords=4, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> P.nparts
3
>>> P = PolyLine(P.coords, closed=True).nparts
>>> print(P)
4
vectors()[source]

Return the vectors from each point to the next one.

Returns:

Coords (nparts,3) – A Coords array holding the vectors from each point of the PolyLine to the next one. The number of vectors is equal to nparts.

Examples

>>> PolyLine('0123').vectors()
Coords([[ 1.,  0.,  0.],
        [ 0.,  1.,  0.],
        [-1.,  0.,  0.]])
directions(return_doubles=False)[source]

Returns unit vectors in the direction of the next point.

Parameters:

return_doubles (bool) – If True, also returns an index of coincident points.

Returns:

  • dirs (array(npoints,3)) – The unit vectors at all points in the direction of the next point. If two subsequent points are identical, the first one gets the direction of the previous segment. If more than two subsequent points are equal, an invalid direction (NaN) is returned. If the curve is not closed, the last direction is set equal to the penultimate.

  • doubles (array) – The indices of the points that coincide with their follower. Only returned if return_doubles is True.

See also

avgDirections

the average direction of the segments ending at the point

Examples

>>> PolyLine('0123').directions()
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [-1.,  0.,  0.],
       [-1.,  0.,  0.]])
>>> P = PolyLine('01.2')
>>> print(P)
PolyLine: nparts=3, ncoords=4, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]]
>>> P.directions(return_doubles=True)
(array([[1., 0., 0.],
       [1., 0., 0.],
       [0., 1., 0.],
       [0., 1., 0.]]), array([1]))
avgDirections(return_indices=False)[source]

Returns the average directions at points.

Parameters:

return_indices (bool) – If True, also returns an index of the points where an average was computed. This excludes the endpoints and subsequent conincident points, where the returned direction is the same as that from directions().

Returns:

  • dirs (array(npoints,3)) – The average direction at all points. The returned direction is the average of the direction from the preceding point to the current, and the direction from the current to the next point. If the curve is open, the end directions are set to mimic a natural free end: the angle with the chord is half the angle at the other end of the segment, and in opposite direction. Where two subsequent points coincide, the average directions are set equal to those of the segment ending in the first point and the segment starting from the last point.

  • doubles (array) – The indices of the points that coincide with their follower. Only returned if return_doubles is True.

See also

directions

the direction from the point to the next point

Examples

>>> PolyLine('0123').avgDirections()
array([[ 0.949, -0.316,  0.   ],
       [ 0.707,  0.707,  0.   ],
       [-0.707,  0.707,  0.   ],
       [-0.949, -0.316,  0.   ]])
>>> P = PolyLine('012.3')
>>> print(P)
PolyLine: nparts=4, ncoords=5, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
>>> P.avgDirections(return_indices=True)
(array([[ 0.949, -0.316,  0.   ],
       [ 0.707,  0.707,  0.   ],
       [ 0.   ,  1.   ,  0.   ],
       [-1.   ,  0.   ,  0.   ],
       [-1.   ,  0.   ,  0.   ]]), array([1]))
lengths(t=(0.0, 1.0), j=None)[source]

Return the length of the parts of the PolyLine.

This is like BezierSpline.lengths() but implemented more efficiently for PolyLine

Examples

>>> PolyLine([[0., 0., 0.], [0.4, 0., 0.], [0.4, 0.9, 0.]]).lengths()
array([0.4, 0.9])
cumLengths()[source]

Return the cumulative length of the curve for all vertices.

relLengths()[source]

Return the relative length of the curve for all vertices.

atLength(div)[source]

Return the parameter values at given relative curve length.

Parameters:

div (array_like) – The list of relative curve lengths (ranging from 0.0 to 1.0 over the full length of the curve). As a convenience, a single integer value may be specified, in which case the relative curve lengths are found by dividing the interval [0.0,1.0] in the specified number of subintervals.

Returns:

list – A list with the parameter values for the points at the specified relative lengths.

Examples

>>> P = PolyLine([[0., 0., 0.], [0.4, 0., 0.], [0.4, 0.9, 0.]])
>>> P.atLength([0., 0.25, 0.5, 0.75, 1.0])
array([0.   , 0.812, 1.278, 1.639, 2.   ])
cosAngles()[source]

Return the cosinus of the angles between subsequent segments.

Returns:

array – An array of floats in the range [-1.0..1.0]. The value at index i is the cosinus of the angle between the segment i and the segment i-1. The number of floats is always equal to the number of points.

If the curve is open, the first value is the cosinus of the angle between the last and the first segment, while the last value is always equal to 1.0. Where a curve has two subsequent coincident points, the value for the the first point is 1.0. Where a curve has more than two subsequent coincident points, NAN values will result.

Examples

>>> C1 = PolyLine('01567')
>>> C2 = PolyLine('01567',closed=True)
>>> C3 = PolyLine('015674')
>>> print(C1.cosAngles())
[-0.707  0.707  0.     0.     1.   ]
>>> print(C2.cosAngles())
[0.    0.707 0.    0.    0.707]
>>> print(C3.cosAngles())
[0.    0.707 0.    0.    0.707 1.   ]
insertPointsAt(t, return_indices=False)[source]

Insert new points at parameter values t

Parameters:
  • t (float array_like) – A list of global parameter values where the new points will be inserted. The values can be in any order, but will be sorted before processing. Usually values are in the range 0..nparts. However, for open PolyLines values < 0. will result in points inserted before the first point, and values > nparts are will result in points beyond the end of the PolyLine. This is a convenient way to extend a PolyLine in the direction of its end segments.

  • return_indices (bool) – If True, returns the indices of the new points in the PolyLine.

Returns:

  • PolyLine – A PolyLine with the new points inserted. Note that the parameter values of the existing points will have changed.

  • indices (int array) – Only returned if return_indices is True: the indices of the inserted points in the returned PolyLine.

Notes

This is like BezierSpline.insertPointsAt() but allows multiple values on the same segment.

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.insertPointsAt([-0.5, 1.5, 2.5, 3.5]).coords
Coords([[-0.5,  0. ,  0. ],
        [ 0. ,  0. ,  0. ],
        [ 1. ,  0. ,  0. ],
        [ 1. ,  0.5,  0. ],
        [ 1. ,  1. ,  0. ],
        [ 1. ,  1.5,  0. ],
        [ 1. ,  2.5,  0. ]])
extend(start=[], end=[])[source]

Extend and open PolyLine beyond its endpoints.

Parameters:
  • start (float or float array_like) – One or more parameter values to extend the PolyLine at the start. Parameter values start at point 0 and run in the direction opposite to that of segment 0, with a value 1.0 being obtained at a distance equal to the length of the first segment.

  • end (float or float array_like) – One or more parameter values to extend the PolyLine at the end. Parameter values start at point nparts and run in the direction opposite to that of the last segment , with a value 1.0 being obtained at a distance equal to the length of the last segment.

Notes

This is equivalent with using insertPointsAt() with t values given by - start and self.nparts + end. Only open curves can be extended. This is like BezierSpline.extend() but allows multiple values for start and/or end.

Examples

>>> PL = PolyLine(Coords('012'))
>>> PL.extend(0.4, [0.3, 0.5]).coords
Coords([[-0.4,  0. ,  0. ],
        [ 0. ,  0. ,  0. ],
        [ 1. ,  0. ,  0. ],
        [ 1. ,  1. ,  0. ],
        [ 1. ,  1.3,  0. ],
        [ 1. ,  1.5,  0. ]])
toFormex()[source]

Return the PolyLine as a Formex.

splitByAngle(cosangle=0.0, angle=None, angle_spec=0.017453292519943295)[source]

Split a PolyLine at points with high change of direction.

Parameters:
  • cosangle (float) – Threshold value for the cosinus of the angle between subsequent segment vectors. The curve is split at all points where the value of cosAngles() is (algebraicallly) lower than or equal to this threshold value. The default value splits the curve where the direction changes with more than 90 degrees. A value 1.0 will split the curve at all points. A value of -1.0 will only split where the curve direction exactly reverses.

  • angle (float, optional) – If provided, cosangle is computed from at.cosd(angle,angle_spec)`

  • angle_spec (float, optional) – Units used for the angle parameter. This is the number of radians for 1 unit.

Returns:

list – A list of PolyLine objects, where each PolyLine has a limited change of direction at its vertices.

cutWithPlane(p, n, side='')[source]

Return the parts of the PolyLine at one or both sides of a plane.

Cuts a PolyLine with a plane and returns the resulting polylines at either side of the plane or both.

Parameters:
  • p (array_like (3,)) – A point in the cutting plane.

  • n (array_like (3,)) – The normal vector to the cutting plane.

  • side (str ('' | '+' | '-')) – Specifies which side of the plane should be returned. If an empty string (default), both sides are returned. If ‘+’ or ‘-’, only the part at the positive, resp. negative side of the plane (as defined by its normal n) is returned.

Returns:

  • PLpos (list of PolyLine) – A list of the resulting polylines at the positive side of the plane. Not returned if side==’-‘.

  • PLneg (list of PolyLine) – A list of the resulting polylines at the negative side of the plane. Not returned if side==’+’.

append(PL, fuse=True, smart=False, **kargs)[source]

Concatenate two open PolyLines.

This combines two open PolyLines into a single one. Closed PolyLines cannot be concatenated.

Parameters:
  • PL (PolyLine) – An open PolyLine, to be appended at the end of the current.

  • fuse (bool) – If True (default), the last point of self and the first point of PL will be fused to a single point if they are close. Extra parameters may be added to tune the fuse operation. See the Coords.fuse() method. The ppb parameter is not allowed.

  • smart (bool) – If True, PL will be connected to self by the endpoint that is closest to the last point of self, thus possibly reverting the sense of PL.

Returns:

PolyLine – The concatenation of the polylines self and PL.

Notes

The same result (with the default parameter values) can also be achieved using operator syntax: PolyLine1 + PolyLine2.

See also

concatenate

concatenate a list of PolyLine’s

static concatenate(PLlist, **kargs)[source]

Concatenate a list of PolyLine objects.

Parameters:
  • PLlist (list of PolyLine.) – The list of PolyLine’s to concatenate

  • **kargs – Other keyword arguments like in append().

Returns:

PolyLine – The concatenation of all the polylines in PLlist.

refine(maxlen)[source]

Insert extra points in the PolyLine to reduce the segment length.

Parameters:

maxlen (float) – The maximum length of the segments. The value is relative to the total curve length().

Returns:

PolyLine – A PolyLine which is geometrically equivalent to the input PolyLine but has no segment longer than maxlen times the total curve length().

vertexReductionDP(tol, maxlen=None, keep=[0, -1])[source]

Douglas-Peucker vertex reduction.

Finds out which points of the PolyLine can be removed while keeping a required accuracy.

Parameters:

tol (float) – Required accuracy of the result. For any subpart of the PolyLine, if the distance of all its vertices to the line connecting its endpoints is smaller than tol, the internal points are removed.

Returns:

bool array – A bool array flagging the vertices to be kept in the reduced form.

See also

coarsen

returns the reduced PolyLine

coarsen(tol=0.01, maxlen=None, keep=[0, -1])[source]

Reduce the number of points of the PolyLine.

Parameters:
  • tol (float) – Maximum relative distance from the chord of the segment for vertices to be removed. The value is relative to the total curve length.

  • keep (int array_like) – List of vertices to keep during the coarsening process. (Not implemented yet !! NEED TO CHECK THIS).

Returns:

Polyline – A coarsened version of the PolyLine.

pzf_dict()[source]

Return the data to save in PZF format.

class curve.Line(coords)[source]

A Line is a straight segment between two points.

Line is implemented as a :class:PolyLine with exactly two points.

Parameters:

coords (array_like (2,3)) – The coordinates of begin and end point of the line.

Examples

>>> L = Line([[0.,0.,0.], [0.,1.,0.]])
>>> print(L)
Line: nparts=1, ncoords=2, open
  Control points:
[[0. 0. 0.]
 [0. 1. 0.]]
class curve.Contour(coords, elems)[source]

A class for storing a contour.

The Contour class stores a continuous (often closed, 2D) curve which consists of a sequence of strokes, each stroke being a Bezier curve. Generally the degree of the Bezier curves is in the range 1..3, but higher degrees are accepted. Each stroke is thus defined by 2, 3 or 4 (or more) points. Each strokes starts at the endpoint of the previous stroke. If the last point of the last stroke and the first point of the first stroke are the same point, the Contour is closed.

The Contour is defined by a list of points and a Varray of element connectivity. This format is well suited to store contours of scalable fonts (the contours are the normally 2D curves).

Parameters:
  • coords (coords_like (npoints, 3)) – The coordinates of all points used in the definitions of the strokes.

  • elems (varray_like) – A Varray defining the strokes as a list of point indices. Each row should start with the same point that ended the previous stroke.

Examples

>>> X = Coords('0123')
>>> C = Contour(X, [(0,1), (1,2,3,0)])
>>> print(C)
Contour: nparts=2, ncoords=4, closed
Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
Strokes: Varray (nrows=2, width=2..4)
  [0 1]
  [1 2 3 0]
>>> print(C.elems)
Varray (nrows=2, width=2..4)
  [0 1]
  [1 2 3 0]
>>> print(C.nparts)
2
>>> print(C.stroke(1))
BezierSpline: degree=3, nparts=1, ncoords=4, open
  Control points:
[[1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]
 [0. 0. 0.]]
>>> print(C.parts(1,2))
Contour: nparts=1, ncoords=4, open
  Control points:
[[0. 0. 0.]
 [1. 0. 0.]
 [1. 1. 0.]
 [0. 1. 0.]]
  Strokes: Varray (nrows=1, width=4..4)
  [1 2 3 0]
pointsOn()[source]

Return the control points that are on the curve.

Returns:

Coords

pointsOff()[source]

Return the control points that are off the curve.

Returns:

Coords

ncoords()[source]

Return the total number of control points.

Returns:

int

endPoints()[source]

Return start and end points of the curve.

Returns a Coords with two points, or None if the curve is closed.

points(i)[source]

Returns the points defining part j of the curve.

compact()[source]

Compact the data, removing unused points

parts(j, k)[source]

Return a Contour only containing parts j to k

stroke(i)[source]

Return curve for part i

sub_points(t, j)[source]

Return the points at values t in part j

t can be an array of parameter values, j is a single segment number.

sub_directions(t, j)[source]

Return the directions at values t in part j

t can be an array of parameter values, j is a single segment number.

toMesh()[source]

Convert the Contour to a Mesh.

class curve.NaturalSpline(coords, closed=False, endzerocurv=False)[source]

A class representing a natural spline.

The use of this class is deprecated. For a closed curve or an open curve with endzerocurv=True, BezierSpline gives a good approximation. For an open curve with endzerocurv=False, a NurbsCurve obtained with nurbs.globalInterpolationCurve will do fine.

sub_points(t, j)[source]

Return the points at parameter values t in part j

Parameters:
  • t (float or float array) – One or more parameter values at which to evaluate the point coordinates. Values are usually between 0.0 and 1.0.

  • j (int) – Curve part index for which to find points.

Returns:

Coords – The coordinates of the points on curve part j at parameter values t.

class curve.Arc(*, p3=None, cbe=None, center=(0.0, 0.0, 0.0), radius=1.0, normal=(0.0, 0.0, 1.0), angles=(0.0, 360.0), angle_spec=0.017453292519943295)[source]

A class representing a circular arc.

The arc can be specified in one of three ways:

  • by specifying 3 points on the arc: the begin point, an intermediate point and the end point. Use the p3 argument to use this method.

  • by specifying the center and the begin and end points: use the cbe argument.

  • by the general method specifying the center, radius, normal, and begin and end angles of the arc.

Parameters:
  • p3 (coords_like (3,3)) – The coordinates of three subsequent points on the arc: the begin point, an intermediate point and the end point. The three points should obviously not be colinear, with one exception: if the begin and end points coincide, a full circle is created, and the normal argument is used to help with orienting the circle’s plane. If p3 is provided, all other arguments but normal are disregarded.

  • cbe (coords_like (3,3)) – The coordinates of the center and the begin and end points of the arc. The three points should not be colinear. Even then, the problem has always two solutions, depending on the choice of the positive normal on the plane of the three points. Those two solutions form a full circle. The chosen solution is the one that corresponds with a positive normal pointing to the same side of the plane as the specified normal vector. If cbe method is used (and no p3 is provided), all other arguments but normal are disregarded.

  • center (coords_like (3,)) – The center point of the arc.

  • radius (float) – The radius of the arc.

  • normal (coords_like (3,)) – The normal on the plane of the arc. The arc is constructed in the x,y plane and then the z-axis is rotated to the specified normal direction.

  • angles ((float, float)) – The start and end angles of the arc, by default in degrees.

  • angle_spec (float) – A multiplier that turns the angles into radians. The default expects the angles to be degrees.

Examples

Three ways to construct a full unit circle in the x,y plane:

>>> A = Arc(center=[0.,0.,0.], radius=1., angles=(0., 360.))
>>> B = Arc(cbe=[[0.,0.,0.], [1.,0.,0.], [1.,0.,0.]])
>>> C = Arc(p3=[[1.,0.,0.], [-1.,0.,0.], [1.,0.,0.]])
>>> print(A,B,C)
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(0.0, 360.0)
  P0=[1. 0. 0.]; P1=[-1.  0.  0.]; P2=[ 1. -0.  0.]
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(0.0, 360.0)
  P0=[1. 0. 0.]; P1=[-1.  0.  0.]; P2=[1. 0. 0.]
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(0.0, 360.0)
  P0=[1. 0. 0.]; P1=[-1.  0.  0.]; P2=[1. 0. 0.]

Three ways to constructing the right half of that circle:

>>> A = Arc(center=[0.,0.,0.], radius=1., angles=(-90., 90.))
>>> B = Arc(cbe=[[0.,0.,0.], [0.,-1.,0.], [0.,1.,0.]])
>>> C = Arc(p3=[[0.,-1.,0.], [1.,0.,0.], [0.,1.,0.]])
>>> print(A,B,C)
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(270.0, 450.0)
  P0=[-0. -1.  0.]; P1=[ 1. -0.  0.]; P2=[0. 1. 0.]
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(270.0, 450.0)
  P0=[ 0. -1.  0.]; P1=[ 1. -0.  0.]; P2=[0. 1. 0.]
Arc
  Center [0. 0. 0.], Radius 1., Normal [0. 0. 1.]
  Angles=(270.0, 450.0)
  P0=[ 0. -1.  0.]; P1=[1. 0. 0.]; P2=[0. 1. 0.]
property points

Call Coords.points method on the Geometry object’s coords.

See coords.Coords.points() for details.

sub_points(t, j)[source]

Return the points at parameter values t in part j

Parameters:
  • t (float or float array) – One or more parameter values at which to evaluate the point coordinates. Values are usually between 0.0 and 1.0.

  • j (int) – Curve part index for which to find points.

Returns:

Coords – The coordinates of the points on curve part j at parameter values t.

sub_directions(t, j)[source]

Return the directions at parameter values t in part j

Parameters:
  • t (float or float array) – One or more parameter values at which to evaluate the curve’s direction vector. Values are usually between 0.0 and 1.0.

  • j (int) – Curve part index for which to find directions.

Returns:

Coords – The direction vector(s) at parameter values t in curve part j.

approx(ndiv=None, chordal=0.001)[source]

Return a PolyLine approximation of the Arc.

Approximates the Arc by a sequence of inscribed straight line segments.

If ndiv is specified, the arc is divided in precisely ndiv segments.

If ndiv is not given, the number of segments is determined from the chordal distance tolerance. It will guarantee that the distance of any point of the arc to the chordal approximation is less or equal than chordal times the radius of the arc.

17.2. Functions defined in module curve

curve.circle()[source]

Create a BezierSpline approximation of a circle.

Returns:

BezierSpline – A closed BezierSpline through 8 points lying on a circle x,y plane, with its center at (0,0,0) and having a radius 1.

Notes

The result can easily be scaled, translated or rotated to create other circles. It is adequate for drawing circles, though it doesn’t exactly represent a circle.

See also

Arc

create exact representation of circles and arcs.

curve.arc2points(x0, x1, R, pos='-')[source]

Create an arc between two points

Given two points x0 and x1, this constructs an arc with radius R through these points. The two points should have the same z-value. The arc will be in a plane parallel with the x-y plane and wind positively around the z-axis when moving along the arc from x0 to x1.

If pos == ‘-’, the center of the arc will be at the left when going along the chord from x0 to x1, creating an arc smaller than a half-circle. If pos == ‘+’, the center of the arc will be at the right when going along the chord from x0 to x1, creating an arc larger than a half-circle.

If R is too small, an exception is raised.

curve.deCasteljau(P, u)[source]

Compute points on a Bezier curve using deCasteljau algorithm

Parameters:

P is an array with n+1 points defining a Bezier curve of degree n. u is a single parameter value between 0 and 1.

Returns:

A list with point sets obtained in the subsequent deCasteljau approximations. The first one is the set of control points, the last one is the point on the Bezier curve.

This function works with Coords as well as Coords4 points.

curve.splitBezier(P, u)[source]

Split a Bezier curve at parametric values

Parameters:

P is an array with n+1 points defining a Bezier curve of degree n. u is a single parameter value between 0 and 1.

Returns two arrays of n+1 points, defining the Bezier curves of degree n obtained by splitting the input curve at parametric value u. These results can be used with the control argument of BezierSpline to create the corresponding curve.

This works for u < 0 and u > 1, to extend the curve. If u < 0, the left part is returned reverse, if u