Beispiel #1
0
    def pack_shape_scale_binary(self, plot=False):
        # TODO: select one of the base_shapes randomly
        # TODO: use bounding circle for first pass
        #       https://www.nayuki.io/res/smallest-enclosing-circle/smallestenclosingcircle.py
        center = self.random_point()
        base = self.base_shapes[0]
        ph = np.random.random() * 2 * np.pi
        R = np.matrix([[np.cos(ph), -np.sin(ph)], [np.sin(ph), np.cos(ph)]])
        rbase = [b * R for b in base]

        if plot:
            self.plot_border()
            plt.plot(center[:, 0], center[:, 1], 'k.')
            hc, = plt.plot([], [], 'k-')

        # binary search on scale to find best fit
        thresh = .001
        lo = 0
        r = .001
        hi = np.inf
        while True:
            transformed = [[(r * b + center).tolist(), []] for b in rbase]

            # a = [(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)]
            # b = [(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)]
            # mp = MultiPolygon([[a, []], [b, []]])
            p = MultiPolygon(transformed)
            intersected = False
            for shape in self.shapes:
                if p.intersects(shape):
                    intersected = True
                    break

            if intersected:
                # too big, reduce size and adjust range
                hi = r
                r = (lo + r) / 2
            else:
                # too small, increase size
                lo = r
                if hi == np.inf:
                    # keep doubling while we haven't yet hit a neighboring shape
                    r = 2*r
                else:
                    r = (r + hi) / 2

            if plot:
                cc = arc(center, r)
                hc.set_xdata(cc[:, 0])
                hc.set_ydata(cc[:, 1])
                plt.show(block=False)
                # plt.pause(.01)

            if hi - lo <= thresh:
                break

        # print('  radius = %f' % r)

        self.shapes.append(p)
Beispiel #2
0
    def insert_randomly(self,
                        grain_object: PySALEObject,
                        max_attempts: int = 100) -> bool:
        """Insert object into the host at random locations until it fits

        "fits" means - "is not intersecting with any other objects."

        Parameters
        ----------
        grain_object : PySALEObject
        max_attempts : int
            The number of attempts the algorithm will make
            before giving up

        Returns
        -------
        success : bool
        """
        assert type(max_attempts) == int and max_attempts > 0,\
            f'Maximum number of attempts ' \
            f'MUST be a positive integer and not {max_attempts}'
        minx, miny, maxx, maxy = self.object.bounds
        if not self.object.has_children:
            intersects_with_other_shapes = False
        else:
            intersects_with_other_shapes = True
        is_within_domain = False
        mp = MultiPolygon(self.object.children)
        counter = 0
        success = False
        while intersects_with_other_shapes \
                or is_within_domain is not True:
            grain_object = self._move_object_to_random_coordinate_in_domain(
                grain_object, maxx, maxy, minx, miny)
            is_within_domain = self.object.contains(grain_object)
            intersects_with_other_shapes = mp.intersects(grain_object)
            counter += 1
            if counter >= max_attempts:
                warnings.warn(f'Max insertion attempts '
                              f'reached ({max_attempts}). '
                              f'Object can not be placed.')
                success = False
                break
            else:
                success = True
        if is_within_domain and not intersects_with_other_shapes:
            self.object.add_child(grain_object)
        return success
Beispiel #3
0
class VehiclesEmissions(EmissionsBase):

    hp2num = {
       'Menys 8 cf': 3, '8 a 8,9': 8.5, '9 a 9,9': 9.5, '10 a 10,9': 10.5, '11 a 11,9': 11.5,
       '12 a 12,9': 12.5, '13 a 13,9': 13.5, '14 a 14,9': 14.5, '15 a 15,9': 15.5, '16 a 19,9': 18,
       '20 i més cf': 25, 'No consta': 5
    }
    
    total_emissions = 4930000000.0
    
    close_nbrs = 3

    def __init__(self):
        self.cars = download_csv_dataset('est-vehicles-potencia-fiscal-turismes')
        self.neighborhoods = get_neighborhoods()
        limits = get_city_limits()
        self.city_limits = MultiPolygon([Polygon(g[0]) for g in limits])
        self.nbr2emi = {}
        for index, car in self.cars.iterrows():
            nbr_id = car['Codi_Barri']
            if not nbr_id in self.nbr2emi:
                self.nbr2emi[nbr_id] = 0
            self.nbr2emi[nbr_id] += self.hp2num[car['Potencia_fiscal']] * car['Nombre_turismes']
    
    def prepare_grid(self, min_lat, min_lon, lat_bins, lon_bins, bin_size):
        self.emis_grid = np.zeros((lat_bins, lon_bins), dtype=float)
        for i in range(lat_bins):
            for j in range(lon_bins):
                lat = min_lat + bin_size * (i + 0.5)
                lon = min_lon + bin_size * (j + 0.5)
                if self.city_limits.intersects(Point(lon, lat)):
                    nbrs = []
                    for index, nbr in self.neighborhoods.iterrows():
                        dist = geopy.distance.vincenty((lat, lon), (nbr['lat'], nbr['lon'])).km
                        nbrs.append((index, 1.0 / dist))
                    nbrs.sort(key=lambda n: n[1], reverse=True)
                    nbrs = nbrs[:self.close_nbrs]
                    s = sum([n[1] for n in nbrs])
                    self.emis_grid[i][j] = np.sum([self.nbr2emi[n[0]] * n[1] / s for n in nbrs])
        s = np.sum(self.emis_grid)
        self.emis_grid = self.total_emissions * self.emis_grid / s
    
    def get_emission(self, i, j, lat, lon):
        return self.emis_grid[i][j]
Beispiel #4
0
    def intersectIslands(self, paths,
                         islands: List[Island]) -> Tuple[Any, Any]:
        """
        Perform the intersection and overlap tests on the island sub regions. This should be performed before any
        clipping operations are performed.

        :param paths: List of coordinates describing the boundary
        :param islands: A list of Islands to have the intersection and overlap test

        :return: A tuple containing lists of clipped and unClipped islands
        """
        polys = []
        for path in paths:
            polys += pathsToClosedPolygons(path)

        poly = MultiPolygon(polys)

        intersectIslands = []
        overlapIslands = []

        intersectIslandsSet = set()
        overlapIslandsSet = set()

        for i in range(len(islands)):

            island = islands[i]
            s = island.boundary()

            if poly.overlaps(s):
                overlapIslandsSet.add(i)  # id
                overlapIslands.append(island.boundary)
                island.setRequiresClipping(True)

            if poly.intersects(s):
                intersectIslandsSet.add(i)  # id
                intersectIslands.append(island.boundary)
                island.setIntersecting(True)

        unTouchedIslandSet = intersectIslandsSet - overlapIslandsSet
        unTouchedIslands = [islands[i] for i in unTouchedIslandSet]

        return overlapIslandsSet, unTouchedIslandSet
    # Python sets are used to perform boolean operations on a set to identify unclipped islands
    intersectIslandsSet = set()
    overlapIslandsSet = set()

    # Iterate across all the islands
    for i in range(len(islands)):

        island = islands[i]
        s = island.boundary()

        if poly.overlaps(s):
            overlapIslandsSet.add(i)  # id
            overlapIslands.append(island)

        if poly.intersects(s):
            intersectIslandsSet.add(i)  # id
            intersectIslands.append(island)

    unTouchedIslandSet = intersectIslandsSet - overlapIslandsSet
    unTouchedIslands = [islands[i] for i in unTouchedIslandSet]

    print('Finished Island Clipping')

    fig, ax = pyslm.visualise.plotPolygon(geomSlice)

    # Plot using visualise.plotPolygon the original islands generated before intersection
    for island in islands:
        x, y = island.boundary().exterior.xy
        pyslm.visualise.plotPolygon([np.vstack([x, y]).T], handle=(fig, ax))
Beispiel #6
0
# first, calculate a bounding box to restrict the diagram
min_x = min(stops_pts[:,0]) - 5000
max_x = max(stops_pts[:,0]) + 5000
min_y = min(stops_pts[:,1]) - 5000
max_y = max(stops_pts[:,1]) + 5000
bbox = np.array([[min_x,min_y], [max_x,max_y], [min_x,max_y], [max_x,min_y]])

# find the voronoi
coords = np.vstack([stops_pts, bbox])
vor = Voronoi(coords)

# rearrange, so that regions are in the same order as their corresponding
# points, so the last four are the bbox dummy observations, and remove them
regions = np.array(vor.regions)[vor.point_region]
regions = regions[:-4]
clipped = []
for region in regions:
    region_vertices = vor.vertices[region]
    region_polygon = Polygon(region_vertices)

    if nyc.intersects(region_polygon):
        clipped.append(nyc.intersection(region_polygon))

clipped = GeoSeries(clipped)
stops = GeoDataFrame(stops)
stops.index = np.arange(stops.shape[0])
stops['region'] = clipped

pickle.dump(stops,open('save/stops.p','wb'))
pickle.dump(nyc,open('save/nyc.p','wb'))
Beispiel #7
0
def ReadMossPolygons(mossBaseFileName, printDiagnostic=False):
    '''
    .ms1 file is fixed format
    
    Header lines 56 characters
    char 1-5 : Item Number(NEGATIVE IF THE COORDINATES ARE LON/LAT)
    char 16-45: Attribute Name
    char 51-55: Number of coord. pairs
    
    X,Y, Coordinate pairs 23 characters
    01-11: x coordinate
    12-22: y coordinate
    
    Long,Lat pairs
    char 01-10: LONGITUDE
    char 11-20: LATITUDE
    char 21-22: FLAG 
        0-NORMAL 
        1-INDICATES FIRST POINT OF ISLAND POLYGON
    
    '''
    # import shapely here so it won't be imported if not needed
    from shapely.geometry import Polygon, MultiPolygon

    # what about MAPBOUND, EXTENDEDOUTLOOKTHREAT
    attributesToRead = [
        "MAPLAND", "FORECASTHEAVY", "FORECASTMEDIUM", "FORECASTLIGHT",
        "FORECASTUNCERTAINTY"
    ]

    landBoundariesList = []
    heavyBoundariesList = []
    mediumBoundariesList = []
    lightBoundariesList = []
    uncertaintyBoundariesList = []

    extension = ".ms1"
    if os.path.exists(mossBaseFileName + extension):
        inFile = file(mossBaseFileName + extension, 'rU')
        alreadyReadNextLine = False
        while True:  # read the header lines
            if not alreadyReadNextLine:
                line = inFile.readline()
            alreadyReadNextLine = False

            if not line: break  # end of this file
            if line.strip() == "":
                continue
                # blank line

            itemNum = int(line[0:5])
            assert itemNum < 0  # we expect long/lat values, so the itemNum should be negative

            attributeName = line[15:45].strip()

            numCoordinates = int(line[50:55])

            # note: for some versions of GNOME analyst
            # the number of coordinates in MAPLAND overflows and is reported as a negative number or incorrect number.
            # To support those files, we will ignore the number and just read lines based on the length of the lines

            if printDiagnostic:
                print itemNum, attributeName, numCoordinates

            readingOuterBoundary = True
            coordList = []

            outerBoundary = None
            innerBoundaries = []

            if numCoordinates <= 0:
                print "*** ignoring bad %s header line value: numCoordinates: %d ***" % (
                    attributeName, numCoordinates)

            # read the points for the polygon for this header
            while True:  #for i in range(0,numCoordinates):
                # since we don't want to rely on numCoordinates
                # we need to look to see if this is the end of this block of coordinates
                ##################
                line = inFile.readline()

                # The lines are fixed format,
                # read until we find a header line
                # header lines lines are longer than coordinate lines
                if (not line) or len(line.strip(
                )) > 50:  # must be end of file or a header line
                    alreadyReadNextLine = True
                    break  # out of this while loop

                if attributeName in attributesToRead:
                    #process this line
                    longitudeStr = line[0:10].strip()
                    latitudeStr = line[10:20].strip()
                    flag = line[20:22].strip()

                    if flag == "1":
                        #then we are starting a new "inner hole"

                        # enforce having the last point of the polygon equal the first point
                        if len(coordList
                               ) > 0 and coordList[0] != coordList[-1]:
                            coordList.append(coordList[0])

                        # save the previous coordList
                        if len(
                                coordList
                        ) >= 4:  # less than 4 would be a degenerate case
                            if readingOuterBoundary:
                                outerBoundary = coordList
                            else:
                                innerBoundaries.append(coordList)

                        # reset the coordinate list
                        coordList = []
                        readingOuterBoundary = False

                    coordList.append((float(longitudeStr), float(latitudeStr)))
                ############# end of while loop

            # finished reading the header
            # record the lists we have filled in

            if not attributeName in attributesToRead:
                continue  # on to the next header line

            # enforce having the last point of the polygon equal the first point
            if len(coordList) > 0 and coordList[0] != coordList[-1]:
                coordList.append(coordList[0])

            #filter out degenerate cases
            if len(coordList) < 4:  # less than 4 would be a degenerate case
                print "*** ignoring degenerate polygon ***"
                continue  # on to the next header line

            # save the coordinate list
            if readingOuterBoundary:
                outerBoundary = coordList
            else:
                innerBoundaries.append(coordList)

            #save thisPolygon
            if len(outerBoundary) > 0:
                # outerBoundary,innerBoundaries = VerifyAndFixGnomeAnalystPolygon(attributeName,outerBoundary,innerBoundaries)
                if len(outerBoundary) > 0:
                    thisPolygon = (outerBoundary, innerBoundaries)
                    if attributeName == "MAPLAND":
                        landBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTHEAVY":
                        heavyBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTMEDIUM":
                        mediumBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTLIGHT":
                        lightBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTUNCERTAINTY":
                        uncertaintyBoundariesList.append(thisPolygon)

        inFile.close()

    # convert the lists of MossPolygons to shapely MultiPolygons
    if len(landBoundariesList) == 0: landPolygons = None
    else:
        landPolygons = MultiPolygon(landBoundariesList)
        if not landPolygons.is_valid:
            # try analysing and fixing the problem
            landPolygons = DiagnoseAndFixMultiPolygon("MAPLAND",
                                                      landBoundariesList)

    if len(heavyBoundariesList) == 0: heavyPolygons = None
    else:
        heavyPolygons = MultiPolygon(heavyBoundariesList)
        if not heavyPolygons.is_valid:
            heavyPolygons = DiagnoseAndFixMultiPolygon("FORECASTHEAVY",
                                                       heavyBoundariesList)

    if len(mediumBoundariesList) == 0: mediumPolygons = None
    else:
        mediumPolygons = MultiPolygon(mediumBoundariesList)
        if not mediumPolygons.is_valid:
            mediumPolygons = DiagnoseAndFixMultiPolygon(
                "FORECASTMEDIUM", mediumBoundariesList)

    if len(lightBoundariesList) == 0: lightPolygons = None
    else:
        lightPolygons = MultiPolygon(lightBoundariesList)
        if not lightPolygons.is_valid:
            lightPolygons = DiagnoseAndFixMultiPolygon("FORECASTLIGHT",
                                                       lightBoundariesList)

    if len(uncertaintyBoundariesList) == 0: uncertaintyPolygons = None
    else:
        uncertaintyPolygons = MultiPolygon(uncertaintyBoundariesList)
        if not uncertaintyPolygons.is_valid:
            uncertaintyPolygons = DiagnoseAndFixMultiPolygon(
                "FORECASTUNCERTAINTY", uncertaintyBoundariesList)

    # clip the oil contours to the shoreline
    # note: we need to check that the polygons are valid before trying to clip to prevent shapely from crashing
    if landPolygons != None:
        if landPolygons.is_valid == False:
            print "*** landPolygons is not valid. We will not clip to the shoreline. ***"
        else:
            if heavyPolygons != None:
                if heavyPolygons.is_valid == False:
                    print "*** heavyPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif heavyPolygons.intersects(landPolygons):
                    print "clipping heavyPolygons to shoreline"
                    heavyPolygons = heavyPolygons.difference(landPolygons)

            if mediumPolygons != None:
                if mediumPolygons.is_valid == False:
                    print "*** mediumPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif mediumPolygons.intersects(landPolygons):
                    print "clipping mediumPolygons to shoreline"
                    mediumPolygons = mediumPolygons.difference(landPolygons)

            if lightPolygons != None:
                if lightPolygons.is_valid == False:
                    print "*** lightPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif lightPolygons.intersects(landPolygons):
                    print "clipping lightPolygons to shoreline"
                    lightPolygons = lightPolygons.difference(landPolygons)

            # note: JerryM wonders we should clip the uncertainty to the shoreline.  That it looks better as simple polygons going over the land.
            if uncertaintyPolygons != None:
                if uncertaintyPolygons.is_valid == False:
                    print "*** uncertaintyPolygons is not valid. It will not be clipped to the shoreline or oil polygons ***"
                else:
                    print "clipping uncertaintyPolygons to shoreline and oil polygons"

                    for polygons, nameOfPolygons in [
                        (lightPolygons, "lightPolygons"),
                        (mediumPolygons, "mediumPolygons"),
                        (heavyPolygons, "heavyPolygons"),
                        (landPolygons, "landPolygons")
                    ]:
                        if polygons != None:
                            print "taking difference with", nameOfPolygons
                            newUncertaintyPolygons = uncertaintyPolygons.difference(
                                polygons)
                            print "finished taking difference"
                            if not newUncertaintyPolygons.is_valid:
                                #print "Uncertainty Polygon is no longer valid after taking difference with",polygons,nameOfPolygons
                                s = "*** uncertaintyPolygons have not been clipped to %s ***" % (
                                    nameOfPolygons)
                                print s
                            else:
                                uncertaintyPolygons = newUncertaintyPolygons

    return (landPolygons, heavyPolygons, mediumPolygons, lightPolygons,
            uncertaintyPolygons)
Beispiel #8
0
min_x = min(stops_pts[:, 0]) - 5000
max_x = max(stops_pts[:, 0]) + 5000
min_y = min(stops_pts[:, 1]) - 5000
max_y = max(stops_pts[:, 1]) + 5000
bbox = np.array([[min_x, min_y], [max_x, max_y], [min_x, max_y],
                 [max_x, min_y]])

# find the voronoi
coords = np.vstack([stops_pts, bbox])
vor = Voronoi(coords)

# rearrange, so that regions are in the same order as their corresponding
# points, so the last four are the bbox dummy observations, and remove them
regions = np.array(vor.regions)[vor.point_region]
regions = regions[:-4]
clipped = []
for region in regions:
    region_vertices = vor.vertices[region]
    region_polygon = Polygon(region_vertices)

    if nyc.intersects(region_polygon):
        clipped.append(nyc.intersection(region_polygon))

clipped = GeoSeries(clipped)
stops = GeoDataFrame(stops)
stops.index = np.arange(stops.shape[0])
stops['region'] = clipped

pickle.dump(stops, open('save/stops.p', 'wb'))
pickle.dump(nyc, open('save/nyc.p', 'wb'))
Beispiel #9
0
def ReadMossPolygons(mossBaseFileName, printDiagnostic = False):
    '''
    .ms1 file is fixed format
    
    Header lines 56 characters
    char 1-5 : Item Number(NEGATIVE IF THE COORDINATES ARE LON/LAT)
    char 16-45: Attribute Name
    char 51-55: Number of coord. pairs
    
    X,Y, Coordinate pairs 23 characters
    01-11: x coordinate
    12-22: y coordinate
    
    Long,Lat pairs
    char 01-10: LONGITUDE
    char 11-20: LATITUDE
    char 21-22: FLAG 
        0-NORMAL 
        1-INDICATES FIRST POINT OF ISLAND POLYGON
    
    '''
    # import shapely here so it won't be imported if not needed
    from shapely.geometry import Polygon, MultiPolygon

    # what about MAPBOUND, EXTENDEDOUTLOOKTHREAT
    attributesToRead = ["MAPLAND","FORECASTHEAVY","FORECASTMEDIUM","FORECASTLIGHT","FORECASTUNCERTAINTY"]
    
    landBoundariesList = [] 
    heavyBoundariesList = [] 
    mediumBoundariesList = [] 
    lightBoundariesList = []
    uncertaintyBoundariesList = []
     
    extension = ".ms1"
    if os.path.exists(mossBaseFileName + extension):
        inFile = file(mossBaseFileName + extension, 'rU')
        alreadyReadNextLine = False
        while True:  # read the header lines     
            if not alreadyReadNextLine:
                line = inFile.readline()
            alreadyReadNextLine = False
            
            if not line: break # end of this file
            if line.strip() == "" : continue; # blank line
            
            itemNum = int(line[0:5])
            assert itemNum < 0 # we expect long/lat values, so the itemNum should be negative
            
            attributeName = line[15:45].strip()

            numCoordinates = int(line[50:55])
            
            
            # note: for some versions of GNOME analyst
            # the number of coordinates in MAPLAND overflows and is reported as a negative number or incorrect number.
            # To support those files, we will ignore the number and just read lines based on the length of the lines
              
            if printDiagnostic: 
                print itemNum,attributeName,numCoordinates
            
            readingOuterBoundary = True
            coordList = []
            
            outerBoundary = None
            innerBoundaries = []
             
            if numCoordinates <= 0:
                print "*** ignoring bad %s header line value: numCoordinates: %d ***"%(attributeName,numCoordinates)
            
            # read the points for the polygon for this header           
            while True: #for i in range(0,numCoordinates):
                # since we don't want to rely on numCoordinates
                # we need to look to see if this is the end of this block of coordinates
                ##################
                line = inFile.readline()
                
                # The lines are fixed format,
                # read until we find a header line
                # header lines lines are longer than coordinate lines 
                if (not line) or len(line.strip()) > 50 : # must be end of file or a header line
                    alreadyReadNextLine = True 
                    break # out of this while loop
                
                if attributeName in attributesToRead:
                    #process this line
                    longitudeStr = line[0:10].strip()
                    latitudeStr = line[10:20].strip()
                    flag = line[20:22].strip()
                    
                    if flag == "1" :
                        #then we are starting a new "inner hole"
                        
                        # enforce having the last point of the polygon equal the first point
                        if len(coordList) > 0 and coordList[0] != coordList[-1]:
                            coordList.append(coordList[0])

                        # save the previous coordList
                        if len(coordList) >= 4: # less than 4 would be a degenerate case                          
                            if readingOuterBoundary:
                                outerBoundary = coordList
                            else:
                                innerBoundaries.append(coordList)
                                
                        # reset the coordinate list 
                        coordList = []                                         
                        readingOuterBoundary = False
                    
                    coordList.append((float(longitudeStr),float(latitudeStr)))
                ############# end of while loop
                
            # finished reading the header
            # record the lists we have filled in
            
            if not attributeName in attributesToRead:
                continue # on to the next header line 
            
            # enforce having the last point of the polygon equal the first point
            if len(coordList) > 0 and coordList[0] != coordList[-1]:
                coordList.append(coordList[0])
                
            #filter out degenerate cases
            if len(coordList) < 4: # less than 4 would be a degenerate case
                print "*** ignoring degenerate polygon ***"
                continue # on to the next header line 
                
            # save the coordinate list                             
            if readingOuterBoundary:
                outerBoundary = coordList
            else:
                innerBoundaries.append(coordList)
                
            
            #save thisPolygon
            if len (outerBoundary) > 0 :
                # outerBoundary,innerBoundaries = VerifyAndFixGnomeAnalystPolygon(attributeName,outerBoundary,innerBoundaries)
                if len (outerBoundary) > 0 :
                    thisPolygon = (outerBoundary,innerBoundaries)
                    if attributeName == "MAPLAND": landBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTHEAVY": heavyBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTMEDIUM": mediumBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTLIGHT": lightBoundariesList.append(thisPolygon)
                    elif attributeName == "FORECASTUNCERTAINTY": uncertaintyBoundariesList.append(thisPolygon) 
                
                
        inFile.close()
        
    # convert the lists of MossPolygons to shapely MultiPolygons
    if len(landBoundariesList) == 0: landPolygons = None
    else: 
        landPolygons = MultiPolygon(landBoundariesList)
        if not landPolygons.is_valid:
            # try analysing and fixing the problem
            landPolygons = DiagnoseAndFixMultiPolygon("MAPLAND",landBoundariesList)
    
    if len(heavyBoundariesList) == 0: heavyPolygons = None
    else: 
        heavyPolygons = MultiPolygon(heavyBoundariesList)
        if not heavyPolygons.is_valid:
            heavyPolygons =DiagnoseAndFixMultiPolygon("FORECASTHEAVY",heavyBoundariesList)
    
    if len(mediumBoundariesList) == 0: mediumPolygons = None
    else: 
        mediumPolygons = MultiPolygon(mediumBoundariesList)
        if not mediumPolygons.is_valid:
            mediumPolygons = DiagnoseAndFixMultiPolygon("FORECASTMEDIUM",mediumBoundariesList)
    
    if len(lightBoundariesList) == 0: lightPolygons = None
    else: 
        lightPolygons = MultiPolygon(lightBoundariesList)
        if not lightPolygons.is_valid:
            lightPolygons = DiagnoseAndFixMultiPolygon("FORECASTLIGHT",lightBoundariesList)
                              
    if len(uncertaintyBoundariesList) == 0: uncertaintyPolygons = None
    else: 
        uncertaintyPolygons = MultiPolygon(uncertaintyBoundariesList)
        if not uncertaintyPolygons.is_valid:
            uncertaintyPolygons = DiagnoseAndFixMultiPolygon("FORECASTUNCERTAINTY",uncertaintyBoundariesList)
        
   
    # clip the oil contours to the shoreline
    # note: we need to check that the polygons are valid before trying to clip to prevent shapely from crashing
    if landPolygons != None :
        if landPolygons.is_valid == False:
            print "*** landPolygons is not valid. We will not clip to the shoreline. ***"
        else :
            if heavyPolygons != None: 
                if heavyPolygons.is_valid == False:
                    print "*** heavyPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif heavyPolygons.intersects(landPolygons):
                    print "clipping heavyPolygons to shoreline"
                    heavyPolygons = heavyPolygons.difference(landPolygons)
                    
            if mediumPolygons != None: 
                if mediumPolygons.is_valid == False:
                    print "*** mediumPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif mediumPolygons.intersects(landPolygons):
                    print "clipping mediumPolygons to shoreline"
                    mediumPolygons = mediumPolygons.difference(landPolygons)
                    
            if lightPolygons != None: 
                if lightPolygons.is_valid == False:
                    print "*** lightPolygons is not valid. It will not be clipped to the shoreline. ***"
                elif lightPolygons.intersects(landPolygons):
                    print "clipping lightPolygons to shoreline"
                    lightPolygons = lightPolygons.difference(landPolygons)
                    
            # note: JerryM wonders we should clip the uncertainty to the shoreline.  That it looks better as simple polygons going over the land.
            if uncertaintyPolygons != None: 
                if uncertaintyPolygons.is_valid == False:
                    print "*** uncertaintyPolygons is not valid. It will not be clipped to the shoreline or oil polygons ***"
                else:
                    print "clipping uncertaintyPolygons to shoreline and oil polygons"
                    
                    for polygons,nameOfPolygons in [(lightPolygons,"lightPolygons"),(mediumPolygons,"mediumPolygons"),(heavyPolygons,"heavyPolygons"),(landPolygons,"landPolygons")]:
                        if polygons != None: 
                            print "taking difference with",nameOfPolygons
                            newUncertaintyPolygons = uncertaintyPolygons.difference(polygons)
                            print "finished taking difference"
                            if not newUncertaintyPolygons.is_valid:
                                #print "Uncertainty Polygon is no longer valid after taking difference with",polygons,nameOfPolygons
                                s = "*** uncertaintyPolygons have not been clipped to %s ***"%(nameOfPolygons)
                                print s
                            else:
                                uncertaintyPolygons = newUncertaintyPolygons
                                
                    
   
           
    return   (landPolygons,heavyPolygons,mediumPolygons,lightPolygons,uncertaintyPolygons)