optiwindnet.geometric¶
Module Contents¶
- optiwindnet.geometric.triangle_AR(base1C: CoordPair, base2C: CoordPair, topC: CoordPair) float[source]¶
Calculate the ratio: dist(base1, base2)/dist(base, top).
Numerator is the length of the base of the triagle (base1C, base2C).
Denominator is the distance from point topC to the base line.
- Parameters:
uC – triangle vertices coordinates as (2,) numpy arrays
vC – triangle vertices coordinates as (2,) numpy arrays
tC – triangle vertices coordinates as (2,) numpy arrays
- Returns:
Aspect ratio of the triangle defined by the three 2D points.
- optiwindnet.geometric.point_d2line(pC: CoordPair, uC: CoordPair, vC: CoordPair) numpy.float64[source]¶
Calculate the distance from point
pCto theuC-vCline.
- optiwindnet.geometric.is_same_side(uC: CoordPair, vC: CoordPair, sC: CoordPair, tC: CoordPair, touch_is_cross: bool = True) bool[source]¶
Check if points
sCandtCare on the same side of the line defined by pointsuCandvC.Note: often used to check crossings with feeder links, where the feeder link
sC-tCis already known to be on a line that crosses the edgeuC–vC(using the angle rank).
- optiwindnet.geometric.any_pairs_opposite_edge(nodesC: CoordPairs, uC: CoordPair, vC: CoordPair, margin: float = 0.0) bool[source]¶
Compare relative position of vertices wrt line segment.
- Parameters:
nodesC – (N, 2) array of test coordinates
uC – (2,) array of coordinates of edge ends
vC – (2,) array of coordinates of edge ends
- Returns:
Trueif any two ofnodesCare on opposite sides of the edge.
- optiwindnet.geometric.rotate(coords: CoordPairs, angle: float) CoordPairs[source]¶
Rotate
coords(numpy array T×2) byangle(degrees).
- optiwindnet.geometric.angle_numpy(aC: CoordPairs, pivotC: CoordPairs, bC: CoordPairs) numpy.ndarray[tuple[int], numpy.dtype[numpy.float64]][source]¶
Calculate the angle a-pivot-b.
can operate on multiple point triplets
angle is within ±π (shortest arc from a to b around pivot)
positive direction is counter-clockwise
- Parameters:
aC – (N, 2) numpy arrays of coordinate pairs
pivotC – (N, 2) numpy arrays of coordinate pairs
bC – (N, 2) numpy arrays of coordinate pairs
- Returns:
Angles a-pivot-b (radians)
- optiwindnet.geometric.angle(aC, pivotC, bC)[source]¶
Calculate the angle aC-pivotC-bC.
angle is within ±π (shortest arc from a to b around pivot)
positive direction is counter-clockwise
- Parameters:
aC – (2,) numpy arrays of coordinate pairs
pivotC – (2,) numpy arrays of coordinate pairs
bC – (2,) numpy arrays of coordinate pairs
- Returns:
Angle aC-pivotC-bC (radians)
- optiwindnet.geometric.angle_helpers(L: networkx.Graph, include_borders: bool = True) tuple[numpy.typing.NDArray[numpy.float64], numpy.typing.NDArray[numpy.int_], list[dict[int, int]]][source]¶
Create auxiliary arrays of node attributes based on polar coordinates.
The ranks of the angles and calculated per root and start from 0. The duplicates mapping is a list of dicts and is indexed first by the root.
- Parameters:
L – location (also works with A or G)
- Returns:
Tuple of (
angle__,angle_rank__,dups_from_root_rank__)
- optiwindnet.geometric.angle_oracles_factory(angle__: numpy.typing.NDArray[numpy.float64], angle_rank__: numpy.typing.NDArray[numpy.int_]) tuple[Callable[[int, int, int, int, int, int, int], tuple[int, int]], Callable[[int, int, int], float]][source]¶
Make functions to answer queries about relative angles.
Inputs are the outputs of
angle_helpers().- Parameters:
angle__ – (T, R)-array of angles wrt root (+-pi)
angle_rank__ – (T, R)-array of the relative placement of angles
- Returns:
union_limits()andangle_ccw()
- optiwindnet.geometric.find_edges_bbox_overlaps(VertexC: CoordPairs, u: int, v: int, edges: IndexPairs) numpy.typing.NDArray[numpy.int_][source]¶
Find which
edgeshave a bounding box overlap with ⟨u, v⟩.This is a preliminary filter for crossing checks. Enables avoiding the more costly geometric crossing calculations for segments that are clearly disjoint.
- Parameters:
VertexC – (N×2) point coordinates
u – indices of probed edge
v – indices of probed edge
edges – list of index pairs representing edges to check against
- Returns:
numpy array with the indices of overlaps in
edges
- optiwindnet.geometric.is_crossing_numpy(u, v, s, t)[source]¶
Checks if (u, v) crosses (s, t).
Parallel or collinear segments (including superposition) are not considered crossings. Touching segments (including common endpoints) are considered crossings.
- Returns:
Truein case of crossing.
- optiwindnet.geometric.is_crossing_no_bbox(uC: CoordPair, vC: CoordPair, sC: CoordPair, tC: CoordPair) bool[source]¶
Checks if (
uC,vC) crosses (sC,tC).Does not check for bounding-box overlap. Use
find_edges_bbox_overlaps()first to filter out edges with disjoint bounding boxes (cheaper than the calculations here).Parallel or collinear segments (including superposition) are not considered crossings. Touching segments (including common endpoints) are considered crossings.
- Returns:
Truein case of crossing.
- optiwindnet.geometric.is_crossing(uC: CoordPair, vC: CoordPair, sC: CoordPair, tC: CoordPair, touch_is_cross: bool = True) bool[source]¶
Checks if (uC, vC) crosses (sC, tC).
Parallel or collinear segments (including superposition) are not considered crossings. For non-parallel segments, behavior for touching points (including common endpoints) is determined by
touch_is_cross.- Parameters:
uC – (2,) numpy array coordinates of edge ends
vC – (2,) numpy array coordinates of edge ends
sC – (2,) numpy array coordinates of edge ends
tC – (2,) numpy array coordinates of edge ends
touch_is_cross – whether to consider any common point as a crossing
- Returns:
Truein case of crossing.
- optiwindnet.geometric.is_bunch_split_by_corner(bunch, a, o, b, margin=0.001)[source]¶
Check if a cone splits a bunch of points in two sets.
- Parameters:
bunch – numpy array of points (T×2)
a – points that define the cone’s angle
o – points that define the cone’s angle
b – points that define the cone’s angle
- Returns:
Trueif points inbunchare both inside and outside conea-o-b
- optiwindnet.geometric.point_to_segment_distance(pC: numpy.ndarray, aC: numpy.ndarray, bC: numpy.ndarray) float[source]¶
Calculate the distance from point
pCto the closed segmentaC-bC.The projection of
pConto the line throughaCandbCis clamped to the segment, so the result is the distance to the nearest endpoint when the foot of the perpendicular lies outside the segment. For an unclamped line distance, seepoint_d2line().- Parameters:
pC – query point coordinates as a (2,) numpy array
aC – segment endpoint coordinates as (2,) numpy arrays
bC – segment endpoint coordinates as (2,) numpy arrays
- Returns:
Euclidean distance from
pCto the closest point on the segment.
- optiwindnet.geometric.unique_rays(rays: list[numpy.ndarray], angle_tol: float) list[numpy.ndarray][source]¶
Deduplicate 2D rays by direction; anti-parallel rays are kept distinct.
Two rays are considered duplicates when their unit vectors are parallel and point the same way: cross-product magnitude ≤
angle_toland dot product ≥ 0. Rays with zero norm are dropped.- Parameters:
rays – rays from a shared origin, each a (2,) numpy array
angle_tol – maximum unit cross-product magnitude treated as parallel
- Returns:
List of unit-length (2,) numpy arrays, one per distinct direction.
- optiwindnet.geometric.polyline_rays_at_point(coords: numpy.ndarray, pC: numpy.ndarray, *, tol: float, angle_tol: float) list[numpy.ndarray][source]¶
Get the local rays of a polyline at a point lying on (or near) it.
For each segment whose perpendicular distance to
pCis at mosttol, rays frompCtoward each segment endpoint that sits farther thantolfrompCare collected, then deduplicated by direction viaunique_rays(). The result is empty ifpCis far from every segment, has at most one ray whenpCis at an endpoint of an extreme segment, or two anti-parallel rays whenpCis interior to a segment.- Parameters:
coords – polyline vertices as an (N, 2) numpy array
pC – query point coordinates as a (2,) numpy array
tol – distance threshold for treating
pCas on a segment or at an endpointangle_tol – passed through to
unique_rays()for direction dedup
- Returns:
List of unit-length (2,) numpy arrays, the directions from
pCalong the polyline atpC.
- optiwindnet.geometric.rays_alternate(rays_a: list[numpy.ndarray], rays_b: list[numpy.ndarray]) bool[source]¶
Check whether two ray sets interleave cyclically around the origin.
Picks every 2-ray pair from each set, orders the four rays by polar angle, and checks for the cyclic label pattern ABAB (or BABA). When found, set
aand setbseparate one another — the geometric definition of a crossing at the shared origin. ReturnsFalsewhen either set has fewer than 2 rays.- Parameters:
rays_a – 2D rays from a shared origin, each a (2,) numpy array
rays_b – 2D rays from a shared origin, each a (2,) numpy array
- Returns:
Trueif some 2-ray pairs fromrays_aandrays_balternate around the origin in cyclic order.
- optiwindnet.geometric.polylines_cross_at_point(coords_a: numpy.ndarray, coords_b: numpy.ndarray, pC: numpy.ndarray, *, tol: float, angle_tol: float) bool[source]¶
Check whether two polylines cross each other at a given point.
Returns
FalsewhenpCis withintolof any vertex of either polyline — those cases are ambiguous and the caller is expected to classify them separately (e.g. via shared-node or endpoint filters). Otherwise extracts the local rays atpCfor each polyline (viapolyline_rays_at_point()) and tests whether they alternate (viarays_alternate()).- Parameters:
coords_a – polyline vertices as (N, 2) and (M, 2) numpy arrays
coords_b – polyline vertices as (N, 2) and (M, 2) numpy arrays
pC – query point coordinates as a (2,) numpy array, expected to lie on the geometric intersection of the two polylines
tol – distance threshold for vertex-coincidence and segment-membership
angle_tol – minimum unit cross-product magnitude used during ray dedup
- Returns:
Truewhen the polylines cross transversely atpC.
- optiwindnet.geometric.is_triangle_pair_a_convex_quadrilateral(uC: CoordPair, vC: CoordPair, sC: CoordPair, tC: CoordPair) bool[source]¶
Check convexity of quadrilateral.
⟨u, v⟩ is the common side; ⟨s, t⟩ are the opposing vertices; only works if ⟨s, t⟩ crosses the line defined by ⟨u, v⟩
- Returns:
Trueif the quadrilateral is convex and is not a triangle
- optiwindnet.geometric.perimeter(VertexC, vertices_ordered)[source]¶
Calculate the perimeter of the polygon defined by
vertices_ordered.- Parameters:
vertices_ordered – indices of
VertexCin clockwise or counter-clockwise orientation.- Returns:
The perimeter length.
- optiwindnet.geometric.complete_graph(G_base: networkx.Graph, *, include_roots: bool = False, prune: bool = True, map_crossings: bool = False) networkx.Graph[source]¶
Create a complete graph based on
G_base.Produces a networkx Graph connecting all non-root nodes to every other non-root node. Edges with an arc > pi/2 around root are discarded The length of each edge is the euclidean distance between its vertices.
- optiwindnet.geometric.minimum_spanning_forest(A: networkx.Graph) networkx.Graph[source]¶
Create the minimum spanning forest from the Delaunay edges of
A.There is one tree for each root and exactly one root per tree. If the graph has more than one root, the minimum spanning tree of the entire graph is split on its longest links between each root pair.
- Returns:
Topology S containing the forest.
- optiwindnet.geometric.rotation_checkers_factory(VertexC: CoordPairs) tuple[Callable[[int, int, int], bool], Callable[[int, int, int], bool], Callable[[int, int, int], float]][source]¶
- optiwindnet.geometric.rotating_calipers(convex_hull: numpy.typing.NDArray, metric: str = 'height') tuple[numpy.typing.NDArray[numpy.int_], float, float, CoordPairs][source]¶
Find the shortest width of a polygon.
Reference: Toussaint, Godfried T. “Solving geometric problems with the rotating calipers.” Proc. IEEE Melecon. Vol. 83. 1983.
- Parameters:
convex_hull – (H, 2) array of coordinates of the convex hull in counter-clockwise order
metric – what should be minimized, one of {
'height','area'}
- Returns:
best_calipers,best_caliper_angle,best_metric,bbox
- optiwindnet.geometric.area_from_polygon_vertices(X: numpy.ndarray, Y: numpy.ndarray) float[source]¶
Calculate the area enclosed by the polygon with the vertices (x, y).
Vertices must be in sequence around the perimeter (either clockwise or counter-clockwise).
- Parameters:
X – array of X coordinates
Y – array of Y coordinates
- Returns:
area