- Timestamp:
- Nov 1, 2017 11:47:41 AM (7 years ago)
- Branches:
- master, core_shell_microgels, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 05e4f8a
- Parents:
- 0f65169
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
explore/guyou.py
r0f65169 rbc386f0 1 # Copyright 2013-2016 Mike Bostock 2 # All rights reserved. 3 # 4 # Redistribution and use in source and binary forms, with or without modification, 5 # are permitted provided that the following conditions are met: 6 # 7 # * Redistributions of source code must retain the above copyright notice, this 8 # list of conditions and the following disclaimer. 9 # 10 # * Redistributions in binary form must reproduce the above copyright notice, 11 # this list of conditions and the following disclaimer in the documentation 12 # and/or other materials provided with the distribution. 13 # 14 # * Neither the name of the author nor the names of contributors may be used to 15 # endorse or promote products derived from this software without specific prior 16 # written permission. 17 # 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 # 29 # https://github.com/d3/d3-geo-projection 30 # commit fd2886555e46b35163c7b898d43c7d1bcebbba7c 2016-07-02 31 # 32 # 2017-11-01 Paul Kienzle 33 # * converted to python, using degrees rather than radians 1 34 from __future__ import division, print_function 2 35 … … 4 37 from numpy import sqrt, pi, tan, cos, sin, log, exp, arctan2 as atan2, sign, radians, degrees 5 38 39 _ = """ 6 40 # mpmath version of special functions 7 _ = """8 41 import mpmath as mp 9 42 sn, cn, dn = [mp.ellipfun(v) for v in 'sn', 'cn', 'dn'] … … 84 117 cotlambda2 = (-b + sqrt(b * b - 4 * c)) / 2 85 118 re = ellipticF(atan(1 / sqrt(cotlambda2)), m) * sign(phi) 86 im = ellipticF(atan(sqrt( (cotlambda2 / cotphi2 - 1) / m)), 1 - m) * sign(psi)119 im = ellipticF(atan(sqrt(np.maximum(0,(cotlambda2 / cotphi2 - 1) / m))), 1 - m) * sign(psi) 87 120 return re + 1j*im 88 121 122 sqrt2 = sqrt(2) 123 124 # [PAK] renamed k_ => cos_u, k => sin_u, k*k => sinsq_u to avoid k,K confusion 125 # cos_u = 0.171572875253809902396622551580603842860656249246103853646... 126 # sinsq_u = 0.970562748477140585620264690516376942836062504523376878120... 127 # K = 5.415790687177373152821133989303623814510776592635531270636... 128 def guyou(lam, phi): 129 # [PAK] wrap into [-pi/2, pi/2] radians 130 x, y = np.asarray(lam), np.asarray(phi) 131 xn, x = divmod(x+90, 180) 132 yn, y = divmod(y+90, 180) 133 xn, lam = xn*180, radians(x-90) 134 yn, phi = yn*180, radians(y-90) 135 136 # Compute constant K 137 cos_u = (sqrt2 - 1) / (sqrt2 + 1) 138 sinsq_u = 1 - cos_u**2 139 K = ellipticF(pi/2, sinsq_u) 140 141 # [PAK] simplify expressions, using the fact that f = -1 142 # Note: exp(f log(x)) => 1/x, cos(f x) => cos(x), sin(f x) => -sin(x) 143 r = 1/(tan(pi/4 + abs(phi)/2) * sqrt(cos_u)) 144 at = atan(r * (cos(lam) - 1j*sin(lam))) 145 t = ellipticFi(at.real, at.imag, sinsq_u) 146 x, y = (-t.imag, sign(phi + (phi==0))*(0.5 * K - t.real)) 147 148 # [PAK] convert to degrees, and return to original tile 149 return degrees(x)+xn, degrees(y)+yn 150 151 def guyou_invert(x, y): 152 # [PAK] wrap into [-pi/2, pi/2] radians 153 x, y = np.asarray(x), np.asarray(y) 154 xn, x = divmod(x+90, 180) 155 yn, y = divmod(y+90, 180) 156 xn, x = xn*180, radians(x-90) 157 yn, y = yn*180, radians(y-90) 158 159 # compute constant K 160 cos_u = (sqrt2 - 1) / (sqrt2 + 1) 161 sinsq_u = 1 - cos_u**2 162 K = ellipticF(pi/2, sinsq_u) 163 164 # [PAK] simplify expressions, using the fact that f = -1 165 # Note: exp(0.5/f log(x)) => 1/sqrt(x), a x.real^2 + a x.imag^2 => a|x|^2 166 j = ellipticJi(0.5 * K - y, -x, sinsq_u) 167 tn = j[0]/j[1] # j[0], j[1] are complex 168 lam = -atan2(tn.imag, tn.real) 169 phi = 2*atan(1/sqrt(cos_u*abs(tn)**2)) - pi/2 170 171 # [PAK] convert to degrees, and return to original tile 172 return degrees(lam)+xn, degrees(phi)+yn 173 174 def plot_grid(): 175 import matplotlib.pyplot as plt 176 from numpy import linspace 177 lat_line = linspace(-90, 90, 400) 178 long_line = linspace(-90, 90, 400) 179 180 #scale = 1 181 limit, step, scale = 90, 10, 2 182 plt.subplot(211) 183 for lat in range(-limit, limit+1, step): 184 x, y = guyou(scale*lat_line, scale*lat) 185 plt.plot(x, y, 'g') 186 187 for long in range(-limit, limit+1, step): 188 x, y = guyou(scale*long, scale*long_line) 189 plt.plot(x, y, 'b') 190 #plt.xlabel('longitude') 191 plt.ylabel('latitude') 192 193 plt.subplot(212) 194 for lat in range(-limit, limit+1, step): 195 x, y = guyou_invert(scale*lat_line, scale*lat) 196 plt.plot(x, y, 'g') 197 198 for long in range(-limit, limit+1, step): 199 x, y = guyou_invert(scale*long, scale*long_line) 200 plt.plot(x, y, 'b') 201 plt.xlabel('longitude') 202 plt.ylabel('latitude') 203 204 if __name__ == "__main__": 205 plot_grid() 206 import matplotlib.pyplot as plt; plt.show() 207 208 89 209 _ = """ 210 // Javascript source for elliptic functions 211 // 90 212 // Returns [sn, cn, dn](u + iv|m). 91 213 export function ellipticJi(u, v, m) { … … 203 325 } 204 326 return phi / (pow(2, i) * a); 327 328 329 export function guyouRaw(lambda, phi) { 330 var k_ = (sqrt2 - 1) / (sqrt2 + 1), 331 k = sqrt(1 - k_ * k_), 332 K = ellipticF(halfPi, k * k), 333 f = -1, 334 psi = log(tan(pi / 4 + abs(phi) / 2)), 335 r = exp(f * psi) / sqrt(k_), 336 at = guyouComplexAtan(r * cos(f * lambda), r * sin(f * lambda)), 337 t = ellipticFi(at[0], at[1], k * k); 338 return [-t[1], (phi >= 0 ? 1 : -1) * (0.5 * K - t[0])]; 339 } 340 341 function guyouComplexAtan(x, y) { 342 var x2 = x * x, 343 y_1 = y + 1, 344 t = 1 - x2 - y * y; 345 return [ 346 0.5 * ((x >= 0 ? halfPi : -halfPi) - atan2(t, 2 * x)), 347 -0.25 * log(t * t + 4 * x2) +0.5 * log(y_1 * y_1 + x2) 348 ]; 349 } 350 351 function guyouComplexDivide(a, b) { 352 var denominator = b[0] * b[0] + b[1] * b[1]; 353 return [ 354 (a[0] * b[0] + a[1] * b[1]) / denominator, 355 (a[1] * b[0] - a[0] * b[1]) / denominator 356 ]; 357 } 358 359 guyouRaw.invert = function(x, y) { 360 var k_ = (sqrt2 - 1) / (sqrt2 + 1), 361 k = sqrt(1 - k_ * k_), 362 K = ellipticF(halfPi, k * k), 363 f = -1, 364 j = ellipticJi(0.5 * K - y, -x, k * k), 365 tn = guyouComplexDivide(j[0], j[1]), 366 lambda = atan2(tn[1], tn[0]) / f; 367 return [ 368 lambda, 369 2 * atan(exp(0.5 / f * log(k_ * tn[0] * tn[0] + k_ * tn[1] * tn[1]))) - halfPi 370 ]; 371 }; 205 372 """ 206 207 def guyouComplexAtan(x, y):208 x2 = x * x209 y_1 = y + 1210 t = 1 - x2 - y * y211 return (212 0.5 * (sign(x+(x==0))*halfPi - atan2(t, 2 * x)),213 -0.25 * log(t * t + 4 * x2) +0.5 * log(y_1 * y_1 + x2)214 )215 216 sqrt2 = sqrt(2)217 halfPi = pi/2218 219 # From d3-geo-projections220 def guyou(lam, phi):221 x, y = np.asarray(lam), np.asarray(phi)222 xn, x = divmod(x+90, 180)223 yn, y = divmod(y+90, 180)224 xn, lam = xn*180, radians(x-90)225 yn, phi = yn*180, radians(y-90)226 227 k_ = (sqrt2 - 1) / (sqrt2 + 1)228 k = sqrt(1 - k_ * k_)229 K = ellipticF(halfPi, k * k)230 f = -1231 psi = log(tan(pi / 4 + abs(phi) / 2))232 r = exp(f * psi) / sqrt(k_)233 at = guyouComplexAtan(r * cos(f * lam), r * sin(f * lam))234 t = ellipticFi(at[0], at[1], k * k)235 #return [-t.imag, (1 if phi >=0 else -1)*(0.5 * K - t.real)]236 x, y = (-t.imag, sign(phi + (phi==0))*(0.5 * K - t.real))237 return degrees(x)+xn, degrees(y)+yn238 239 #def guyouComplexDivide(a, b):240 # denominator = b[0] * b[0] + b[1] * b[1]241 # return [242 # (a[0] * b[0] + a[1] * b[1]) / denominator,243 # (a[1] * b[0] - a[0] * b[1]) / denominator244 # ]245 246 def guyou_invert(x, y):247 x, y = np.asarray(x), np.asarray(y)248 xn, x = divmod(x+90, 180)249 yn, y = divmod(y+90, 180)250 xn, x = xn*180, radians(x-90)251 yn, y = yn*180, radians(y-90)252 253 k_ = (sqrt2 - 1) / (sqrt2 + 1)254 k = sqrt(1 - k_ * k_)255 K = ellipticF(halfPi, k * k)256 f = -1257 j = ellipticJi(0.5 * K - y, -x, k * k)258 #tn = guyouComplexDivide(j[0], j[1])259 #lam = atan2(tn[1], tn[0]) / f260 tn = j[0]/j[1] # j[0], j[1] are complex261 lam = atan2(tn.imag, tn.real) / f262 phi = 2 * atan(exp(0.5 / f * log(k_ * tn.real**2 + k_ * tn.imag**2))) - halfPi263 return degrees(lam)+xn, degrees(phi)+yn264 265 def plot_grid():266 import matplotlib.pyplot as plt267 from numpy import linspace268 lat_line = linspace(-90, 90, 100)[1:-1]269 long_line = linspace(-90, 90, 100)[1:-1]270 271 #scale = 1272 scale = 2273 plt.subplot(211)274 for lat in range(-80, 81, 10):275 x, y = guyou(scale*lat_line, scale*lat)276 plt.plot(x, y, 'g')277 278 for long in range(-80, 81, 10):279 x, y = guyou(scale*long, scale*long_line)280 plt.plot(x, y, 'b')281 plt.subplot(212)282 for lat in range(-80, 81, 10):283 x, y = guyou_invert(scale*lat_line, scale*lat)284 plt.plot(x, y, 'g')285 286 for long in range(-80, 81, 10):287 x, y = guyou_invert(scale*long, scale*long_line)288 plt.plot(x, y, 'b')289 290 if __name__ == "__main__":291 plot_grid()292 import matplotlib.pyplot as plt; plt.show()
Note: See TracChangeset
for help on using the changeset viewer.