|
| 1 | +#include <math.h> |
| 2 | +#include "mpblock.h" |
| 3 | + |
| 4 | +long double double_fac(int x) |
| 5 | +{ |
| 6 | + if (x == -3) |
| 7 | + return -1; |
| 8 | + else { |
| 9 | + long double y = 1; |
| 10 | + while (x > 0) { |
| 11 | + y *= x; |
| 12 | + x -= 2; |
| 13 | + } |
| 14 | + return y; |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +int isblock(struct Coordinates *vertex) |
| 19 | +{ |
| 20 | + int block = 1; |
| 21 | + block &= (vertex->lat == (vertex + 1)->lat && (vertex + 2)->lat == (vertex + 3)->lat && (vertex + 1)->lon == (vertex + 2)->lon && vertex->lon == (vertex + 3)->lon); |
| 22 | + block |= (vertex->lon == (vertex + 1)->lon && (vertex + 2)->lon == (vertex + 3)->lon && (vertex + 1)->lat == (vertex + 2)->lat && vertex->lat == (vertex + 3)->lat); |
| 23 | + return block; |
| 24 | +} |
| 25 | + |
| 26 | +int ispolariso(struct Coordinates *vertex) |
| 27 | +{ |
| 28 | + int k; |
| 29 | + for (k = 0; k < 3; k++) { |
| 30 | + if (fabsl((vertex + k)->lat) / RAD == 90 && (vertex + (k + 1) % 3)->lat == (vertex + (k + 2) % 3)->lat) |
| 31 | + break; |
| 32 | + } |
| 33 | + return k; |
| 34 | +} |
| 35 | + |
| 36 | +long double ellipblock(long double lat0, long double lat1, long double lon0, long double lon1) |
| 37 | +{ |
| 38 | + long double londiff = fabsl(normalise_c(lon1 - lon0)); |
| 39 | + long double latdiff = sinl(lat1) / (1.0l - ECC * sqr(sinl(lat1))) - sinl(lat0) / (1.0l - ECC * sqr(sinl(lat0))); |
| 40 | + latdiff += logl((1.0l + sqrtl(ECC) * sinl(lat1)) * (1.0l - sqrtl(ECC) * sinl(lat0)) / (1.0l - sqrtl(ECC) * sinl(lat1)) / (1.0l + sqrtl(ECC) * sinl(lat0))) / (2.0l * sqrtl(ECC)); |
| 41 | + |
| 42 | + return sqr(RAD_MIN) * londiff * latdiff / 2.0l; |
| 43 | +} |
| 44 | + |
| 45 | +long double parallel_length(long double lon0, long double lon1, long double lat) |
| 46 | +{ |
| 47 | + return cosl(lat) * fabsl(normalise_c(lon1 - lon0)) / sqrtl(1.0l - ECC * sqr(sinl(lat))); |
| 48 | +} |
| 49 | + |
| 50 | +long double meridian_arc(long double lat0, long double lat1) |
| 51 | +{ |
| 52 | + int k, j; |
| 53 | + long double c = 0, m = 0; |
| 54 | + |
| 55 | + for (j = 0; j < 11; j++) |
| 56 | + c += sqr(double_fac(2 * j - 3) / double_fac(2 * j)) * powl(FLAT_3, 2 * j); |
| 57 | + m += c * (lat1 - lat0); |
| 58 | + |
| 59 | + for (k = 1; k < 6; k++) { |
| 60 | + c = 0; |
| 61 | + for (j = 0; j < 11; j++) |
| 62 | + c += double_fac(2 * j - 3) / double_fac(2 * j) * double_fac(2 * j + 2 * k - 3) / double_fac(2 * j + 2 * k) * powl(FLAT_3, k + 2 * j); |
| 63 | + c /= k; |
| 64 | + m += powl(-1.0l, k) * c * (sin(2.0l * lat1) - sin(2.0l * lat0)); |
| 65 | + } |
| 66 | + |
| 67 | + return (RAD_MAJ + RAD_MIN) / 2 * m; |
| 68 | +} |
| 69 | + |
| 70 | +void mpblock(struct Coordinates *vertex, int i, long double s, long double a, long double *res) |
| 71 | +{ |
| 72 | + int h, k; |
| 73 | + |
| 74 | + if (i == 4 && isblock(vertex)) { |
| 75 | + long double lat[2], lon[2]; |
| 76 | + if (vertex->lat < (vertex + 2)->lat) { |
| 77 | + lat[0] = vertex->lat; |
| 78 | + lat[1] = (vertex + 2)->lat; |
| 79 | + } |
| 80 | + else { |
| 81 | + lat[0] = (vertex + 2)->lat; |
| 82 | + lat[1] = vertex->lat; |
| 83 | + } |
| 84 | + |
| 85 | + if (vertex->lon < (vertex + 2)->lon) { |
| 86 | + lon[0] = vertex->lon; |
| 87 | + lon[1] = (vertex + 2)->lon; |
| 88 | + } |
| 89 | + else { |
| 90 | + lon[0] = (vertex + 2)->lon; |
| 91 | + lon[1] = vertex->lon; |
| 92 | + } |
| 93 | + |
| 94 | + if (a == 1) |
| 95 | + *(res + 1) = ellipblock(lat[0], lat[1], lon[0], lon[1]); |
| 96 | + if (s == 1) { |
| 97 | + *res = parallel_length(lat[0], lat[1], lon[0]); |
| 98 | + *res += parallel_length(lat[0], lat[1], lon[1]); |
| 99 | + *res += meridian_arc(lat[0], lat[1]) * 2.0l; |
| 100 | + } |
| 101 | + } |
| 102 | + else if (i == 3 && (k = ispolariso(vertex)) < 3) { |
| 103 | + long double lon[2]; |
| 104 | + |
| 105 | + if ((vertex + k + 1)->lon < (vertex + ((k + 2) % 3))->lon) { |
| 106 | + lon[0] = (vertex + k + 1)->lon; |
| 107 | + lon[1] = (vertex + ((k + 2) % 3))->lon; |
| 108 | + } |
| 109 | + else { |
| 110 | + lon[1] = (vertex + k + 1)->lon; |
| 111 | + lon[0] = (vertex + ((k + 2) % 3))->lon; |
| 112 | + } |
| 113 | + |
| 114 | + if (a == 1) |
| 115 | + *(res + 1) = ellipblock((vertex + k + 1)->lat, (vertex + k)->lat, lon[0], lon[1]); |
| 116 | + if (s == 1) { |
| 117 | + *res = parallel_length(lon[0], lon[1], (vertex + k + 1)->lat); |
| 118 | + *res += meridian_arc((vertex + k + 1)->lat, (vertex + k)->lat) * 2.0l; |
| 119 | + } |
| 120 | + } |
| 121 | + else { |
| 122 | + *res = NAN; |
| 123 | + *(res + 1) = NAN; |
| 124 | + } |
| 125 | + return; |
| 126 | +} |
0 commit comments