Boundaries#

Boundary shapes, introduced in Boundary shapes. Boundary, string and layout modifiers are grouped under oowl.modifiers.

Generated boundaries take area as their size in square meters, and shape arguments such as rectangle width and height or ellipse semi-axes fix only proportions. Polygon keeps its source coordinates unless area or center is given. Modifiers may change the area and centroid afterwards.

Boundary()

Abstract wind-farm boundary backed by a Shapely geometry in meters.

Union(boundaries, *[, area])

One logical boundary formed by the geometric union of other boundaries.

Polygon(exterior[, holes, area, center])

Boundary given by explicit vertices or an existing Shapely geometry.

Rectangle([width, height, area, center, ...])

Rectangle whose width and height set only the aspect ratio.

Square(*[, area, center, rotation])

Square of a given area, turned by rotation degrees.

RegularPolygon(n_sides, *[, area, center, ...])

Regular polygon with n_sides sides, at least 3, and a given area.

Circle(*[, area, center, n_segments])

Circle of a given area, drawn as a polygon of n_segments vertices.

Ellipse([semi_major, semi_minor, area, ...])

Ellipse whose semi_major and semi_minor axes set only the shape.

Annulus([outer_radius, inner_radius, area, ...])

Ring whose outer_radius and inner_radius set only the shape.

RadialPolygon(radii[, angular_offsets, ...])

Star-shaped polygon given by the radius and angular step of each vertex.

RandomRadialPolygon([n_vertices, area, ...])

Random star-shaped polygon jittered from a regular n_vertices-gon.

SmoothBlob(*[, area, n_segments, roughness, ...])

Random smooth outline from a low-frequency Fourier radius function.

ConvexHull(*[, area, n_points, center, ...])

Boundary as the hull of random scattered points, convex or concave.

FourierPolygon([model, temperature, ...])

Polygon sampled from a fitted Fourier descriptor model.

OffshorePolygon(*[, area, center, rotation, ...])

Boundary sampled from the morphology of operating offshore wind farms.

Composite(base, modifiers, *[, area])

A base boundary with an ordered chain of boundary modifiers.

Boundary geometries for wind farms.

Concrete boundaries subclass Boundary and wrap a Shapely Polygon or MultiPolygon in meters. Modifiers from oowl.modifiers compose with every boundary. Union merges several boundaries into one logical farm.

class oowl.boundaries.Annulus(outer_radius=1.0, inner_radius=0.4, *, area=None, center=None, n_segments=64)[source]#

Ring whose outer_radius and inner_radius set only the shape.

area is the area of the ring itself, excluding the hole. Each circle has n_segments vertices, rounded down to a multiple of four.

Parameters:
  • outer_radius (float)

  • inner_radius (float)

  • area (float | None)

  • center (Point2D | None)

  • n_segments (int)

class oowl.boundaries.Boundary[source]#

Abstract wind-farm boundary backed by a Shapely geometry in meters.

Subclasses build an unscaled shape about the origin, which is scaled about its centroid to target_area and then moved so its centroid lies at center, where either is set. Placing the shape last keeps a site far from the origin, as in UTM coordinates, as accurate as one at it.

property area: float#

Enclosed area in square meters.

property bounds: tuple[float, float, float, float]#

Axis-aligned bounding box as (min_x, min_y, max_x, max_y) in meters.

property centroid: tuple[float, float]#

Geometric center of mass as (x, y) in meters.

It may lie outside a concave or multipart boundary. See interior_point.

contains(points)[source]#

Test which points lie in the boundary, counting the edge as inside.

Parameters:

points (ArrayLike) – Array-like of shape (N, 2), or one point of shape (2,).

Returns:

Boolean array of length N.

Return type:

numpy.ndarray

Raises:
  • TypeError – For points that are not numbers.

  • ValueError – For another shape or a point that is not finite.

property geometry: Polygon | MultiPolygon#

The Shapely Polygon or MultiPolygon of this boundary, in meters.

Raises TypeError for another geometry type and ValueError for an empty, zero-area or invalid one.

property interior_point: tuple[float, float]#

A point inside the boundary, as (x, y) in meters.

The centroid if contained, otherwise Shapely’s representative point.

metadata()[source]#

JSON-compatible record of this boundary’s type and resolved seed.

Return type:

dict[str, Any]

modify(*modifiers)[source]#

Return a Composite applying modifiers in order.

This boundary is left unchanged.

Parameters:

modifiers (BoundaryModifier)

Return type:

Composite

property parts: tuple[Boundary, ...]#

The boundaries a farm is built from, this one alone without a partition.

plot(ax=None, **kwargs)[source]#

Plot the boundary and return its Matplotlib axes.

Parameters:
Return type:

matplotlib.axes.Axes

class oowl.boundaries.Circle(*, area=None, center=None, n_segments=64)[source]#

Circle of a given area, drawn as a polygon of n_segments vertices.

n_segments is rounded down to a multiple of four.

Parameters:
  • area (float | None)

  • center (Point2D | None)

  • n_segments (int)

class oowl.boundaries.Composite(base, modifiers, *, area=None)[source]#

A base boundary with an ordered chain of boundary modifiers.

Modifiers apply left to right. A chain holds at most one partition, and modifiers after it apply to each partition cell separately. area sets the area of the finished boundary in square meters, None to leave it as the chain makes it. Composing a composite flattens the chains and keeps its area unless area is given. Raises TypeError for a non-boundary base or a non-modifier item.

Resizing a composite whose modifiers are given in meters, such as a setback distance, a partition gap or exclusion zones, resizes the base and re-applies the chain to it, so those stay in meters while the result has the requested area to rounding. Where GEOS’s buffer simplification makes the area jump, the nearest size is kept, within a hundredth of the buffered distance times the edge length. A chain without one scales as a whole with its cells.

Parameters:
modify(*modifiers)[source]#

Return a new composite with modifiers appended to this chain.

Parameters:

modifiers (BoundaryModifier)

Return type:

Composite

property partition_metadata: dict | None#

JSON-compatible record of the partition, or None without one.

property parts: tuple[Boundary, ...]#

Partition cells as boundaries, or this composite alone without one.

class oowl.boundaries.ConvexHull(*, area=None, n_points=20, center=None, concavity=None, seed=None)[source]#

Boundary as the hull of random scattered points, convex or concave.

The default concavity=None gives the exact convex hull. A value in (0, 1] is Shapely’s concave_hull ratio. Smaller values wrap the points more tightly and 1.0 reproduces the convex hull. The shape is always scaled to area.

Parameters:
  • area (float | None) – Realized enclosed area in square meters, None for a unit-size shape to size later.

  • n_points (int) – Number of scattered points to draw, at least 3. A concave hull needs a dense cloud.

  • center (Point2D | None) – Centroid of the realized boundary.

  • concavity (float | None) – None for a convex hull, or a ratio in (0, 1] for a concave one.

  • seed (int | np.random.Generator | None) – Seed or generator for the scattered points, drawn from a standard normal distribution before the hull is moved to center.

Raises:

ValueError – If concavity is outside (0, 1] or not finite, or if the point set admits no valid hull with positive area at that ratio.

class oowl.boundaries.Ellipse(semi_major=1.0, semi_minor=1.0, *, area=None, center=None, rotation=0.0, n_segments=64)[source]#

Ellipse whose semi_major and semi_minor axes set only the shape.

area sets the size and rotation turns the major axis counterclockwise from the x axis, in degrees. The outline has n_segments vertices, rounded down to a multiple of four.

Parameters:
  • semi_major (float)

  • semi_minor (float)

  • area (float | None)

  • center (Point2D | None)

  • rotation (float)

  • n_segments (int)

class oowl.boundaries.FourierPolygon(model=None, *, temperature=2.0, max_attempts=128, area=None, center=None, rotation=None, seed=None)[source]#

Polygon sampled from a fitted Fourier descriptor model.

Each attempt draws PCA scores scaled by temperature, inverse-FFTs the coefficients to a smooth curve, and simplifies it to a vertex count drawn from the model. Invalid results are retried up to max_attempts times, then a RuntimeError is raised. model is a model or .npz path and defaults to the packaged model. The shape is scaled to area and moved to center. A heading is drawn per sample unless rotation pins it in degrees.

Parameters:
  • model (_ShapeModel | str | Path | None)

  • temperature (float)

  • max_attempts (int)

  • area (float | None)

  • center (Point2D | None)

  • rotation (float | None)

  • seed (int | np.random.Generator | None)

class oowl.boundaries.OffshorePolygon(*, area=None, center=None, rotation=None, seed=None, max_attempts=256)[source]#

Boundary sampled from the morphology of operating offshore wind farms.

Sampling is parametric and copies no reference polygon. The shape is scaled to area and moved to center. A heading is drawn per sample unless rotation pins it in degrees. Raises RuntimeError after max_attempts invalid draws.

Parameters:
  • area (float | None)

  • center (Point2D | None)

  • rotation (float | None)

  • seed (int | np.random.Generator | None)

  • max_attempts (int)

class oowl.boundaries.Polygon(exterior, holes=None, *, area=None, center=None)[source]#

Boundary given by explicit vertices or an existing Shapely geometry.

exterior and each of holes are (N, 2) rings in meters, kept as given unless area or center is passed to rescale or move the shape. Invalid geometry is never repaired, and building one raises ValueError naming what is wrong. A non-numeric center raises TypeError, and one other than two finite coordinates ValueError.

Parameters:
  • exterior (ArrayLike)

  • holes (Sequence | None)

  • area (float | None)

  • center (Point2D | None)

classmethod from_geometry(geometry, *, area=None, center=None)[source]#

Construct from a Shapely Polygon or MultiPolygon.

Parameters:
Return type:

Polygon

class oowl.boundaries.RadialPolygon(radii, angular_offsets=None, *, area=None, center=None)[source]#

Star-shaped polygon given by the radius and angular step of each vertex.

Vertex i of the generating shape lies at distance radii[i] from its origin and at the cumulative sum of angular_offsets up to i, in degrees. The offsets are positive and default to equal steps. radii set only the shape, since area sets the size, and center places its centroid, which need not be that origin.

Parameters:
  • radii (Sequence[float])

  • angular_offsets (Sequence[float] | None)

  • area (float | None)

  • center (Point2D | None)

class oowl.boundaries.RandomRadialPolygon(n_vertices=8, *, area=None, radius_jitter=0.35, angular_jitter=0.5, center=None, seed=None)[source]#

Random star-shaped polygon jittered from a regular n_vertices-gon.

Each unit radius is perturbed uniformly by up to radius_jitter and each equal angular step by up to the fraction angular_jitter, before the steps are rescaled to a full turn. Radii stay positive.

Parameters:
  • n_vertices (int)

  • area (float | None)

  • radius_jitter (float)

  • angular_jitter (float)

  • center (Point2D | None)

  • seed (int | np.random.Generator | None)

class oowl.boundaries.Rectangle(width=1.0, height=1.0, *, area=None, center=None, rotation=0.0)[source]#

Rectangle whose width and height set only the aspect ratio.

area sets the size in square meters, None for a unit-size shape to size later, and rotation turns the rectangle counterclockwise about its center, in degrees.

Parameters:
class oowl.boundaries.RegularPolygon(n_sides, *, area=None, center=None, rotation=0.0)[source]#

Regular polygon with n_sides sides, at least 3, and a given area.

The first vertex lies at rotation degrees counterclockwise from the positive x axis.

Parameters:
  • n_sides (int)

  • area (float | None)

  • center (Point2D | None)

  • rotation (float)

class oowl.boundaries.SmoothBlob(*, area=None, n_segments=200, roughness=0.3, n_harmonics=5, center=None, seed=None)[source]#

Random smooth outline from a low-frequency Fourier radius function.

The radius at n_segments equally spaced angles is

\[r(\theta) = 1 + \sum_{k=1}^{K} \frac{\rho\,\xi_k}{k}\sin(k\theta + \phi_k)\]

with K = n_harmonics, roughness \(\rho\), standard-normal \(\xi_k\) and uniform phases \(\phi_k\). The radius is clipped at 0.1 to keep it positive.

Parameters:
  • area (float | None)

  • n_segments (int)

  • roughness (float)

  • n_harmonics (int)

  • center (Point2D | None)

  • seed (int | np.random.Generator | None)

class oowl.boundaries.Square(*, area=None, center=None, rotation=0.0)[source]#

Square of a given area, turned by rotation degrees.

Parameters:
  • area (float | None)

  • center (Point2D | None)

  • rotation (float)

class oowl.boundaries.Union(boundaries, *, area=None)[source]#

One logical boundary formed by the geometric union of other boundaries.

Overlapping members merge into a single polygon. Disconnected members remain components of one MultiPolygon farm. Each member is scaled to its own area before the union. area then scales the union to that many square meters, None to keep the members’ sizes.

Resizing a union with a member whose modifiers are given in meters, such as a setback distance, a partition gap or exclusion zones, scales the bases of all members by one factor about the centroid of the union and re-applies their chains, so those stay in meters while the result has the requested area, as for a Composite. A union without one scales as a whole.

Parameters: