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
|
|
required |
holes
|
list[ndarray]
|
|
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 ( |
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
|
None
|
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 |
required |
layer
|
str | None
|
For a directory, the name of the file to read, without extension
( |
None
|
Returns:
| Type | Description |
|---|---|
Polygons
|
One |
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 |
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:
|
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 |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Boolean, one per point. Edges and vertices count as inside (see
|
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 |
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 |
None
|
max
|
float | None
|
Keep points whose cell value lies in |
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 |
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 |
required |
min
|
Raster
|
As for |
required |
max
|
Raster
|
As for |
required |
values
|
Raster
|
As for |
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
|
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 ( |
TypeError
|
If |
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 |
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.
|
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 |
required | |
distance
|
float
|
Maximum distance to the nearest point of |
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 |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
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 |
required | |
distance
|
As for |
required | |
horizontal
|
As for |
required | |
invert
|
bool
|
Keep the points farther than |
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 |
required | |
distance
|
float
|
Points at more than this distance from their nearest neighbour in
|
required |
horizontal
|
bool
|
Measure the distance in x, y only. |
False
|
Returns:
| Type | Description |
|---|---|
PointCloud
|
The kept points with all attributes; the same as
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |