Mentions légales du service

Skip to content
Snippets Groups Projects
edge_update.py 5.43 KiB
Newer Older
NADAL Morgane's avatar
NADAL Morgane committed
# Copyright CNRS/Inria/UNS
# Contributor(s): Eric Debreuve (since 2018)
#
# eric.debreuve@cnrs.fr
#
# This software is governed by the CeCILL  license under French law and
# abiding by the rules of distribution of free software.  You can  use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.

import sklgraph.brick.edge as dg_
import sklgraph.brick.node as nd_
import sklgraph.skl_map as sm_
NADAL Morgane's avatar
NADAL Morgane committed

from typing import List, Tuple

import numpy as np_


array_t = np_.ndarray


def AssignNodeIDsToEdges(
    e_nodes: List[nd_.end_node_t],
    e_node_lmap: array_t,
    b_nodes: List[nd_.branch_node_t],
    b_node_lmap: array_t,
    edges: List[dg_.edge_t],
    edge_lmap: array_t,
) -> None:
    #
    # Not uint to allow for subtraction
    edge_parts = sm_.SkeletonPartMap(
        (edge_lmap > 0).astype(np_.int8), check_validity=None
    )

    # ep=edge end point; Leave < 2 since ==0 (length-1 edges) and ==1 (other edges) are needed
    for ep_coords in zip(*(edge_parts < 2).nonzero()):
        edge_label = edge_lmap[ep_coords]
        edge = edges[edge_label - 1]
        e_node_label = e_node_lmap[ep_coords]

        if e_node_label > 0:
            # End node-to-X edge (i.e., edge end point is also an end node)
            _AppendNodeIDToEdge(
                edge,
                np_.zeros(ep_coords.__len__(), dtype=np_.int64),
                e_nodes[e_node_label - 1],
            )
            if edge.sites[0].__len__() == 1:
                # End node-to-branch node edge (and there is a unique non-zero value in b_neighborhood)
                nh_slices_starts, b_neighborhood = _LMapNeighborhood(
                    b_node_lmap, ep_coords
                )
                b_node_label = b_neighborhood.max()
                b_coords = np_.transpose((b_neighborhood == b_node_label).nonzero())[0]
                _AppendNodeIDToEdge(
                    edge, nh_slices_starts.__add__(b_coords), b_nodes[b_node_label - 1]
                )
        else:
            nh_slices_starts, b_neighborhood = _LMapNeighborhood(b_node_lmap, ep_coords)
            force_after = False
            # Looping only for length-1, b-to-b edges
            for b_coords in zip(*b_neighborhood.nonzero()):
                b_node_label = b_neighborhood[b_coords]
                _AppendNodeIDToEdge(
                    edge,
                    nh_slices_starts.__add__(b_coords),
                    b_nodes[b_node_label - 1],
                    force_after=force_after,
                )
                force_after = not force_after


def _AppendNodeIDToEdge(
    edge: dg_.edge_t, b_coords: array_t, node: nd_.node_t, force_after: bool = False
) -> None:
    #
    edge.node_uids.append(node.uid)

    space_dim = b_coords.size
    first_site = tuple(edge.sites[idx_][0] for idx_ in range(space_dim))

    if isinstance(node, nd_.branch_node_t):
        sq_distance = (b_coords.__sub__(first_site) ** 2).sum()

        if sq_distance <= space_dim:
            edge.origin_node = node.uid

        if edge.sites[0].__len__() > 1:
            if sq_distance <= space_dim:
                edge.sites = tuple(
                    np_.hstack((b_coords[idx_], edge.sites[idx_]))
                    for idx_ in range(space_dim)
                )
            else:
                edge.sites = tuple(
                    np_.hstack((edge.sites[idx_], b_coords[idx_]))
                    for idx_ in range(space_dim)
                )
        elif force_after:
            edge.sites = tuple(
                np_.hstack((edge.sites[idx_], b_coords[idx_]))
                for idx_ in range(space_dim)
            )
        else:
            edge.sites = tuple(
                np_.hstack((b_coords[idx_], edge.sites[idx_]))
                for idx_ in range(space_dim)
            )
    #
    elif np_.array_equal(first_site, node.position):
        edge.origin_node = node.uid


def _LMapNeighborhood(lmsk: array_t, site: Tuple[int, ...]) -> Tuple[array_t, array_t]:
    #
    slices_starts = tuple(max(site[idx_] - 1, 0) for idx_ in range(site.__len__()))
    slices = tuple(
        slice(slices_starts[idx_], min(site[idx_] + 2, lmsk.shape[idx_]))
        for idx_ in range(site.__len__())
    )
    neighborhood = lmsk[slices]

    return np_.array(slices_starts, dtype=np_.int64), neighborhood