Example #1
0
def handle_edge_event_3sides(evt, step, skel, queue, immediate):
    """Handle a collapse of a triangle with 3 sides collapsing.
    It does not matter whether the 3-triangle has wavefront edges or not.

    Important: The triangle vertices should collapse to 1 point.

    The following steps are performed:
    - stop the 3 kinetic vertices of the triangle
    - optionally make a new skeleton node
    - schedule all neighbours, if any, for immediate processing
      (these also collapse to the same point)
    """
    now = evt.time
    t = evt.triangle

    logging.info("* edge 3sides    :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug(evt.side)
    assert len(evt.side) == 3
    # we stop the vertices always at the same geometric location
    # This means that the triangle collapse leads to 1 point
    sk_node, newly_made = stop_kvertices(t.vertices, step, now)
    if newly_made:
        skel.sk_nodes.append(sk_node)
    # get neighbours around collapsing triangle, if any, and schedule them
    for n in t.neighbours:
        if n is not None and n.event is not None and n.stops_at is None:
            n.neighbours[n.neighbours.index(t)] = None
            schedule_immediately(n, now, queue, immediate)
    # we "remove" the triangle itself
    t.stops_at = now
Example #2
0
def handle_edge_event_1side(evt, step, skel, queue, immediate, pause):
    """Handle a collapse of a triangle with 1 side collapsing.

    Important: The triangle collapses to a line segment.
    """
    t = evt.triangle

    logging.info("* edge 1side     :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug(evt.side)
    assert len(evt.side) == 1, len(evt.side)
    e = evt.side[0]
    logging.debug(
        "wavefront edge collapsing? {0}".format(t.neighbours[e] is None))
    now = evt.time
    v0 = t.vertices[e]
    v1 = t.vertices[ccw(e)]
    v2 = t.vertices[cw(e)]
    # stop the two vertices of this edge and make new skeleton node
    # replace 2 vertices with new kinetic vertex
    sk_node, newly_made = stop_kvertices([v1, v2], step, now)
    if newly_made:
        skel.sk_nodes.append(sk_node)
    kv = compute_new_kvertex(v1.ul, v2.ur, now, sk_node,
                             len(skel.vertices) + 1, v1.internal
                             or v2.internal, pause)
    # FIXME: should we update the left and right wavefront line refs here?
    logging.debug("Computed new kinetic vertex {} [{}]".format(
        id(kv), kv.info))
    logging.debug("v1 := {} [{}]".format(id(v1), v1.info))
    logging.debug("v2 := {} [{}]".format(id(v2), v2.info))
    logging.debug(kv.position_at(now))
    logging.debug(kv.position_at(now + 1))
    # append to skeleton structure, new kinetic vertex
    skel.vertices.append(kv)
    sk_node, newly_made = stop_kvertices([v0, kv], step, now)
    if newly_made:
        skel.sk_nodes.append(sk_node)
    # we "remove" the triangle itself
    t.stops_at = now
Example #3
0
def handle_parallel_edge_event_even_legs(t, e, pivot, now, step, skel, queue, immediate):

    logging.info("* parallel|even  :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug('At start of handle_parallel_edge_event with same size legs')
    logging.debug("Edge with inf fast vertex collapsing! {0}".format(t.neighbours[e] is None))

    # FIXME: pre-conditions for this handler
    # there should be 1 edge with zero length, and other 2 edges should have length?
    # can it also be that this handler deals with collapse to point ???

    # does not hold! -> 

    # triangle can also be like:
    # *-------------------------*
    #  `---------------*'''''''

    # we are collapsing the edge opposite of the inf fast pivot vertex
    # this assumes that v1 and v2 need to be on the same location!!!
    assert t.vertices.index(pivot) == e
    assert t.vertices[e] is pivot
#    assert pivot.inf_fast
    # stop the non-infinite vertices
    v1 = t.vertices[ccw(e)]
    v2 = t.vertices[cw(e)]
    sk_node, newly_made = stop_kvertices([v1,v2], step, now)
    if newly_made:
        skel.sk_nodes.append(sk_node)

    # stop the pivot as well
    if pivot.stop_node is not None:
        logging.debug("Infinite fast pivot already stopped, but should not be stopped(?)")
#    assert pivot.stop_node is None
#    assert pivot.stops_at is None
    pivot.stop_node = sk_node
    pivot.stops_at = now
    # this is not necessary, is it?
    ## update_circ(pivot, v1, now)
    ## update_circ(v2, pivot, now)

    # we "remove" the triangle itself
    t.stops_at = now

    n = t.neighbours[e]
    msg = "schedule adjacent neighbour for *IMMEDIATE* processing" if n is not None else "no neighbour to collapse simultaneously"
    logging.debug("*** neighbour n: {} ".format(msg))
    if n is not None:
        n.neighbours[n.neighbours.index(t)] = None
        if n.event is not None and n.stops_at is None:
            logging.debug(n.event)
            schedule_immediately(n, now, queue, immediate)
Example #4
0
def handle_split_event(evt, step, skel, queue, immediate, pause):
    """Handles a split event where a wavefront edge is hit on its interior
    This splits the wavefront in two pieces
    """
    t = evt.triangle

    logging.info("* split          :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug("{}".format(t.neighbours))
    assert len(evt.side) == 1
    e = evt.side[0]
    now = evt.time
    v = t.vertices[(e) % 3]
    n = t.neighbours[e]
    assert n is None
    v1 = t.vertices[(e + 1) % 3]
    v2 = t.vertices[(e + 2) % 3]

    logging.debug("v1 := {} [{}]".format(id(v1), v1.info))
    logging.debug("v2 := {} [{}]".format(id(v2), v2.info))

    assert v1.wfr is v2.wfl

    # ---- new use of wavefronts ------------------------------ #
    # split leads to 2 bisectors
    a = v.wfr
    b = v1.wfr
    assert v2.wfl is b
    c = v.wfl

    # TODO: are we having the correct bisectors here?
    intersector = WaveFrontIntersector(a, b)  #
    bi0 = intersector.get_bisector()
    # print(bi0)
    #
    intersector = WaveFrontIntersector(a, c)  #
    bi1 = intersector.get_bisector()
    # print(bi1)

    # the position of the node is witnessed by 3 pairs of wavefronts
    try:
        intersector = WaveFrontIntersector(a, b)
        pos_at_now = intersector.get_intersection_at_t(now)
    except ValueError:
        pass
    # print("POINT({0[0]} {0[1]})".format(pos_at_now))

    try:
        intersector = WaveFrontIntersector(a, c)
        pos_at_now = intersector.get_intersection_at_t(now)
        # print("POINT({0[0]} {0[1]})".format(pos_at_now))
    except ValueError:
        pass
    try:
        intersector = WaveFrontIntersector(b, c)
        pos_at_now = intersector.get_intersection_at_t(now)
        # print("POINT({0[0]} {0[1]})".format(pos_at_now))            #
    except ValueError:
        pass

    # ---- new use of wavefronts ------------------------------ #

    sk_node, newly_made = stop_kvertices([v], step, now)
    # add the skeleton node to the skeleton
    if newly_made:
        skel.sk_nodes.append(sk_node)
#     assert v1.right is v2
#     assert v2.left is v1

    assert v1.ur is v2.ul

    # pos_vr = v.right.position_at(now)
    # pos_v1 = v1.position_at(now)
    # from grassfire.vectorops import make_vector, mul, add, unit, norm
    # ha = add(v1.position_at(now), mul(make_vector(pos_vr, pos_v1), 0.5)) # pt halfway a

    # pos_vl = v.left.position_at(now)
    # pos_v2 = v2.position_at(now)
    # hb = add(v2.position_at(now), mul(make_vector(pos_vl, pos_v2), 0.5)) # pt halfway b

    # with open('/tmpfast/split_pts_halfway.wkt', 'w') as fh:
    #     fh.write('wkt')
    #     fh.write('\n')
    #     fh.write("POINT({0[0]} {0[1]})".format(v.position_at(now)))
    #     fh.write('\n')
    #     fh.write("POINT({0[0]} {0[1]})".format(ha))
    #     fh.write('\n')
    #     fh.write("POINT({0[0]} {0[1]})".format(hb))
    #     fh.write('\n')
    # print('written out points')

    # # the geometric bisector based on the position of the vertices
    # bi_b = make_vector(hb, v.position_at(now))
    # bi_a = make_vector(ha, v.position_at(now))

    # def sign(scalar):
    #     if scalar < 0:
    #         return -1
    #     elif scalar == 0:
    #         return 0
    #     else:
    #         return 1

    # the position of the stop_node can be computed by:
    # taking the original wavefronts and translate these lines to 'now'
    # then intersect them -> stop_node position
    # maybe this is more robust than relying on the direction vector and the velocity of the original point

    # a bisector based on the original line equations
    # BI = compute_crossing_bisector(v.ul, v2.ul, now)
    vb = compute_new_kvertex(v.ul, v2.ul, now, sk_node,
                             len(skel.vertices) + 1, v.internal or v2.internal,
                             pause)
    # FIXME: new wavefront
    vb.wfl = v.wfl
    vb.wfr = v2.wfl
    #     logging.debug("""
    # -- BISECTOR BI   {}
    #             bi_b {}
    #             vb.v {}""".format(BI, bi_b, vb.velocity)
    #     )
    skel.vertices.append(vb)

    # if not vb.inf_fast:
    #     if sign(vb.velocity[0]) != sign(bi_b[0]) or sign(vb.velocity[1]) != sign(bi_b[1]):
    #         vb.velocity = mul(unit(bi_b), norm(vb.velocity))

    if pause:
        logging.debug('split l.194 -- computed new vertex B')
        from grassfire.inout import interactive_visualize
        interactive_visualize(queue, skel, step, now)

    # BI = compute_crossing_bisector(v1.ur, v.ur, now)
    va = compute_new_kvertex(v1.ur, v.ur, now, sk_node,
                             len(skel.vertices) + 1, v.internal or v1.internal,
                             pause)
    va.wfl = v1.wfr
    va.wfr = v.wfr

    #     logging.debug("""
    # -- BISECTOR BI   {}
    #             bi_a {}
    #             va.v {}""".format(BI, bi_a, va.velocity)
    #     )
    skel.vertices.append(va)

    if pause:
        logging.debug('split l.211  -- computed new vertex A')
        interactive_visualize(queue, skel, step, now)

    # if not va.inf_fast:
    #     if sign(va.velocity[0]) != sign(bi_a[0]) or sign(va.velocity[1]) != sign(bi_a[1]):
    #         va.velocity = mul(unit(bi_a), norm(va.velocity))

    logging.debug("-- update circular list at B-side: {} [{}]".format(
        id(vb), vb.info))
    update_circ(v.left, vb, now)
    update_circ(vb, v2, now)

    # FIXME: why do these assertions not hold?
    assert vb.left.wfr is vb.wfl
    assert vb.right.wfl is vb.wfr

    logging.debug("-- update circular list at A-side: {} [{}]".format(
        id(va), va.info))
    update_circ(v1, va, now)
    update_circ(va, v.right, now)

    logging.debug("-- [{}]".format(va.info))
    logging.debug("   [{}]".format(va.right.info))
    logging.debug("   {}".format(va.right.wfl))
    logging.debug("   {}".format(va.wfr))

    # FIXME: why do these assertions not hold?
    assert va.left.wfr is va.wfl
    assert va.right.wfl is va.wfr

    # updates (triangle fan) at neighbour 1
    b = t.neighbours[(e + 1) % 3]
    assert b is not None
    b.neighbours[b.neighbours.index(t)] = None
    fan_b = replace_kvertex(b, v, vb, now, ccw, queue, immediate)

    if pause:
        logging.debug('split l.243 -- replaced vertex B')
        from grassfire.inout import interactive_visualize
        interactive_visualize(queue, skel, step, now)

    # updates (triangle fan) at neighbour 2
    a = t.neighbours[(e + 2) % 3]
    assert a is not None
    a.neighbours[a.neighbours.index(t)] = None
    fan_a = replace_kvertex(a, v, va, now, cw, queue, immediate)

    if pause:
        logging.debug('split l.255 -- replaced vertex A')
        from grassfire.inout import interactive_visualize
        interactive_visualize(queue, skel, step, now)

    t.stops_at = now

    # handle infinitely fast vertices
    if va.inf_fast:
        handle_parallel_fan(fan_a, va, now, cw, step, skel, queue, immediate,
                            pause)
    if vb.inf_fast:
        handle_parallel_fan(fan_b, vb, now, ccw, step, skel, queue, immediate,
                            pause)


#     # we "remove" the triangle itself

# def is_infinitely_fast(fan):
#     times = [tri.event.time if tri.event is not None else -1 for tri in fan]
#     is_inf_fast = all(map(near_zero, [time - now for time in times]))
#     if fan and is_inf_fast:
#         return True
#     else:
#         return False
#    is_inf_fast_b = is_infinitely_fast(get_fan(b, v, ccw))
#    is_inf_fast_a = is_infinitely_fast(get_fan(a, v, cw))

# double check: infinitely fast vertices
# (might have been missed by adding wavefront vectors cancelling out)
#    if is_inf_fast_a and not va.inf_fast:
#        logging.debug("New kinetic vertex vA: ***Upgrading*** to infinitely fast moving vertex!")
#        va.inf_fast = True
#    if is_inf_fast_b and not vb.inf_fast:
#        logging.debug("New kinetic vertex vB: ***Upgrading*** to infinitely fast moving vertex!")
#        vb.inf_fast = True
Example #5
0
def handle_edge_event(evt, step, skel, queue, immediate, pause):
    """Handles triangle collapse, where exactly 1 edge collapses"""
    t = evt.triangle
    logging.info("* edge           :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug(evt.side)
    assert len(evt.side) == 1, len(evt.side)
    # take edge e
    e = evt.side[0]
    logging.debug(
        "wavefront edge collapsing? {0}".format(t.neighbours[e] is None))
    is_wavefront_collapse = t.neighbours[e] is None
    #    if t.neighbours.count(None) == 2:
    #        assert t.neighbours[e] is None
    now = evt.time
    v1 = t.vertices[ccw(e)]
    v2 = t.vertices[cw(e)]

    # v1.
    logging.debug("v1 := {} [{}] -- stop_node: {}".format(
        id(v1), v1.info, v1.stop_node))
    logging.debug("v2 := {} [{}] -- stop_node: {}".format(
        id(v2), v2.info, v2.stop_node))

    # FIXME: assertion is not ok when this is triangle from spoke collapse?
    if is_wavefront_collapse and not v1.is_stopped and not v2.is_stopped:
        assert v1.right is v2
        assert v2.left is v1

    # stop the two vertices of this edge and make new skeleton node
    # replace 2 vertices with new kinetic vertex

    # +--- new use of wavefronts ------------------------------ #
    # ⋮
    a = v1.wfl
    b = v1.wfr
    if is_wavefront_collapse and not v1.is_stopped and not v2.is_stopped:
        assert v2.wfl is b
    c = v2.wfr
    #
    intersector = WaveFrontIntersector(a, c)
    bi = intersector.get_bisector()
    logging.debug(bi)
    # in general position the new position of the node can be constructed by intersecting 3 pairs of wavefronts
    # (a,c), (a,b), (b,c)
    # in case (a,c) are parallel, this is new infinitely fast vertex and triangles are locked between
    # or (a,c) are parallel due to spoke collapse (then new vertex is on straight line, splitting it in 2 times 90 degree angles)
    # in case (a,b) are parallel, then v1 is straight -- no turn
    # in case (b,c) are parallel, then v2 is straight -- no turn
    pos_at_now = None
    try:
        intersector = WaveFrontIntersector(a, c)
        pos_at_now = intersector.get_intersection_at_t(now)
        logging.debug("POINT({0[0]} {0[1]});a;c".format(pos_at_now))
    except ValueError:
        pass
    # iff the wavefronts wfl/wfr are parallel
    # then only the following 2 pairs of wavefronts can be properly intersected!
    # try:
    #     intersector = WaveFrontIntersector(a, b)
    #     pos_at_now = intersector.get_intersection_at_t(now)
    #     logging.debug("POINT({0[0]} {0[1]});a;b".format(pos_at_now))
    # except ValueError:
    #     pass
    # #
    # try:
    #     intersector = WaveFrontIntersector(b, c)
    #     pos_at_now = intersector.get_intersection_at_t(now)
    #     logging.debug("POINT({0[0]} {0[1]});b;c".format(pos_at_now))            #
    # except ValueError:
    #     pass
    # ⋮
    # +--- new use of wavefronts ------------------------------ #

    sk_node, newly_made = stop_kvertices([v1, v2], step, now, pos=pos_at_now)
    if newly_made:
        skel.sk_nodes.append(sk_node)
    kv = compute_new_kvertex(v1.ul, v2.ur, now, sk_node,
                             len(skel.vertices) + 1, v1.internal
                             or v2.internal, pause)

    # ---- new use of wavefronts ---------- #
    kv.wfl = v1.wfl  #
    kv.wfr = v2.wfr  #
    # ---- new use of wavefronts ---------- #

    logging.debug("Computed new kinetic vertex {} [{}]".format(
        id(kv), kv.info))
    logging.debug("v1 := {} [{}]".format(id(v1), v1.info))
    logging.debug("v2 := {} [{}]".format(id(v2), v2.info))
    # logging.debug(kv.position_at(now))
    # logging.debug(kv.position_at(now+1))
    # logging.debug("||| {} | {} | {} ||| ".format( v1.left.position_at(now), sk_node.pos, v2.right.position_at(now) ))
    # logging.debug("||| {} ||| ".format(signed_turn( v1.left.position_at(now), sk_node.pos, v2.right.position_at(now) )))
    # logging.debug("||| {} ||| ".format(get_bisector( v1.left.position_at(now), sk_node.pos, v2.right.position_at(now) )))

    if v1.left:
        logging.debug(v1.left.position_at(now))
    else:
        logging.warning("no v1.left")
    if v2.right:
        logging.debug(v2.right.position_at(now))
    else:
        logging.warning("no v2.right")
    if kv.inf_fast:
        logging.debug("New kinetic vertex moves infinitely fast!")
    # append to skeleton structure, new kinetic vertex
    skel.vertices.append(kv)
    # update circular list of kinetic vertices
    update_circ(v1.left, kv, now)
    update_circ(kv, v2.right, now)

    # def sign(val):
    #     if val > 0:
    #         return +1
    #     elif val < 0:
    #         return -1
    #     else:
    #         return 0

    # bisector_check = get_bisector( v1.left.position_at(now), sk_node.pos, v2.right.position_at(now) )
    # if not kv.inf_fast:
    #     logging.debug("{} [{}]".format(v1.left, v1.left.info))
    #     logging.debug("{} [{}]".format(v2.right, v2.right.info))
    #     logging.debug("{0} vs {1}".format(bisector_check, kv.velocity))
    #     if sign(bisector_check[0]) == sign(kv.velocity[0]) and sign(bisector_check[1]) == sign(kv.velocity[1]):
    #         logging.debug('signs agree')
    #     else:
    #         logging.warning("""

    #         BISECTOR SIGNS DISAGREE

    #         """)

    #         kv.velocity = (sign(bisector_check[0]) * abs(kv.velocity[0]), sign(bisector_check[1]) * abs(kv.velocity[1]))
    #         raise ValueError('bisector signs disagree')

    # ---- new use of wavefronts ---------- #
    # post condition
    assert kv.wfl is kv.left.wfr
    assert kv.wfr is kv.right.wfl
    # ---- new use of wavefronts ---------- #

    # get neighbours around collapsing triangle
    a = t.neighbours[ccw(e)]
    b = t.neighbours[cw(e)]
    n = t.neighbours[e]
    # second check: is vertex infinitely fast?

    #    is_inf_fast_a = is_infinitely_fast(get_fan(a, v2, cw), now)
    #    is_inf_fast_b = is_infinitely_fast(get_fan(b, v1, ccw), now)
    #    if is_inf_fast_a and is_inf_fast_b:
    #        if not kv.inf_fast:
    #            logging.debug("New kinetic vertex: ***Upgrading*** to infinitely fast moving vertex!")
    #            kv.inf_fast = True
    #

    fan_a = []
    fan_b = []
    if a is not None:
        logging.debug("replacing vertex for neighbours at side A")
        a_idx = a.neighbours.index(t)
        a.neighbours[a_idx] = b
        fan_a = replace_kvertex(a, v2, kv, now, cw, queue, immediate)

        if fan_a:
            e = Edge(fan_a[-1], cw(fan_a[-1].vertices.index(kv)))
            orig, dest = e.segment
            import math
            if (near_zero(math.sqrt(orig.distance2_at(dest, now)))):
                logging.info(
                    "collapsing neighbouring edge, as it is very tiny -- cw")
                schedule_immediately(fan_a[-1], now, queue, immediate)
    if b is not None:
        logging.debug("replacing vertex for neighbours at side B")
        b_idx = b.neighbours.index(t)
        b.neighbours[b_idx] = a
        fan_b = replace_kvertex(b, v1, kv, now, ccw, queue, immediate)
        if fan_b:
            e = Edge(fan_b[-1], ccw(fan_b[-1].vertices.index(kv)))
            orig, dest = e.segment
            import math
            if (near_zero(math.sqrt(orig.distance2_at(dest, now)))):
                logging.info(
                    "collapsing neighbouring edge, as it is very tiny -- ccw")
                schedule_immediately(fan_b[-1], now, queue, immediate)

    if n is not None:
        logging.debug(
            "*** neighbour n: schedule adjacent neighbour for *IMMEDIATE* processing"
        )
        n.neighbours[n.neighbours.index(t)] = None
        if n.event is not None and n.stops_at is None:
            schedule_immediately(n, now, queue, immediate)


#    if t.info == 134:
#        raise NotImplementedError('problem: #134 exists now')

# we "remove" the triangle itself
    t.stops_at = now

    # process parallel fan
    if kv.inf_fast:
        if fan_a and fan_b:
            # combine both fans into 1
            fan_a = list(fan_a)
            fan_a.reverse()
            fan_a.extend(fan_b)
            handle_parallel_fan(fan_a, kv, now, ccw, step, skel, queue,
                                immediate, pause)
            return
        elif fan_a:
            handle_parallel_fan(fan_a, kv, now, cw, step, skel, queue,
                                immediate, pause)
            return
        elif fan_b:
            handle_parallel_fan(fan_b, kv, now, ccw, step, skel, queue,
                                immediate, pause)
            return
Example #6
0
def handle_parallel_edge_event_3tri(t, e, pivot, now, step, skel, queue, immediate):
    logging.info("* parallel|even#3 :: tri>> #{} [{}]".format(id(t), t.info))

    logging.debug('At start of handle_parallel_edge_event for 3 triangle')
    logging.debug("Edge with inf fast vertex collapsing! {0}".format(t.neighbours[e] is None))

    # triangle is like:
    # *-------------------------*
    #  `---------------*'''''''

    # we are collapsing the edge opposite of the inf fast pivot vertex
    # this assumes that v1 and v2 need to be on the same location!!!
    assert t.vertices.index(pivot) == e
    assert t.vertices[e] is pivot
#    assert pivot.inf_fast

    left_leg_idx = ccw(t.vertices.index(pivot))
    left_leg = Edge(t, left_leg_idx)
    left_dist = dist(*map(lambda x: x.position_at(now), left_leg.segment))
    v1 = t.vertices[ccw(e)]

    right_leg_idx = cw(t.vertices.index(pivot))
    right_leg = Edge(t, right_leg_idx)
    right_dist = dist(*map(lambda x: x.position_at(now), right_leg.segment))
    v2 = t.vertices[cw(e)]

    assert v1 is not pivot
    assert v2 is not pivot

    assert pivot in t.vertices
    assert v1 in t.vertices
    assert v2 in t.vertices

    from grassfire.vectorops import dot, norm
    logging.debug(v1.velocity)
    logging.debug(v2.velocity)
    magn_v1 = norm(v1.velocity)
    magn_v2 = norm(v2.velocity)

    logging.debug('  velocity magnitude: {}'.format([magn_v1, magn_v2]))

    dists = [left_dist, right_dist]
    logging.debug('  distances: {}'.format(dists))
    dists_sub_min = [near_zero(_ - min(dists)) for _ in dists]
    logging.debug(dists_sub_min)

    # stop the non-infinite vertices at the same location
    # use the slowest moving vertex to determine the location
    if magn_v2 < magn_v1:
        sk_node, newly_made = stop_kvertices([v2], step, now)
        if newly_made:
            skel.sk_nodes.append(sk_node)
        v1.stop_node = sk_node
        v1.stops_at = now
    else:
        sk_node, newly_made = stop_kvertices([v1], step, now)
        if newly_made:
            skel.sk_nodes.append(sk_node)
        v2.stop_node = sk_node
        v2.stops_at = now

    


    # FIXME:
    # make edge between v1 and v2

#    assert pivot.stop_node is None
#    assert pivot.stops_at is None

    #FIXME: wrong sk_node for pivot
    pivot.stop_node = sk_node
    pivot.stops_at = now
    # this is not necessary, is it?
    ## update_circ(pivot, v1, now)
    ## update_circ(v2, pivot, now)

    # we "remove" the triangle itself
    t.stops_at = now


    for kv in t.vertices:
        assert kv.stops_at is not None
Example #7
0
def handle_parallel_edge_event_shorter_leg(t, e, pivot, now, step, skel, queue, immediate, pause):
    """Handles triangle collapse, where exactly 1 edge collapses
    
    One of the vertices of the triangle moves *infinitely* fast.

    There are 2 cases handled in this function
    
    a. triangle with long left leg, short right leg
    b. triangle with long right leg, short left leg

    Arguments:
    t -- triangle that collapses
    e -- short side over which pivot moves inf fast

    """

    logging.info("* parallel|short :: tri>> #{} [{}]".format(id(t), t.info))
    logging.debug('At start of handle_parallel_edge_event_shorter_leg')

    logging.debug("Edge with inf fast vertex collapsing! {0}".format(t.neighbours[e] is None))
    assert pivot.inf_fast
    # vertices, that are not inf fast, need to stop
    # FIXME: this is not necessarily correct ... 
    #  where they need to stop depends on the configuration
    #  -- now they are *always* snapped to same location

    v1 = t.vertices[ccw(e)]
    v2 = t.vertices[cw(e)]
    v3 = t.vertices[e]
    logging.debug("* tri>> #{} [{}]".format(id(t), t.info))
    logging.debug("* pivot #{} [{}]".format(id(pivot), pivot.info))
    logging.debug("* v1 #{} [{}]".format(id(v1), v1.info))
    logging.debug("* v2 #{} [{}]".format(id(v2), v2.info))
    logging.debug("* v3 #{} [{}]".format(id(v3), v3.info))
    assert pivot is v1 or pivot is v2

    to_stop = []
    for v in [v1, v2]:
        if not v.inf_fast:
            to_stop.append(v)

    # stop the non-infinite vertices
    sk_node, newly_made = stop_kvertices(to_stop, step, now)
    if newly_made:
        skel.sk_nodes.append(sk_node)
    if pivot.stop_node is None:
        assert pivot.stop_node is None
        assert pivot.stops_at is None
        pivot.stop_node = sk_node
        pivot.stops_at = now
        # we will update the circular list
        # at the pivot a little bit later
    else:
        logging.debug("Infinite fast pivot already stopped,"
                     " but should not be stopped(?)")
    # we "remove" the triangle itself
    t.stops_at = now
    # check that the edge that collapses is not opposite of the pivot
    # i.e. the edge is one of the two adjacent legs at the pivot
    assert t.vertices.index(pivot) != e
    kv = compute_new_kvertex(v1.ul, v2.ur, now, sk_node, len(skel.vertices) + 1, v1.internal or v2.internal, pause)
    # FIXME new wavefront -- update refs
    kv.wfl = v1.left.wfr
    kv.wfr = v2.right.wfl

    logging.debug("Computed new kinetic vertex {} [{}]".format(id(kv), kv.info))
    if kv.inf_fast:
        logging.debug("New kinetic vertex moves infinitely fast!")
    # get neighbours around collapsing triangle
    a = t.neighbours[ccw(e)]
    b = t.neighbours[cw(e)]
    n = t.neighbours[e]
    # second check:
    # is vertex infinitely fast?
    # in this case, both sides of the new vertex 
    # should collapse to be infinitely fast!
    # is_inf_fast_a = is_infinitely_fast(get_fan(a, v2, cw), now)
    # is_inf_fast_b = is_infinitely_fast(get_fan(b, v1, ccw), now)
    # if is_inf_fast_a and is_inf_fast_b:
    #     assert kv is not None
    #     if not kv.inf_fast:
    #         logging.debug("New kinetic vertex: ***Not upgrading*** to infinitely fast moving vertex!")
            # we if the vertex is in a 90.0 degree angle for which both sides are inf-fast
            # kv.inf_fast = True
    # append to skeleton structure, new kinetic vertex
    skel.vertices.append(kv)

    # update circular list of kinetic vertices
    logging.debug("-- update circular list for new kinetic vertex kv: {} [{}]".format(id(kv), kv.info))
    update_circ(v1.left, kv, now)
    update_circ(kv, v2.right, now)
    # update the triangle fans incident
    fan_a = []
    fan_b = []
    if a is not None:
        logging.debug("- replacing vertex for neighbours at side A {} [{}]".format(id(a), a.info))
        a_idx = a.neighbours.index(t)
        a.neighbours[a_idx] = b
        fan_a = replace_kvertex(a, v2, kv, now, cw, queue, immediate)
        if pause:
            logging.debug('replaced neighbour A')
            interactive_visualize(queue, skel, step, now)

    if b is not None:
        logging.debug("- replacing vertex for neighbours at side B {} [{}]".format(id(b), b.info))
        b_idx = b.neighbours.index(t)
        b.neighbours[b_idx] = a
        fan_b = replace_kvertex(b, v1, kv, now, ccw, queue, immediate)
        if pause:
            logging.debug('replaced neighbour B')
            interactive_visualize(queue, skel, step, now)
    #
    logging.debug("*** neighbour n: {} ".format("schedule adjacent neighbour for *IMMEDIATE* processing" if n is not None else "no neighbour to collapse simultaneously"))
    if n is not None:
        n.neighbours[n.neighbours.index(t)] = None
        if n.event is not None and n.stops_at is None:
            schedule_immediately(n, now, queue, immediate)
    #visualize(queue, skel, now-1.0e-3)
    
    #raw_input('continue after parallel -- one of two legs')
    # process parallel fan, only if the fan has all un-dealt with triangles
    if kv and kv.inf_fast:
#        # fan - cw
#        if fan_a and all([t.stops_at is None for t in fan_a]):
#            handle_parallel_fan(fan_a, kv, now, cw, step, skel, queue, immediate, pause)
#            return
#        elif fan_a:
#            # we should have a fan in which all triangles are already stopped
#            assert all([t.stops_at is not None for t in fan_a])
#        # fan - ccw
#        if fan_b and all([t.stops_at is None for t in fan_b]):
#            handle_parallel_fan(fan_b, kv, now, ccw, step, skel, queue, immediate, pause)
#            return
#        elif fan_b:
#            # we should have a fan in which all triangles are already stopped
#            assert all([t.stops_at is not None for t in fan_b])

        if fan_a and fan_b:
            # combine both fans into 1
            fan_a = list(fan_a)
            fan_a.reverse()
            fan_a.extend(fan_b)
            handle_parallel_fan(fan_a, kv, now, ccw, step, skel, queue, immediate, pause)
            return
        elif fan_a:
            handle_parallel_fan(fan_a, kv, now, cw, step, skel, queue, immediate, pause)
            return
        elif fan_b:
            handle_parallel_fan(fan_b, kv, now, ccw, step, skel, queue, immediate, pause)
            return