Module sverchok.utils.geom_2d.make_monotone

Expand source code
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE

from sverchok.utils.avl_tree import AVLTree
from .dcel import Point as Point_template, HalfEdge as HalfEdge_template, DCELMesh as DCELMesh_template
from .sort_mesh import SortPointsUpDown, SortHalfEdgesCCW, SortEdgeSweepingAlgorithm

from .dcel_debugger import Debugger


def monotone_sv_face_with_holes(vert_face, vert_holes=None, face_holes=None, accuracy=1e-5):
    """
    Get one face in Sverhok format and splitting it into monotone pieces
    Vertices of face should be given in ordered along face indexes order
    Also it is possible to create holes in input face
    Mesh of holes should be inside face without any intersection
    :param vert_face: 
    :param vert_holes: 
    :param face_holes: 
    :param accuracy: two floats figures are equal if their difference is lower then accuracy value, float
    :return: vertices in Sverchok format, faces in Sverchok format
    """
    mesh = DCELMesh(accuracy)
    mesh.from_sv_faces(vert_face, [list(range(len(vert_face)))])
    main_face = mesh.faces[0]  # once this will be broken
    if vert_holes and face_holes:
        main_face.insert_holes(vert_holes, face_holes)
    make_monotone(main_face)
    rebuild_face_list(mesh)
    return mesh.to_sv_mesh(edges=False, only_select=True)


def monotone_faces_with_holes(dcel_mesh, del_flag='del'):
    """
    Split polygons with holes into monotone pieces of DCEL mesh data structure
    Faces already should have actual information about inner component
    :param dcel_mesh: DCELMesh
    :param del_flag: faces with such flag just are just ignore by the algorithm
    :return: DCELMesh with split faces
    """
    is_inners = False
    for face in dcel_mesh.faces:
        if del_flag in face.flags:
            continue
        elif face.outer and face.inners:
            is_inners = True
            make_monotone(face)
    if is_inners:
        rebuild_face_list(dcel_mesh)
    return dcel_mesh


# #############################################################################
# ########### - partitioning to monotone pieces algorithm - ###################
# #############################################################################


x, y, z = 0, 1, 2


class Point(Point_template, SortPointsUpDown):
    monotone_current_face = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._type = None
        self._monotone_face = None

    @property
    def type(self):
        # the type should be updated each time when polygon is changed in partitioning algorithm
        # during handle of polygon point does not change type
        face = self.monotone_face
        if not self._type:
            hedge = None  # is hedge with origin in the point and belonging to current monotone face
            for coin_hedge in self.hedge.ccw_hedges:
                if coin_hedge.face == face:
                    hedge = coin_hedge
                    break
            if not hedge:
                raise LookupError("This mean that either monotone face is marked incorrect or "
                                  "coincidence half edges are marked incorrect or something else")
            next_point = hedge.next.origin
            last_point = hedge.last.origin
            is_up_next = next_point < self  # the less point the upper it is
            is_up_last = last_point < self
            if not is_up_next and not is_up_last:
                self._type = 'start' if hedge < hedge.last.twin else 'split'
            elif is_up_last and is_up_next:
                self._type = 'merge' if hedge > hedge.last.twin else 'end'
            else:
                self._type = 'regular'
        return self._type

    @property
    def monotone_face(self):
        # returns face coincidence to a point which is handling by the algorithm
        if not self.monotone_current_face:
            raise Exception('Which polygon is handling should be set before')
        elif self._monotone_face != self.monotone_current_face:
            self._monotone_face = self.monotone_current_face
            self._type = None
        return self._monotone_face


class HalfEdge(HalfEdge_template, SortHalfEdgesCCW):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.edge = None


class DCELMesh(DCELMesh_template):
    Point = Point
    HalfEdge = HalfEdge


class Edge(SortEdgeSweepingAlgorithm):

    def __init__(self, up_p, low_p):
        super().__init__(up_p, low_p)

        self.helper = None


def make_monotone(face):
    """
    Splits polygon into monotone pieces optionally with holes
    :param face: face of half edge data structure
    :return new half edges
    Probably approach of implementation of monotone algorithm should be reconsidered according new DCEL data structure
    """
    face.mesh.Point.monotone_current_face = face
    status = AVLTree()
    q = sorted(build_points_list(face))[::-1]
    _ = [p.type for p in q]  # not very cool but this will set type for all points before main algorithm
    while q:
        event_point = q.pop()
        Edge.global_event_point = event_point
        handle_functions[event_point.type](event_point, status, find_hedge(event_point))


def build_points_list(face):
    # build list of points for partitioning algorithm, all point of outer and inners components
    verts = []
    for hedge in face.outer.loop_hedges:
        verts.append(hedge.origin)
    for inner_hedge in face.inners:
        for hedge in inner_hedge.loop_hedges:
            verts.append(hedge.origin)
    return verts


def find_hedge(point):
    # find hedge with origin in current point and with partitioning face
    for hedge in point.hedge.ccw_hedges:
        if hedge.face == point.monotone_face:
            break
    return hedge


def rebuild_face_list(dcel_mesh):
    # rebuild face list after partition algorithm
    # this function should correct boundless face but it does not !!!!
    for hedge in dcel_mesh.hedges:
        if hedge.face:
            continue
        face = dcel_mesh.Face(dcel_mesh)
        face.select = True
        face.outer = hedge
        for h in hedge.loop_hedges:
            h.face = face
    used = set()
    faces = []
    for hedge in dcel_mesh.hedges:
        if hedge.face == dcel_mesh.unbounded:
            continue
        if hedge not in used:
            faces.append(hedge.face)
            [used.add(h) for h in hedge.loop_hedges]
    dcel_mesh.faces = faces


def insert_edge(up_p, low_p):
    # insert new edge into half edge data structure
    up_hedge = up_p.mesh.HalfEdge(up_p.mesh, up_p)
    up_p.mesh.hedges.append(up_hedge)
    low_hedge = up_p.mesh.HalfEdge(up_p.mesh, low_p)
    up_p.mesh.hedges.append(low_hedge)
    up_hedge.twin = low_hedge
    low_hedge.twin = up_hedge
    up_p_hedge = find_hedge(up_p)
    low_p_hedge = find_hedge(low_p)

    up_ccw_hedges = []
    status = 1
    for h in up_p_hedge.ccw_hedges:
        up_ccw_hedges.append(h)
        if h.twin.face and h.twin.face == up_p_hedge.face:
            status -= 1
            break
    if status != 0:
        raise Exception('Hedge ({}) does not have neighbour with the same face'.format(up_p_hedge))

    if len(up_ccw_hedges) == 2:
        up_next = up_ccw_hedges[0]
    elif 2 < len(up_ccw_hedges) < 5:
        if up_ccw_hedges[0] > up_hedge:
            if ((up_ccw_hedges[2] < up_hedge and up_ccw_hedges[2] < up_ccw_hedges[0]) or
                    (up_ccw_hedges[2] > up_hedge and up_ccw_hedges[2] > up_ccw_hedges[0])):
                up_next = up_ccw_hedges[2]
            elif ((up_ccw_hedges[1] < up_hedge and up_ccw_hedges[1] < up_ccw_hedges[0]) or
                    (up_ccw_hedges[1] > up_hedge and up_ccw_hedges[1] > up_ccw_hedges[0])):
                up_next = up_ccw_hedges[1]
            else:
                up_next = up_ccw_hedges[0]
        else:
            up_next = up_ccw_hedges[1] if up_ccw_hedges[0] < up_ccw_hedges[1] < up_hedge else up_ccw_hedges[0]
    else:
        raise Exception('Unexpected number of half edges in point {}'.format(up_p))

    low_ccw_hedges = []
    status = 1
    for h in low_p_hedge.ccw_hedges:
        low_ccw_hedges.append(h)
        if h.twin.face and h.twin.face == low_p_hedge.face:
            status -= 1
            break
    if status != 0:
        raise Exception('Hedge ({}) does not have neighbour with the same face'.format(low_p.hedge.i))

    if len(low_ccw_hedges) == 2:
        low_next = low_ccw_hedges[0]
    elif len(low_ccw_hedges) == 3:
        if low_ccw_hedges[0] > low_hedge:
            if ((low_ccw_hedges[0] > low_ccw_hedges[1] < low_hedge) or
                    (low_ccw_hedges[0] < low_ccw_hedges[1] > low_hedge)):
                low_next = low_ccw_hedges[1]
            else:
                low_next = low_ccw_hedges[0]
        else:
            low_next = low_ccw_hedges[1] if low_ccw_hedges[0] < low_ccw_hedges[1] < low_hedge else low_ccw_hedges[0]
    else:
        raise Exception('Unexpected number of half edges in point {}'.format(low_p))
    up_hedge.last = up_next.last
    up_hedge.next = low_next
    low_hedge.next = up_next
    low_hedge.last = low_next.last
    up_next.last.next = up_hedge
    up_next.last = low_hedge
    low_next.last.next = low_hedge
    low_next.last = up_hedge
    if hasattr(up_hedge, 'in_faces'):
        # actually this part related with merge mesh algorithm only
        up_hedge.in_faces = set(up_hedge.next.in_faces)
        low_hedge.in_faces = set(low_hedge.next.in_faces)


def handle_start_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    edge = Edge(point, hedge.twin.origin)
    hedge.edge = edge
    hedge.twin.edge = edge
    edge.helper = point
    status.insert(edge)


def handle_end_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    status.remove(hedge.last.edge)
    helper = hedge.last.edge.helper
    if helper.type == 'merge':
        insert_edge(helper, point)


def handle_split_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    left_node = status.find_nearest_left(point.co[x])
    insert_edge(left_node.key.helper, point)
    left_node.key.helper = point
    edge = Edge(point, hedge.twin.origin)
    hedge.edge = edge
    hedge.twin.edge = edge
    edge.helper = point
    status.insert(edge)


def handle_merge_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    right_helper = hedge.last.edge.helper
    last_hedge = hedge.last
    if right_helper.type == 'merge':
        insert_edge(right_helper, point)
    status.remove(last_hedge.edge)
    left_node = status.find_nearest_left(point.co[x])
    left_helper = left_node.key.helper
    if left_helper.type == 'merge':
        insert_edge(left_helper, point)
    left_node.key.helper = point


def handle_regular_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    if point < hedge.twin.origin:
        right_helper = hedge.last.edge.helper
        status.remove(hedge.last.edge)
        edge = Edge(point, hedge.twin.origin)
        hedge.edge = edge
        hedge.twin.edge = edge
        edge.helper = point
        status.insert(edge)
        if right_helper.type == 'merge':
            insert_edge(right_helper, point)
    else:
        left_node = status.find_nearest_left(point.co[x])
        left_helper = left_node.key.helper
        left_node.key.helper = point
        if left_helper.type == 'merge':
            insert_edge(left_helper, point)


handle_functions = {'start': handle_start_point, 'end': handle_end_point, 'split': handle_split_point,
                    'merge': handle_merge_point, 'regular': handle_regular_point}

Functions

def build_points_list(face)
Expand source code
def build_points_list(face):
    # build list of points for partitioning algorithm, all point of outer and inners components
    verts = []
    for hedge in face.outer.loop_hedges:
        verts.append(hedge.origin)
    for inner_hedge in face.inners:
        for hedge in inner_hedge.loop_hedges:
            verts.append(hedge.origin)
    return verts
def find_hedge(point)
Expand source code
def find_hedge(point):
    # find hedge with origin in current point and with partitioning face
    for hedge in point.hedge.ccw_hedges:
        if hedge.face == point.monotone_face:
            break
    return hedge
def handle_end_point(point, status, hedge)
Expand source code
def handle_end_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    status.remove(hedge.last.edge)
    helper = hedge.last.edge.helper
    if helper.type == 'merge':
        insert_edge(helper, point)
def handle_merge_point(point, status, hedge)
Expand source code
def handle_merge_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    right_helper = hedge.last.edge.helper
    last_hedge = hedge.last
    if right_helper.type == 'merge':
        insert_edge(right_helper, point)
    status.remove(last_hedge.edge)
    left_node = status.find_nearest_left(point.co[x])
    left_helper = left_node.key.helper
    if left_helper.type == 'merge':
        insert_edge(left_helper, point)
    left_node.key.helper = point
def handle_regular_point(point, status, hedge)
Expand source code
def handle_regular_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    if point < hedge.twin.origin:
        right_helper = hedge.last.edge.helper
        status.remove(hedge.last.edge)
        edge = Edge(point, hedge.twin.origin)
        hedge.edge = edge
        hedge.twin.edge = edge
        edge.helper = point
        status.insert(edge)
        if right_helper.type == 'merge':
            insert_edge(right_helper, point)
    else:
        left_node = status.find_nearest_left(point.co[x])
        left_helper = left_node.key.helper
        left_node.key.helper = point
        if left_helper.type == 'merge':
            insert_edge(left_helper, point)
def handle_split_point(point, status, hedge)
Expand source code
def handle_split_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    left_node = status.find_nearest_left(point.co[x])
    insert_edge(left_node.key.helper, point)
    left_node.key.helper = point
    edge = Edge(point, hedge.twin.origin)
    hedge.edge = edge
    hedge.twin.edge = edge
    edge.helper = point
    status.insert(edge)
def handle_start_point(point, status, hedge)
Expand source code
def handle_start_point(point, status, hedge):
    # Read Computational Geometry by Mark de Berg
    edge = Edge(point, hedge.twin.origin)
    hedge.edge = edge
    hedge.twin.edge = edge
    edge.helper = point
    status.insert(edge)
def insert_edge(up_p, low_p)
Expand source code
def insert_edge(up_p, low_p):
    # insert new edge into half edge data structure
    up_hedge = up_p.mesh.HalfEdge(up_p.mesh, up_p)
    up_p.mesh.hedges.append(up_hedge)
    low_hedge = up_p.mesh.HalfEdge(up_p.mesh, low_p)
    up_p.mesh.hedges.append(low_hedge)
    up_hedge.twin = low_hedge
    low_hedge.twin = up_hedge
    up_p_hedge = find_hedge(up_p)
    low_p_hedge = find_hedge(low_p)

    up_ccw_hedges = []
    status = 1
    for h in up_p_hedge.ccw_hedges:
        up_ccw_hedges.append(h)
        if h.twin.face and h.twin.face == up_p_hedge.face:
            status -= 1
            break
    if status != 0:
        raise Exception('Hedge ({}) does not have neighbour with the same face'.format(up_p_hedge))

    if len(up_ccw_hedges) == 2:
        up_next = up_ccw_hedges[0]
    elif 2 < len(up_ccw_hedges) < 5:
        if up_ccw_hedges[0] > up_hedge:
            if ((up_ccw_hedges[2] < up_hedge and up_ccw_hedges[2] < up_ccw_hedges[0]) or
                    (up_ccw_hedges[2] > up_hedge and up_ccw_hedges[2] > up_ccw_hedges[0])):
                up_next = up_ccw_hedges[2]
            elif ((up_ccw_hedges[1] < up_hedge and up_ccw_hedges[1] < up_ccw_hedges[0]) or
                    (up_ccw_hedges[1] > up_hedge and up_ccw_hedges[1] > up_ccw_hedges[0])):
                up_next = up_ccw_hedges[1]
            else:
                up_next = up_ccw_hedges[0]
        else:
            up_next = up_ccw_hedges[1] if up_ccw_hedges[0] < up_ccw_hedges[1] < up_hedge else up_ccw_hedges[0]
    else:
        raise Exception('Unexpected number of half edges in point {}'.format(up_p))

    low_ccw_hedges = []
    status = 1
    for h in low_p_hedge.ccw_hedges:
        low_ccw_hedges.append(h)
        if h.twin.face and h.twin.face == low_p_hedge.face:
            status -= 1
            break
    if status != 0:
        raise Exception('Hedge ({}) does not have neighbour with the same face'.format(low_p.hedge.i))

    if len(low_ccw_hedges) == 2:
        low_next = low_ccw_hedges[0]
    elif len(low_ccw_hedges) == 3:
        if low_ccw_hedges[0] > low_hedge:
            if ((low_ccw_hedges[0] > low_ccw_hedges[1] < low_hedge) or
                    (low_ccw_hedges[0] < low_ccw_hedges[1] > low_hedge)):
                low_next = low_ccw_hedges[1]
            else:
                low_next = low_ccw_hedges[0]
        else:
            low_next = low_ccw_hedges[1] if low_ccw_hedges[0] < low_ccw_hedges[1] < low_hedge else low_ccw_hedges[0]
    else:
        raise Exception('Unexpected number of half edges in point {}'.format(low_p))
    up_hedge.last = up_next.last
    up_hedge.next = low_next
    low_hedge.next = up_next
    low_hedge.last = low_next.last
    up_next.last.next = up_hedge
    up_next.last = low_hedge
    low_next.last.next = low_hedge
    low_next.last = up_hedge
    if hasattr(up_hedge, 'in_faces'):
        # actually this part related with merge mesh algorithm only
        up_hedge.in_faces = set(up_hedge.next.in_faces)
        low_hedge.in_faces = set(low_hedge.next.in_faces)
def make_monotone(face)

Splits polygon into monotone pieces optionally with holes :param face: face of half edge data structure :return new half edges Probably approach of implementation of monotone algorithm should be reconsidered according new DCEL data structure

Expand source code
def make_monotone(face):
    """
    Splits polygon into monotone pieces optionally with holes
    :param face: face of half edge data structure
    :return new half edges
    Probably approach of implementation of monotone algorithm should be reconsidered according new DCEL data structure
    """
    face.mesh.Point.monotone_current_face = face
    status = AVLTree()
    q = sorted(build_points_list(face))[::-1]
    _ = [p.type for p in q]  # not very cool but this will set type for all points before main algorithm
    while q:
        event_point = q.pop()
        Edge.global_event_point = event_point
        handle_functions[event_point.type](event_point, status, find_hedge(event_point))
def monotone_faces_with_holes(dcel_mesh, del_flag='del')

Split polygons with holes into monotone pieces of DCEL mesh data structure Faces already should have actual information about inner component :param dcel_mesh: DCELMesh :param del_flag: faces with such flag just are just ignore by the algorithm :return: DCELMesh with split faces

Expand source code
def monotone_faces_with_holes(dcel_mesh, del_flag='del'):
    """
    Split polygons with holes into monotone pieces of DCEL mesh data structure
    Faces already should have actual information about inner component
    :param dcel_mesh: DCELMesh
    :param del_flag: faces with such flag just are just ignore by the algorithm
    :return: DCELMesh with split faces
    """
    is_inners = False
    for face in dcel_mesh.faces:
        if del_flag in face.flags:
            continue
        elif face.outer and face.inners:
            is_inners = True
            make_monotone(face)
    if is_inners:
        rebuild_face_list(dcel_mesh)
    return dcel_mesh
def monotone_sv_face_with_holes(vert_face, vert_holes=None, face_holes=None, accuracy=1e-05)

Get one face in Sverhok format and splitting it into monotone pieces Vertices of face should be given in ordered along face indexes order Also it is possible to create holes in input face Mesh of holes should be inside face without any intersection :param vert_face: :param vert_holes: :param face_holes: :param accuracy: two floats figures are equal if their difference is lower then accuracy value, float :return: vertices in Sverchok format, faces in Sverchok format

Expand source code
def monotone_sv_face_with_holes(vert_face, vert_holes=None, face_holes=None, accuracy=1e-5):
    """
    Get one face in Sverhok format and splitting it into monotone pieces
    Vertices of face should be given in ordered along face indexes order
    Also it is possible to create holes in input face
    Mesh of holes should be inside face without any intersection
    :param vert_face: 
    :param vert_holes: 
    :param face_holes: 
    :param accuracy: two floats figures are equal if their difference is lower then accuracy value, float
    :return: vertices in Sverchok format, faces in Sverchok format
    """
    mesh = DCELMesh(accuracy)
    mesh.from_sv_faces(vert_face, [list(range(len(vert_face)))])
    main_face = mesh.faces[0]  # once this will be broken
    if vert_holes and face_holes:
        main_face.insert_holes(vert_holes, face_holes)
    make_monotone(main_face)
    rebuild_face_list(mesh)
    return mesh.to_sv_mesh(edges=False, only_select=True)
def rebuild_face_list(dcel_mesh)
Expand source code
def rebuild_face_list(dcel_mesh):
    # rebuild face list after partition algorithm
    # this function should correct boundless face but it does not !!!!
    for hedge in dcel_mesh.hedges:
        if hedge.face:
            continue
        face = dcel_mesh.Face(dcel_mesh)
        face.select = True
        face.outer = hedge
        for h in hedge.loop_hedges:
            h.face = face
    used = set()
    faces = []
    for hedge in dcel_mesh.hedges:
        if hedge.face == dcel_mesh.unbounded:
            continue
        if hedge not in used:
            faces.append(hedge.face)
            [used.add(h) for h in hedge.loop_hedges]
    dcel_mesh.faces = faces

Classes

class DCELMesh (accuracy=None)
Expand source code
class DCELMesh(DCELMesh_template):
    Point = Point
    HalfEdge = HalfEdge

Ancestors

Subclasses

Class variables

var HalfEdge

Half edges are sorting in counterclockwise direction from -X direction. Should be used with HalfEdge class from dcel_mesh module

var Point

This allowed sort points from upward to downward direction. Besides points with equal Y coordinate are sorted from left to right. (0, 1, 0) < (0, 0, 0) (0, 1, 0) < (1, 1, 0) (0, 1.001, 0) == (0, 1.002, 0) if accuracy <= 1e-3

Should be used with another class with "co" - (x, y, z) and "accuracy" - (float) attributes

class Edge (up_p, low_p)

Sorting edges for sweeping line algorithm. Edges are sorted along horizontal sweeping line from left to right according their intersection with sweep line. If Edges intersects in one points they are sorted in cww order from -X direction.

There is global event point parameter determining position of sweep line. It should be updated each time when sweep line is changing its position.

Expand source code
class Edge(SortEdgeSweepingAlgorithm):

    def __init__(self, up_p, low_p):
        super().__init__(up_p, low_p)

        self.helper = None

Ancestors

class HalfEdge (*args, **kwargs)

Half edges are sorting in counterclockwise direction from -X direction. Should be used with HalfEdge class from dcel_mesh module

Expand source code
class HalfEdge(HalfEdge_template, SortHalfEdgesCCW):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.edge = None

Ancestors

Subclasses

Inherited members

class Point (*args, **kwargs)

This allowed sort points from upward to downward direction. Besides points with equal Y coordinate are sorted from left to right. (0, 1, 0) < (0, 0, 0) (0, 1, 0) < (1, 1, 0) (0, 1.001, 0) == (0, 1.002, 0) if accuracy <= 1e-3

Should be used with another class with "co" - (x, y, z) and "accuracy" - (float) attributes

Expand source code
class Point(Point_template, SortPointsUpDown):
    monotone_current_face = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._type = None
        self._monotone_face = None

    @property
    def type(self):
        # the type should be updated each time when polygon is changed in partitioning algorithm
        # during handle of polygon point does not change type
        face = self.monotone_face
        if not self._type:
            hedge = None  # is hedge with origin in the point and belonging to current monotone face
            for coin_hedge in self.hedge.ccw_hedges:
                if coin_hedge.face == face:
                    hedge = coin_hedge
                    break
            if not hedge:
                raise LookupError("This mean that either monotone face is marked incorrect or "
                                  "coincidence half edges are marked incorrect or something else")
            next_point = hedge.next.origin
            last_point = hedge.last.origin
            is_up_next = next_point < self  # the less point the upper it is
            is_up_last = last_point < self
            if not is_up_next and not is_up_last:
                self._type = 'start' if hedge < hedge.last.twin else 'split'
            elif is_up_last and is_up_next:
                self._type = 'merge' if hedge > hedge.last.twin else 'end'
            else:
                self._type = 'regular'
        return self._type

    @property
    def monotone_face(self):
        # returns face coincidence to a point which is handling by the algorithm
        if not self.monotone_current_face:
            raise Exception('Which polygon is handling should be set before')
        elif self._monotone_face != self.monotone_current_face:
            self._monotone_face = self.monotone_current_face
            self._type = None
        return self._monotone_face

Ancestors

Subclasses

Class variables

var monotone_current_face

Instance variables

var monotone_face
Expand source code
@property
def monotone_face(self):
    # returns face coincidence to a point which is handling by the algorithm
    if not self.monotone_current_face:
        raise Exception('Which polygon is handling should be set before')
    elif self._monotone_face != self.monotone_current_face:
        self._monotone_face = self.monotone_current_face
        self._type = None
    return self._monotone_face
var type
Expand source code
@property
def type(self):
    # the type should be updated each time when polygon is changed in partitioning algorithm
    # during handle of polygon point does not change type
    face = self.monotone_face
    if not self._type:
        hedge = None  # is hedge with origin in the point and belonging to current monotone face
        for coin_hedge in self.hedge.ccw_hedges:
            if coin_hedge.face == face:
                hedge = coin_hedge
                break
        if not hedge:
            raise LookupError("This mean that either monotone face is marked incorrect or "
                              "coincidence half edges are marked incorrect or something else")
        next_point = hedge.next.origin
        last_point = hedge.last.origin
        is_up_next = next_point < self  # the less point the upper it is
        is_up_last = last_point < self
        if not is_up_next and not is_up_last:
            self._type = 'start' if hedge < hedge.last.twin else 'split'
        elif is_up_last and is_up_next:
            self._type = 'merge' if hedge > hedge.last.twin else 'end'
        else:
            self._type = 'regular'
    return self._type