def merge_polygons(polygons,rotation_model, time=0,sampling=1.,area_threshold=None,filename=None, return_raster=False): multipoints = create_gpml_regular_long_lat_mesh(sampling) grid_dims = (int(180/sampling)+1,int(360/sampling)+1) for multipoint in multipoints: for mp in multipoint.get_all_geometries(): points = mp.to_lat_lon_point_list() bi = run_grid_pip(time,points,polygons,rotation_model,grid_dims) if return_raster: return bi else: # To handle edge effects, pad grid before making contour polygons ## --- start pad_hor = np.zeros((1,bi.shape[1])) pad_ver = np.zeros((bi.shape[0]+2,1)) pad1 = np.vstack((pad_hor,bi,pad_hor)) # add row of zeros to top and bottom pad2 = np.hstack((pad_ver,pad1,pad_ver)) # add row of zeros to left and right #pad3 = np.hstack((pad2,pad_ver)) contours = measure.find_contours(pad2, 0.5, fully_connected='low') ## --- end contour_polygons = [] contour_features = [] for n,cp in enumerate(contours): # To handle edge effects again - strip off parts of polygon # due to padding, and adjust from image coordinates to long/lat # --- start cp[:,1] = (cp[:,1]*sampling)-sampling cp[:,0] = (cp[:,0]*sampling)-sampling cp[np.where(cp[:,0]<0.),0] = 0 cp[np.where(cp[:,0]>180.),0] = 180 cp[np.where(cp[:,1]<0.),1] = 0 cp[np.where(cp[:,1]>360.),1] = 360 ## --- end cpf = pygplates.PolygonOnSphere(zip(cp[:,0]-90,cp[:,1]-180)) contour_polygons.append(cpf) feature = pygplates.Feature() feature.set_geometry(cpf) contour_features.append(feature) if filename is not None: pygplates.FeatureCollection(contour_features).write(filename) else: return contour_features
def check_points_within_polygon(lons, lats, polygon_points): polygon = pygplates.PolygonOnSphere( zip(polygon_points[1::2], polygon_points[::2])) ret = [] for lon, lat in zip(lons, lats): #print(lon,lat) try: if polygon.is_point_in_polygon((lat, lon)): ret.append(True) else: ret.append(False) except: ret.append(False) return ret
def grdcontour2feature(grdfile,clevel,return_polygons=True): # call GMT to get a single contour at the specified value of clevel call_system_command(['gmt', 'grdcontour', grdfile, '-Rd', '-C+%0.8f' % clevel, '-S4', '-Dcontour_%c.txt']) # read in the GMT delimited xyz ascii file, # create a list of lists with polygon coordinates f = open('./contour_C.txt', 'r') polygons = [] contourlist = [] for line in f: if line[0] == '>': if len(contourlist)>0: polygons.append(contourlist) contourlist = [] else: line = line.split() contourlist.append([float(j) for j in line]) #break # create gplates-format features polyline_features = [] for p in polygons: pf = pygplates.PolylineOnSphere(zip(list(zip(*p))[1],list(zip(*p))[0])) polyline_features.append(pf) # use join to handle polylines split across dateline joined_polyline_features = pygplates.PolylineOnSphere.join(polyline_features) if return_polygons: # force polylines to be polygons joined_polygon_features = [] for geom in joined_polyline_features: polygon = pygplates.Feature() polygon.set_geometry(pygplates.PolygonOnSphere(geom)) joined_polygon_features.append(polygon) return joined_polygon_features else: return joined_polyline_features
def force_polygon_geometries(input_features): # given any pygplates feature collection, creates an output feature collection # where all geometries are polygons based on the input geometries # intended for use in forcing features that are strictly polylines to close polygons = [] for feature in input_features: for geom in feature.get_all_geometries(): polygon = pygplates.Feature() polygon.set_geometry(pygplates.PolygonOnSphere(geom)) polygon.set_reconstruction_plate_id(feature.get_reconstruction_plate_id()) # some features in COBTerranes had invalid time ranges - these with throw an error if # we try to create a new feature with same times if feature.get_valid_time()[0]>=feature.get_valid_time()[1]: polygon.set_valid_time(feature.get_valid_time()[0],feature.get_valid_time()[1]) polygons.append(polygon) polygon_features = pygplates.FeatureCollection(polygons) return polygon_features
def seds_filter_points_in_polygon(latitude, longitude, zvalue, reconstructed_coastlines): ''' This function returns the plateID of latitude/longitude points at a given time from a rotation file It uses the topological plate boundary network to assign a plate ID. So it needs pyGPlates. ''' #because of how the data is formatted we need two for loops to check each point #because we are loading in a 2d array of longitude and latitude *each* filtered_lats = [] filtered_lons = [] filtered_zvals = [] for x, y, z in itertools.izip(latitude, longitude, zvalue): inputlatLon = pygplates.LatLonPoint(x, y) latLonPoint = pygplates.convert_lat_lon_point_to_point_on_sphere( inputlatLon) #print latLonPoint isPoly = [] #get geometry of static polygons at reconstructed time for coastline in reconstructed_coastlines: #print coastline coastline = pygplates.PolygonOnSphere( coastline.get_reconstructed_geometry()) #if int(coastline.is_point_in_polygon(latLonPoint)) == 1: #break#print tmp tmp = int(coastline.is_point_in_polygon(latLonPoint)) isPoly.append(tmp) if np.sum(isPoly) == 0: filtered_lats.append(x) filtered_lons.append(y) filtered_zvals.append(z) return filtered_lats, filtered_lons, filtered_zvals
def reconstruct_coastlines(time): shp_path = settings.MODEL_STORE_DIR+'/'+settings.MODEL_DEFAULT+'/coastlines_low_res/Seton_etal_ESR2012_Coastlines_2012.shp' import shapefile sf = shapefile.Reader(shp_path) features = [] for record in sf.shapeRecords(): if record.shape.shapeType != 5: continue for idx in range(len(record.shape.parts)): start_idx = record.shape.parts[idx] end_idx = len(record.shape.points) if idx < (len(record.shape.parts) -1): end_idx = record.shape.parts[idx+1] polygon_feature = pygplates.Feature() points = record.shape.points[start_idx:end_idx] polygon_feature.set_geometry( pygplates.PolygonOnSphere([(lat,lon) for lon, lat in points])) polygon_feature.set_reconstruction_plate_id(int(record.record[0])) features.append(polygon_feature) break feature_collection = pygplates.FeatureCollection(features) reconstructed_polygons = [] model_dict = get_reconstruction_model_dict(settings.MODEL_DEFAULT) rotation_model = pygplates.RotationModel([str('%s/%s/%s' % (settings.MODEL_STORE_DIR,settings.MODEL_DEFAULT,rot_file)) for rot_file in model_dict['RotationFile']]) pygplates.reconstruct( feature_collection, rotation_model, reconstructed_polygons, float(time)) return reconstructed_polygons
def _create_node(self, node_centre_lon, node_centre_lat, node_half_width_degrees, is_north_hemisphere): # Create the points of the polygon bounding the current quad tree node. bounding_polygon_points = [] left_lon = node_centre_lon - node_half_width_degrees right_lon = node_centre_lon + node_half_width_degrees bottom_lat = node_centre_lat - node_half_width_degrees top_lat = node_centre_lat + node_half_width_degrees # Northern and southern hemispheres handled separately. if is_north_hemisphere: # Northern hemisphere. left_boundary = pygplates.PolylineOnSphere([(0, left_lon), (90, left_lon)]) right_boundary = pygplates.PolylineOnSphere([(0, right_lon), (90, right_lon)]) # Midpoint of small circle arc bounding the bottom of quad tree node. bottom_mid_point = pygplates.PointOnSphere( bottom_lat, 0.5 * (left_lon + right_lon)) # Find the great circle (rotation) that passes through the bottom midpoint (and is oriented towards North pole). bottom_great_circle_rotation_axis = pygplates.Vector3D.cross( bottom_mid_point.to_xyz(), pygplates.Vector3D.cross( pygplates.PointOnSphere.north_pole.to_xyz(), bottom_mid_point.to_xyz())).to_normalised() bottom_great_circle_rotation = pygplates.FiniteRotation( bottom_great_circle_rotation_axis.to_xyz(), 0.5 * math.pi) # Intersect great circle bottom boundary with left and right boundaries to find bottom-left and bottom-right points. # The bottom boundary is actually a small circle (due to lat/lon grid), but since we need to use *great* circle arcs # in our geometries we need to be a bit loose with our bottom boundary otherwise it will go inside the quad tree node. bottom_boundary = pygplates.PolylineOnSphere([ bottom_great_circle_rotation * bottom_mid_point, bottom_mid_point, bottom_great_circle_rotation.get_inverse() * bottom_mid_point ]) _, _, bottom_left_point = pygplates.GeometryOnSphere.distance( bottom_boundary, left_boundary, return_closest_positions=True) _, _, bottom_right_point = pygplates.GeometryOnSphere.distance( bottom_boundary, right_boundary, return_closest_positions=True) bounding_polygon_points.append(bottom_left_point) bounding_polygon_points.append(bottom_right_point) bounding_polygon_points.append( pygplates.PointOnSphere(top_lat, right_lon)) bounding_polygon_points.append( pygplates.PointOnSphere(top_lat, left_lon)) else: # Southern hemisphere. left_boundary = pygplates.PolylineOnSphere([(0, left_lon), (-90, left_lon)]) right_boundary = pygplates.PolylineOnSphere([(0, right_lon), (-90, right_lon)]) # Midpoint of small circle arc bounding the top of quad tree node. top_mid_point = pygplates.PointOnSphere( top_lat, 0.5 * (left_lon + right_lon)) # Find the great circle (rotation) that passes through the top midpoint (and is oriented towards North pole). top_great_circle_rotation_axis = pygplates.Vector3D.cross( top_mid_point.to_xyz(), pygplates.Vector3D.cross( pygplates.PointOnSphere.north_pole.to_xyz(), top_mid_point.to_xyz())).to_normalised() top_great_circle_rotation = pygplates.FiniteRotation( top_great_circle_rotation_axis.to_xyz(), 0.5 * math.pi) # Intersect great circle top boundary with left and right boundaries to find top-left and top-right points. # The top boundary is actually a small circle (due to lat/lon grid), but since we need to use *great* circle arcs # in our geometries we need to be a bit loose with our top boundary otherwise it will go inside the quad tree node. top_boundary = pygplates.PolylineOnSphere([ top_great_circle_rotation * top_mid_point, top_mid_point, top_great_circle_rotation.get_inverse() * top_mid_point ]) _, _, top_left_point = pygplates.GeometryOnSphere.distance( top_boundary, left_boundary, return_closest_positions=True) _, _, top_right_point = pygplates.GeometryOnSphere.distance( top_boundary, right_boundary, return_closest_positions=True) bounding_polygon_points.append(top_left_point) bounding_polygon_points.append(top_right_point) bounding_polygon_points.append( pygplates.PointOnSphere(bottom_lat, right_lon)) bounding_polygon_points.append( pygplates.PointOnSphere(bottom_lat, left_lon)) bounding_polygon = pygplates.PolygonOnSphere(bounding_polygon_points) return QuadTreeNode(bounding_polygon)
def get_area_in_band(polygon, lat_min, lat_max): """ Calculate the area of a given polygon inside a given latitude band. Parameters ---------- polygon : pygpplates polygon lat_min : float the minimum latitude of the latitude band lat_max : float the maximum latitude of the latitude band Returns ------- area : float the area of the polygon within the latitude band (in km^2) band_polygon : pygplates polygon with the parts outside of the latitude band removed """ # pull out lat/lon vertices lat_lon_array = polygon.to_lat_lon_array() lats = lat_lon_array[:, 0] lons = lat_lon_array[:, 1] # storage lists bookmarks = [] lat_add_list = [] lon_add_list = [] # iterate through the points for i in range(1, len(lats)): top_cross = False bot_cross = False # case where we move into the band from above if lats[i - 1] > lat_max and lats[i] < lat_max: top_cross = True # case where we move out of the band from below if lats[i - 1] < lat_max and lats[i] > lat_max: top_cross = True # case where we move out of the band from above if lats[i - 1] > lat_min and lats[i] < lat_min: bot_cross = True # case where we move into the band from below if lats[i - 1] < lat_min and lats[i] > lat_min: bot_cross = True # do calculations if we cross if top_cross or bot_cross: # convert the endpoints of the polygon segment into cartesian A = lat_lon_2_cart(lats[i - 1], lons[i - 1]) B = lat_lon_2_cart(lats[i], lons[i]) # get the intersection point (for the top and bottom cases), and convert back to lat/lon if top_cross: C_top = lat_lon_2_cart(lat_max, min([lons[i], lons[i - 1]])) D_top = lat_lon_2_cart(lat_max, max([lons[i], lons[i - 1]])) T = intersection(A, B, C_top, D_top) else: C_bot = lat_lon_2_cart(lat_min, min([lons[i], lons[i - 1]])) D_bot = lat_lon_2_cart(lat_min, max([lons[i], lons[i - 1]])) T = intersection(A, B, C_bot, D_bot) lat_add, lon_add = cart_2_lat_lon(T) # add to the storage lists bookmarks.append(i) lat_add_list.append(lat_add) lon_add_list.append(lon_add) # now insert the stored values into the original arrays new_lats = np.insert(lats, bookmarks, lat_add_list) new_lons = np.insert(lons, bookmarks, lon_add_list) # only keep values below the maximum latitude (with small buffer) mask = np.less(new_lats, lat_max + 0.1) new_lats = new_lats[mask] new_lons = new_lons[mask] # only keep values above the minimum latitude mask = np.greater(new_lats, lat_min - 0.1) new_lats = new_lats[mask] new_lons = new_lons[mask] # create a Polygon, if we are left with enough points if len(new_lats) >= 3: band_polygon = pygplates.PolygonOnSphere(zip(new_lats, new_lons)) # get the area in km2 area = band_polygon.get_area() * 6371.009**2 # if we don't... else: area = 0 band_polygon = None return area, band_polygon
def subLoop(recsSub,shapesSub,fieldsSub,NshpSub,recsTopo,shapesTopo,fieldsTopo,NshpTopo,isright): ''' Determines the overriding and subducting plate ID along a trench. Takes the subduction zone and plate polygon shapefile data as input. Returns a list of points of the form [Lon, Lat, SPid, TRENCHid, OPid] And puts some header information indicated by '>' for each subduction segment. ''' #Initiialise the output array: [lon, lat, SPid, TRENCHid, OPid] testingArray=[] FinalArray=[] #Go through subduction zones 1 by 1 #print "Subdction zone number in file, and PlateID:" #NshpSub=[8,9] for nshpSub in xrange(NshpSub): #Get the Lat Lon points along the trench shapeArray=shapesSub[nshpSub].points #Reverse the order of LH arrays so convergence is +ve reversedSub=0 if not isright: #print "Reversing, LH array" shapeArray=shapeArray[::-1] reversedSub=1 #Get the Trench ID and Time # Note this section looks both for a PLATE_ID and a PLATEID1 field for the trench # index, due to changes between different GPlates versions. If both are present for # some reason, the TRENCHid would be taken from the second one to be encountered for i in range(len(fieldsSub)): if 'PLATE_ID' in fieldsSub[i]: TRENCHidIndex = i-1 elif 'PLATEID1' in fieldsSub[i]: TRENCHidIndex = i-1 elif 'TIME' in fieldsSub[i]: TimeIndex = i-1 elif 'FEATURE_ID' in fieldsSub[i]: GplatesTagIndex = i-1 elif 'NAME' in fieldsSub[i]: NameIndex = i-1 #Get the Trench ID and Time TRENCHid=recsSub[nshpSub][TRENCHidIndex] #3 new, 0 old (GPlates 1.2) Time=recsSub[nshpSub][TimeIndex] #2 old GplatesTag=recsSub[nshpSub][GplatesTagIndex] name=recsSub[nshpSub][NameIndex] #print nshpSub,TRENCHid,GplatesTag,name #Store the Lat and Lon in seperate arrays, remove end points because #they are prone to errors and confusing triple junctions! shapeArrayLon = [round(i[0],4) for i in shapeArray[:]] shapeArrayLat = [round(i[1],4) for i in shapeArray[:]] shapeArray=zip(shapeArrayLon,shapeArrayLat) #Append some header information #NPB!!! This is currently not used for much FinalArray.append(['> Name:' , name]) FinalArray.append(['> GplatesTag:' , GplatesTag]) FinalArray.append(['> PlateId:' , TRENCHid]) FinalArray.append(['> Age:' , Time]) FinalArray.append(['> Begin:' , 0]) FinalArray.append(['> End:' , 0]) FinalArray.append(['> Type:' , 0]) FinalArray.append(['> Polygon:' , 0]) FinalArray.append(['> Reversed:' , reversedSub]) FinalArray.append(['> BoundaryPoints:' , len(shapeArray)]) #Now we must loop through every point along the subduction zone and #check the polygons that it is attached to. for index, point in enumerate(shapeArray): OPcount=0 SPcount=0 for nshpTopo in xrange(NshpTopo): #Get the Lat Lon points of the plate polygon topoArray=shapesTopo[nshpTopo].points #Store the Lat and Lon in seperate arrays topoArrayLon = [round(i[0],4) for i in topoArray] topoArrayLat = [round(i[1],4) for i in topoArray] topoArray=zip(topoArrayLon,topoArrayLat) #topoArray=numpy.around(shapesTopo[nshpTopo].points,decimals=5) #Test whether the subduction point is in the current #polygon. If it is, we can find out more information... try: i = topoArray.index(point) pointFlag = 1 except: pointFlag = 0 ######################################### #Now if the point exists on the polygon # #Let's find out whether it is OP or SP # ######################################### if pointFlag == 1: #Get the PLATEid of the polygon (same comment as above - looks for field called either PLATE_ID or PLATEID1) for i in range(len(fieldsTopo)): if 'PLATE_ID' in fieldsTopo[i]: PlateIndex = i-1 elif 'PLATEID1' in fieldsTopo[i]: PlateIndex = i-1 PLATEid=recsTopo[nshpTopo][PlateIndex] #3 new, 0 old (GPlates 1.2) #Now get the entire polygon as a pygplates entitiy latlonPoints=[] for latlon in topoArray: pointLatLon = pygplates.LatLonPoint(latlon[1],latlon[0]) latlonPoints.append(pygplates.convert_lat_lon_point_to_point_on_sphere(pointLatLon)) polygon = pygplates.PolygonOnSphere(latlonPoints) #Convert our trench segment to pygplates format if index < len(shapeArray)-1: latPoint1 = shapeArray[index][1] lonPoint1 = shapeArray[index][0] pointXYZ, pointXYZcart = latlon2pygplates(latPoint1,lonPoint1) latPoint2 = shapeArray[index+1][1] lonPoint2 = shapeArray[index+1][0] pointXYZ2, pointXYZcart2 = latlon2pygplates(latPoint2,lonPoint2) #If we are at the last trench segment, just jump back a point else: latPoint1 = shapeArray[index-1][1] lonPoint1 = shapeArray[index-1][0] pointXYZ, pointXYZcart = latlon2pygplates(latPoint1,lonPoint1) latPoint2 = shapeArray[index][1] lonPoint2 = shapeArray[index][0] pointXYZ2, pointXYZcart2 = latlon2pygplates(latPoint2,lonPoint2) #Find the vector between 2 points on the trench line = pygplates.PolylineOnSphere([pointXYZ,pointXYZ2]) #Find the midpoint between those two points midPoint = line.get_centroid() midLatLon = pygplates.convert_point_on_sphere_to_lat_lon_point(midPoint) midPointLatLon = numpy.array([midLatLon.get_longitude(), midLatLon.get_latitude()]) #Find the bearing of point 1 to point 2 (ALL IN RADIANS) #eqns from http://www.movable-type.co.uk/scripts/latlong.html radLat1 = numpy.radians(latPoint1) radLat2 = numpy.radians(latPoint2) radLon1 = numpy.radians(lonPoint1) radLon2 = numpy.radians(lonPoint2) #θ = atan2( sin(Δλ).cos(φ2), cos(φ1).sin(φ2) − sin(φ1).cos(φ2).cos(Δλ) ) bearingRad = numpy.arctan2( numpy.sin(radLon2-radLon1) * numpy.cos(radLat2),\ numpy.cos(radLat1)*numpy.sin(radLat2) - numpy.sin(radLat1)*numpy.cos(radLat2)*numpy.cos(radLon2-radLon1)) #Now we march inside the polygon, to check if it is OP or SP #Turn 90 degrees to the left or right #if isright: bearingPerp = bearingRad + 1.57 #else: # bearingPerp = bearingRad - 1.57 #March into the plate a few km along the bearing. #new Lat Lon are given below d = 20.0 #km #Arbitrary small distance... R=6371.0 #km Radius of Earth km #φ2 = asin( sin(φ1)*cos(d/R) + cos(φ1)*sin(d/R)*cos(θ) ) lat2 = numpy.arcsin(numpy.sin(radLat1)*numpy.cos(d/R) + numpy.cos(radLat1)*numpy.sin(d/R)*numpy.cos(bearingPerp)) #λ2 = λ1 + atan2( sin(θ)*sin(d/R)*cos(φ1), cos(d/R)−sin(φ1)*sin(φ2) ) lon2 = radLon1 + numpy.arctan2(numpy.sin(bearingPerp)*numpy.sin(d/R)*numpy.cos(radLat1),numpy.cos(d/R)-numpy.sin(radLat1)*numpy.sin(radLat2)) pointSurface = pygplates.LatLonPoint(numpy.degrees(lat2),numpy.degrees(lon2)) pointSurfaceXYZ = pygplates.convert_lat_lon_point_to_point_on_sphere(pointSurface) #Test whether it is in the polygon or not cwcheck = polygon.is_point_in_polygon(pointSurfaceXYZ) #If it is then we have marched into the cojugate plate (probably)! if cwcheck: OPid=PLATEid OPcount+=1 else: SPid=PLATEid SPcount+=1 #If the point does not exist on the polygon, pass else: pass #After looping through the polygons, we should have one OPid, #and one SPid, but these may be wrong for triple junctions. if (OPcount == 1) and (SPcount == 1): #Now exit the Polygon loop and save the information about the point and move on #print point[0],point[1], SPid, TRENCHid, OPid FinalArray.append([point[0],point[1], SPid, TRENCHid, OPid]) else: pass #print OPcount, SPcount #print "Warning, point: ", point, TRENCHid, " found no match in polygons." #print "'BoundaryPoints' will not match actual points!" #print FinalArray return(FinalArray)
def reconstruct_feature_collection(request): if request.method == 'POST': params = request.POST elif request.method == 'GET': params = request.GET else: return HttpResponseBadRequest('Unrecognized request type') anchor_plate_id = params.get('pid', 0) if 'time' in params: time = params['time'] elif 'geologicage' in params: time = params['geologicage'] else: time = 140 #default reconstruction age output_format = params.get('output', 'geojson') fc_str = params.get('feature_collection') model = str(params.get('model',settings.MODEL_DEFAULT)) if 'keep_properties' in params: keep_properties = True else: keep_properties = False try: timef = float(time) except: return HttpResponseBadRequest('The "time" parameter is invalid ({0}).'.format(time)) try: anchor_plate_id = int(anchor_plate_id) except: return HttpResponseBadRequest('The "pid" parameter is invalid ({0}).'.format(anchor_plate_id)) # Convert geojson input to gplates feature collection features=[] try: fc = json.loads(fc_str)#load the input feature collection for f in fc['features']: geom = f['geometry'] feature = pygplates.Feature() if geom['type'] == 'Point': feature.set_geometry(pygplates.PointOnSphere( float(geom['coordinates'][1]), float(geom['coordinates'][0]))) if geom['type'] == 'LineString': feature.set_geometry( pygplates.PolylineOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if geom['type'] == 'Polygon': feature.set_geometry( pygplates.PolygonOnSphere([(point[1],point[0]) for point in geom['coordinates'][0]])) if geom['type'] == 'MultiPoint': feature.set_geometry( pygplates.MultiPointOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if keep_properties and 'properties' in f: for pk in f['properties']: p = f['properties'][pk] if isinstance(p, str): p=str(p) feature.set_shapefile_attribute(str(pk),p) features.append(feature) except Exception as e: #print e return HttpResponseBadRequest('Invalid input feature collection') model_dict = get_reconstruction_model_dict(model) if not model_dict: return HttpResponseBadRequest('The "model" ({0}) cannot be recognized.'.format(model)) rotation_model = pygplates.RotationModel([str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,rot_file)) for rot_file in model_dict['RotationFile']]) assigned_features = pygplates.partition_into_plates( settings.MODEL_STORE_DIR+model+'/'+model_dict['StaticPolygons'], rotation_model, features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period], partition_method = pygplates.PartitionMethod.most_overlapping_plate ) reconstructed_geometries = [] pygplates.reconstruct(assigned_features, rotation_model, reconstructed_geometries, timef, anchor_plate_id=anchor_plate_id) # convert feature collection back to geojson data = {"type": "FeatureCollection"} data["features"] = [] for g in reconstructed_geometries: geom = g.get_reconstructed_geometry() feature = {"type": "Feature"} feature["geometry"] = {} if isinstance(geom, pygplates.PointOnSphere): feature["geometry"]["type"] = "Point" p = geom.to_lat_lon_list()[0] feature["geometry"]["coordinates"] = [p[1], p[0]] elif isinstance(geom, pygplates.MultiPointOnSphere): feature["geometry"]["type"] = 'MultiPoint' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolylineOnSphere): feature["geometry"]["type"] = 'LineString' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolygonOnSphere): feature["geometry"]["type"] = 'Polygon' feature["geometry"]["coordinates"] = [[[lon,lat] for lat, lon in geom.to_lat_lon_list()]] else: return HttpResponseServerError('Unsupported Geometry Type.') feature["properties"] = {} if keep_properties: for pk in g.get_feature().get_shapefile_attributes(): feature["properties"][pk] = g.get_feature().get_shapefile_attribute(pk) #print feature["properties"] data["features"].append(feature) ret = json.dumps(pretty_floats(data)) #add header for CORS #http://www.html5rocks.com/en/tutorials/cors/ response = HttpResponse(ret, content_type='application/json') #TODO: response['Access-Control-Allow-Origin'] = '*' return response
def plot_groups(equal_area_points, bin_values, fig=None, filename=None, grid_resolution=0.2, color_range=None, cmap='hot', reverse=True, pen='0.1p,gray50', transparency=0, **kwargs): """ Generate a visual representation of spatially binned data generated by 'groupby_healpix'. The result can either be added to a pygmt figure or saved to a GIS file (with the file type taken from the filename extension of the optional 'filename' parameter, e.g. shp, gmt, geojson) """ points = pygplates.MultiPointOnSphere(zip(equal_area_points.latitude,equal_area_points.longitude)).to_xyz_array() radius = 1 center = np.array([0, 0, 0]) sv = spatial.SphericalVoronoi(points, radius, center) sv.sort_vertices_of_regions() polygon_features = [] for region,zval in zip(sv.regions,bin_values): polygon = np.vstack((sv.vertices[region],sv.vertices[region][0,:])) polygon_feature = pygplates.Feature() polygon_feature.set_geometry(pygplates.PolygonOnSphere(polygon)) polygon_feature.set_shapefile_attribute('zval', zval) polygon_features.append(polygon_feature) if filename: return_file = True pygplates.FeatureCollection(polygon_features).write(filename) else: return_file = False plot_file = tempfile.NamedTemporaryFile(delete=False, suffix='.gmt') plot_file.close() filename = plot_file.name pygplates.FeatureCollection(polygon_features).write(filename) if fig: grid_lon, grid_lat = np.meshgrid(np.arange(-180.,180.,grid_resolution),np.arange(-90.,90.,grid_resolution)) d,l = sampleOnSphere(np.radians(equal_area_points.longitude), np.radians(equal_area_points.latitude), np.array(bin_values), np.radians(grid_lon).ravel(), np.radians(grid_lat).ravel(), k=1) grid_z = np.array(bin_values)[l].reshape(grid_lon.shape) #spherical_triangulation = stripy.sTriangulation(lons=np.radians(equal_area_points.longitude), lats=np.radians(equal_area_points.latitude)) #grid_z,_ = spherical_triangulation.interpolate_nearest(np.radians(grid_lon).ravel(), np.radians(grid_lat).ravel(), np.array(bin_values)) ds = xr.DataArray(grid_z.reshape(grid_lon.shape), coords=[('lat',grid_lat[:,0]), ('lon',grid_lon[0,:])], name='z') #pygmt.config(COLOR_FOREGROUND='white', COLOR_BACKGROUND='black') if not color_range: color_range = (np.nanmin(bin_values), np.nanmax(bin_values)) reverse = True pygmt.makecpt(cmap=cmap, series='{:f}/{:f}'.format(color_range[0],color_range[1]), reverse=reverse, background='o') # This line would allow the polygons to be plotted directly with a colormap, but tends to crash when # healpix of N=32 or greater is input #fig.plot(data=filename, pen=pen, color='+z', cmap=True, a='Z=zval', close=True, **kwargs) fig.grdimage(ds, transparency=transparency, cmap=True, nan_transparent=True) fig.plot(data=filename, pen=pen, transparency=transparency, close=True, **kwargs) if not return_file: os.unlink(plot_file.name)
def get_coastline_polygons(request): #pr = cProfile.Profile() #pr.enable() time = request.GET.get('time', 0) features = [] ''' polygons = CoastlinePolygons.objects.all() #polygons = StaticPolygons.objects.all() for p in polygons: polygon_feature = pygplates.Feature() polygon_feature.set_geometry( pygplates.PolygonOnSphere([(lat,lon) for lon, lat in p.geom[0][0]])) polygon_feature.set_reconstruction_plate_id(int(p.plateid1)) features.append(polygon_feature) ''' import shapefile sf = shapefile.Reader( MODEL_DEFAULT+"coastlines_low_res/Seton_etal_ESR2012_Coastlines_2012.shp") for record in sf.shapeRecords(): if record.shape.shapeType != 5: continue for idx in range(len(record.shape.parts)): start_idx = record.shape.parts[idx] end_idx = len(record.shape.points) if idx < (len(record.shape.parts) -1): end_idx = record.shape.parts[idx+1] polygon_feature = pygplates.Feature() points = record.shape.points[start_idx:end_idx] polygon_feature.set_geometry( pygplates.PolygonOnSphere([(lat,lon) for lon, lat in points])) polygon_feature.set_reconstruction_plate_id(int(record.record[0])) features.append(polygon_feature) break feature_collection = pygplates.FeatureCollection(features) reconstructed_polygons = [] rotation_model = pygplates.RotationModel( MODEL_DEFAULT+"Seton_etal_ESR2012_2012.1.rot") ''' pr.disable() s = StringIO.StringIO() sortby = 'cumulative' ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats(20) print s.getvalue() ''' pygplates.reconstruct( feature_collection, rotation_model, reconstructed_polygons, float(time)) #return HttpResponse('OK') data = {"type": "FeatureCollection"} data["features"] = [] for p in reconstructed_polygons: feature = {"type": "Feature"} feature["geometry"] = {} feature["geometry"]["type"] = "Polygon" feature["geometry"]["coordinates"] = [[(lon,lat) for lat, lon in p.get_reconstructed_geometry().to_lat_lon_list()]] data["features"].append(feature) ret = json.dumps(pretty_floats(data)) return HttpResponse(ret, content_type='application/json')
def reconstruct_feature_collection(request): DATA_DIR = Model_Root+'caltech/' if request.method == 'POST': return HttpResponse('POST method is not accepted for now.') geologicage = request.GET.get('geologicage', 140) output_format = request.GET.get('output', 'geojson') fc_str = request.GET.get('feature_collection') fc = json.loads(fc_str) features=[] for f in fc['features']: geom = f['geometry'] feature = pygplates.Feature() if geom['type'] == 'Point': feature.set_geometry(pygplates.PointOnSphere( float(geom['coordinates'][1]), float(geom['coordinates'][0]))) if geom['type'] == 'LineString': feature.set_geometry( pygplates.PolylineOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if geom['type'] == 'Polygon': feature.set_geometry( pygplates.PolygonOnSphere([(point[1],point[0]) for point in geom['coordinates'][0]])) if geom['type'] == 'MultiPoint': feature.set_geometry( pygplates.MultiPointOnSphere([(point[1],point[0]) for point in geom['coordinates']])) features.append(feature) if float(geologicage) < 250: rotation_files = [DATA_DIR+'/Seton_etal_ESR2012_2012.1.rot'] else : rotation_files = [DATA_DIR+'/Global_EB_410-250Ma_GK07_Matthews_etal.rot'] rotation_model = pygplates.RotationModel(rotation_files) assigned_features = pygplates.partition_into_plates( DATA_DIR+'Seton_etal_ESR2012_StaticPolygons_2012.1.gpmlz', rotation_model, features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period], partition_method = pygplates.PartitionMethod.most_overlapping_plate ) reconstructed_geometries = [] pygplates.reconstruct(assigned_features, rotation_model, reconstructed_geometries, float(geologicage), 0) data = {"type": "FeatureCollection"} data["features"] = [] for g in reconstructed_geometries: geom = g.get_reconstructed_geometry() feature = {"type": "Feature"} feature["geometry"] = {} if isinstance(geom, pygplates.PointOnSphere): feature["geometry"]["type"] = "Point" p = geom.to_lat_lon_list()[0] feature["geometry"]["coordinates"] = [p[1], p[0]] elif isinstance(geom, pygplates.MultiPointOnSphere): feature["geometry"]["type"] = 'MultiPoint' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolylineOnSphere): feature["geometry"]["type"] = 'LineString' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolygonOnSphere): feature["geometry"]["type"] = 'Polygon' feature["geometry"]["coordinates"] = [[[lon,lat] for lat, lon in geom.to_lat_lon_list()]] else: raise 'Unrecognized Geometry Type.' feature["properties"]={} data["features"].append(feature) ret = json.dumps(pretty_floats(data)) return HttpResponse(ret, content_type='application/json')
def wrap_resolved_polygons(resolved_polygons, wrap=False, central_meridian=0, avoid_map_boundary=False, tesselate_degrees=2): polygons = [] if wrap: wrapped_polygons = [] date_line_wrapper = pygplates.DateLineWrapper(central_meridian) for p in resolved_polygons: wrapped_polygons += date_line_wrapper.wrap(p.get_geometry(), tesselate_degrees) for p in wrapped_polygons: lats = [i.get_latitude() for i in p.get_exterior_points()] lons = [i.get_longitude() for i in p.get_exterior_points()] if pygplates.PolygonOnSphere(list(zip( lats, lons))).get_orientation( ) == pygplates.PolygonOnSphere.Orientation.clockwise: polygons.append((lons, lats)) else: polygons.append((lons[::-1], lats[::-1])) else: for p in resolved_polygons: lats, lons = list(zip(*p.get_geometry().to_lat_lon_list())) lats = list(lats) lons = list(lons) if pygplates.PolygonOnSphere(list(zip( lats, lons))).get_orientation( ) == pygplates.PolygonOnSphere.Orientation.clockwise: polygons.append((lons, lats)) else: polygons.append((lons[::-1], lats[::-1])) data = {"type": "FeatureCollection"} data["features"] = [] for p in polygons: feature = {"type": "Feature"} feature["geometry"] = {} feature["geometry"]["type"] = "Polygon" #make sure the coordinates are valid. lats = p[1] lons = p[0] #print lats, lons #some map plotting program(such as leaflet) does not like points on the map boundary, #for example the longitude 180 and -180. #So, move the points slightly inwards. if avoid_map_boundary: for idx, x in enumerate(lons): if x < central_meridian - 179.99: lons[idx] = central_meridian - 179.99 elif x > central_meridian + 179.99: lons[idx] = central_meridian + 179.99 for idx, x in enumerate(lats): if x < -89.99: lats[idx] = -89.99 elif x > 89.99: lats[idx] = 89.99 feature["geometry"]["coordinates"] = [ list(zip(lons + lons[:1], lats + lats[:1])) ] data["features"].append(feature) return data