LineCollection#

class LineCollection(lines: Iterable[LineString | LinearRing | Iterable[complex]] | MultiLineString | LineCollection | LineString | LinearRing = (), metadata: dict[str, Any] | None = None)#

LineCollection encapsulate a list of piecewise linear lines (or paths). Lines are implemented as 1D numpy arrays of complex numbers whose real and imaginary parts represent the X, respectively Y, coordinates of point in the paths.

An instance of LineCollection is used to model a single layer in vpype’s pipeline. The complete pipeline is modelled by a Document instance, which essentially is a mapping of int (layer ID) to LineCollection.

Although the actual list is stored as private data member in LineCollection instances, the class provides a sequence API similar to list:

>>> import vpype, numpy as np
>>> lc = vpype.LineCollection()
>>> lc.append(np.array([0, 10. + 10.j]))
>>> lc.append(np.array([10.j, 5. + 5.j]))
>>> len(lc)
2
>>> lc[0]
array([ 0. +0.j, 10.+10.j])
>>> for line in lc:
...    print(repr(line))
...
array([ 0. +0.j, 10.+10.j])
array([0.+10.j, 5. +5.j])

In addition to Numpy arrays, the class accepts paths expressed in a variety of format including Python list or Shapely objects:

>>> from shapely.geometry import LineString, LinearRing, MultiLineString
>>> lc = vpype.LineCollection()
>>> lc.append([5, 5+5j])
>>> lc.append(LineString([(1, 1), (3, 2)]))
>>> lc.append(LinearRing([(0, 0), (1, 0), (1, 1), (0, 1)]))
>>> lc.extend(MultiLineString([[(0, 0), (10, 0)], [(4, 4), (0, 4)]]))
>>> lc
LineCollection([array([5.+0.j, 5.+5.j]), array([1.+1.j, 3.+2.j]), array([0.+0.j,
1.+0.j, 1.+1.j, 0.+1.j, 0.+0.j]), array([ 0.+0.j, 10.+0.j]), array([4.+4.j, 0.+4.j])])

Instances can also be converted to Shapely’s MultiLineString:

>>> mls = lc.as_mls()
>>> print(mls)
MULTILINESTRING ((5 0, 5 5), (1 1, 3 2), (0 0, 1 0, 1 1, 0 1, 0 0), (0 0, 10 0),
(4 4, 0 4))

Finally, LineCollection implements a number of operations such as geometrical transformation, cropping, merging, etc. (see member function documentation for details).

Parameters:
  • lines (LineCollectionLike) -- iterable of line (accepts the same input as append()).

  • metadata (dict[str, Any] | None) -- if provided, used as layer metadata

Methods

append

Append a single line.

as_mls

Converts the LineCollection to a MultiLineString.

bounds

Returns the geometries' bounding box.

clone

Creates a new LineCollection with the same metadata.

crop

Crop all lines to a rectangular area.

extend

Append lines from a collection.

filter

Remove lines from the LineCollection for which key returns False.

flip_lines

Flip the direction of all lines.

height

Returns the total height of the geometries.

is_empty

Check for emptiness.

length

Return the total length of the paths.

merge

Merge lines whose endings overlap or are very close.

pen_up_length

Returns statistics on the pen-up distance corresponding to the path.

pen_up_trajectories

Returns a LineCollection containing the pen-up trajectories.

reloop

Randomizes the seam of closed paths.

reverse

Reverse order of the lines.

rotate

Rotates the geometry by angle amount.

scale

Scale the geometry.

segment_count

Returns the total number of segment across all lines.

skew

Skew the geometry by some angular amounts along X and Y axes.

translate

Translates all line by a given offset.

width

Returns the total width of the geometries.

Attributes

lines

Returns the list of line.

Methods#

LineCollection.append(line: LineString | LinearRing | Iterable[complex]) None#

Append a single line.

This function accepts an iterable of complex or a Shapely geometry (LineString or LinearRing).

Parameters:

line (LineLike) -- line to append

Return type:

None

LineCollection.as_mls() MultiLineString#

Converts the LineCollection to a MultiLineString.

Returns:

a MultiLineString Shapely object

Return type:

MultiLineString

LineCollection.bounds() tuple[float, float, float, float] | None#

Returns the geometries’ bounding box.

Returns:

tuple (xmin, ymin, xmax, ymax) for the bounding box or None if the LineCollection is empty

Return type:

tuple[float, float, float, float] | None

LineCollection.clone(lines: Iterable[LineString | LinearRing | Iterable[complex]] | MultiLineString | LineCollection | LineString | LinearRing = ()) LineCollection#

Creates a new LineCollection with the same metadata.

If lines is provided, its content is added to the new LineCollection instance.

Parameters:

lines (Iterable[LineString | LinearRing | Iterable[complex]] | MultiLineString | LineCollection | LineString | LinearRing) -- path to add to the new LineCollection instance

Returns:

the new LineCollection instance

Return type:

LineCollection

LineCollection.crop(x1: float, y1: float, x2: float, y2: float) None#

Crop all lines to a rectangular area.

Parameters:
  • x1 (float) -- first corner of the crop area

  • y1 (float) -- first corner of the crop area

  • x2 (float) -- second corner of the crop area

  • y2 (float) -- second corner of the crop area

Return type:

None

LineCollection.extend(lines: Iterable[LineString | LinearRing | Iterable[complex]] | MultiLineString | LineCollection | LineString | LinearRing) None#

Append lines from a collection.

This function accepts an iterable of iterable of complex, another LineCollection instance, or a Shapely geometry (MultiLineString, LineString or LinearRing).

Shapely’s LineString and LinearRing are occasionally obtained when a MultiLineString is actually expected. As a result, they are accepted as input even though they are not, strictly speaking, a line collection.

Parameters:

lines (LineCollectionLike) -- lines to append

Return type:

None

LineCollection.filter(key: Callable[[ndarray], bool]) None#

Remove lines from the LineCollection for which key returns False.

Parameters:

key (Callable[[ndarray], bool]) -- filter (returns True if the line should be kept or False otherwise)

Return type:

None

LineCollection.flip_lines() None#

Flip the direction of all lines.

Return type:

None

LineCollection.height() float#

Returns the total height of the geometries.

Returns:

the width (ymax - ymin) or 0.0 if the LineCollection is empty

Return type:

float

LineCollection.is_empty() bool#

Check for emptiness.

Returns:

True if the instance does not contain any line, False otherwise.

Return type:

bool

LineCollection.length() float#

Return the total length of the paths.

Returns:

the total length

Return type:

float

LineCollection.merge(tolerance: float, flip: bool = True) None#

Merge lines whose endings overlap or are very close.

Parameters:
  • tolerance (float) -- max distance between line ending that may be merged

  • flip (bool) -- allow flipping line direction for further merging

Return type:

None

LineCollection.pen_up_length() tuple[float, float, float]#

Returns statistics on the pen-up distance corresponding to the path.

The total, mean, and median distance are returned. The pen-up distance is the distance between a path’s end and the next path’s beginning.

Returns:

tuple (total, mean, median) for the pen-up distances

Return type:

tuple[float, float, float]

LineCollection.pen_up_trajectories() LineCollection#

Returns a LineCollection containing the pen-up trajectories.

Return type:

LineCollection

LineCollection.reloop(tolerance: float) None#

Randomizes the seam of closed paths. Paths are considered closed when their first and last point are closer than tolerance.

Parameters:

tolerance (float) -- tolerance to determine if a path is closed

Return type:

None

LineCollection.reverse() None#

Reverse order of the lines.

Return type:

None

LineCollection.rotate(angle: float) None#

Rotates the geometry by angle amount.

The angle is expressed in radian. Positive value rotate clockwise.

The rotation is performed about the coordinates origin (0, 0). To rotate around a specific location, appropriate translations must be performed before and after the scaling:

>>> import vpype
>>> lc = vpype.LineCollection([(-1+1j, 1+1j)])
>>> lc.translate(0, -1)
>>> lc.rotate(1.2)
>>> lc.translate(0, 1)
Parameters:

angle (float) -- rotation angle in rad

Return type:

None

LineCollection.scale(sx: float, sy: float | None = None) None#

Scale the geometry.

The scaling is performed about the coordinates origin (0, 0). To scale around a specific location, appropriate translations must be performed before and after the scaling:

>>> import vpype
>>> lc = vpype.LineCollection([(-1+1j, 1+1j)])
>>> lc.translate(0, -1)
>>> lc.scale(1.2)
>>> lc.translate(0, 1)
>>> lc
LineCollection([array([-1.2+1.j,  1.2+1.j])])
Parameters:
  • sx (float) -- scale factor along x

  • sy (float | None) -- scale factor along y (if None, then sx is used)

Return type:

None

LineCollection.segment_count() int#

Returns the total number of segment across all lines.

Returns:

the total number of segments in the geometries

Return type:

int

LineCollection.skew(ax: float, ay: float) None#

Skew the geometry by some angular amounts along X and Y axes.

The angle is expressed in radians.

The skew is performed about the coordinates origin (0, 0). To rotate around a specific location, appropriate translations must be performed before and after the scaling:

>>> import vpype
>>> lc = vpype.LineCollection([(-1+1j, 1+1j)])
>>> lc.translate(0, -1)
>>> lc.skew(0., 1.2)
>>> lc.translate(0, 1)
Parameters:
  • ax (float) -- skew angle in rad along X axis

  • ay (float) -- skew angle in rad along Y axis

Return type:

None

LineCollection.translate(dx: float, dy: float) None#

Translates all line by a given offset.

Parameters:
  • dx (float) -- offset along X axis

  • dy (float) -- offset along Y axis

Return type:

None

LineCollection.width() float#

Returns the total width of the geometries.

Returns:

the width (xmax - xmin) or 0.0 if the LineCollection is empty

Return type:

float

Attributes#

LineCollection.lines#

Returns the list of line.

Returns:

list of line