optiwindnet.crossings ===================== .. py:module:: optiwindnet.crossings Module Contents --------------- .. py:function:: get_interferences_list(Edge: numpy.ndarray, VertexC: numpy.ndarray, fnT: numpy.ndarray | None = None, EPSILON=1e-15) -> list[tuple[tuple[int, int, int, int], int | None]] List all crossings between edges in the `Edge` (E×2) numpy array. Coordinates must be provided in the `VertexC` (V×2) array. `Edge` contains indices to VertexC. If `Edge` includes detour nodes (i.e. indices go beyond `VertexC`'s length), `fnT` translation table must be provided. Should be used when edges are not limited to the expanded Delaunay set. :returns: ((4 vertices of the two edges involved), one of the vertices or None) the last tuple element indicates the index (0..3) of the vertex that lays exactly on the edge in cases of touching (not crossing) :rtype: list of interferences, where each interference is .. py:function:: edge_conflicts(u: int, v: int, diagonals: bidict.bidict) -> collections.abc.Iterator[tuple[int, int]] Iterate over edges conflicting with (u, v). :param u: node :param v: node :param diagonals: map of crossings Delaunay<->diagonals .. py:function:: edge_crossings(u: int, v: int, G: networkx.Graph, diagonals: bidict.bidict) -> list[tuple[int, int]] .. py:function:: edgeset_edgeXing_iter(diagonals: bidict.bidict) -> collections.abc.Iterator[list[tuple[int, int]]] Iterator over all edge crossings in an expanded Delaunay edge set `A`. Each crossing is a 2 or 3-tuple of (u, v) edges. Does not include gates. .. py:function:: gateXing_iter(G: networkx.Graph, *, hooks: collections.abc.Iterable | None = None, touch_is_cross: bool = True) -> collections.abc.Iterator[tuple[tuple[int, int], tuple[int, int]]] Iterate over all crossings between gates and edges/borders in G. If `hooks` is `None`, all nodes that are not a root neighbor are considered. Used in constraint generation for ILP model. :param G: Routeset or edgeset (A) to examine. :param hooks: Nodes to check, grouped by root in sub-sequences from root `-R` to `-1`. If `None`, all non-root nodes are checked using `'root'` node attribute. :param touch_is_cross: If `True`, count as crossing a gate going over a node. :Yields: Pair of (edge, gate) that cross (each a 2-tuple of nodes). .. py:function:: validate_routeset(G: networkx.Graph) -> list[tuple[int, int, int, int]] Validate G's tree topology and absence of crossings. Check if the routeset represented by G's edges is topologically sound, repects capacity and has no edge crossings nor branch splitting. :param G: graph to evaluate :returns: list of crossings/splits, G is valid if an empty list is returned Example:: Xings = validate_routeset(G) for u, v, s, t in Xings: if u != v: print(f'{u}–{v} crosses {s}–{t}') else: print(f'detour @ {u} splits {s}–{v}–{t}') .. py:function:: find_geometric_crossings(G: networkx.Graph, *, include_touches: bool = False, length_tol: float = 1e-12, angle_tol: float = 1e-10, endpoint_tol: float = 1e-09) -> list[dict] Find route intersections in a routeset using Shapely geometries. Geometry-first diagnostic complement to :func:`validate_routeset` and :func:`list_edge_crossings`. Unlike :func:`list_edge_crossings`, which only detects crossings between extended-Delaunay edges (i.e. it requires a routeset built from ``A``, OptiWindNet's available-edges graph), this routine works on **any** routeset graph that exposes ``VertexC`` (and ``fnT`` if it carries contour or detour clones). It can therefore validate routes produced by external tools, hand-built test graphs, or post-edited OptiWindNet results — at the cost of a heavier geometry-based check. Polylines are extracted from ``G`` (one per feeder, plus one per junction-to-junction link) and translated through ``fnT`` so that contour and detour clones are tested at their prime coordinates. :param G: routeset graph. Must have graph attributes ``T``, ``R``, ``B``, and ``VertexC``; ``fnT`` is required iff ``C > 0`` or ``D > 0``. :param include_touches: also report point contacts that are not proper crossings (otherwise touches are silently dropped). :param length_tol: collinear overlaps shorter than this are not classified. :param angle_tol: minimum cross-product magnitude used to deduplicate co-directional rays in the local crossing test. :param endpoint_tol: distance below which an intersection point is treated as coincident with a path endpoint, shared node, or detour-split prime. :returns: - ``kind``: one of - ``'cross'``: two polylines cross at one or more isolated points; - ``'overlap_cross'``: two polylines share a sub-run and exit the overlap on opposite sides at both ends (a true cross expressed as a coincident segment); - ``'branch_split'``: a detour-clone whose prime is a real terminal cuts that terminal's subtree into pieces; - ``'touch'`` (only when ``include_touches=True``): point contact that is not classified as a cross (e.g. tangent kiss). - ``path_nodes_a``, ``path_nodes_b``: the raw polyline node sequences. - ``path_a``, ``path_b``: canonical prime-path tuples (sorted so that ``path_a < path_b`` lexicographically). - ``geometry``: WKT string of the offending Shapely geometry (Point, MultiPoint, LineString, MultiLineString, …). :rtype: One dict per finding, with keys .. py:function:: list_edge_crossings(S: networkx.Graph, A: networkx.Graph) -> list[tuple[tuple[int, int], tuple[int, int]]] List edge×edge crossings for the network topology in S. `S` must only use extended Delaunay edges. It will not detect crossings of non-extDelaunay gates or detours. :param S: solution topology :param A: available edges used in creating `S` :returns: list of 2-tuple (crossing) of 2-tuple (edge, ordered)