00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 package require Tcl 8.4
00014 package require math::interpolate 1.0
00015 package require math::special 0.2.1
00016
00017 package provide mapproj 1.0
00018
00019
00020
00021
00022
00023 namespace ::mapproj {
00024
00025
00026
00027 namespace export toPlateCarree fromPlateCarree
00028 namespace export toCassini fromCassini
00029 namespace export toCylindricalEqualArea fromCylindricalEqualArea
00030 namespace export toMercator fromMercator
00031
00032
00033
00034
00035 namespace export toLambertCylindricalEqualArea \
00036 fromLambertCylindricalEqualArea
00037 namespace export toBehrmann fromBehrmann
00038 namespace export toTrystanEdwards fromTrystanEdwards
00039 namespace export toHoboDyer fromHoboDyer
00040 namespace export toGallPeters fromGallPeters
00041 namespace export toBalthasart fromBalthasart
00042
00043
00044
00045 namespace export toSinusoidal fromSinusoidal
00046 namespace export toMillerCylindrical fromMillerCylindrical
00047 namespace export toMollweide fromMollweide
00048 namespace export toEckertIV fromEckertIV toEckertVI fromEckertVI
00049
00050
00051
00052 namespace export toRobinson fromRobinson
00053
00054
00055
00056 namespace export toAzimuthalEquidistant fromAzimuthalEquidistant
00057 namespace export toLambertAzimuthalEqualArea fromLambertAzimuthalEqualArea
00058 namespace export toStereographic fromStereographic
00059 namespace export toOrthographic fromOrthographic
00060 namespace export toGnomonic fromGnomonic
00061
00062
00063
00064 namespace export toHammer fromHammer
00065
00066
00067
00068 namespace export toConicEquidistant fromConicEquidistant
00069 namespace export toLambertConformalConic fromLambertConformalConic
00070 namespace export toAlbersEqualAreaConic fromAlbersEqualAreaConic
00071
00072
00073
00074 namespace export toPeirceQuincuncial fromPeirceQuincuncial
00075
00076
00077
00078 variable pi [expr {acos(-1.0)}]
00079 variable twopi [expr {2.0 * $pi}]
00080 variable halfpi [expr {0.5 * $pi}]
00081 variable quarterpi [expr {0.25 * $pi}]
00082 variable threequarterpi [expr {0.75 * $pi}]
00083 variable mquarterpi [expr {-0.25 * $pi}]
00084 variable mthreequarterpi [expr {-0.75 * $pi}]
00085 variable radian [expr {180. / $pi}]
00086 variable degree [expr {$pi / 180.}]
00087 variable sqrt2 [expr {sqrt(2.)}]
00088 variable sqrt8 [expr {2. * $sqrt2}]
00089 variable halfSqrt3 [expr {sqrt(3.) / 2.}]
00090 variable halfSqrt2 [expr {sqrt(2.) / 2.}]
00091 variable EckertIVK1 [expr {2.0 / sqrt($pi * (4.0 + $pi))}]
00092 variable EckertIVK2 [expr {2.0 * sqrt($pi / (4.0 + $pi))}]
00093 variable EckertVIK1 [expr {sqrt(2.0 + $pi)}]
00094 variable PeirceQuincuncialScale 3.7081493546027438 ;
00095 variable PeirceQuincuncialLimit 1.8540746773013719 ;
00096
00097
00098
00099
00100 variable RobinsonLatitude {
00101 -90.0 -85.0 -80.0 -75.0 -70.0 -65.0
00102 -60.0 -55.0 -50.0 -45.0 -40.0 -35.0
00103 -30.0 -25.0 -20.0 -15.0 -10.0 -5.0
00104 0.0 5.0 10.0 15.0 20.0 25.0 30.0
00105 35.0 40.0 45.0 50.0 55.0 60.0
00106 65.0 70.0 75.0 80.0 85.0 90.0
00107 }
00108 variable RobinsonPLEN {
00109 0.5322 0.5722 0.6213 0.6732 0.7186 0.7597
00110 0.7986 0.8350 0.8679 0.8962 0.9216 0.9427
00111 0.9600 0.9730 0.9822 0.9900 0.9954 0.9986
00112 1.0000 0.9986 0.9954 0.9900 0.9822 0.9730 0.9600
00113 0.9427 0.9216 0.8962 0.8679 0.8350 0.7986
00114 0.7597 0.7186 0.6732 0.6213 0.5722 0.5322
00115 }
00116 variable RobinsonPDFE {
00117 -1.0000 -0.9761 -0.9394 -0.8936 -0.8435 -0.7903
00118 -0.7346 -0.6769 -0.6176 -0.5571 -0.4958 -0.4340
00119 -0.3720 -0.3100 -0.2480 -0.1860 -0.1240 -0.0620
00120 0.0000 0.0620 0.1240 0.1860 0.2480 0.3100 0.3720
00121 0.4340 0.4958 0.5571 0.6176 0.6769 0.7346
00122 0.7903 0.8435 0.8936 0.9394 0.9761 1.0000
00123 }
00124
00125
00126
00127 variable RobinsonSplinePLEN \
00128 [math::interpolate::prepare-cubic-splines \
00129 $RobinsonLatitude $RobinsonPLEN]
00130 variable RobinsonSplinePDFE \
00131 [math::interpolate::prepare-cubic-splines \
00132 $RobinsonLatitude $RobinsonPDFE]
00133 variable RobinsonM [expr {0.5072 * $pi}]
00134
00135 namespace import ::math::special::cn
00136
00137 }
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 ret ::mapproj::ellF (type phi , type k) {
00159 return [ellFaux [expr {cos($phi)}] [expr {sin($phi)}] $k]
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 ret ::mapproj::ellFaux (type cos_, type phi , type sin_, type phi , type k) {
00177 set rf [ellRF [expr {$cos_phi * $cos_phi}] \
00178 [expr {1.0 - $k * $k * $sin_phi * $sin_phi}] \
00179 1.0]
00180 return [expr {$sin_phi * $rf}]
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 ret ::mapproj::ellRF (type x , type y , type z) {
00197 if {$x < 0.0 || $y < 0.0 || $z < 0.0} {
00198 return -code error "Negative argument to Carlson's ellRF" \
00199 -errorCode "ellRF negArgument"
00200 }
00201 set delx 1.0; set dely 1.0; set delz 1.0
00202 while {abs($delx) > 0.0025 || abs($dely) > 0.0025 || abs($delz) > 0.0025} {
00203 set sx [expr {sqrt($x)}]
00204 set sy [expr {sqrt($y)}]
00205 set sz [expr {sqrt($z)}]
00206 set len [expr {$sx * ($sy + $sz) + $sy * $sz}]
00207 set x [expr {0.25 * ($x + $len)}]
00208 set y [expr {0.25 * ($y + $len)}]
00209 set z [expr {0.25 * ($z + $len)}]
00210 set mean [expr {($x + $y + $z) / 3.0}]
00211 set delx [expr {($mean - $x) / $mean}]
00212 set dely [expr {($mean - $y) / $mean}]
00213 set delz [expr {($mean - $z) / $mean}]
00214 }
00215 set e2 [expr {$delx * $dely - $delz * $delz}]
00216 set e3 [expr {$delx * $dely * $delz}]
00217 return [expr {(1.0 + ($e2 / 24.0 - 0.1 - 3.0 * $e3 / 44.0) * $e2
00218 + $e3 / 14.) / sqrt($mean)}]
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 ret ::mapproj::toPlateCarree (type lambda_0 , type phi_0 , type lambda , type phi) {
00236 variable degree
00237 set lambda [expr {$lambda - $lambda_0 + 180.}]
00238 if {$lambda < 0.0 || $lambda > 360.0} {
00239 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00240 }
00241 set lambda [expr {$lambda - 180.}]
00242 set x [expr {$lambda * $degree}]
00243 set y [expr {($phi - $phi_0) * $degree}]
00244 return [list $x $y]
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 ret ::mapproj::fromPlateCarree (type phi_0 , type lambda_0 , type x , type y) {
00261 variable radian
00262 set lambda [expr {$lambda_0 + $x * $radian + 180.}]
00263 if {$lambda < 0.0 || $lambda > 360.0} {
00264 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00265 }
00266 set lambda [expr {$lambda - 180.}]
00267 set phi [expr {$y * $radian + $phi_0}]
00268 return [list $lambda $phi]
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 ret ::mapproj::toCylindricalEqualArea (type phi_1 , type lambda_0 , type phi_0 , type lambda , type phi) {
00288 variable degree
00289 set cos_phi_s [expr {cos($phi_1 * $degree)}]
00290 set lambda [expr {$lambda - $lambda_0 + 180.}]
00291 if {$lambda < 0.0 || $lambda > 360.0} {
00292 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00293 }
00294 set lambda [expr {$lambda - 180.}]
00295 set x [expr {$lambda * $degree * $cos_phi_s}]
00296 set y0 [expr {sin($phi_0 * $degree) / $cos_phi_s}]
00297 set y [expr {sin($phi * $degree) / $cos_phi_s}]
00298 return [list $x [expr {$y - $y0}]]
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 ret ::mapproj::fromCylindricalEqualArea (type phi_1 , type lambda_0 , type phi_0 , type x , type y) {
00316 variable degree
00317 variable radian
00318 set cos_phi_s [expr {cos($phi_1 * $degree)}]
00319 set lambda [expr {$lambda_0 + $x / $cos_phi_s * $radian + 180.}]
00320 if {$lambda < 0.0 || $lambda > 360.0} {
00321 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00322 }
00323 set lambda [expr {$lambda - 180.}]
00324 set y0 [expr {sin($phi_0 * $degree) / $cos_phi_s}]
00325 set phi [expr {asin(($y + $y0) * $cos_phi_s) * $radian}]
00326 return [list $lambda $phi]
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 ret ::mapproj::toMercator (type lambda_0 , type phi_0 , type lambda , type phi) {
00345 variable trace; if {[info exists trace]} { puts [info level 0] }
00346 variable degree
00347 variable quarterpi
00348 set lambda [expr {$lambda - $lambda_0 + 180.}]
00349 if {$lambda < 0.0 || $lambda > 360.0} {
00350 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00351 }
00352 set lambda [expr {$lambda - 180.}]
00353 set x [expr {$lambda * $degree}]
00354 set y [expr {log(tan($quarterpi + 0.5 * $phi * $degree))}]
00355 set y0 [expr {log(tan($quarterpi + 0.5 * $phi_0 * $degree))}]
00356 if {[info exists trace]} { puts "[info level 0] -> $x [expr {$y - $y0}]" }
00357 return [list $x [expr {$y - $y0}]]
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 ret ::mapproj::fromMercator (type lambda_0 , type phi_0 , type x , type y) {
00373 variable quarterpi
00374 variable degree
00375 variable radian
00376 set y0 [expr {log(tan($quarterpi + 0.5 * $phi_0 * $degree))}]
00377 set lambda [expr {$lambda_0 + $x * $radian + 180.}]
00378 if {$lambda < 0.0 || $lambda > 360.0} {
00379 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00380 }
00381 set lambda [expr {$lambda - 180.}]
00382 set phi [expr {$radian * 2.0 * atan(exp($y + $y0)) - 90.0}]
00383 return [list $lambda $phi]
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 ret ::mapproj::toMillerCylindrical (type lambda_0 , type lambda , type phi) {
00401 foreach {x y} [toMercator $lambda_0 0.0 \
00402 $lambda [expr {0.8 * $phi}]] break
00403 set y [expr {1.25 * $y}]
00404 return [list $x $y]
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 ret ::mapproj::fromMillerCylindrical (type lambda_0 , type x , type y) {
00420 foreach {lambda phi} [fromMercator $lambda_0 0.0 \
00421 $x [expr {0.8 * $y}]] break
00422 return [list $lambda [expr {1.25 * $phi}]]
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 ret ::mapproj::toSinusoidal (type lambda_0 , type phi_0 , type lambda , type phi) {
00441 variable degree
00442 variable quarterpi
00443 set lambda [expr {$lambda - $lambda_0 + 180.}]
00444 if {$lambda < 0.0 || $lambda > 360.0} {
00445 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00446 }
00447 set lambda [expr {($lambda - 180.) * $degree}]
00448 set phi [expr {$phi * $degree}]
00449 set x [expr {$lambda * cos($phi)}]
00450 set phi [expr {$phi - $phi_0 * $degree}]
00451 return [list $x $phi]
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 ret ::mapproj::fromSinusoidal (type lambda_0 , type phi_0 , type x , type y) {
00468 variable degree
00469 variable radian
00470 set y [expr {$y + $phi_0 * $degree}]
00471 set phi [expr {$y * $radian}]
00472 set lambda [expr {180. + $lambda_0 + $radian * $x / cos($y)}]
00473 if {$lambda < 0.0 || $lambda > 360.0} {
00474 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00475 }
00476 set lambda [expr {$lambda - 180.}]
00477 return [list $lambda $phi]
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 ret ::mapproj::toMollweide (type lambda_0 , type lambda , type phi) {
00495 variable degree
00496 variable pi
00497 variable halfpi
00498 variable sqrt2
00499 variable sqrt8
00500 set lambda [expr {$lambda - $lambda_0 + 180.}]
00501 if {$lambda < 0.0 || $lambda > 360.0} {
00502 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00503 }
00504 set lambda [expr {($lambda - 180.) * $degree}]
00505 set phi [expr {$phi * $degree}]
00506 set theta [expr {2.0 * asin(2.0 * $phi / $pi)}]
00507 set diff 1.0
00508 set pisinphi [expr {$pi * sin($phi)}]
00509 while {abs($diff) >= 1.0e-4} {
00510 set diff [expr {($theta + sin($theta) - $pisinphi)
00511 / (1.0 + cos($theta))}]
00512 set theta [expr {$theta - $diff}]
00513 }
00514 set theta [expr {0.5 * $theta}]
00515 set x [expr {$sqrt8 * $lambda * cos($theta) / $pi}]
00516 set y [expr {$sqrt2 * sin($theta)}]
00517 return [list $x $y]
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 ret ::mapproj::fromMollweide (type lambda_0 , type x , type y) {
00533 variable pi
00534 variable radian
00535 variable degree
00536 variable halfpi
00537 variable sqrt2
00538 variable sqrt8
00539 set theta [expr {asin($y / $sqrt2)}]
00540 set lambda [expr {$lambda_0 + $radian * $pi * $x /
00541 ($sqrt8 * cos($theta)) + 180.}]
00542 set phi [expr {asin((2.0 * $theta + sin(2.0 * $theta)) / $pi)}]
00543 if {$lambda < 0.0 || $lambda > 360.0} {
00544 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00545 }
00546 set lambda [expr {$lambda - 180.}]
00547 return [list $lambda [expr {$phi * $radian}]]
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 ret ::mapproj::toEckertIV (type lambda_0 , type lambda , type phi) {
00565 variable degree
00566 variable pi
00567 variable halfpi
00568 variable EckertIVK1
00569 variable EckertIVK2
00570 set lambda [expr {$lambda - $lambda_0 + 180.}]
00571 if {$lambda < 0.0 || $lambda > 360.0} {
00572 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00573 }
00574 set lambda [expr {($lambda - 180.) * $degree}]
00575 set phi [expr {$phi * $degree}]
00576 set theta [expr {$phi / 2}]
00577 set diff 1.0
00578 set A [expr {(2.0 + $halfpi) * sin($phi)}]
00579 while {abs($diff) >= 1.0e-4} {
00580 set costheta [expr {cos($theta)}]
00581 set sintheta [expr {sin($theta)}]
00582 set diff \
00583 [expr {($theta + $sintheta * $costheta + 2.0 * sin($theta) - $A)
00584 / (2.0 * $costheta * (1.0 + $costheta))}]
00585 set theta [expr {$theta - $diff}]
00586 }
00587 set x [expr {$EckertIVK1 * $lambda * (1.0 + cos($theta))}]
00588 set y [expr {$EckertIVK2 * sin($theta)}]
00589 return [list $x $y]
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 ret ::mapproj::fromEckertIV (type lambda_0 , type x , type y) {
00605 variable pi
00606 variable radian
00607 variable degree
00608 variable halfpi
00609 variable sqrt2
00610 variable EckertIVK1
00611 variable EckertIVK2
00612 set sintheta [expr {$y / $EckertIVK2}]
00613 set costheta [expr {sqrt(1.0 - $sintheta * $sintheta)}]
00614 set theta [expr {atan2($sintheta, $costheta)}]
00615 set phi [expr {asin(($theta + $sintheta*$costheta + 2.*$sintheta)
00616 / (2. + $halfpi))}]
00617 set lambda [expr {180.0 + $lambda_0
00618 + $radian / $EckertIVK1 * $x / (1.0 + $costheta)}]
00619 if {$lambda < 0.0 || $lambda > 360.0} {
00620 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00621 }
00622 set lambda [expr {$lambda - 180.}]
00623 return [list $lambda [expr {$phi * $radian}]]
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 ret ::mapproj::toEckertVI (type lambda_0 , type lambda , type phi) {
00641 variable degree
00642 variable pi
00643 variable halfpi
00644 variable EckertVIK1
00645 set lambda [expr {$lambda - $lambda_0 + 180.}]
00646 if {$lambda < 0.0 || $lambda > 360.0} {
00647 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00648 }
00649 set lambda [expr {($lambda - 180.) * $degree}]
00650 set phi [expr {$phi * $degree}]
00651 set theta [expr {$phi / 2}]
00652 set diff 1.0
00653 set A [expr {(1.0 + $halfpi) * sin($phi)}]
00654 while {abs($diff) >= 1.0e-4} {
00655 set costheta [expr {cos($theta)}]
00656 set sintheta [expr {sin($theta)}]
00657 set diff \
00658 [expr {($theta + $sintheta - $A)
00659 / (1.0 + $costheta)}]
00660 set theta [expr {$theta - $diff}]
00661 }
00662 set x [expr {$lambda * (1.0 + cos($theta)) / $EckertVIK1}]
00663 set y [expr {2.0 * $theta / $EckertVIK1}]
00664 return [list $x $y]
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 ret ::mapproj::fromEckertVI (type lambda_0 , type x , type y) {
00680 variable pi
00681 variable radian
00682 variable degree
00683 variable halfpi
00684 variable sqrt2
00685 variable EckertVIK1
00686 puts [info level 0]
00687 set theta [expr {0.5 * $EckertVIK1 * $y}]
00688 puts [list theta = $theta]
00689 set phi [expr {asin(($theta + sin($theta)) / (1.0 + $halfpi))}]
00690 puts [list phi = $phi]
00691 set lambda [expr {180.0 + $lambda_0 + $radian * $EckertVIK1 * $x
00692 / (1 + cos($theta))}]
00693 if {$lambda < 0.0 || $lambda > 360.0} {
00694 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00695 }
00696 set lambda [expr {$lambda - 180.}]
00697 return [list $lambda [expr {$phi * $radian}]]
00698 }
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 ret ::mapproj::toRobinson (type lambda_0 , type lambda , type phi) {
00714 variable RobinsonLatitude
00715 variable RobinsonSplinePLEN
00716 variable RobinsonSplinePDFE
00717 variable RobinsonM
00718 variable pi
00719 variable degree
00720 set lambda [expr {$lambda - $lambda_0 + 180.}]
00721 if {$lambda < 0.0 || $lambda > 360.0} {
00722 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00723 }
00724 set lambda [expr {$lambda - 180.}]
00725 set y [math::interpolate::interp-cubic-splines $RobinsonSplinePDFE $phi]
00726 set y [expr {$RobinsonM * $y}]
00727 set s [math::interpolate::interp-cubic-splines $RobinsonSplinePLEN $phi]
00728 set x [expr {$degree * $s * $lambda}]
00729 return [list $x $y]
00730 }
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 ret ::mapproj::fromRobinson (type lambda_0 , type x , type y) {
00745 variable RobinsonLatitude
00746 variable RobinsonPDFE
00747 variable RobinsonSplinePLEN
00748 variable RobinsonSplinePDFE
00749 variable RobinsonM
00750 variable radian
00751
00752 # We know that Robinson latitudes are equally spaced from [-90..90]
00753 # at 5-degree intervals. Find the values for RobinsonPDFE that
00754 # bracket the y co-ordinate.
00755
00756 set y [expr {$y / $RobinsonM}]
00757 set l 0
00758 set u [expr {[llength $RobinsonPDFE] - 1}]
00759 while {$l < $u} {
00760 set m [expr {($l + $u + 1) / 2}]
00761 if {$y >= [lindex $RobinsonPDFE $m]} {
00762 set l $m
00763 } else {
00764 set u [expr {$m - 1}]
00765 }
00766 }
00767 set u [lindex $RobinsonLatitude [expr {$l+1}]]
00768 set l [lindex $RobinsonLatitude $l]
00769 for {set i 0} {$i < 12} {incr i} {
00770 set m [expr {0.5 * ($u + $l)}]
00771 set ystar [math::interpolate::interp-cubic-splines \
00772 $RobinsonSplinePDFE $m]
00773 if {$ystar < $y} {
00774 set l $m
00775 } else {
00776 set u $m
00777 }
00778 }
00779 puts "latitude $m"
00780 set s [math::interpolate::interp-cubic-splines $RobinsonSplinePLEN $m]
00781 puts "parallel length $s"
00782 set lambda [expr {180.0 + $lambda_0 + $radian * $x / $s}]
00783 if {$lambda < 0.0 || $lambda > 360.0} {
00784 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00785 }
00786 set lambda [expr {$lambda - 180.}]
00787 return [list $lambda $m]
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 ret ::mapproj::toCassini (type lambda_0 , type phi_0 , type lambda , type phi) {
00805 variable degree
00806 variable pi
00807 variable twopi
00808 variable quarterpi
00809 set lambda [expr {$lambda - $lambda_0 + 180.}]
00810 if {$lambda < 0.0 || $lambda > 360.0} {
00811 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00812 }
00813 set lambda [expr {($lambda - 180.) * $degree}]
00814 set phi [expr {$phi * $degree}]
00815 set x [expr {asin(cos($phi) * sin($lambda))}]
00816 set y [expr {atan2(tan($phi), cos($lambda)) - $degree * $phi_0}]
00817 if {$y < -$pi} {
00818 set y [expr {$y + $twopi}]
00819 } elseif {$y > $pi} {
00820 set y [expr {$y - $twopi}]
00821 }
00822 return [list $x $y]
00823 }
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 ret ::mapproj::fromCassini (type lambda_0 , type phi_0 , type x , type y) {
00838 variable degree
00839 variable radian
00840 set y [expr {$y + $degree * $phi_0}]
00841 set phi [expr {$radian * asin(cos($x) * sin($y))}]
00842 set lambda [expr {180. + $lambda_0 + $radian * atan2(tan($x), cos($y))}]
00843 if {$lambda < 0.0 || $lambda > 360.0} {
00844 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00845 }
00846 set lambda [expr {$lambda - 180.}]
00847 return [list $lambda $phi]
00848 }
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862 ret ::mapproj::toPeirceQuincuncial (type lambda_0 , type lambda , type phi) {
00863 variable degree
00864 variable halfSqrt2
00865 variable pi
00866 variable quarterpi
00867 variable mquarterpi
00868 variable threequarterpi
00869 variable mthreequarterpi
00870 variable PeirceQuincuncialScale
00871
00872 # Convert latitude and longitude to radians relative to the
00873 # central meridian
00874
00875 set lambda [expr {$lambda - $lambda_0 + 180.}]
00876 if {$lambda < 0.0 || $lambda > 360.0} {
00877 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
00878 }
00879 set lambda [expr {($lambda - 180.) * $degree}]
00880 set phi [expr {$phi * $degree}]
00881
00882 # Compute the auxiliary quantities 'm' and 'n'. Set 'm' to match
00883 # the sign of 'lambda' and 'n' to be positive if |lambda| > pi/2
00884
00885 set cos_phiosqrt2 [expr {$halfSqrt2 * cos($phi)}]
00886 set cos_lambda [expr {cos($lambda)}]
00887 set sin_lambda [expr {sin($lambda)}]
00888 set cos_a [expr {$cos_phiosqrt2 * ($sin_lambda + $cos_lambda)}]
00889 set cos_b [expr {$cos_phiosqrt2 * ($sin_lambda - $cos_lambda)}]
00890 set sin_a [expr {sqrt(1.0 - $cos_a * $cos_a)}]
00891 set sin_b [expr {sqrt(1.0 - $cos_b * $cos_b)}]
00892 set cos_a_cos_b [expr {$cos_a * $cos_b}]
00893 set sin_a_sin_b [expr {$sin_a * $sin_b}]
00894 set sin2_m [expr {1.0 + $cos_a_cos_b - $sin_a_sin_b}]
00895 set sin2_n [expr {1.0 - $cos_a_cos_b - $sin_a_sin_b}]
00896 if {$sin2_m < 0.0} {set sin2_m 0.0}
00897 set sin_m [expr {sqrt($sin2_m)}]
00898 if {$sin2_m > 1.0} { set sin2_m 1.0 }
00899 set cos_m [expr {sqrt(1.0 - $sin2_m)}]
00900 if {$sin_lambda < 0.0} {
00901 set sin_m [expr {-$sin_m}]
00902 }
00903 if {$sin2_n < 0.0} { set sin2_n 0.0 }
00904 set sin_n [expr {sqrt($sin2_n)}]
00905 if {$sin2_n > 1.0} { set sin2_n 1.0 }
00906 set cos_n [expr {sqrt(1.0 - $sin2_n)}]
00907 if {$cos_lambda > 0.0} {
00908 set sin_n [expr {-$sin_n}]
00909 }
00910
00911 # Compute elliptic integrals to map the disc to the square
00912
00913 set x [ellFaux $cos_m $sin_m $halfSqrt2]
00914 set y [ellFaux $cos_n $sin_n $halfSqrt2]
00915
00916 # Reflect the Southern Hemisphere outward
00917
00918 if {$phi < 0} {
00919 if {$lambda < $mthreequarterpi} {
00920 set y [expr {$PeirceQuincuncialScale - $y}]
00921 } elseif {$lambda < $mquarterpi} {
00922 set x [expr {-$PeirceQuincuncialScale - $x}]
00923 } elseif {$lambda < $quarterpi} {
00924 set y [expr {-$PeirceQuincuncialScale - $y}]
00925 } elseif {$lambda < $threequarterpi} {
00926 set x [expr {$PeirceQuincuncialScale - $x}]
00927 } else {
00928 set y [expr {$PeirceQuincuncialScale - $y}]
00929 }
00930 }
00931
00932 # Rotate the square by 45 degrees to fit the screen better
00933
00934 set X [expr {($x - $y) * $halfSqrt2}]
00935 set Y [expr {($x + $y) * $halfSqrt2}]
00936
00937 return [list $X $Y]
00938 }
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951 ret ::mapproj::fromPeirceQuincuncial (type lambda_0 , type x , type y) {
00952 variable halfSqrt2
00953 variable radian
00954 variable pi
00955 variable halfpi
00956 variable quarterpi
00957 variable PeirceQuincuncialScale
00958 variable PeirceQuincuncialLimit
00959
00960 # Rotate x and y 45 degrees
00961
00962 set X [expr {($x + $y) * $halfSqrt2}]
00963 set Y [expr {($y - $x) * $halfSqrt2}]
00964
00965 # Reflect Southern Hemisphere into the Northern
00966
00967 set southern 0
00968 if {$X < -$PeirceQuincuncialLimit} {
00969 set X [expr {-$PeirceQuincuncialScale - $X}]
00970 set southern 1
00971 } elseif {$X > $PeirceQuincuncialLimit} {
00972 set X [expr {$PeirceQuincuncialScale - $X}]
00973 set southern 1
00974 } elseif {$Y < -$PeirceQuincuncialLimit} {
00975 set Y [expr {-$PeirceQuincuncialScale - $Y}]
00976 set southern 1
00977 } elseif {$Y > $PeirceQuincuncialLimit} {
00978 set Y [expr {$PeirceQuincuncialScale - $Y}]
00979 set southern 1
00980 }
00981
00982 # Now we know that latitude will be positive. If X is negative, then
00983 # longitude will be negative; reflect the Western Hemisphere into the
00984 # Eastern.
00985
00986 set western 0
00987 if {$X < 0.0} {
00988 set western 1
00989 set X [expr {-$X}]
00990 }
00991
00992 # If Y is positive, the point is in the back hemisphere. Reflect
00993 # it to the front.
00994
00995 set back 0
00996 if {$Y > 0.0} {
00997 set back 1
00998 set Y [expr {-$Y}]
00999 }
01000
01001 # Finally, constrain longitude to be less than pi/4, by reflecting across
01002 # the 45 degree meridian.
01003
01004 set complement 0
01005 if {$X > -$Y} {
01006 set complement 1
01007 set t [expr {-$X}]
01008 set X [expr {-$Y}]
01009 set Y $t
01010 }
01011
01012 # Compute the elliptic functions to map the plane onto the sphere
01013
01014 set cnx [cn $X $halfSqrt2]
01015 set cny [cn $Y $halfSqrt2]
01016
01017 # Undo the mapping to latitude and longitude
01018
01019 set a1 [expr {acos(-$cnx * $cnx)}]
01020 set a2 [expr {acos($cny * $cny)}]
01021 set b [expr {0.5 * ($a1 + $a2)}]
01022 set a [expr {0.5 * ($a1 - $a2)}]
01023 set cos_a [expr {cos($a)}]
01024 set cos_b [expr {-cos($b)}]
01025 set lambda [expr {$quarterpi - atan2($cos_b, $cos_a)}]
01026 set phi [expr {acos(hypot($cos_b, $cos_a))}]
01027
01028 # Undo the reflections that were done above, to get correct latitude
01029 # and longitude
01030
01031 if {$complement} {
01032 set lambda [expr {$halfpi - $lambda}]
01033 }
01034 if {$back} {
01035 set lambda [expr {$pi - $lambda}]
01036 }
01037 if {$western} {
01038 set lambda [expr {-$lambda}]
01039 }
01040 if {$southern} {
01041 set phi [expr {-$phi}]
01042 }
01043
01044 # Convert latitude and longitude to degrees
01045
01046 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01047 if {$lambda < 0.0 || $lambda > 360.0} {
01048 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01049 }
01050 set lambda [expr {$lambda - 180.}]
01051 set phi [expr {$phi * $radian}]
01052
01053 return [list $lambda $phi]
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 ret ::mapproj::RotateCartesianY (type phi , type x , type y , type z) {
01068 variable degree
01069 set phi [expr {$degree * $phi}]
01070 set cos_phi [expr {cos($phi)}]
01071 set sin_phi [expr {sin($phi)}]
01072 return [list [expr {$x * $cos_phi - $z * $sin_phi}] \
01073 $y \
01074 [expr {$z * $cos_phi + $x * $sin_phi}]]
01075 }
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 ret ::mapproj::ToCartesian (type lambda , type phi) {
01095 variable degree
01096 set lambda [expr {$degree * $lambda}]
01097 set phi [expr {$degree * $phi}]
01098 set cos_phi [expr cos($phi)]
01099 return [list [expr {$cos_phi * cos($lambda)}] \
01100 [expr {$cos_phi * sin($lambda)}] \
01101 [expr {sin($phi)}]]
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118 ret ::mapproj::CartesianToRangeAndBearing (type x , type y , type z) {
01119 set c [expr {hypot($z, $y)}]
01120 if {$c == 0} {
01121 set cos_b 1.0
01122 set sin_b 0.0
01123 } else {
01124 set cos_b [expr {$y / $c}]
01125 set sin_b [expr {$z / $c}]
01126 }
01127 set range [expr {atan2($c, $x)}]
01128 return [list $cos_b $sin_b $range]
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143 ret ::mapproj::RangeAndBearingToCartesian (type cos_, type b , type sin_, type b , type range) {
01144 set c [expr {sin($range)}]
01145 set x [expr {cos($range)}]
01146 set y [expr {$cos_b * $c}]
01147 set z [expr {$sin_b * $c}]
01148 return [list $x $y $z]
01149 }
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164 ret ::mapproj::CartesianToSpherical (type x , type y , type z) {
01165 return [list [expr {atan2($y, $x)}] [expr {atan2($z, hypot($y, $x))}]]
01166 }
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183 ret ::mapproj::toOrthographic (type lambda_0 , type phi_0 , type lambda , type phi) {
01184 foreach {x y z} [ToCartesian [expr {$lambda-$lambda_0}] $phi] \
01185 break
01186 foreach {x y z} [RotateCartesianY [expr {-$phi_0}] $x $y $z] \
01187 break
01188 if {$x < 0} {
01189 return {}
01190 } else {
01191 return [list $y $z]
01192 }
01193 }
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209 ret ::mapproj::fromOrthographic (type lambda_0 , type phi_0 , type x , type y) {
01210 variable radian
01211 set r [expr {hypot($x, $y)}]
01212 set alpha [expr {asin($r)}]
01213 set z [expr {sqrt(1.0 - $r*$r)}]
01214 foreach {x y z} [RotateCartesianY $phi_0 $z $x $y] break
01215 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01216
01217 # Convert latitude and longitude to degrees
01218
01219 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01220 if {$lambda < 0.0 || $lambda > 360.0} {
01221 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01222 }
01223 set lambda [expr {$lambda - 180.}]
01224 set phi [expr {$phi * $radian}]
01225
01226 return [list $lambda $phi]
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244 ret ::mapproj::toStereographic (type lambda_0 , type phi_0 , type lambda , type phi) {
01245 foreach {x y z} [ToCartesian [expr {$lambda-$lambda_0}] $phi] \
01246 break
01247 foreach {x y z} [RotateCartesianY [expr {-$phi_0}] $x $y $z] \
01248 break
01249 if {$x < -0.5} {
01250 return {}
01251 } else {
01252 set y [expr {2. * $y / (1. + $x)}]
01253 set z [expr {2. * $z / (1. + $x)}]
01254 return [list $y $z]
01255 }
01256 }
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272 ret ::mapproj::fromStereographic (type lambda_0 , type phi_0 , type x , type y) {
01273 variable radian
01274 variable halfpi
01275 set denom [expr {4.0 + $x*$x + $y*$y}]
01276 foreach {x y z} [list \
01277 [expr {(4.0 - $x*$x - $y*$y) / $denom}] \
01278 [expr {4. * $x / $denom}] \
01279 [expr {4. * $y / $denom}]] break
01280
01281 foreach {x y z} [RotateCartesianY $phi_0 $x $y $z] break
01282 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01283
01284 # Convert latitude and longitude to degrees
01285
01286 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01287 if {$lambda < 0.0 || $lambda > 360.0} {
01288 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01289 }
01290 set lambda [expr {$lambda - 180.}]
01291 set phi [expr {$phi * $radian}]
01292
01293 return [list $lambda $phi]
01294 }
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311 ret ::mapproj::toGnomonic (type lambda_0 , type phi_0 , type lambda , type phi) {
01312 foreach {x y z} [ToCartesian [expr {$lambda-$lambda_0}] $phi] \
01313 break
01314 foreach {x y z} [RotateCartesianY [expr {-$phi_0}] $x $y $z] \
01315 break
01316 if {$x < 0.01} {
01317 return {}
01318 } else {
01319 set y [expr {$y / $x}]
01320 set z [expr {$z / $x}]
01321 return [list $y $z]
01322 }
01323 }
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339 ret ::mapproj::fromGnomonic (type lambda_0 , type phi_0 , type x , type y) {
01340 variable radian
01341 variable halfpi
01342 set denom [expr {hypot(1.0, hypot($x, $y))}]
01343 foreach {x y z} [list \
01344 [expr {1.0 / $denom}] \
01345 [expr {$x / $denom}] \
01346 [expr {$y / $denom}]] break
01347
01348 foreach {x y z} [RotateCartesianY $phi_0 $x $y $z] break
01349 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01350
01351 # Convert latitude and longitude to degrees
01352
01353 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01354 if {$lambda < 0.0 || $lambda > 360.0} {
01355 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01356 }
01357 set lambda [expr {$lambda - 180.}]
01358 set phi [expr {$phi * $radian}]
01359
01360 return [list $lambda $phi]
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378 ret ::mapproj::toAzimuthalEquidistant (type lambda_0 , type phi_0 , type lambda , type phi) {
01379 foreach {x y z} [ToCartesian [expr {$lambda-$lambda_0}] $phi] \
01380 break
01381 foreach {x y z} [RotateCartesianY [expr {-$phi_0}] $x $y $z] \
01382 break
01383 foreach {cs sn range} [CartesianToRangeAndBearing $x $y $z] break
01384 return [list [expr {$cs * $range}] [expr {$sn * $range}]]
01385 }
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 ret ::mapproj::fromAzimuthalEquidistant (type lambda_0 , type phi_0 , type x , type y) {
01402 variable radian
01403 variable halfpi
01404
01405 set range [expr {hypot($y, $x)}]
01406 set cos_b [expr {$x / $range}]
01407 set sin_b [expr {$y / $range}]
01408 foreach {x y z} [RangeAndBearingToCartesian $cos_b $sin_b $range] break
01409 foreach {x y z} [RotateCartesianY $phi_0 $x $y $z] break
01410 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01411
01412 # Convert latitude and longitude to degrees
01413
01414 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01415 if {$lambda < 0.0 || $lambda > 360.0} {
01416 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01417 }
01418 set lambda [expr {$lambda - 180.}]
01419 set phi [expr {$phi * $radian}]
01420
01421 return [list $lambda $phi]
01422 }
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439 ret ::mapproj::toLambertAzimuthalEqualArea (type lambda_0 , type phi_0 , type lambda , type phi) {
01440 foreach {x y z} [ToCartesian [expr {$lambda-$lambda_0}] $phi] \
01441 break
01442 foreach {x y z} [RotateCartesianY [expr {-$phi_0}] $x $y $z] \
01443 break
01444 foreach {cs sn range} [CartesianToRangeAndBearing $x $y $z] break
01445 set range [expr {2.0 * sin(0.5 * $range)}]
01446 return [list [expr {$cs * $range}] [expr {$sn * $range}]]
01447 }
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463 ret ::mapproj::fromLambertAzimuthalEqualArea (type lambda_0 , type phi_0 , type x , type y) {
01464 variable radian
01465 variable halfpi
01466
01467 set range [expr {hypot($y, $x)}]
01468 set cos_b [expr {$x / $range}]
01469 set sin_b [expr {$y / $range}]
01470 set range [expr {2.0 * asin(0.5 * $range)}]
01471 foreach {x y z} [RangeAndBearingToCartesian $cos_b $sin_b $range] break
01472 foreach {x y z} [RotateCartesianY $phi_0 $x $y $z] break
01473 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01474
01475 # Convert latitude and longitude to degrees
01476
01477 set lambda [expr {$lambda * $radian + 180. + $lambda_0}]
01478 if {$lambda < 0.0 || $lambda > 360.0} {
01479 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01480 }
01481 set lambda [expr {$lambda - 180.}]
01482 set phi [expr {$phi * $radian}]
01483
01484 return [list $lambda $phi]
01485 }
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502 ret ::mapproj::toHammer (type lambda_0 , type lambda , type phi) {
01503 set lambda [expr {$lambda - $lambda_0 + 180.}]
01504 if {$lambda < 0.0 || $lambda > 360.0} {
01505 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01506 }
01507 set lambda [expr {$lambda - 180.0}]
01508 foreach {x y z} [ToCartesian [expr {$lambda/2.}] $phi] \
01509 break
01510 foreach {cs sn range} [CartesianToRangeAndBearing $x $y $z] break
01511 set range [expr {2.0 * sin(0.5 * $range)}]
01512 return [list [expr {2.0 * $cs * $range}] [expr {$sn * $range}]]
01513 }
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529 ret ::mapproj::fromHammer (type lambda_0 , type x , type y) {
01530 variable radian
01531 variable halfpi
01532
01533 set x [expr {0.5 * $x}]
01534 set range [expr {hypot($y, $x)}]
01535 set cos_b [expr {$x / $range}]
01536 set sin_b [expr {$y / $range}]
01537 set range [expr {2.0 * asin(0.5 * $range)}]
01538 foreach {x y z} [RangeAndBearingToCartesian $cos_b $sin_b $range] break
01539 foreach {lambda phi} [CartesianToSpherical $x $y $z] break
01540
01541 # Convert latitude and longitude to degrees
01542
01543 set lambda [expr {2.0 * $lambda * $radian + 180. + $lambda_0}]
01544 if {$lambda < 0.0 || $lambda > 360.0} {
01545 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01546 }
01547 set lambda [expr {$lambda - 180.}]
01548 set phi [expr {$phi * $radian}]
01549
01550 return [list $lambda $phi]
01551 }
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567 ret ::mapproj::toConicEquidistant (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type lambda , type phi) {
01568 variable degree
01569 set phi_0 [expr {$phi_0 * $degree}]
01570 set phi_1 [expr {$phi_1 * $degree}]
01571 set phi_2 [expr {$phi_2 * $degree}]
01572 set lambda [expr {$lambda - $lambda_0 + 180.}]
01573 if {$lambda < 0.0 || $lambda > 360.0} {
01574 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01575 }
01576 set lambda [expr {($lambda - 180.0) * $degree}]
01577 set phi [expr {$phi * $degree}]
01578 set cos_phi_1 [expr {cos($phi_1)}]
01579 set n [expr {($cos_phi_1 - cos($phi_2)) / ($phi_2 - $phi_1)}]
01580 set G [expr {$cos_phi_1 / $n + $phi_1}]
01581 set rho_0 [expr {$G - $phi_0}]
01582 set theta [expr {$n * $lambda}]
01583 set rho [expr {$G - $phi}]
01584 set x [expr {$rho * sin($theta)}]
01585 set y [expr {$rho_0 - $rho * cos($theta)}]
01586 return [list $x $y]
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603 ret ::mapproj::fromConicEquidistant (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type x , type y) {
01604 variable degree
01605 variable radian
01606 set phi_0 [expr {$phi_0 * $degree}]
01607 set phi_1 [expr {$phi_1 * $degree}]
01608 set phi_2 [expr {$phi_2 * $degree}]
01609 set cos_phi_1 [expr {cos($phi_1)}]
01610 set n [expr {($cos_phi_1 - cos($phi_2)) / ($phi_2 - $phi_1)}]
01611 set G [expr {$cos_phi_1 / $n + $phi_1}]
01612 set rho_0 [expr {$G - $phi_0}]
01613 set rho_0my [expr {$rho_0 - $y}]
01614 set theta [expr {atan2($x, $rho_0my)}]
01615 set rho [expr {sqrt($x*$x + $rho_0my * $rho_0my)}]
01616 if {$n < 0.0} {set rho [expr {-$rho}]}
01617 set phi [expr {($G - $rho) * $radian}]
01618 set lambda [expr {($theta / $n * $radian) + $lambda_0 + 180.}]
01619 if {$lambda < 0.0 || $lambda > 360.0} {
01620 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01621 }
01622 set lambda [expr {$lambda - 180.}]
01623 return [list $lambda $phi]
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640 ret ::mapproj::toAlbersEqualAreaConic (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type lambda , type phi) {
01641 variable degree
01642 set phi_0 [expr {$phi_0 * $degree}]
01643 set phi_1 [expr {$phi_1 * $degree}]
01644 set phi_2 [expr {$phi_2 * $degree}]
01645 set lambda [expr {$lambda - $lambda_0 + 180.}]
01646 if {$lambda < 0.0 || $lambda > 360.0} {
01647 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01648 }
01649 set lambda [expr {($lambda - 180.0) * $degree}]
01650 set phi [expr {$phi * $degree}]
01651 set cos_phi_1 [expr {cos($phi_1)}]
01652 set sin_phi_1 [expr {sin($phi_1)}]
01653 set n [expr {0.5 * ($sin_phi_1 + sin($phi_2))}]
01654 set theta [expr {$n * $lambda}]
01655 set C [expr {$cos_phi_1 * $cos_phi_1 + 2.0 * $n * $sin_phi_1}]
01656 set rho [expr {sqrt($C - 2.0 * $n * sin($phi)) / $n}]
01657 set rho_0 [expr {sqrt($C - 2.0 * $n * sin($phi_0)) / $n}]
01658 set x [expr {$rho * sin($theta)}]
01659 set y [expr {$rho_0 - $rho * cos($theta)}]
01660 return [list $x $y]
01661 }
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 ret ::mapproj::fromAlbersEqualAreaConic (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type x , type y) {
01678 variable degree
01679 variable radian
01680 variable twopi
01681 set phi_0 [expr {$phi_0 * $degree}]
01682 set phi_1 [expr {$phi_1 * $degree}]
01683 set phi_2 [expr {$phi_2 * $degree}]
01684 set cos_phi_1 [expr {cos($phi_1)}]
01685 set sin_phi_1 [expr {sin($phi_1)}]
01686 set n [expr {0.5 * ($sin_phi_1 + sin($phi_2))}]
01687 set C [expr {$cos_phi_1 * $cos_phi_1 + 2.0 * $n * $sin_phi_1}]
01688 set rho_0 [expr {sqrt($C - 2.0 * $n * sin($phi_0)) / $n}]
01689 set theta [expr {atan2($x, $rho_0 - $y)}]
01690 set rho [expr {hypot($x, $rho_0 - $y)}]
01691 set phi [expr {$radian * asin(($C - $rho*$rho*$n*$n) / (2.0 * $n))}]
01692 set lambda [expr {($theta / $n * $radian) + $lambda_0 + 180.}]
01693 if {$lambda < 0.0 || $lambda > 360.0} {
01694 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01695 }
01696 set lambda [expr {$lambda - 180.}]
01697 return [list $lambda $phi]
01698 }
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 ret ::mapproj::toLambertConformalConic (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type lambda , type phi) {
01715 variable degree
01716 variable quarterpi
01717 set phi_0 [expr {$phi_0 * $degree}]
01718 set phi_1 [expr {$phi_1 * $degree}]
01719 set phi_2 [expr {$phi_2 * $degree}]
01720 set lambda [expr {$lambda - $lambda_0 + 180.}]
01721 if {$lambda < 0.0 || $lambda > 360.0} {
01722 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01723 }
01724 set lambda [expr {($lambda - 180.0) * $degree}]
01725 set phi [expr {$phi * $degree}]
01726 set cos_phi_1 [expr {cos($phi_1)}]
01727 set sin_phi_1 [expr {sin($phi_1)}]
01728 set tan1 [expr {tan($quarterpi + 0.5 * $phi_1)}]
01729 set n [expr {log($cos_phi_1 / cos($phi_2))
01730 / log(tan($quarterpi + 0.5 * $phi_2) / $tan1)}]
01731 set F [expr {$cos_phi_1 * pow($tan1, $n) / $n}]
01732 set rho [expr {$F * pow(tan($quarterpi + 0.5 * $phi), -$n)}]
01733 set rho_0 [expr {$F * pow(tan($quarterpi + 0.5 * $phi_0), -$n)}]
01734 set x [expr {$rho * sin($n * $lambda)}]
01735 set y [expr {$rho_0 - $rho * cos($n * $lambda)}]
01736 return [list $x $y]
01737 }
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753 ret ::mapproj::fromLambertConformalConic (type lambda_0 , type phi_0 , type phi_1 , type phi_2 , type x , type y) {
01754 variable degree
01755 variable radian
01756 variable quarterpi
01757 set phi_0 [expr {$phi_0 * $degree}]
01758 set phi_1 [expr {$phi_1 * $degree}]
01759 set phi_2 [expr {$phi_2 * $degree}]
01760 set cos_phi_1 [expr {cos($phi_1)}]
01761 set sin_phi_1 [expr {sin($phi_1)}]
01762 set tan1 [expr {tan($quarterpi + 0.5 * $phi_1)}]
01763 set n [expr {log($cos_phi_1 / cos($phi_2))
01764 / log(tan($quarterpi + 0.5 * $phi_2) / $tan1)}]
01765 set F [expr {$cos_phi_1 * pow($tan1, $n) / $n}]
01766 set rho_0 [expr {$F * pow(tan($quarterpi + 0.5 * $phi_0), -$n)}]
01767 set y [expr {$rho_0 - $y}]
01768 set rho [expr {sqrt($x*$x + $y*$y)}]
01769 if {$n < 0} { set rho [expr {-$rho}] }
01770 set theta [expr {atan2($x, $y)}]
01771 set phi [expr {$radian * 2 * atan(pow($F / $rho, 1.0 / $n)) - 90.}]
01772 set lambda [expr {($theta / $n * $radian) + $lambda_0 + 180.}]
01773 if {$lambda < 0.0 || $lambda > 360.0} {
01774 set lambda [expr {$lambda - 360. * floor($lambda / 360.)}]
01775 }
01776 set lambda [expr {$lambda - 180.}]
01777 return [list $lambda $phi]
01778 }
01779
01780
01781
01782 ret ::mapproj::toLambertCylindricalEqualArea (type lambda_0 , type phi_0 , type lambda , type phi) {
01783 toCylindricalEqualArea 0.0 $lambda_0 $phi_0 $lambda $phi
01784 }
01785 ret ::mapproj::fromLambertCylindricalEqualArea (type lambda_0 , type phi_0 , type x , type y) {
01786 fromCylindricalEqualArea 0.0 $lambda_0 $phi_0 $x $y
01787 }
01788 ret ::mapproj::toBehrmann (type lambda_0 , type phi_0 , type lambda , type phi) {
01789 toCylindricalEqualArea 30.0 $lambda_0 $phi_0 $lambda $phi
01790 }
01791 ret ::mapproj::fromBehrmann (type lambda_0 , type phi_0 , type x , type y) {
01792 fromCylindricalEqualArea 30.0 $lambda_0 $phi_0 $x $y
01793 }
01794 ret ::mapproj::toTrystanEdwards (type lambda_0 , type phi_0 , type lambda , type phi) {
01795 toCylindricalEqualArea 37.4 $lambda_0 $phi_0 $lambda $phi
01796 }
01797 ret ::mapproj::fromTrystanEdwards (type lambda_0 , type phi_0 , type x , type y) {
01798 fromCylindricalEqualArea 37.4 $lambda_0 $phi_0 $x $y
01799 }
01800 ret ::mapproj::toHoboDyer (type lambda_0 , type phi_0 , type lambda , type phi) {
01801 toCylindricalEqualArea 37.5 $lambda_0 $phi_0 $lambda $phi
01802 }
01803 ret ::mapproj::fromHoboDyer (type lambda_0 , type phi_0 , type x , type y) {
01804 fromCylindricalEqualArea 37.5 $lambda_0 $phi_0 $x $y
01805 }
01806 ret ::mapproj::toGallPeters (type lambda_0 , type phi_0 , type lambda , type phi) {
01807 toCylindricalEqualArea 45.0 $lambda_0 $phi_0 $lambda $phi
01808 }
01809 ret ::mapproj::fromGallPeters (type lambda_0 , type phi_0 , type x , type y) {
01810 fromCylindricalEqualArea 45.0 $lambda_0 $phi_0 $x $y
01811 }
01812 ret ::mapproj::toBalthasart (type lambda_0 , type phi_0 , type lambda , type phi) {
01813 toCylindricalEqualArea 50.0 $lambda_0 $phi_0 $lambda $phi
01814 }
01815 ret ::mapproj::fromBalthasart (type lambda_0 , type phi_0 , type x , type y) {
01816 fromCylindricalEqualArea 50.0 $lambda_0 $phi_0 $x $y
01817 }
01818