################# # CRS CLASSES ################# # first classes for each crs element, from the proj4 common paramter listing # https://trac.osgeo.org/proj/wiki/GenParms # note also that in wkt the names of "PROJECTION", "DATUM", and "SPHEROID" # matter and seem to be interpreted and computed upon, ie they carry meaning # that is commonly understood by programs, so is not explicit in the crs specification. # the paramters below simply modify certain aspects of the proj/datum/spheroids # note that the names in wkt of "PROJCS" and "GEOGCS" seem to be purely # for identifying and branding and can be changed at will. # they do however act as shortcuts, so that proj4 can use +init=... to load # everything automatically # some of these names imply certain combinations of datum and spheroid and paramters. # so in proj4 one simply needs to give that name, but in wkt one needs to spell it all out. # +unit and +to_metre are what makes up 'UNIT["Meter",1.0]' from . import directions # ONLY PURE VALUES INSIDE ELLIPSOID... ##+a Semimajor radius of the ellipsoid axis class SemiMajorRadius: proj4 = "+a" 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, datumshift=None): """ Arguments: - **name**: Specific datum name instance. - **ellipsoid**: Ellipsoid parameter instance. """ self.name = name self.ellips = ellipsoid self.datumshift = datumshift def to_proj4(self): 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): 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() def to_geotiff(self): pass #return "GeogGeodeticDatum" ##+ellps Ellipsoid name (see `proj -le`) 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 +a=%s +f=%s" % (self.name.proj4, self.semimaj_ax, self.inv_flat) def to_ogc_wkt(self): 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" #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): 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 self.unit = unit 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) string += " %s" % self.unit.to_proj4() # 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): 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 += ', %s' % self.unit.to_ogc_wkt() 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) ##+k_0 Scaling factor (new name) class ScalingFactor: def __init__(self, value): self.value = value def to_proj4(self): return "+k_0=%s" %self.value def to_ogc_wkt(self): return 'PARAMETER["scale_factor", %s]' %self.value def to_esri_wkt(self): raise Exception("Paramater not supported by ESRI WKT") def to_geotiff(self): pass #return "ScaleAtNatOrigin" # or ScaleAtCenter? ##+lat_0 Latitude of origin class LatitudeOrigin: def __init__(self, value): self.value = value def to_proj4(self): 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): raise Exception("Paramater not supported by ESRI WKT") def to_geotiff(self): pass #return "ProjCenterLat" ##+lat_1 Latitude of first standard parallel class LatitudeFirstStndParallel: 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: 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: def __init__(self, value): self.value = value def to_proj4(self): return "+lat_ts=%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 "ProjStdParallel1" ##+lon_0 Central meridian class CentralMeridian: def __init__(self, value): self.value = value def to_proj4(self): return "+lon_0=%s" %self.value def to_ogc_wkt(self): return 'PARAMETER["Central_Meridian", %s]' %self.value def to_esri_wkt(self): return self.to_ogc_wkt() def to_geotiff(self): pass #return "ProjCenterLong" ##+lonc ? Longitude used with Oblique Mercator and possibly a few others class LongitudeCenter: proj4 = "+lonc" def __init__(self, value): 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) ##+over Allow longitude output outside -180 to 180 range, disables wrapping (see below) ##+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): return "+pm=%s" %self.value def to_ogc_wkt(self): return 'PRIMEM["Greenwich", %s]' %self.value def to_esri_wkt(self): return self.to_ogc_wkt() ##+proj Projection name (see `proj -l`) class Projection: def __init__(self, value): self.value = value def to_proj4(self): return "+proj=%s" %self.value.proj4 def to_ogc_wkt(self): return 'PROJECTION["%s"]' %self.value.ogc_wkt def to_esri_wkt(self): return self.to_ogc_wkt() ##+zone UTM zone ##+south Denotes southern hemisphere UTM zone ##+towgs84 3 or 7 term datum transform parameters (see below) class DatumShift: def __init__(self, value): self.value = value def to_proj4(self): return "+towgs84=%s" %",".join((bytes(val) for val in self.value)) def to_ogc_wkt(self): return "TOWGS84[%s]" %",".join((bytes(val) for val in self.value)) def to_esri_wkt(self): raise Exception("Paramater not supported by ESRI WKT") ##+to_meter Multiplier to convert map units to 1.0m class MeterMultiplier: def __init__(self, value): self.value = value def to_proj4(self): return "+to_meter=%s" %self.value def to_ogc_wkt(self): # the stuff that comes after UNITS["meter", ... # must be combined with unittype in a unit class to make wkt return bytes(self.value) def to_esri_wkt(self): return self.to_ogc_wkt() ##+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.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 bytes(self.value.ogc_wkt) def to_esri_wkt(self): return self.to_ogc_wkt() # special... class Unit: def __init__(self, unittype, metermultiplier): self.unittype = unittype self.metermultiplier = metermultiplier def to_proj4(self): 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()) def to_esri_wkt(self): return self.to_ogc_wkt() ##+x_0 False easting class FalseEasting: proj4 = "+x_0" esri_wkt = "False_Easting" ogc_wkt = "false_easting" geotiff = "FalseEasting" def __init__(self, value): self.value = value def to_proj4(self): return "+x_0=%s" %self.value def to_ogc_wkt(self): return 'PARAMETER["false_easting", %s]' % self.value def to_esri_wkt(self): return self.to_ogc_wkt() ##+y_0 False northing class FalseNorthing: proj4 = "+y_0" esri_wkt = "False_Northing" ogc_wkt = "false_northing" geotiff = "FalseNorthing" def __init__(self, value): self.value = value def to_proj4(self): return "+y_0=%s" %self.value def to_ogc_wkt(self): return 'PARAMETER["false_northing", %s]' % self.value def to_esri_wkt(self): return self.to_ogc_wkt() ##+h Satellite height class SatelliteHeight: def __init__(self, value): self.value = value def to_proj4(self): return "+h=%s" %self.value def to_ogc_wkt(self): return 'PARAMETER["satellite_height", %s]' % self.value def to_esri_wkt(self): return self.to_ogc_wkt() ##+tilt Tilt angle class TiltAngle: def __init__(self, value): self.value = value def to_proj4(self): return "+tilt=%s" %self.value def to_ogc_wkt(self): raise Exception("Paramater not supported by OGC WKT") def to_esri_wkt(self): raise Exception("Paramater not supported by ESRI 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()