Skip to content

sylva.geo.masks

sylva.geo.masks

Boolean masks over the points of a cloud: polygons, rasters, attribute expressions and distance to another cloud.

Every mask is a boolean array with one entry per point, True where the point is kept. Masks combine with &, | and ~ and index a cloud directly (cloud[mask]). Each mask function has a crop_* companion that returns the kept points in one call, with invert=True to keep the others.

Polygons and rasters are taken in the cloud's coordinate frame. Nothing here reprojects: if a layer is stored in another CRS, reproject the layer or the cloud first.

Polygon dataclass

A polygon: an exterior ring and optional holes, in x, y.

Rings are (K, 2) arrays of vertices in either orientation, open or closed (a repeated first vertex is ignored). Extra columns, such as z, are dropped.

Parameters:

Name Type Description Default
exterior ndarray

(K, 2) vertices of the outer boundary.

required
holes list[ndarray]

(K, 2) vertices of each hole.

list()

Raises:

Type Description
ValueError

If a ring is not a 2-D array with at least two columns.

MultiPolygon dataclass

One feature of a polygon layer: polygons treated as one shape.

A point is inside a multipolygon if it is inside any of its parts. A feature with no parts (a null geometry in the file) contains nothing.

Parameters:

Name Type Description Default
parts list[Polygon]

The polygons.

list()
properties dict

The feature's attributes (.dbf fields or GeoJSON properties).

dict()

Polygons dataclass

A polygon layer, as returned by read_polygons.

Behaves as a sequence of MultiPolygon: len(layer), iteration, layer[i] for one feature, and layer[mask] or layer[[0, 3]] for a sub-layer, e.g. layer[[f.properties["plot"] == 7 for f in layer]].

Parameters:

Name Type Description Default
features list[MultiPolygon]

The features, in file order.

list()
crs str | None

The layer's CRS as stored in the file: the WKT of a shapefile's .prj, or the name in a GeoJSON crs member (for example "urn:ogc:def:crs:EPSG::28355"). It is informative only; coordinates are never reprojected.

None

properties property

properties: list[dict]

The attributes of every feature, in order.

read_polygons

read_polygons(path: str | Path, layer: str | None = None) -> Polygons

Read the polygons of a shapefile or a GeoJSON file.

Parameters:

Name Type Description Default
path str | Path

A .shp file (its .dbf attributes and .prj CRS are read when present), a .geojson or .json file, or a directory holding such files.

required
layer str | None

For a directory, the name of the file to read, without extension ("plots" for plots.shp). It may be omitted when the directory holds a single layer. For a file it must be None or the file's own name.

None

Returns:

Type Description
Polygons

One MultiPolygon per record, with holes and multiple parts as stored. A shapefile's hole is attached to the exterior ring that contains it. Null geometries give features with no parts. Coordinates are as stored in the file, in its CRS.

Raises:

Type Description
OSError

If the file is missing or cannot be parsed.

ValueError

If the file holds points or lines rather than polygons, or its format is not supported.

Notes

No reprojection is done: the polygons must be in the same frame as the clouds they will mask. Polygons.crs reports the file's CRS so that it can be checked.

polygon_index

polygon_index(cloud: PointCloud, polygons) -> np.ndarray

Which polygon each point falls in.

Parameters:

Name Type Description Default
cloud PointCloud

Input points; only x and y are used.

required
polygons

A Polygons layer, a MultiPolygon, a Polygon, a (K, 2) array of vertices (one polygon without holes), or a list of any of these (one feature each).

required

Returns:

Type Description
ndarray

int64, one per point: the index of the first feature containing the point, or -1. Useful to label points with a plot or stand number: layer[i].properties.

Raises:

Type Description
ValueError

If a ring has fewer than three distinct vertices or a non-finite coordinate.

Notes

Polygons are closed sets: a point on an edge or vertex is inside, a point on the boundary of a hole is inside, and only the open interior of a hole is excluded. The test uses exact orientation predicates, so points on edges are classified consistently whatever the edge's slope, and a point on an edge shared by two polygons belongs to both (it is reported for the first). Points with a non-finite x or y are outside.

inside_polygons

inside_polygons(cloud: PointCloud, polygons) -> np.ndarray

Mask of the points whose x, y fall inside any of the polygons.

Parameters:

Name Type Description Default
cloud PointCloud

Input points; only x and y are used.

required
polygons

As for polygon_index: a layer from read_polygons, a Polygon or MultiPolygon, a (K, 2) vertex array, or a list of these.

required

Returns:

Type Description
ndarray

Boolean, one per point. Edges and vertices count as inside (see polygon_index).

Raises:

Type Description
ValueError

If a ring has fewer than three distinct vertices or a non-finite coordinate.

Notes

Polygons are taken in the cloud's frame. There is no reprojection, even when the layer's crs differs from the cloud's; reproject one of them first.

Examples:

>>> from sylva.geo import masks
>>> plots = masks.read_polygons("plots.shp")
>>> keep = masks.inside_polygons(cloud, plots) & (cloud.z > 0)

crop_polygons

crop_polygons(cloud: PointCloud, polygons, invert: bool = False) -> PointCloud

Keep the points inside (or outside) polygons.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
polygons

As for inside_polygons.

required
invert bool

Keep the points outside every polygon instead.

False

Returns:

Type Description
PointCloud

The kept points with all attributes, in their original order.

raster_mask

raster_mask(cloud: PointCloud, raster: Raster, min: float | None = None, max: float | None = None, values: Iterable[float] | None = None) -> np.ndarray

Mask of the points whose raster cell satisfies a condition.

Parameters:

Name Type Description Default
cloud PointCloud

Input points; only x and y are used.

required
raster Raster

Grid in the cloud's frame, e.g. a CHM, a DTM or a classification.

required
min float | None

Keep points whose cell value lies in [min, max] (bounds inclusive; either may be omitted).

None
max float | None

Keep points whose cell value lies in [min, max] (bounds inclusive; either may be omitted).

None
values Iterable[float] | None

Keep points whose cell value equals one of these (compared as float64), e.g. land-cover classes. Give either a range or values. With neither, every point over a valid (non-NaN) cell is kept.

None

Returns:

Type Description
ndarray

Boolean, one per point. Points outside the raster and points over a NaN cell are False.

Raises:

Type Description
ValueError

If both a range and values are given, min > max, a bound is NaN, or the raster's resolution is not positive.

Notes

A point belongs to the cell floor((x - xmin) / resolution), floor((y - ymin) / resolution): cells include their southern and western edges, so a point exactly on the raster's northern or eastern edge is outside.

crop_raster

crop_raster(cloud: PointCloud, raster: Raster, min: float | None = None, max: float | None = None, values: Iterable[float] | None = None, invert: bool = False) -> PointCloud

Keep the points whose raster cell satisfies a condition.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
raster Raster

As for raster_mask.

required
min Raster

As for raster_mask.

required
max Raster

As for raster_mask.

required
values Raster

As for raster_mask.

required
invert bool

Keep the other points instead, including those outside the raster and over NaN cells.

False

Returns:

Type Description
PointCloud

The kept points with all attributes, in their original order.

expression

expression(cloud: PointCloud, expr: str) -> np.ndarray

Mask of the points satisfying an expression over their attributes.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
expr str

A condition such as "height > 2 & classification != 2". It may use:

  • the coordinates x, y, z and any attribute of the cloud by name (the coordinates hide attributes named x, y or z);
  • numbers (2, -0.5, 1e3) and true, false;
  • arithmetic + - * / and unary minus;
  • comparisons < <= > >= == !=, which may be chained (1.3 <= z < 40);
  • membership: classification in (3, 4, 5) and not in;
  • logic: & (or and), | (or or), ! (or not), and parentheses.

& and | bind more loosely than comparisons, so no parentheses are needed around them (unlike NumPy). The expression is parsed and evaluated by the Rust core; it is never run as Python.

required

Returns:

Type Description
ndarray

Boolean, one per point.

Raises:

Type Description
ValueError

On a syntax error (the message gives the position and marks it), an unknown attribute (the message lists the cloud's attributes), or a number used where a condition is needed (height & z > 1).

TypeError

If expr is not a string.

Notes

Values are compared as float64, so integers beyond 2**53 lose precision. Comparisons follow IEEE rules: any comparison with NaN is False except !=. Boolean attributes are conditions in their own right (withheld & z > 1) and count as 0 or 1 in arithmetic.

Examples:

>>> from sylva.geo import masks
>>> keep = masks.expression(cloud, "height > 2 & classification != 2")
>>> canopy = cloud.where("height > 2 & classification != 2")

crop_expression

crop_expression(cloud: PointCloud, expr: str, invert: bool = False) -> PointCloud

Keep the points satisfying an attribute expression.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
expr str

Condition, as for expression.

required
invert bool

Keep the points that do not satisfy it instead.

False

Returns:

Type Description
PointCloud

The kept points with all attributes, in their original order. sylva.PointCloud.where is the same without invert.

near

near(cloud: PointCloud, other, distance: float, horizontal: bool = False) -> np.ndarray

Mask of the points within a distance of another cloud.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
other

Reference points: a ~sylva.PointCloud or an (M, 3) array.

required
distance float

Maximum distance to the nearest point of other (m, inclusive).

required
horizontal bool

Measure the distance in x, y only, ignoring z (for example to keep everything above or below a set of stem points).

False

Returns:

Type Description
ndarray

Boolean, one per point of cloud. With an empty other, all False.

Raises:

Type Description
ValueError

If distance is negative or not finite.

Notes

A k-d tree is built on other and queried for every point in parallel; the answer for each point is its exact nearest distance, so the mask does not depend on the number of threads. Points of other with a non-finite coordinate are ignored, and points of cloud with one are never near. Building the tree takes memory of the order of other.xyz; tens of millions of points on both sides are fine.

crop_near

crop_near(cloud: PointCloud, other, distance: float, horizontal: bool = False, invert: bool = False) -> PointCloud

Keep the points within a distance of another cloud.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
other

As for near.

required
distance

As for near.

required
horizontal

As for near.

required
invert bool

Keep the points farther than distance instead (as difference).

False

Returns:

Type Description
PointCloud

The kept points with all attributes, in their original order.

difference

difference(cloud: PointCloud, other, distance: float, horizontal: bool = False) -> PointCloud

Points of cloud farther than distance from every point of other.

The points that other does not explain: for change detection between two epochs (difference(after, before, 0.05) is what appeared, difference(before, after, 0.05) what was lost), or to remove an already-segmented object from a scene.

Parameters:

Name Type Description Default
cloud PointCloud

Input points.

required
other

Reference points: a ~sylva.PointCloud or an (M, 3) array.

required
distance float

Points at more than this distance from their nearest neighbour in other are kept (m).

required
horizontal bool

Measure the distance in x, y only.

False

Returns:

Type Description
PointCloud

The kept points with all attributes; the same as cloud[~near(cloud, other, distance)], so points with a non-finite coordinate are kept.

Raises:

Type Description
ValueError

If distance is negative or not finite.