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 subsequences 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)