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 pC to the uC-vC line.

optiwindnet.geometric.is_same_side(uC: CoordPair, vC: CoordPair, sC: CoordPair, tC: CoordPair, touch_is_cross: bool = True) bool[source]

Check if points sC an tC are on the same side of the line defined by points uC and vC.

Note: often used to check crossings with feeder links, where the feeder link sC-tC is already known to be on a line that crosses the edge uCvC (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:

True if any two of nodesC are on opposite sides of the edge.

optiwindnet.geometric.rotate(coords: CoordPairs, angle: float) CoordPairs[source]

Rotates coords (numpy array T×2) by angle (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() and angle_ccw()

optiwindnet.geometric.find_edges_bbox_overlaps(VertexC: CoordPairs, u: int, v: int, edges: IndexPairs) numpy.typing.NDArray[numpy.int_][source]

Find which edges have 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).

Returns:

True in 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_overlap() first to filter out edges with disjoint bounding boxes (cheaper than the calculations here).

Returns:

True in 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).

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:

True in 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:

True if points in bunch are both inside and outside cone a-o-b

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:

True if 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 VertexC in clockwise or counter-clockwise orientation.

Returns:

The perimeter length.

optiwindnet.geometric.assign_root(A: networkx.Graph) None[source]

Add node attribute ‘root’ with the root closest to each node.

Changes A in-place.

Parameters:

A – available-edges graph

optiwindnet.geometric.get_crossings_map(Edge, VertexC, prune=True)[source]
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]][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

Experimental. Add attributes ‘blocked__’ to edges and nodes.

Edges’ ‘blocked__’ are R-long list of T-long bitarray maps. A 1-bit in position t on the bitarray for root r means the edge crosses the line-of-sight t-r.

Changes A in place. A should have no feeder edges.

Add cosine of the angle wrt each root to all links of A as attribute ‘_cos’.

Changes A in-place. The cosine is of the acute angle between the link line and the line that contains the mid-point of the link and the root (for each root).