Return the geometry and attributes of a shapefile that lie within (or intersect) a bounding box

    :param sf: shapefile
    :type sf: shapefile object
    :param bbox: bounding box
    :type bbox: list of floats [x_min,y_min,x_max,y_max]
    :inside_only: True if the objects returned are those that lie within the bbox and False if the objects returned are any that intersect the bbox
    :type inside_only: Boolean

def bbox_match(sf,bbox,inside_only=True):
    """
    Return the geometry and attributes of a shapefile that lie within (or intersect) a bounding box

    :param sf: shapefile
    :type sf: shapefile object
    :param bbox: bounding box
    :type bbox: list of floats [x_min,y_min,x_max,y_max]
    :inside_only: True if the objects returned are those that lie within the bbox and False if the objects returned are any that intersect the bbox
    :type inside_only: Boolean
    """
    A,B,C,D = bbox
    index = []
    shape_records = []
    for rec in enumerate(sf.shapeRecords()):
        a,b,c,d = rec[1].shape.bbox
        if inside_only:
            if A <= a and B <= b and C >= c and D >= d:
                index.append(rec[0])
                shape_records.append(rec[1])
        else:
            cond1 = A <= a and B <= b and C >= a and D >= b
            cond2 = A <= c and B <= d and C >= c and D >= d
            cond3 = A <= a and D >= d and C >= a and B <= d
            cond4 = A <= c and D >= b and C >= c and B <= b
            cond5 = a <= C and b <= B and d >= D
            cond6 = c <= A and b <= B and d >= D
            cond7 = d <= B and a <= A and c >= C
            cond8 = b <= D and a <= A and c >= C
            if cond1 or cond2 or cond3 or cond4 or cond5 or cond6 or cond7 or cond8:
                index.append(rec[0])
                shape_records.append(rec[1])
    return index,shape_records