|
|
1.1 root 1: #include "map.h"
2: #include <stdio.h>
3:
4: /* development of a loxodrome from a unit sphere onto a plane
5: the loxodrome passes through 0,0 on the sphere,
6: inclined a (alpha) from the equator
7:
8: latitude p (phi) positive north
9: longitude t (theta) positive east - opposite to "map"
10: all angles in radians
11:
12: x,y are coords of developed curve
13: c (chi) is angle of inclination of developed curve from x axis
14:
15: dx/dp = cos(c)/sin(a)
16: dy/dp = sin(c)/sin(a)
17: dc/dp = tan(p)/tan(a)
18: dt/dp = 1/(cos(p)*tan(a))
19:
20: cc lox.c -lport -lF77 -lI77
21: a.out alpha here alpha is in degrees
22: */
23: extern char *realloc();
24: static double renorm();
25: static bsearch(), getxy(), calcf(), solve();
26: #define DEG (180/PI)
27: #define MAX 85
28:
29: /* curlicue is an ordered sequence of points
30: along the midline of the spiral, in both geographic
31: and developed coordinates */
32: struct curl {
33: double phi,x,y,theta,chi;
34: } *curlicue; /* the midline */
35: int nc; /* number of points on the midline */
36:
37: struct coord a; /* alpha, angle from equator */
38: static signa = 1;
39: static double z[4]; /* x==z[0],y==z[1],t=z[2],c==z[3] */
40:
41: /* inputs to dodes, port library integration routine */
42:
43: static int n = 4;
44: static double z0[4]; /* initial values = 0,0,0,a */
45: static double p0; /* initial value of p = 0 */
46: static double p1 = 86*PI/180; /* final value, 89.99+ degrees */
47: static double dt; /* current time step */
48: static double deg = PI/180; /* 1 degree */
49: static float errpar[2] = {1.e-7,1.e-7};
50:
51: static
52: f(p,z,n,r)
53: double *p, *z, *r;
54: int *n;
55: {
56: r[0] = cos(z[3])/a.s;
57: r[1] = sin(z[3])/a.s;
58: r[2] = a.c/(cos(*p)*a.s);
59: r[3] = sin(*p)*r[2];
60: }
61: static
62: handle(t0,z0,t1,z1,n,dt,ts,e)
63: double *t0,*z0,*t1,*z1,*dt,*ts;
64: float *e;
65: int *n;
66: {
67: if(*dt > deg) *dt = deg;
68: if(fabs(z1[3]-z0[3])>.1 && *dt >.00001)
69: *dt *= .1/fabs(z1[3]-z0[3]);
70: if(*t1 + *dt >= PI/2)
71: *dt = (PI/2 - *t1)/2;
72: if(*t1 + *dt > *ts)
73: *dt = *ts - *t1 + .00001;
74: curlicue = (struct curl*)realloc((char*)curlicue,
75: (nc+1)*sizeof(*curlicue));
76: curlicue[nc].phi = *t1;
77: curlicue[nc].x = z1[0];
78: curlicue[nc].y = z1[1];
79: curlicue[nc].theta = z1[2];
80: curlicue[nc].chi = z1[3];
81: nc++;
82: /*printf("%f %f %f %f %f\n",*t1*DEG,
83: z1[0]*DEG,z1[1]*DEG,z1[2]*DEG,z1[3]*DEG);
84: fflush(stdout);*/
85: if(*t0==*t1) abort();
86: }
87: static
88: struct place negplace(place)
89: struct place *place;
90: {
91: struct place iplace;
92: iplace = *place;
93: iplace.nlat.l = -place->nlat.l;
94: iplace.nlat.s = -place->nlat.s;
95: iplace.wlon.l = -place->wlon.l;
96: iplace.wlon.s = -place->wlon.s;
97: return iplace;
98: }
99: static
100: Xloxodromic(place, x, y)
101: struct place *place;
102: float *x, *y;
103: {
104: double u1 = place->nlat.l;
105: double v1 = -place->wlon.l;
106: double d,p,t;
107: if(fabs(u1) > MAX*RAD) return 0;
108: if(u1 < 0) {
109: struct place iplace;
110: int ret;
111: iplace = negplace(place);
112: ret = Xloxodromic(&iplace,x,y);
113: *x = -*x;
114: *y = -*y;
115: return ret;
116: }
117: v1 = renorm(u1,bsearch(u1,0),v1);
118: solve(u1,v1,&d,&p,&t);
119: /*printf("%f %f %f %f %f %f\n",
120: u,v,v1*DEG,d*DEG,p*DEG,t*DEG);
121: fflush(stdout);*/
122: getxy(d,p,x,y);
123: /*printf("%f %f\n",x*DEG,y*DEG);
124: fflush(stdout);*/
125: return 1;
126: }
127: int (*loxodromic(par))()
128: float par;
129: {
130: deg2rad(par, &a);
131: if(par < 0)
132: signa = -1;
133: z0[3] = a.l;
134: dt = deg;
135: handle(°,z0,&p0,z0,&n,°,&p1,errpar);
136: dodes_(f,z0,&n,&p0,&p1,&dt,errpar,handle);
137: return Xloxodromic;
138: }
139:
140: /* find the index for latitude (i=0) or longitude (i=1)
141: in array curlicue. In case of longitude, u must have
142: been normalized by renorm() */
143: static
144: bsearch(u,i)
145: double u;
146: {
147: int top = nc;
148: int bot = 0;
149: int mid;
150: while(bot<top-1) {
151: mid = (bot+top)/2;
152: if(i==0&&curlicue[mid].phi<=u||
153: i==1&&(signa>0&&curlicue[mid].theta<=u||
154: signa<0&&curlicue[mid].theta>=u))
155: bot = mid;
156: else
157: top = mid;
158: }
159: return bot;
160: }
161: /* wind v thru multiples of 2*PI until it lies within PI
162: of the (linearly interpolated) midline */
163: static double
164: renorm(u,n,v)
165: double u,v;
166: {
167: double t,fract;
168: fract = (u-curlicue[n].phi)/
169: (curlicue[n+1].phi-curlicue[n].phi);
170: t = curlicue[n].theta*(1-fract) +
171: curlicue[n+1].theta*fract;
172: if(signa > 0) while(v<t-PI)
173: v += 2*PI;
174: else while(v>t+PI)
175: v -= 2*PI;
176: return v;
177: }
178: /* given the height (d) and foot (p,t) of the perpendicular projection
179: of a point onto the midline, return the x-y coordinates of the point*/
180: static
181: getxy(d,p,xp,yp)
182: float d,p,*xp,*yp;
183: {
184: int n, sign = 1;
185: double fract, x0, y0, c0;
186: if(p < 0) {
187: p = -p;
188: sign = -1;
189: }
190: n = bsearch(p,0);
191: fract = (p-curlicue[n].phi)/
192: (curlicue[n+1].phi-curlicue[n].phi);
193: x0 = sign*(curlicue[n].x*(1-fract) +
194: curlicue[n+1].x*fract);
195: y0 = sign*(curlicue[n].y*(1-fract) +
196: curlicue[n+1].y*fract);
197: c0 = curlicue[n].chi*(1-fract) +
198: curlicue[n+1].chi*fract;
199: *xp = x0 - d*sin(c0);
200: *yp = y0 + d*cos(c0);
201: }
202:
203: /*
204: solve simultaneously for d,p,t (dist to midline,
205: phi lat on midline,
206: theta lon on midline)
207: given a, u, v (rhumb angle from parallels, lat, east lon)
208:
209: sin d sin a = cos u sin(t-v) law of sines
210: sin u = cos d sin p + sin d cos p cos a law of cosines
211: t tan a = log tan (p/2 + PI/4) eqn of rhumb line
212:
213: initial guess: d=u-p, t=v, p from table lookup in curlicue
214: */
215: static double su,cu,v0;
216: static int n3 = 3, jmax = 50;
217: static double acc = 1e-6;
218: static
219: calcf(n,x,nf,g)
220: int *n, *nf;
221: double *x,*g;
222: {
223: double f[3], sd;
224: if(x[1]>=PI/2) {
225: *nf = 0;
226: return;
227: }
228: sd = sin(x[0]);
229: f[0] = sd*a.s-cu*sin(x[2]-v0);
230: f[1] = su - cos(x[0])*sin(x[1]) - sd*cos(x[1])*a.c;
231: f[2] = x[2]*a.s/a.c - log(tan(x[1]/2+PI/4));
232: /*printf("calcf: d p t %g %f %f",
233: x[0]*DEG,x[1]*DEG,x[2]*DEG);
234: printf(" resid %f %f %f\n",f[0],f[1],f[2]);
235: fflush(stdout);*/
236: *g = f[0]*f[0]+f[1]*f[1]+f[2]*f[2];
237: }
238: /* given renormed lat-lon (u,v) find the height (*dp) and foot
239: (*pp,*tp) of a perpendicular to the midline. precondition: u>=0 */
240: static
241: solve(u,v,dp,pp,tp)
242: double u,v,*dp,*pp,*tp;
243: {
244: double z[3]; /* d, p, t */
245: int n;
246: if(u < 0) {
247: abort();
248: solve(-u,-v,dp,pp,tp);
249: *dp = -*dp;
250: *pp = -*pp;
251: *tp = -*tp;
252: return;
253: }
254: n = bsearch(signa*fabs(v),1);
255: su = sin(u);
256: cu = cos(u);
257: z[1] = curlicue[n].phi; /* initial guess */
258: if(signa*v < 0) z[1] = -z[1];
259: z[0] = u - z[1];
260: z[2] = v0 = v;
261: /*printf("inputs (deg) %f %f\n",u*DEG,v*DEG);
262: printf("interval %d guess (deg) %f %f %f\n",n,
263: z[0]*DEG,z[1]*DEG,z[2]*DEG);
264: fflush(stdout);*/
265: dsmnf_(&n3,z,calcf,&jmax,&acc);
266: *dp = z[0];
267: *pp = z[1];
268: *tp = z[2];
269: }
270: loxcut(g,og,cutlon)
271: struct place *g, *og;
272:
273: {
274: double glon, oglon;
275: double sign = g->nlat.l>=0? 1: -1;
276: double nlat = sign*g->nlat.l;
277: if(nlat > MAX*RAD)
278: return 0;
279: glon = sign*renorm(nlat, bsearch(nlat,0),
280: -sign*g->wlon.l);
281: sign = og->nlat.l>=0? 1: -1;
282: nlat = sign*og->nlat.l;
283: if(nlat > MAX*RAD)
284: return 0;
285: oglon = sign*renorm(nlat, bsearch(nlat,0),
286: -sign*og->wlon.l);
287: return fabs(glon-oglon) < PI;
288: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.