From fcc463fa76fdea77224f31e9bc526b0940b2b9b1 Mon Sep 17 00:00:00 2001 From: Karim Bahgat Date: Mon, 29 Jun 2015 03:29:02 +0200 Subject: [PATCH] Basic fromproj4 works, except need better handle when unprojected (longlat and latlong) Also just need to expand to more projection name, datum name, and ellipsoid name definitions, and also additional special parameters. After that, test, and move onto from_wkt()... --- namemappings.py | 12 -- parser.py | 88 ---------- pycrs/__init__.py | 4 + pycrs/__init__.pyc | Bin 0 -> 269 bytes crstable.txt => pycrs/crstable.txt | 0 pycrs/datums.py | 5 + pycrs/datums.pyc | Bin 0 -> 388 bytes pycrs/directions.py | 31 ++++ pycrs/directions.pyc | Bin 0 -> 1583 bytes pycrs/ellipsoids.py | 9 + pycrs/ellipsoids.pyc | Bin 0 -> 454 bytes loader.py => pycrs/loader.py | 0 pycrs/loader.pyc | Bin 0 -> 1189 bytes params.py => pycrs/parameters.py | 196 ++++++++++++++++++---- pycrs/parameters.pyc | Bin 0 -> 22395 bytes pycrs/parser.py | 260 +++++++++++++++++++++++++++++ pycrs/parser.pyc | Bin 0 -> 4218 bytes pycrs/projections.py | 10 ++ pycrs/projections.pyc | Bin 0 -> 636 bytes pycrs/units.py | 11 ++ pycrs/units.pyc | Bin 0 -> 655 bytes webscrape.py => pycrs/webscrape.py | 0 pycrs/webscrape.pyc | Bin 0 -> 2416 bytes tester.py | 10 ++ 24 files changed, 504 insertions(+), 132 deletions(-) delete mode 100644 namemappings.py delete mode 100644 parser.py create mode 100644 pycrs/__init__.py create mode 100644 pycrs/__init__.pyc rename crstable.txt => pycrs/crstable.txt (100%) create mode 100644 pycrs/datums.py create mode 100644 pycrs/datums.pyc create mode 100644 pycrs/directions.py create mode 100644 pycrs/directions.pyc create mode 100644 pycrs/ellipsoids.py create mode 100644 pycrs/ellipsoids.pyc rename loader.py => pycrs/loader.py (100%) create mode 100644 pycrs/loader.pyc rename params.py => pycrs/parameters.py (56%) create mode 100644 pycrs/parameters.pyc create mode 100644 pycrs/parser.py create mode 100644 pycrs/parser.pyc create mode 100644 pycrs/projections.py create mode 100644 pycrs/projections.pyc create mode 100644 pycrs/units.py create mode 100644 pycrs/units.pyc rename webscrape.py => pycrs/webscrape.py (100%) create mode 100644 pycrs/webscrape.pyc create mode 100644 tester.py diff --git a/namemappings.py b/namemappings.py deleted file mode 100644 index bb430c7..0000000 --- a/namemappings.py +++ /dev/null @@ -1,12 +0,0 @@ - -# CRS Names - -class proj_NAD87: - proj4 = "" - ogc_wkt = "" - -class datum_WGS84: - proj4 = "" - ogc_wkt = "" - - diff --git a/parser.py b/parser.py deleted file mode 100644 index c80d414..0000000 --- a/parser.py +++ /dev/null @@ -1,88 +0,0 @@ - -# parse from text strings -# possible use module: https://github.com/rockdoc/grabbag/wiki/CRS-WKT-Parser -# also note some paramter descriptions: http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html -# and see gdal source code: http://gis.stackexchange.com/questions/129764/how-are-esri-wkt-projections-different-from-ogc-wkt-projections - -def from_epsg_code(string): - # must go online (or look up local table) to get crs details - pass - -def from_esri_code(string): - # must go online (or look up local table) to get crs details - pass - -def from_sr_code(string): - # must go online (or look up local table) to get crs details - 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 - 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 - - if string.startswith("urn:"): - from_ogc_urn(string) - - elif string.startswith("+proj="): - from_proj4(string) - - elif string.startswith("PROJCS["): - from_unknown_wkt(string) - - elif string.startswith("EPSG:"): - from_epsg_code(string) - - elif string.startswith("ESRI:"): - from_esri_code(string) - - elif string.startswith("SR-ORG:"): - from_sr_code(string) - - else: raise Exception("Could not detect which type of crs") - -def from_geotiff_params(**params): - pass diff --git a/pycrs/__init__.py b/pycrs/__init__.py new file mode 100644 index 0000000..de33765 --- /dev/null +++ b/pycrs/__init__.py @@ -0,0 +1,4 @@ +from . import loader +from . import parser +from . import webscrape + diff --git a/pycrs/__init__.pyc b/pycrs/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65e754e04709eefd01119fd50a713f8f499347e8 GIT binary patch literal 269 zcmYL@O$x#=5Jo3W6%~XYqbpb9LPUfLx)N#WrUXKNvIsV9X;P$TaN{LBp%-vcm4?g< zkIZ}teJ>ZU$1~31w;VhVSbB{pa1$s26oG^QvF;4+K;nFz4o)GV=q^P51P3KS_!ef0 zDC@Kk?dVO~>c7wN{w^||w`n6TzH4W&ARJ&LLi;D*>Il6-4Yn-C9L;W0)$Ca3of4JN q>?F;(%hbs6x>I%0m11x6wSChg9{B*Bp)zs+ literal 0 HcmV?d00001 diff --git a/crstable.txt b/pycrs/crstable.txt similarity index 100% rename from crstable.txt rename to pycrs/crstable.txt diff --git a/pycrs/datums.py b/pycrs/datums.py new file mode 100644 index 0000000..77ef7cb --- /dev/null +++ b/pycrs/datums.py @@ -0,0 +1,5 @@ + +class WGS84: + proj4 = "WGS84" + ogc_wkt = "WGS_1984" + diff --git a/pycrs/datums.pyc b/pycrs/datums.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e66f59de16f0d258c467cf7e653318f76ea9955 GIT binary patch literal 388 zcmbVH!D_-l5S>k|ErH&I{z6WIkb^BniVF55k|1JOSZoqX)OCZqq2#O|(0}y@e7li) z@3QlD-ptOt8UOMejMu-*jBdxr`vKE0fE?GSoY9%+M6^!9Jxan3a^?ZBnkB>Nua+S) zhUp%lAWE6-kb1U5>QkJA9uhH(%o70BV(>bQ+I}`7#9<=~Axz+iRC&F()M`~nwT;Xp zJoTN4pPdQe(j9aJI(g$uT^u#vl~VDk%4%60jOMe_eAZul(M;lmS51Z=`Nq^z_p8PY hWGB;huP*DddE3?QNQHO3uIa{){kjv7DX=T zReNLtfIg)rOW7>wQv$Mi5KcWuzcqJ`rXX$6Y1SD|m&kZtbT^nOa46k|^pjx_Y2{vrx|!U&HY;Si#dG7%($pp}lO*yOZgecxsL(J|$~~-}@VKy&Q)C literal 0 HcmV?d00001 diff --git a/pycrs/ellipsoids.py b/pycrs/ellipsoids.py new file mode 100644 index 0000000..112a64e --- /dev/null +++ b/pycrs/ellipsoids.py @@ -0,0 +1,9 @@ + + +class WGS84: + proj4 = "WGS84" + ogc_wkt = "WGS_1984" + + semimaj_ax = 6378137 + inv_flat = 298.257223563 + diff --git a/pycrs/ellipsoids.pyc b/pycrs/ellipsoids.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0699d29e2f3d51c5ec1cb130176b4588d17a55a5 GIT binary patch literal 454 zcmbtQ&r8EF6n<^DDFe@*1dlxlLJw6$h7;yVq-DrLAk;RFY)w;|RPEUvJbDtm??3b( z@Fi9E2bdpU@{%v#m-m9NgYkCpKF{H&1-MRd>O+JAM*xKf8-Q1U1;N;dG#uca86w=z z(m48i>*2{2PJN8P0f=W6h;J1L>i9qgR*(!K=|vJGg4stvC3boiN8&TdVEHD^$I-T# zgrnbk#;Qzm#>^N`7?Y}KOB>o>)Qwt2W)F92nX~7$aU{*9klBi5FU~+zPwcVGOo%kt zfsQepp3}MJjizfM6}?t@D|ux!oe6W(KG3^vnxwSua%Awb6tz~O&?j~0zHck0Z3-g~ dyFc=7dv#k4N7$LU-M<`NDi?kBm(Ceo;2RRVVu%0$ literal 0 HcmV?d00001 diff --git a/loader.py b/pycrs/loader.py similarity index 100% rename from loader.py rename to pycrs/loader.py diff --git a/pycrs/loader.pyc b/pycrs/loader.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17d0b89353f3cb07f16ca7a91c058f1068e5003d GIT binary patch literal 1189 zcmb_b&2AGh5FT&-nzSW_s-RxbUXXG?i7LURLI^2TaEj1Iy;PN|H0z{JcJ0M>Xd|T@ zXrG8j;0<_&9(VvA0KRdWqF%T_l%1XVJpMf2c((L&vvDwfemJDtUxfD?Jnk7xioc+Y z=qNa8MAw3jB1%hi4Y0(k{Z<*7>KA^!A@5#2U1oU#vk+wKq#NXkyr3&V0>u56z*?`x z>HZk}_8ysrXv-YPv_W|a`nY!>j5vH8HafKV{*1-$Nl=g>*(I#ZRK z&Ra8_!_ri+b@ zdHb>~uSUxn;Ee7{;~)&o9df_eRyaE7`U?Tq9cDx7)SaV(APG8jaI74peiJ!ibfmND zIe=lhO+R==oa^IIfE*b#lW8>+-P5eK_`?RnS?)) zgn|Dt?tFTvd4%&GBXCb)NHoQc*o>NDJK7Qt;IZ9C)C3kj@uZ2gAh2h&3{sLEK!1t~ X-oJf_uX2;lGWnV%hdbV=Z>;|YzKZ@f literal 0 HcmV?d00001 diff --git a/params.py b/pycrs/parameters.py similarity index 56% rename from params.py rename to pycrs/parameters.py index b0136ca..1614863 100644 --- a/params.py +++ b/pycrs/parameters.py @@ -22,6 +22,8 @@ # +unit and +to_metre are what makes up 'UNIT["Meter",1.0]' +from . import directions + ##+a Semimajor radius of the ellipsoid axis @@ -39,15 +41,6 @@ class Azimuth: def __init__(self, value): pass -##+axis Axis orientation (new in 4.8.0) -class AxisOrientation: - proj4 = "+axis" - esri_wkt = None - ogc_wkt = "AXIS" - geotiff = None - def __init__(self, value): - pass - ##+b Semiminor radius of the ellipsoid axis class SemiMinorRadius: proj4 = "+b" @@ -55,15 +48,22 @@ class SemiMinorRadius: pass ##+datum Datum name (see `proj -ld`) -class DatumName: - def __init__(self, value): - self.value = value +class Datum: + def __init__(self, name, ellipsoid): + """ + Arguments: + + - **name**: Specific datum name instance. + - **ellipsoid**: Ellipsoid parameter instance. + """ + self.name = name + self.ellips = ellipsoid def to_proj4(self): - return "+datum=%s" %self.value + return "+datum=%s %s" % (self.name.proj4, self.ellips.to_proj4()) def to_ogc_wkt(self): - return 'DATUM[%s]' %self.value + return 'DATUM["%s", %s]' % (self.name.ogc_wkt, self.ellips.to_ogc_wkt()) def to_esri_wkt(self): return self.to_ogc_wkt() @@ -73,22 +73,96 @@ class DatumName: #return "GeogGeodeticDatum" ##+ellps Ellipsoid name (see `proj -le`) -class EllipsoidName: - def __init__(self, value): - self.value = value +class Ellipsoid: + def __init__(self, name, semimaj_ax=None, inv_flat=None): + """ + Arguments: + + - **name**: Specific ellipsoid name instance. + """ + self.name = name + + # get default values if not specified + if semimaj_ax == None: + semimaj_ax = self.name.semimaj_ax + if inv_flat == None: + inv_flat = self.name.inv_flat + + self.semimaj_ax = semimaj_ax + self.inv_flat = inv_flat def to_proj4(self): - return "+ellps=%s" %self.value + return "+ellps=%s +a=%s +f=%s" % (self.name.proj4, self.semimaj_ax, self.inv_flat) def to_ogc_wkt(self): - return 'SPHEROID[%s]' %self.value - + return 'SPHEROID["%s", %s, %s]' % (self.name.ogc_wkt, self.semimaj_ax, self.inv_flat) + def to_esri_wkt(self): return self.to_ogc_wkt() def to_geotiff(self): pass - #return "GeogEllipsoid" + #return "GeogEllipsoid" + +#GEOGCS +class GeogCS: + def __init__(self, name, datum, prime_mer, angunit, twin_ax=None): + """ + Arguments: + + - **name**: Arbitrary name. + """ + self.name = name + self.datum = datum + self.prime_mer = prime_mer + self.angunit = angunit + if twin_ax == None: + # default axes + twin_ax = directions.East(), directions.North() + 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): + return 'GEOGCS["%s", %s, %s, %s, AXIS["Lon", %s], AXIS["Lat", %s]]' % (self.name, self.datum.to_ogc_wkt(), self.prime_mer.to_ogc_wkt(), self.angunit.to_ogc_wkt(), self.twin_ax[0].ogc_wkt, self.twin_ax[1].ogc_wkt ) + + def to_esri_wkt(self): + return self.to_ogc_wkt() + +#PROJCS +class ProjCS: + def __init__(self, name, geogcs, proj, params, unit, twin_ax=None): + """ + Arguments: + + - **name**: Arbitrary name. + """ + self.name = name + self.geogcs = geogcs + self.proj = proj + self.params = params + if twin_ax == None: + # default axes + twin_ax = directions.East(), directions.North() + self.twin_ax = twin_ax + + 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... + return string + + def to_ogc_wkt(self): + string = 'PROJCS["%s", %s, %s, ' % (self.name, self.geogcs.to_ogc_wkt(), self.proj.to_ogc_wkt() ) + string += ", ".join(param.to_ogc_wkt() for param in self.params) + string += ', AXIS["X", %s], AXIS["Y", %s]]' % (self.twin_ax[0].ogc_wkt, self.twin_ax[1].ogc_wkt ) + return string + + def to_esri_wkt(self): + return self.to_ogc_wkt() ##+k Scaling factor (old name) @@ -190,6 +264,11 @@ class LongitudeSpecial: ##+pm Alternate prime meridian (typically a city name, see below) class PrimeMeridian: def __init__(self, value): + """ + Arguments: + + - **value**: Longitude value relative to Greenwich. + """ self.value = value def to_proj4(self): @@ -202,15 +281,15 @@ class PrimeMeridian: return self.to_ogc_wkt() ##+proj Projection name (see `proj -l`) -class ProjectionName: +class Projection: def __init__(self, value): self.value = value def to_proj4(self): - return "+proj=%s" %self.value + return "+proj=%s" %self.value.proj4 def to_ogc_wkt(self): - return 'PROJECTION["%s"]' %self.value + return 'PROJECTION["%s"]' %self.value.ogc_wkt def to_esri_wkt(self): return self.to_ogc_wkt() @@ -250,14 +329,19 @@ class MeterMultiplier: ##+units meters, US survey feet, etc. class UnitType: def __init__(self, value): + """ + Arguments: + + - **value**: A specific unit type instance, eg Meter(). + """ self.value = value def to_proj4(self): - return "+units=%s" %self.value + return "+units=%s" %self.value.proj4 def to_ogc_wkt(self): # the stuff that comes after UNITS[... # must be combined with metermultiplier in a unit class to make wkt - return str(self.value) + return str(self.value.ogc_wkt) def to_esri_wkt(self): return self.to_ogc_wkt() @@ -269,7 +353,23 @@ class Unit: self.metermultiplier = metermultiplier def to_proj4(self): - return "+%s +%s" %(self.unittype, self.metermultiplier) + return "%s %s" %(self.unittype.to_proj4(), self.metermultiplier.to_proj4()) + + def to_ogc_wkt(self): + return 'UNIT["%s", %s]' %(self.unittype.to_ogc_wkt(), self.metermultiplier.to_ogc_wkt()) + + def to_esri_wkt(self): + return self.to_ogc_wkt() + +# angular unit +class AngularUnit: + def __init__(self, unittype, metermultiplier): + self.unittype = unittype + self.metermultiplier = metermultiplier + + def to_proj4(self): + # cannot be specified in proj4, so just return nothing + return "" def to_ogc_wkt(self): return 'UNIT["%s", %s]' %(self.unittype.to_ogc_wkt(), self.metermultiplier.to_ogc_wkt()) @@ -283,23 +383,55 @@ class FalseEasting: esri_wkt = "False_Easting" ogc_wkt = "false_easting" geotiff = "FalseEasting" + def __init__(self, value): - pass + self.value = value + + def to_proj4(self): + return "+x_0=%s" %self.value + + def to_ogc_wkt(self): + # the stuff that comes after UNITS[... # must be combined with metermultiplier in a unit class to make wkt + return 'PARAMETER["false_easting", %s]' % self.value + + def to_esri_wkt(self): + return self.to_ogc_wkt() ##+y_0 False northing -class FalseEasting: +class FalseNorthing: proj4 = "+y_0" esri_wkt = "False_Northing" ogc_wkt = "false_northing" geotiff = "FalseNorthing" + def __init__(self, value): - pass + self.value = value + + def to_proj4(self): + return "+y_0=%s" %self.value + + def to_ogc_wkt(self): + # the stuff that comes after UNITS[... # must be combined with metermultiplier in a unit class to make wkt + return 'PARAMETER["false_northing", %s]' % self.value + + 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 # ... - - +class CRS: + def __init__(self, toplevel): + self.toplevel = toplevel + + def to_proj4(self): + return "%s +no_defs" % self.toplevel.to_proj4() + + def to_ogc_wkt(self): + return "%s" % self.toplevel.to_ogc_wkt() + + def to_esri_wkt(self): + return self.to_ogc_wkt() diff --git a/pycrs/parameters.pyc b/pycrs/parameters.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4bf0daef0c425ff97eadee6372746198ef88222 GIT binary patch literal 22395 zcmds9TWlOx89wW^*Rh*47dK7Q^fJw*IC0|U;xuWJCiN|Dn%aqGonG9etIeLVGs$|_ z?2MBbwGwI~3J*x|LIn~CBp$d41VZ8kBqSsxUJwt62S7+jNW6fAR0)YE_`ZK;&aBrP zH@0VYL)JMbGiNU6KmXy6_n@v%d(p!{1sdSGi!n+?+`jpaJP0=GtKd$u4 zN^dhosO|}+Pb76XH5}^vXmZD`Z-gy zS?Qfh4=cUP6oJm&N{=YL#}xG_{k+nnN`J}}f%IOb&nmsw6m3;{pVDJW_n9KJX1~&} zDt*8dZBx2m>2pfIV2aSdgG#@q^dVEUUFpLr+j|~Tb|GZd%gpaarrnBD@ZECB^Ecu& z>&&|2`RnD1o!9QXXLN-34jRdJwFKY}hmT-G6 zC!EOTX3KiM$Wu}>S1Df~uz71tjvTFtCY$_t21)plNo7)gC(Z^x>u$u>KUEat@8 zm_Rz&vPd9gfla2{B;Mw!$j9+2Ztm6%Um8-LDVXCKr|i4a)5(j6Dzh8Oqis+;!C!0} zZfUKyakbT)e}V0*GKCt>C(qPJQQ-krO1X>9Q`RGSe|~nU#vjEcqw#kaV+=H&B~bl9 z>7o7YQX<;Vmlmj|Ol;pUlJ_{W_fqOTKmiWg z21LHur!fTY>1C4wJKTgLzsp=f4M|$%0A4I&Qk`9?0>O%jwF@(!#sOFdW?sj?;Gj)i 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 literal 0 HcmV?d00001 diff --git a/pycrs/parser.py b/pycrs/parser.py new file mode 100644 index 0000000..3eca539 --- /dev/null +++ b/pycrs/parser.py @@ -0,0 +1,260 @@ + +# parse from text strings +# possible use module: https://github.com/rockdoc/grabbag/wiki/CRS-WKT-Parser +# also note some paramter descriptions: http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html +# and see gdal source code: http://gis.stackexchange.com/questions/129764/how-are-esri-wkt-projections-different-from-ogc-wkt-projections + +from . import datums +from . import ellipsoids +from . import parameters +from . import units +from . import projections + +def from_epsg_code(string): + # must go online (or look up local table) to get crs details + pass + +def from_esri_code(string): + # must go online (or look up local table) to get crs details + pass + +def from_sr_code(string): + # must go online (or look up local table) to get crs details + 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"]] + + params = [] + + partdict = dict([part.split("=") for part in string.split() + if not part.startswith("+no_defs")]) + + # DATUM + + # datum param is required + if "+datum" in partdict: + + # get predefined datum def + 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() + + 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) + + else: + raise Exception("Could not find required +datum element") + + # PRIME MERIDIAN + + # set default + prime_mer = parameters.PrimeMeridian(0) + + # overwrite with user input + if "+pm" in partdict: + # for now only support longitude, later add name support: +## greenwich 0dE +## lisbon 9d07'54.862"W +## paris 2d20'14.025"E +## bogota 74d04'51.3"E +## madrid 3d41'16.48"W +## rome 12d27'8.4"E +## bern 7d26'22.5"E +## jakarta 106d48'27.79"E +## ferro 17d40'W +## brussels 4d22'4.71"E +## stockholm 18d3'29.8"E +## athens 23d42'58.815"E +## oslo 10d43'22.5"E + prime_mer = parameters.PrimeMeridian(partdict["+pm"]) + + # ANGULAR UNIT + + ## proj4 cannot set angular unit, so just set to default + metmulti = parameters.MeterMultiplier(0.017453292519943295) + unittype = parameters.UnitType(units.Degree()) + angunit = parameters.AngularUnit(unittype, metmulti) + + # GEOGCS (note, currently does not load axes) + + geogcs = parameters.GeogCS("Unknown", datum, prime_mer, angunit) #, twin_ax) + + # PROJECTION + + if "+proj" in partdict: + + # get predefined proj def + if partdict["+proj"] == "robin": + projdef = projections.Robinson() + + elif partdict["+proj"] == "longlat": + projdef = None + # set geogcs axis in correct order + + elif partdict["+proj"] == "latlong": + projdef = None + # set geogcs axis in correct order + + # ALSO SHOULDNT EXCLUDE +proj, NEED WAY TO INCLUDE IT... + # ... + + else: + projdef = None + + else: + raise Exception("Could not find required +proj element") + + if projdef: + + # create proj param obj + proj = parameters.Projection(projdef) + + # CENTRAL MERIDIAN + + if "+lon_0" in partdict: + val = partdict["+lon_0"] + obj = parameters.CentralMeridian(val) + params.append(obj) + + # FALSE EASTING + + if "+x_0" in partdict: + val = partdict["+x_0"] + obj = parameters.FalseEasting(val) + params.append(obj) + + # FALSE NORTHING + + if "+y_0" in partdict: + val = partdict["+y_0"] + obj = parameters.FalseNorthing(val) + params.append(obj) + + # UNIT + + ## set default + metmulti = parameters.MeterMultiplier(1.0) + unittype = parameters.UnitType(units.Meter()) + + ## override with user input + if "+to_meter" in partdict: + metmulti = parameters.MeterMultiplier(partdict["+to_meter"]) + if "+units" in partdict: + if partdict["+units"] == "m": + unittype = parameters.UnitType(units.Meter()) + + ## create unitobj + unit = parameters.Unit(unittype, metmulti) + + # PROJCS + + projcs = parameters.ProjCS("Unknown", geogcs, proj, params, unit) + + # CRS + + crs = parameters.CRS(projcs) + + else: + crs = parameters.CRS(geogcs) + + # FINISHED + + 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_unknown_text(text): + # detect type and load with appropriate function + + if string.startswith("urn:"): + from_ogc_urn(string) + + elif string.startswith("+proj="): + from_proj4(string) + + elif string.startswith("PROJCS["): + from_unknown_wkt(string) + + elif string.startswith("EPSG:"): + from_epsg_code(string) + + elif string.startswith("ESRI:"): + from_esri_code(string) + + elif string.startswith("SR-ORG:"): + from_sr_code(string) + + else: raise Exception("Could not detect which type of crs") + +def from_geotiff_parameters(**params): + pass diff --git a/pycrs/parser.pyc b/pycrs/parser.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5fa8243ab24e883e11198135552556423918b2d GIT binary patch literal 4218 zcmc&%&2Jk;6o30=XB|6soaVCyS$s9fDk@SBC8D&I(}oWs)&9m`W zA@}!#&o-Md`lsXfHT;P0u<`J}23>%j23s0vr0cBfu%#>AVBLT%L+K{#CTy8Xw^+Ae z%R)T^p8#xSz{|3b1#g0d3Gi$dZ18d{E>( zM#zDN%`!DILpyL~zbBNQL*4IogIGj?cdRdV6SwC}KNhVg0xas3-%sDn5SHW zxeXWj7!hWnGXVpOk{mA5!IU;ZCd_anHAm`^rVlghoP&W0101fyFq_Ucd2BXLfwTim zlZ6!4d5spDWN-yoRAvNDy_hPeX#CJ-wE&nrIz`$Xb>_IU1Or^y=2a)TXPVOK06`;q zT;7Bs&Vz1>v7a?!tb{a7Gh<(CvJ9OWW~=~vzm3ghHvd46#qeK-88-a*$e=t%^qm=P zcu;`ku0gw)1(XRe=6RGAjMsI7F$;^sB7??Y615qt8Zp1}-0 zWaseSt&0h4t6|je{FadP;$0E+q*nP¦ScddT;lIp~VH5TF(?5suou2%^oS!o5K zS4sT6evtTHrOGZ9zw6UuC+Rg7elO^`orZhB&qmdiv}O?AZ?w9uRDG>yPs(7@Ndp`W z0&@ja<6irX2hKM)fBF0>vJJ4QGL0bEReH{O14(o*2-)6^!Zxm{WLJ_ZUPj-i?uO<_ z*HskYn8rn}2C4_CaM-wrd5ix2c~#i>Rh3ag6&uVY*BMN1Z<%tk zx``C~f!uLuGKZcQhpQZ#^u|HckEuFws2Y&ml@>af*Dz)JYQj}2ha?T&NP?b!%TEF? za6?(do?BD`-RgH`fUEimhhh`UpgV`L@6aS%P_6py#P=l?Mc2c2zw0LC!=^PqYS-!x z?SKb6M6QTJ-qU&%`W*9(aVf>C*6=JOZg-4?SaIXn4?Rh5)=jr7{2Q*2SVS>y?pTi! zxkEh^O~%b@jFHe9wL0${E2(9AO1SJ{m|X4&9)O}`s3dsAI-Ng0Qh4Z@M^!MAM#z-L z%c@&IRL4Xm231jp!R--=JQamkB7c0WT;wa|s*PMV1$WayqWOt8k{R}Wx69wry$&13 z1IYsiQarFcJc&AvE+SVdH1(xdQ4DXyl7? zR#BVP%I1Q}UV2Hh(c8}2MqbYtMKiDE(7*KfH;uxX=Cr(4(#{%X^Q>7$?`B$6(|3(< z@MU;HWqo2b?7zyQeiHsft8zs>KSo0;qxl{MEI+XDP=!Wv4x~;!{N8+#+PLaSE>l5~ z+6Jl3Am8K;UGvoTQEJ2D18p%?7pZMEwOMTYl&)ZETTX3UcO+PqWXCovNU&7M(jY8I zJYtXz_Bs=a+gwozivoT{PJTVr0UPxLjWdUTAWz~{ z({B+z)oF<-apFI)Q!HTvMo}y1Px>^;njXaWP=5L$ynxn|fJz)OR7?soXtf%gq4)=> zfk@PO)Yg}&YR2dzW!w-*&i9<0Iqg19EyscGw<7);NgND1&(10~kMOhf|9_oM;AC(1 gBCp@|-=f$Gsv$~vzxhwMP5!fN%g)%}+Kcx5KOdWDP5=M^ literal 0 HcmV?d00001 diff --git a/pycrs/projections.py b/pycrs/projections.py new file mode 100644 index 0000000..2eefd9d --- /dev/null +++ b/pycrs/projections.py @@ -0,0 +1,10 @@ + + +class Robinson: + proj4 = "robin" + ogc_wkt = "Robinson" + +class UTM: + proj4 = "utm" + ogc_wkt = "Transverse_Mercator" + diff --git a/pycrs/projections.pyc b/pycrs/projections.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9ad95bf139e1808c0497623b4d3baa2f02f14a2 GIT binary patch literal 636 zcmbtRy-ve05I#3)K$V!vLqrTrEFgpsMS`UWIn6+1$x3Ytg%Uf89Z+Xj*mwZmk{94E zptLJ$6o0<|yYC!*A51>JK63?sUxfE19)E@KB&W0-b=41``7vLzeDg zc-TkaZdqCH>`;-R@d}SWL@)paW*}l621NusOGoGkV}zD+ISP=*WTSdg+OjrMhDoo~ zPIu3wQhd|8r;|Xf-J_DPtB|4y8}O&7&dx;cP3y&~s-3uYs;i9+UffjSwp)t(^^9kt zSu2d7dParHS%2KD`$1?Qo`y+S!UAdeV*X!ll-7khOz~c{rS&g3kCAiJsxr8?C(CII yoFX~3nq?dN2lVC;K)j;QNtA5`doxmw<%R#o?8u!n5{`+tjM9@>SY5W7byn{9X literal 0 HcmV?d00001 diff --git a/pycrs/units.py b/pycrs/units.py new file mode 100644 index 0000000..6b2a174 --- /dev/null +++ b/pycrs/units.py @@ -0,0 +1,11 @@ + + +class Meter: + proj4 = "m" + ogc_wkt = "Meters" # or is it metre?? sometimes even Meter? + esri_wkt = "Meter" + +class Degree: + proj4 = "degrees" + ogc_wkt = "degree" + esri_wkt = "Degree" diff --git a/pycrs/units.pyc b/pycrs/units.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1220c6e2d81aa72eaf0feafa865d0c07e94e57bf GIT binary patch literal 655 zcmbVJ%SyyR5bSIo%7Q0venIfyMNc9k?t)$vnXm`LK+w#v#5E5y6C`K-0DsW0@CUYQ zBAY!YNmsfjJzZ59|LHqTieZyf+85BPuDUZI1zKEVvu4kkoQvPnqBNb2* zA8@-386LFN?QWdME4Lixgh3Of+|I~DJW72`O9K)~3|fok(ngGKh!LDojG^|BA#uf_;o6&JDscH1h3s61)p-H zxUnVsDqJEix#t16=LvWLo`EOe0pL5cCP}3tT2Uu+_Uz30{mz-Q?w^&?qwd|uKFxj( zo}XjsBM^yyK_Su8D_+o3LDHe`vFVU>E#s2RStds+Pclzu4y9j{g1{VI3KEeubX=Q< z(cmxq4t)W335&OOvGgCw9dg;*A`hf@7hDliJ=4tBCL{J|`^VA3Luz6Xa4fZnn zNyrV_JN;2iU7EPGe;~^sU7{&WRA`!~(a&UDN^@fT1Ia}en&heD(E4yvckX&Nv4Y^DklX*gXd#CF(EzqPu{UQs?725pHq4Qs8TBJ#l^zU@UdA~7p zv41dugAyNcu<(nJb`VqZT#^vt2#+UNO}UDoN57F-AZS2#@AOwX0U#xsE|7fFM!oQ& zs0HVt;d9Hw$vUA)4opsL2wrMhj!c=ussv=))!%`h@^(|e0n0Q_F*_PHE zqusRb>a`Pj=XQWSZX`qxDQoh|xi%@s(23K5XEZ;n%JX|w&Qtj&h$DRqiZ2lYqR_Wr zT9l<3@@qfUt$Rb2G%#5O z`*9H2vv1R(vQ-VuOtllJQ0fMk{;CPNKN_rM z!w-Y#%rZSQ2yKoioZqvY?Hj|&L4!NlhLFY=ri7PN>0xMWM{|(bYYiM(qIbaU-mgE_ zD%JI~U=Y{$VjpQmM%VWPb1-bzkH))=6w!vkM0>;tMCLuYY&p&X7GH%9(Ye*pSlQ{bUiUh4OF4!zPO$RK?l z=4*uQsl8Yk0QSa3>f#3I82$joI?wuAzs@qO!Z^y1dA}~i1NO-`i=2{J%W=QjJKJgv zydY||bUD+r*J0a?OpRNmVbfe@?tLb=m@v3A-N+lLR_nTf{{Q7H!1$+wSPnz=z