def contour_lines_from_endpoints(endpoints, crossing_points, connections,
    min_length=3, backtrack_from_end=False, extend_endpoints=True):
    """
    Follow contour lines and create contours

    - endpoints: an iterable of crossing point IDs (could be facet ids)
    - crossing_points: a mapping from crossing point ID to position coordinates
    - connections: a mapping from ID to IDs
    """
    contours = []
    endpoint_ids = list(endpoints)
    while endpoint_ids:
        end_id = endpoint_ids.pop()
        if not end_id in crossing_points:
            continue
        contour = [crossing_points.pop(end_id)]
        queue = list(connections[end_id])
        prev = end_id
        has_backtracked = False
        while queue:
            nb_id = queue.pop()
            if nb_id in crossing_points:
                cpoint = crossing_points.pop(nb_id)
                if cpoint != contour[-1]:
                    contour.append(cpoint)
                if extend_endpoints:
                    for candidate in queue:
                        if candidate in crossing_points:
                            endpoint_ids.append(candidate)
                queue = list(connections[nb_id])
                prev = nb_id
            if nb_id == end_id and prev in connections[end_id] and len(contour
                ) > min_length - 1 and not has_backtracked:
                contour.append(contour[0])
                break
            if backtrack_from_end and not queue and not has_backtracked:
                contour = contour[::-1]
                queue = list(connections[end_id])
                has_backtracked = True
        contours.append(contour)
    return contours
