def extend_tile(p1, p2, currentcase, oldcase, tile):
    # Copy of visualize
    visitedcases = [currentcase % len(tile)]
    tilepoints = list()
    to_visit = [(p1, p2, currentcase, oldcase)]
    while to_visit:
        p1, p2, currentcase, oldcase = to_visit.pop()
        realcurrent = currentcase % len(tile)
        # visitedcases.append(realcurrent) #too late! if two cases go to the same case that doesn't get explored until after
        points = get_face_points(p1, p2, len(tile[realcurrent]))
        if DEBUG1: Draw.polygon_shape(points, (255, 0, 0), alpha=0.1, outline=1)
        if DEBUG4: print("Extend", currentcase)
        if DEBUG4: print(visitedcases)
        if DEBUG1: Draw.text_center(str(realcurrent), *centerpoint(points), (0, 0, 0), 12)
        if DEBUG1: Draw.refresh()
        # sleep(0.01)
        tilepoints.append(points)
        currentborder = tile[realcurrent]  # print(currentborder, 'of shape', realcurrent, ', coming from', oldcase)
        base, match = find_matching(oldcase, currentcase, tile)
        # if(DEBUG1):print(match)
        shift = currentborder.index(match)  # index = current.index(-oldcase + 2 * (oldcase % len(order)))
        # if(DEBUG1):print("Aligned on %d index %d"%(oldcase,shift))
        # print(index)
        currentborder = currentborder[shift:] + currentborder[:shift + 1]
        for index, nextcase in enumerate(currentborder):
            p1 = points[index % len(points)]
            p2 = points[(index + 1) % len(points)]
            if (nextcase not in visitedcases) and (nextcase % len(tile) == nextcase):
                to_visit.append([p2, p1, nextcase, currentcase])
                visitedcases.append(nextcase)
                # if(DEBUG1):print("De %d, index %d next %d"%(realcurrent, index,nextcase))
        if DEBUG1: Draw.wait_for_input()
    return tilepoints
def visualise(p1, p2, newshape, oldshape, color=0, drawnshapes=None, shapespoly=None, fill=True, ord=None,
              prints=False, refresh = False):
    realshape = newshape % len(order)
    if (drawnshapes == None):
        drawnshapes = list()
    if (prints): print("Visualise---------", newshape, oldshape, "(%s)" % realshape, shape[realshape])
    if (shapespoly == None):
        shapespoly = list()
    points = get_face_points(p1, p2, newshape, False)
    shapespoly.append(RollyPoly(newshape, points, color, fill))
    current = shape[realshape]
    if (prints): print(current, 'of shape', realshape, ', coming from', oldshape)
    try:
        index = current.index(oldshape)
    except:
        # Maybe the -P +P formula is not respected
        index = current.index(-oldshape + 2 * (oldshape % len(order)))
        #print("Exception matching", oldshape % len(order), "+%dP" % (oldshape // len(order)))

    current = current[index:] + current[:index]
    shapespoly[-1].fill(current)
    drawnshapes.append(realshape)
    if(refresh):
        Draw.refresh()
    # sleep(0.1)
    # print("I have",len(points),"points")
    # if(newshape==realshape):
    # print("Next ones:",current)
    for index, p in enumerate(current):
        # print("Looking",p)
        # print(index)
        p1 = points[index % len(points)]
        p2 = points[(index + 1) % len(points)]
        if (p not in drawnshapes) and (p % len(order) == p):
            visualise(p2, p1, p, newshape, color, drawnshapes, shapespoly, fill)
        """else:
			if(p in drawnshapes):
				print("P in drawn:",p,drawnshapes,p not in drawnshapes)
			if(p%len(order)!=p):
				print("P not to draw",p,p%len(order))"""
    return shapespoly
def get_neighbours_positions(tile, p1=P1, p2=P2, startcase=0, recurse=0):
    neighbours_coords = dict()
    if recurse:
        neighbours_neighbours = dict()
        if DEBUG4:
            nn_debug = dict()
    explored = list()
    ####PART 1 : explore and list all neighbouring tiles
    to_explore = [list((p1, p2, startcase))]
    while to_explore:
        initial_p1, initial_p2, case = to_explore.pop()  # the initial shape from which the exploration starts
        if recurse:
            c = centeroftilestarting(initial_p1, initial_p2, tile[case % len(tile)][0], case, tile, 1)
            if DEBUG4:
                print("Center received", c)
                Draw.text_center("_0_", *c, (128, 0, 0), 30)
        initial_points = get_face_points(initial_p1, initial_p2, len(tile[case]))
        if DEBUG1: Draw.polygon_shape(initial_points, (0, 255 * recurse, 0), alpha=.5, outline=1)
        initial_points = initial_points + initial_points
        if DEBUG1: Draw.text_center(str(case), *centerpoint(initial_points), (0, 0, 255), 12)
        if DEBUG1: Draw.refresh()
        explored.append(case)
        if DEBUG1: Draw.wait_for_input()
        for index, next in enumerate(tile[case]):
            branch_p1 = initial_points[index]
            branch_p2 = initial_points[index + 1]
            branch_points = 2 * get_face_points(branch_p2, branch_p1, len(
                tile[next % len(tile)]))  # the direction of the segment has to be reversed
            # branch_points triangle starts at [case] as its origin
            # but next triangle loop considers starts at 0 (forgets previous)
            # rotate the triangle so that the origin side is 0
            if next % len(tile) == next and next != case:
                side_offset = len(tile[next]) - tile[next].index(case)
                next_p1, next_p2 = branch_points[side_offset:side_offset + 2]
                # inside the net (excluding self-ref which are outside)
                if next not in explored:
                    # Branch out inside
                    to_explore.append([next_p1, next_p2, next])
            else:
                # outside the net= neighbour data
                branch_p1 = initial_points[index]
                branch_p2 = initial_points[index + 1]
                # branch_points = 2*get_face_points(branch_p2, branch_p1, len(tile[case])) #the direction of the segment has to be reversed
                # side_offset = len(tile[next%len(tile)])-index#len(tile[next%len(tile)])-find_matching_offset(case,next,tile)
                # next_p1, next_p2 = branch_points[side_offset:side_offset+2]
                if DEBUG1: print("Going outside: %d to %d index %d" % (case, next % len(tile), index))
                neighbour = centeroftilestarting(branch_p2, branch_p1, case, next,
                                                 tile)  # this takes prev tile so no shift
                neighbours_coords.setdefault(neighbour, [])
                neighbours_coords[neighbour].append((case, next))

                if recurse:
                    # current, sym = find_matching(case,next,tile)
                    side_offset = len(tile[next % len(tile)]) - find_matching_offset(case, next, tile)
                    next_p1, next_p2 = branch_points[side_offset:side_offset + 2]
                    nn = get_neighbours_positions(tile, next_p1, next_p2, next % len(tile), recurse=False)
                    for n in nn:
                        nn[n].sort()
                    if DEBUG4:
                        debug_data = (next_p1, next_p2, next % len(tile))
                        if neighbour in neighbours_neighbours:
                            if neighbours_neighbours[neighbour] != nn:
                                print("Not matching when reading neighbour", neighbour,
                                      "'s neighbours from two different sides:\nOriginal:")
                                print(nn_debug[neighbour])
                                pp.pprint(neighbours_neighbours[neighbour])
                                print("New: (coming from %d to %d)" % (case, next))
                                print(debug_data)
                                pp.pprint(nn)
                        nn_debug.setdefault(neighbour, debug_data)
                    neighbours_neighbours.setdefault(neighbour, nn)
 if len(tile[case % len(tile)]) != len(poly[face]):
     continue
 # caseorientation = 0
 # orientation is tileorientation
 # print("Known positions for",case%len(tile),face,orientation)
 # print(positions[(case%len(tile),face,orientation)])
 if tilecoord in positions[(case % len(tile), face, orientation)]:
     continue
 # if(not is_known((case,face,orientation),tilecoord,positions,symmetry_axis)):
 startpoints = get_face_points(p1, p2, len(poly[face]))
 color = Draw.colors[sum([abs(x * (n + 1)) for n, x in enumerate(tilecoord)]) % len(Draw.colors)]
 Draw.polygon_shape(startpoints, color, 0.75, 1)
 # Draw.text_center("%d/%d+%d"%(face,case%len(tile),(case-(case%len(tile)))//len(tile)),*centerpoint(startpoints),(255,255,255),int(ext/2))
 Draw.text_center(str(tilecoord) + str(tilecoordsign), *centerpoint(startpoints), (255, 255, 255), int(ext / 4))
 # Draw.text_center("%d(%d)"%(case,(case-(case%len(tile)))//len(tile)),*centerpoint(startpoints),(255,255,255),int(ext/2))
 Draw.refresh()
 # Draw.wait_for_input()
 if len(positions[(case % len(tile), face, orientation)]) == 0:
     # add_new_symmetry((case,face,orientation),tilecoord,positions,symmetry_axis)
     # Draw.wait_for_input()
     newcases = tile[case % len(tile)]
     newfaces = poly[face][orientation:] + poly[face][:orientation]
     if DEBUG3: print(case % len(tile), newcases)
     if DEBUG3: print(face % len(poly), newfaces)
     for i in range(len(newcases)):
         newface = newfaces[i]
         newcase = newcases[i]
         # if(newcase%len(tile)!=newcase):
         #    continue
         if DEBUG3: print("index", i, "going to", newcase)
         if len(tile[newcase % len(tile)]) != len(poly[newface]):