Added almost all params, made front API usable, and added crs transform draw testing.

Next step figure out more stable proj4 parsing of datums and proj etc,
with adding more specific names.
Then consistently make to_esriwkt work.
This commit is contained in:
Karim Bahgat
2015-06-30 04:14:12 +02:00
parent fcc463fa76
commit a8aad24a13
15 changed files with 365 additions and 124 deletions
+28
View File
@@ -2,4 +2,32 @@
class WGS84:
proj4 = "WGS84"
ogc_wkt = "WGS_1984"
esri_wkt = "D_WGS_1984"
ellipsdef = "" # ellipsoids.WGS84()
to_wgs84 = None
class WGS72_BE:
proj4 = "" # no datum name, just ellips + towgs84 params...
ogc_wkt = "WGS_1972_Transit_Broadcast_Ephemeris"
esri_wkt = "D_WGS_1972_BE"
ellipsdef = "" # ellipsoids.WGS72()
to_wgs84 = 0,0,1.9,0,0,0.814,-0.38
class NAD83:
proj4 = "NAD83" # no datum name, just ellips + towgs84 params...
ogc_wkt = "North_American_Datum_1983"
esri_wkt = "D_North_American_1983"
ellipsdef = "" # ellipsoids.WGS72()
to_wgs84 = None
class Unknown:
proj4 = "unknown" # no datum name, just ellips + towgs84 params...
ogc_wkt = "Unknown"
esri_wkt = "Unknown"
ellipsdef = "" # ellipsoids.WGS72()
to_wgs84 = None,None
BIN
View File
Binary file not shown.
+25
View File
@@ -3,7 +3,32 @@
class WGS84:
proj4 = "WGS84"
ogc_wkt = "WGS_1984"
esri_wkt = "WGS_1984"
semimaj_ax = 6378137
inv_flat = 298.257223563
class WGS72:
proj4 = "WGS72"
ogc_wkt = "WGS 72"
esri_wkt = "WGS_1972"
semimaj_ax = 6378135
inv_flat = 298.26
class International:
proj4 = "intl"
ogc_wkt = "International_1924"
esri_wkt = "International_1924"
semimaj_ax = 6378388.0
inv_flat = 297.0
class GRS80:
proj4 = "GRS80"
ogc_wkt = "GRS_1980"
esri_wkt = "GRS_1980"
semimaj_ax = 6378137.0
inv_flat = 298.257222101
Binary file not shown.
+20 -12
View File
@@ -1,5 +1,7 @@
import json
import urllib2
from . import parser
#################
@@ -10,37 +12,43 @@ import json
def from_url(url, format=None):
# first get string from url
# ...
string = urllib2.urlopen(url).read()
# then determine parser
if format:
# user specified format
format = format.lower().replace(" ", "_")
func = parser.__getattr__("from_%s" % format)
else:
# unknown format
func = parser.from_unknown_text
# then load
if format:
# load string using specified format
pass
else:
from_unknown_text(string)
crs = func(string)
return crs
def from_file(filepath):
if filepath.endswith(".prj"):
string = open(filepath, "r").read()
from_esri_wkt(string)
return parser.from_esri_wkt(string)
elif filepath.endswith((".geojson",".json")):
crsinfo = json.load(filepath)["crs"]
if crsinfo["type"] == "name":
string = crsinfo["properties"]["name"]
from_unknown_text(string)
return parser.from_unknown_text(string)
elif crsinfo["type"] == "link":
url = crsinfo["properties"]["name"]
type = crsinfo["properties"].get("type")
from_url(url, format=type)
return from_url(url, format=type)
else: raise Exception("invalid geojson crs type: must be either name or link")
elif filepath.endswith((".tif",".tiff",".geotiff")):
pass
# ...
## elif filepath.endswith((".tif",".tiff",".geotiff")):
## pass
## # ...
BIN
View File
Binary file not shown.
+77 -25
View File
@@ -25,6 +25,7 @@
from . import directions
# ONLY PURE VALUES INSIDE ELLIPSOID...
##+a Semimajor radius of the ellipsoid axis
class SemiMajorRadius:
@@ -32,24 +33,37 @@ class SemiMajorRadius:
def __init__(self, value):
pass
##+alpha ? Used with Oblique Mercator and possibly a few others
class Azimuth:
proj4 = "+alpha"
esri_wkt = "azimuth"
ogc_wkt = "azimuth"
geotiff = "AzimuthAngle"
def __init__(self, value):
pass
##+b Semiminor radius of the ellipsoid axis
class SemiMinorRadius:
proj4 = "+b"
def __init__(self, value):
pass
#################
##+alpha ? Used with Oblique Mercator and possibly a few others
class Azimuth:
proj4 = "+alpha"
esri_wkt = "azimuth"
ogc_wkt = "azimuth"
geotiff = "AzimuthAngle"
def __init__(self, value):
self.value = value
def to_proj4(self):
return "+alpha=%s" % self.value
def to_ogc_wkt(self):
return 'PARAMETER["Azimuth",%s]' % self.value
def to_esri_wkt(self):
return self.to_ogc_wkt()
##+datum Datum name (see `proj -ld`)
class Datum:
def __init__(self, name, ellipsoid):
def __init__(self, name, ellipsoid, datumshift=None):
"""
Arguments:
@@ -58,12 +72,19 @@ class Datum:
"""
self.name = name
self.ellips = ellipsoid
self.datumshift = datumshift
def to_proj4(self):
return "+datum=%s %s" % (self.name.proj4, self.ellips.to_proj4())
if self.datumshift:
return "%s %s" % (self.ellips.to_proj4(), self.datumshift.to_proj4())
else:
return "+datum=%s %s" % (self.name.proj4, self.ellips.to_proj4())
def to_ogc_wkt(self):
return 'DATUM["%s", %s]' % (self.name.ogc_wkt, self.ellips.to_ogc_wkt())
if self.datumshift:
return 'DATUM["%s", %s, %s]' % (self.name.ogc_wkt, self.ellips.to_ogc_wkt(), self.datumshift.to_ogc_wkt())
else:
return 'DATUM["%s", %s]' % (self.name.ogc_wkt, self.ellips.to_ogc_wkt())
def to_esri_wkt(self):
return self.to_ogc_wkt()
@@ -122,7 +143,6 @@ class GeogCS:
self.twin_ax = twin_ax
def to_proj4(self):
# axis excluded because not sure if should be set from geogcs or projcs
return "%s %s %s" % (self.datum.to_proj4(), self.prime_mer.to_proj4(), self.angunit.to_proj4() ) #+axis= AND #, self.twin_ax[0].proj4, self.twin_ax[1].proj4 )
def to_ogc_wkt(self):
@@ -151,8 +171,8 @@ class ProjCS:
def to_proj4(self):
string = "%s %s " % (self.proj.to_proj4(), self.geogcs.to_proj4())
string += " ".join(param.to_proj4() for param in self.params)
# axis excluded because not sure if should be set from geogcs or projcs
#string += " +axis=" + self.twin_ax[0].proj4 + self.twin_ax[1].proj4 + "u" # up set as default because only proj4 can set it I think...
# in proj4, axis only applies to the cs, ie the projcs (not the geogcs, where wkt can specify with axis)
string += " +axis=" + self.twin_ax[0].proj4 + self.twin_ax[1].proj4 + "u" # up set as default because only proj4 can set it I think...
return string
def to_ogc_wkt(self):
@@ -164,7 +184,6 @@ class ProjCS:
def to_esri_wkt(self):
return self.to_ogc_wkt()
##+k Scaling factor (old name)
##+k_0 Scaling factor (new name)
class ScalingFactor:
@@ -193,6 +212,7 @@ class LatitudeOrigin:
return "+lat_0=%s" %self.value
def to_ogc_wkt(self):
# SAME AS LATITUDE OF CENTER???
return 'PARAMETER["latitude_of_origin", %s]' %self.value
def to_esri_wkt(self):
@@ -204,15 +224,39 @@ class LatitudeOrigin:
##+lat_1 Latitude of first standard parallel
class LatitudeFirstStndParallel:
proj4 = "+lat_1"
def __init__(self, value):
self.value = value
def to_proj4(self):
return "+lat_1=%s" %self.value
def to_ogc_wkt(self):
return 'PARAMETER["standard_parallel_1", %s]' %self.value
def to_esri_wkt(self):
return self.to_ogc_wkt()
def to_geotiff(self):
pass
#return "StdParallel1"
##+lat_2 Latitude of second standard parallel
class LatitudeSecondStndParallel:
proj4 = "+lat_2"
def __init__(self, value):
self.value = value
def to_proj4(self):
return "+lat_2=%s" %self.value
def to_ogc_wkt(self):
return 'PARAMETER["standard_parallel_2", %s]' %self.value
def to_esri_wkt(self):
return self.to_ogc_wkt()
def to_geotiff(self):
pass
#return "StdParallel2"
##+lat_ts Latitude of true scale
class LatitudeTrueScale:
@@ -250,12 +294,20 @@ class CentralMeridian:
pass
#return "ProjCenterLong"
##+lonc ? Longitude used with Oblique Mercator and possibly a few others
class LongitudeSpecial:
class LongitudeCenter:
proj4 = "+lonc"
def __init__(self, value):
pass
self.value = value
def to_proj4(self):
return "+lonc=%s" %self.value
def to_ogc_wkt(self):
return 'PARAMETER["Longitude_Of_Center", %s]' %self.value
def to_esri_wkt(self):
return self.to_ogc_wkt()
##+lon_wrap Center longitude to use for wrapping (see below)
@@ -294,6 +346,7 @@ class Projection:
def to_esri_wkt(self):
return self.to_ogc_wkt()
##+zone UTM zone
##+south Denotes southern hemisphere UTM zone
@@ -303,10 +356,10 @@ class DatumShift:
self.value = value
def to_proj4(self):
return "+towgs84=%s" %"".join((str(val) for val in self.value))
return "+towgs84=%s" %",".join((str(val) for val in self.value))
def to_ogc_wkt(self):
return "TOWGS84[%s]" %"".join((str(val) for val in self.value))
return "TOWGS84[%s]" %",".join((str(val) for val in self.value))
def to_esri_wkt(self):
raise Exception("Paramater not supported by ESRI WKT")
@@ -416,8 +469,7 @@ class FalseNorthing:
def to_esri_wkt(self):
return self.to_ogc_wkt()
# then the final CRS object which is instantiated with all of these?
# remember to use +no_defs when outputting to proj4
# ...
Binary file not shown.
+167 -83
View File
@@ -9,59 +9,59 @@ from . import ellipsoids
from . import parameters
from . import units
from . import projections
from . import webscrape
def from_epsg_code(string):
def from_epsg_code(code):
# must go online (or look up local table) to get crs details
pass
code = str(code)
proj4 = webscrape.crscode_to_string("epsg", code, "proj4")
crs = from_proj4(proj4)
return crs
def from_esri_code(string):
def from_esri_code(code):
# must go online (or look up local table) to get crs details
pass
code = str(code)
proj4 = webscrape.crscode_to_string("esri", code, "proj4")
crs = from_proj4(proj4)
return crs
def from_sr_code(string):
def from_sr_code(code):
# must go online (or look up local table) to get crs details
pass
code = str(code)
proj4 = webscrape.crscode_to_string("sr-org", code, "proj4")
crs = from_proj4(proj4)
return crs
def from_esri_wkt(string):
# parse arguments into components
# use args to create crs
pass
def from_ogc_wkt(string):
# parse arguments into components
# use args to create crs
pass
def from_unknown_wkt(string):
# detect if ogc wkt or esri wkt
# TIPS: esri wkt datums all use "D_" before the datum name
# then load with appropriate function
pass
##def from_esri_wkt(string):
## # parse arguments into components
## # use args to create crs
## pass
##
##def from_ogc_wkt(string):
## # parse arguments into components
## # use args to create crs
## pass
##
##def from_unknown_wkt(string):
## # detect if ogc wkt or esri wkt
## # TIPS: esri wkt datums all use "D_" before the datum name
## # then load with appropriate function
## pass
def from_proj4(string):
# parse arguments into components
# use args to create crs
## proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs
##
## PROJCS["World_Robinson",
## GEOGCS["GCS_WGS_1984",
## DATUM["WGS_1984",
## SPHEROID["WGS_1984",6378137,298.257223563]],
## PRIMEM["Greenwich",0],
## UNIT["Degree",0.017453292519943295]],
## PROJECTION["Robinson"],
## PARAMETER["False_Easting",0],
## PARAMETER["False_Northing",0],
## PARAMETER["Central_Meridian",0],
## UNIT["Meter",1],
## AUTHORITY["EPSG","54030"]]
# SLIGTHLY MESSY STILL, CLEANUP..
params = []
partdict = dict([part.split("=") for part in string.split()
if not part.startswith("+no_defs")])
# INIT CODES...?
# eg, +init=epsg code...?
# DATUM
# datum param is required
@@ -71,26 +71,58 @@ def from_proj4(string):
if partdict["+datum"] == "WGS84":
datumdef = datums.WGS84()
# ELLIPS
# ellipse param is required
if "+ellps" in partdict:
# get predefined ellips def
if partdict["+ellps"] == "WGS84":
ellipsdef = ellipsoids.WGS84()
elif partdict["+datum"] == "NAD83":
datumdef = datums.NAD83()
else:
raise Exception("Could not find required +ellps element")
## create datum and ellips param objs
ellips = parameters.Ellipsoid(ellipsdef,
semimaj_ax=partdict.get("+a"),
inv_flat=partdict.get("+f"))
datum = parameters.Datum(datumdef, ellips)
datumdef = datums.Unknown()
else:
raise Exception("Could not find required +datum element")
datumdef = datums.Unknown()
# ELLIPS
# ellipse param is required
if "+ellps" in partdict:
# get predefined ellips def
if partdict["+ellps"] == "WGS84":
ellipsdef = ellipsoids.WGS84()
elif partdict["+ellps"] == "WGS72":
ellipsdef = ellipsoids.WGS72()
elif partdict["+ellps"] == "intl":
ellipsdef = ellipsoids.International()
elif partdict["+ellps"] == "GRS80":
ellipsdef = ellipsoids.GRS80()
else:
raise Exception("Could not find required +ellps element")
# TO WGS 84 COEFFS
if "+towgs84" in partdict:
coeffs = partdict["+towgs84"].split(",")
datumshift = parameters.DatumShift(coeffs)
# if no datum, use ellips + towgs84 params to create the correct datum
# ...??
# COMBINE DATUM AND ELLIPS
## create datum and ellips param objs
ellips = parameters.Ellipsoid(ellipsdef,
semimaj_ax=partdict.get("+a"),
inv_flat=partdict.get("+f"))
if "+datum" in partdict:
datum = parameters.Datum(datumdef, ellips)
elif "+towgs84" in partdict:
datum = parameters.Datum(datumdef, ellips, datumshift)
else:
datum = parameters.Datum(datumdef, ellips)
# PRIME MERIDIAN
@@ -99,7 +131,7 @@ def from_proj4(string):
# overwrite with user input
if "+pm" in partdict:
# for now only support longitude, later add name support:
# for now only support longitude, later add name support from below:
## greenwich 0dE
## lisbon 9d07'54.862"W
## paris 2d20'14.025"E
@@ -134,6 +166,9 @@ def from_proj4(string):
if partdict["+proj"] == "robin":
projdef = projections.Robinson()
elif partdict["+proj"] == "omerc":
projdef = projections.ObliqueMercator()
elif partdict["+proj"] == "longlat":
projdef = None
# set geogcs axis in correct order
@@ -177,6 +212,56 @@ def from_proj4(string):
obj = parameters.FalseNorthing(val)
params.append(obj)
# SCALING FACTOR
if "+k_0" in partdict or "+k" in partdict:
if "+k_0" in partdict: val = partdict["+k_0"]
elif "+k" in partdict: val = partdict["+k"]
obj = parameters.ScalingFactor(val)
params.append(obj)
# LATITUDE ORIGIN
if "+lat_0" in partdict:
val = partdict["+lat_0"]
obj = parameters.LatitudeOrigin(val)
params.append(obj)
# LATITUDE TRUE SCALE
if "+lat_ts" in partdict:
val = partdict["+lat_ts"]
obj = parameters.LatitudeTrueScale(val)
params.append(obj)
# LONGITUDE CENTER
if "+lonc" in partdict:
val = partdict["+lonc"]
obj = parameters.LongitudeCenter(val)
params.append(obj)
# AZIMUTH
if "+alpha" in partdict:
val = partdict["+alpha"]
obj = parameters.Azimuth(val)
params.append(obj)
# STD PARALLEL 1
if "+lat1" in partdict:
val = partdict["+lat1"]
obj = parameters.LatitudeFirstStndParallel(val)
params.append(obj)
# STD PARALLEL 2
if "+lat2" in partdict:
val = partdict["+lat2"]
obj = parameters.LatitudeSecondStndParallel(val)
params.append(obj)
# UNIT
## set default
@@ -208,33 +293,32 @@ def from_proj4(string):
return crs
def from_ogc_urn(string):
# hmmm, seems like ogc urn could be anything incl online link, epsg, etc...
# if necessary, must go online (or lookup local table) to get details
# maybe test which of these and run their function?
# examples urn:ogc:def:crs:OGC:1.3:CRS1
# or with EPSG instead of OGC
# If OGC, 1.3 is pdf version, and after that is a name from list below
# as found in pdf: "Definition identifier URNs in OGC namespace"
# OGC crs definitions
# URN | CRS name | Definition reference
# urn:ogc:def:crs:OGC:1.3:CRS1 Map CS B.2 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:CRS84 WGS 84 longitude-latitude B.3 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:CRS83 NAD83 longitude-latitude B.4 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:CRS27 NAD27 longitude-latitude B.5 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:CRS88 NAVD 88 B.6 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:AUTO42001:99:8888 Auto universal transverse mercator B.7 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:AUTO42002:99:8888 Auto transverse mercator B.8 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:AUTO42003:99:8888 Auto orthographic B.9 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:AUTO42004:99:8888 Auto equirectangular B.10 in OGC 06-042
# urn:ogc:def:crs:OGC:1.3:AUTO42005:99 Auto Mollweide B.11 in OGC 06-042
pass
##def from_ogc_urn(string):
## # hmmm, seems like ogc urn could be anything incl online link, epsg, etc...
## # if necessary, must go online (or lookup local table) to get details
## # maybe test which of these and run their function?
## # examples urn:ogc:def:crs:OGC:1.3:CRS1
## # or with EPSG instead of OGC
##
## # If OGC, 1.3 is pdf version, and after that is a name from list below
## # as found in pdf: "Definition identifier URNs in OGC namespace"
## # OGC crs definitions
## # URN | CRS name | Definition reference
## # urn:ogc:def:crs:OGC:1.3:CRS1 Map CS B.2 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:CRS84 WGS 84 longitude-latitude B.3 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:CRS83 NAD83 longitude-latitude B.4 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:CRS27 NAD27 longitude-latitude B.5 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:CRS88 NAVD 88 B.6 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:AUTO42001:99:8888 Auto universal transverse mercator B.7 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:AUTO42002:99:8888 Auto transverse mercator B.8 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:AUTO42003:99:8888 Auto orthographic B.9 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:AUTO42004:99:8888 Auto equirectangular B.10 in OGC 06-042
## # urn:ogc:def:crs:OGC:1.3:AUTO42005:99 Auto Mollweide B.11 in OGC 06-042
##
## pass
def from_unknown_text(text):
# detect type and load with appropriate function
"""Detect type and load with appropriate function"""
if string.startswith("urn:"):
from_ogc_urn(string)
@@ -246,15 +330,15 @@ def from_unknown_text(text):
from_unknown_wkt(string)
elif string.startswith("EPSG:"):
from_epsg_code(string)
from_epsg_code(string.split(":")[1])
elif string.startswith("ESRI:"):
from_esri_code(string)
from_esri_code(string.split(":")[1])
elif string.startswith("SR-ORG:"):
from_sr_code(string)
from_sr_code(string.split(":")[1])
else: raise Exception("Could not detect which type of crs")
def from_geotiff_parameters(**params):
pass
##def from_geotiff_parameters(**params):
## pass
BIN
View File
Binary file not shown.
+4
View File
@@ -8,3 +8,7 @@ class UTM:
proj4 = "utm"
ogc_wkt = "Transverse_Mercator"
class ObliqueMercator:
proj4 = "omerc"
ogc_wkt = "Hotine_Oblique_Mercator"
Binary file not shown.
+2 -2
View File
@@ -71,7 +71,7 @@ def crsstring_to_string(string, newformat):
return result
if __name__ == "__main__":
build_crs_table("crstable.txt")
##if __name__ == "__main__":
## build_crs_table("crstable.txt")
Binary file not shown.
+42 -2
View File
@@ -1,10 +1,50 @@
import pycrs
proj4 = "+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
proj4 = "+proj=longlat +ellps=WGS84 +datum=WGS84"
#proj4 = "+proj=longlat +ellps=WGS84 +datum=WGS84"
#crs = pycrs.parser.from_esri_code(54030)
#crs = pycrs.parser.from_sr_code(7898)
#crs = pycrs.parser.from_epsg_code(4324)
#crs = pycrs.parser.from_sr_code(6618)
crs = pycrs.parser.from_proj4(proj4)
print crs.to_ogc_wkt()
print crs.to_proj4()
import urllib2
import json
import pygeoj
import pyagg
import pyproj
c = pyagg.Canvas(600,600)
c.geographic_space()
raw = urllib2.urlopen("https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json").read()
rawdict = json.loads(raw)
data = pygeoj.load(data=rawdict)
proj4 = crs.to_proj4()
fromproj = pyproj.Proj("+init=EPSG:4326")
toproj = pyproj.Proj(proj4)
print data.bbox
for feat in data:
if feat.geometry.type == "Polygon":
feat.geometry.coordinates = [zip(*pyproj.transform(fromproj, toproj, zip(*ring)[0], zip(*ring)[1]))
for ring in feat.geometry.coordinates]
data.add_all_bboxes()
xmins, ymins, xmaxs, ymaxs = zip(*(feat.geometry.bbox for feat in data))
bbox = (min(xmins), min(ymins), max(xmaxs), max(ymaxs))
# print data.bbox #PYGEOJ data.bbox doesnt update.........FIX!
print bbox
c.zoom_bbox(*bbox)
for feat in data:
if feat.geometry.type == "Polygon":
try: c.draw_geojson(feat.geometry, outlinecolor="white")
except:
# NOTE: feat.__geo_interface__ is one level too high maybe??
print feat.geometry
c.view()