Menu

[r6263]: / trunk / toolkits / basemap / src / _geod.pyx  Maximize  Restore  History

Download this file

166 lines (158 with data), 7.3 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# Make changes to this file, not the c-wrappers that Pyrex generates.
include "_pyproj.pxi"
cdef class Geod:
cdef GEODESIC_T geodesic_t
cdef public object geodstring
cdef public object proj_version
cdef char *geodinitstring
def __new__(self, geodstring):
cdef GEODESIC_T GEOD_T
# setup geod initialization string.
self.geodstring = geodstring
self.geodinitstring = PyString_AsString(self.geodstring)
# initialize projection
self.geodesic_t = GEOD_init_plus(self.geodinitstring, &GEOD_T)[0]
if pj_errno != 0:
raise RuntimeError(pj_strerrno(pj_errno))
self.proj_version = PJ_VERSION/100.
def __reduce__(self):
"""special method that allows pyproj.Geod instance to be pickled"""
return (self.__class__,(self.geodstring,))
def _fwd(self, object lons, object lats, object az, object dist, radians=False):
"""
forward transformation - determine longitude, latitude and back azimuth
of a terminus point given an initial point longitude and latitude, plus
forward azimuth and distance.
if radians=True, lons/lats are radians instead of degrees.
"""
cdef Py_ssize_t buflenlons, buflenlats, buflenaz, buflend, ndim, i
cdef double *lonsdata, *latsdata, *azdata, *distdata
cdef void *londata, *latdata, *azdat, *distdat
# if buffer api is supported, get pointer to data buffers.
if PyObject_AsWriteBuffer(lons, &londata, &buflenlons) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(lats, &latdata, &buflenlats) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(az, &azdat, &buflenaz) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(dist, &distdat, &buflend) <> 0:
raise RuntimeError
# process data in buffer
if not buflenlons == buflenlats == buflenaz == buflend:
raise RuntimeError("Buffer lengths not the same")
ndim = buflenlons/_doublesize
lonsdata = <double *>londata
latsdata = <double *>latdata
azdata = <double *>azdat
distdata = <double *>distdat
for i from 0 <= i < ndim:
if radians:
self.geodesic_t.p1.v = lonsdata[i]
self.geodesic_t.p1.u = latsdata[i]
self.geodesic_t.ALPHA12 = azdata[i]
self.geodesic_t.DIST = distdata[i]
else:
self.geodesic_t.p1.v = _dg2rad*lonsdata[i]
self.geodesic_t.p1.u = _dg2rad*latsdata[i]
self.geodesic_t.ALPHA12 = _dg2rad*azdata[i]
self.geodesic_t.DIST = distdata[i]
geod_pre(&self.geodesic_t)
if pj_errno != 0:
raise RuntimeError(pj_strerrno(pj_errno))
geod_for(&self.geodesic_t)
if pj_errno != 0:
raise RuntimeError(pj_strerrno(pj_errno))
if isnan(self.geodesic_t.ALPHA21):
raise ValueError('undefined forward geodesic (may be an equatorial arc)')
if radians:
lonsdata[i] = self.geodesic_t.p2.v
latsdata[i] = self.geodesic_t.p2.u
azdata[i] = self.geodesic_t.ALPHA21
else:
lonsdata[i] = _rad2dg*self.geodesic_t.p2.v
latsdata[i] = _rad2dg*self.geodesic_t.p2.u
azdata[i] = _rad2dg*self.geodesic_t.ALPHA21
def _inv(self, object lons1, object lats1, object lons2, object lats2, radians=False):
"""
inverse transformation - return forward and back azimuths, plus distance
between an initial and terminus lat/lon pair.
if radians=True, lons/lats are radians instead of degrees.
"""
cdef Py_ssize_t buflenlons, buflenlats, buflenaz, buflend, ndim, i
cdef double *lonsdata, *latsdata, *azdata, *distdata
cdef void *londata, *latdata, *azdat, *distdat
# if buffer api is supported, get pointer to data buffers.
if PyObject_AsWriteBuffer(lons1, &londata, &buflenlons) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(lats1, &latdata, &buflenlats) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(lons2, &azdat, &buflenaz) <> 0:
raise RuntimeError
if PyObject_AsWriteBuffer(lats2, &distdat, &buflend) <> 0:
raise RuntimeError
# process data in buffer
if not buflenlons == buflenlats == buflenaz == buflend:
raise RuntimeError("Buffer lengths not the same")
ndim = buflenlons/_doublesize
lonsdata = <double *>londata
latsdata = <double *>latdata
azdata = <double *>azdat
distdata = <double *>distdat
for i from 0 <= i < ndim:
if radians:
self.geodesic_t.p1.v = lonsdata[i]
self.geodesic_t.p1.u = latsdata[i]
self.geodesic_t.p2.v = azdata[i]
self.geodesic_t.p2.u = distdata[i]
else:
self.geodesic_t.p1.v = _dg2rad*lonsdata[i]
self.geodesic_t.p1.u = _dg2rad*latsdata[i]
self.geodesic_t.p2.v = _dg2rad*azdata[i]
self.geodesic_t.p2.u = _dg2rad*distdata[i]
geod_inv(&self.geodesic_t)
if isnan(self.geodesic_t.DIST):
raise ValueError('undefined inverse geodesic (may be an antipodal point)')
if pj_errno != 0:
raise RuntimeError(pj_strerrno(pj_errno))
if radians:
lonsdata[i] = self.geodesic_t.ALPHA12
latsdata[i] = self.geodesic_t.ALPHA21
else:
lonsdata[i] = _rad2dg*self.geodesic_t.ALPHA12
latsdata[i] = _rad2dg*self.geodesic_t.ALPHA21
azdata[i] = self.geodesic_t.DIST
def _npts(self, double lon1, double lat1, double lon2, double lat2, int npts, radians=False):
"""
given initial and terminus lat/lon, find npts intermediate points."""
cdef int i
cdef double del_s
if radians:
self.geodesic_t.p1.v = lon1
self.geodesic_t.p1.u = lat1
self.geodesic_t.p2.v = lon2
self.geodesic_t.p2.u = lat2
else:
self.geodesic_t.p1.v = _dg2rad*lon1
self.geodesic_t.p1.u = _dg2rad*lat1
self.geodesic_t.p2.v = _dg2rad*lon2
self.geodesic_t.p2.u = _dg2rad*lat2
# do inverse computation to set azimuths, distance.
geod_inv(&self.geodesic_t)
# set up some constants needed for forward computation.
geod_pre(&self.geodesic_t)
# distance increment.
del_s = self.geodesic_t.DIST/(npts+1)
# initialize output tuples.
lats = ()
lons = ()
# loop over intermediate points, compute lat/lons.
for i from 1 <= i < npts+1:
self.geodesic_t.DIST = i*del_s
geod_for(&self.geodesic_t)
if radians:
lats = lats + (self.geodesic_t.p2.u,)
lons = lons + (self.geodesic_t.p2.v,)
else:
lats = lats + (_rad2dg*self.geodesic_t.p2.u,)
lons = lons + (_rad2dg*self.geodesic_t.p2.v,)
return lons, lats
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.