"Fossies" - the Fresh Open Source Software Archive 
Member "xearth-1.1/scan.c" (7 Nov 1999, 29542 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * scan.c
3 * kirk johnson
4 * august 1993
5 *
6 * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
7 *
8 * Parts of the source code (as marked) are:
9 * Copyright (C) 1989, 1990, 1991 by Jim Frost
10 * Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
11 *
12 * Permission to use, copy, modify and freely distribute xearth for
13 * non-commercial and not-for-profit purposes is hereby granted
14 * without fee, provided that both the above copyright notice and this
15 * permission notice appear in all copies and in supporting
16 * documentation.
17 *
18 * Unisys Corporation holds worldwide patent rights on the Lempel Zev
19 * Welch (LZW) compression technique employed in the CompuServe GIF
20 * image file format as well as in other formats. Unisys has made it
21 * clear, however, that it does not require licensing or fees to be
22 * paid for freely distributed, non-commercial applications (such as
23 * xearth) that employ LZW/GIF technology. Those wishing further
24 * information about licensing the LZW patent should contact Unisys
25 * directly at (lzw_info@unisys.com) or by writing to
26 *
27 * Unisys Corporation
28 * Welch Licensing Department
29 * M/S-C1SW19
30 * P.O. Box 500
31 * Blue Bell, PA 19424
32 *
33 * The author makes no representations about the suitability of this
34 * software for any purpose. It is provided "as is" without express or
35 * implied warranty.
36 *
37 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
40 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
43 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 */
45
46 #include "xearth.h"
47 #include "kljcpyrt.h"
48
49 #define MAP_DATA_SCALE (30000)
50
51 #define XingTypeEntry (0)
52 #define XingTypeExit (1)
53
54 typedef struct
55 {
56 int type;
57 int cidx;
58 double x, y;
59 double angle;
60 } EdgeXing;
61
62 void scan_map _P((void));
63 void orth_scan_outline _P((void));
64 void orth_scan_curves _P((void));
65 double *orth_extract_curve _P((int, short *));
66 void orth_scan_along_curve _P((double *, double *, int));
67 void orth_find_edge_xing _P((double *, double *, double *));
68 void orth_handle_xings _P((void));
69 void orth_scan_arc _P((double, double, double, double, double, double));
70 void merc_scan_outline _P((void));
71 void merc_scan_curves _P((void));
72 double *merc_extract_curve _P((int, short *));
73 void merc_scan_along_curve _P((double *, double *, int));
74 double merc_find_edge_xing _P((double *, double *));
75 void merc_handle_xings _P((void));
76 void merc_scan_edge _P((EdgeXing *, EdgeXing *));
77 void cyl_scan_outline _P((void));
78 void cyl_scan_curves _P((void));
79 double *cyl_extract_curve _P((int, short *));
80 void cyl_scan_along_curve _P((double *, double *, int));
81 double cyl_find_edge_xing _P((double *, double *));
82 void cyl_handle_xings _P((void));
83 void cyl_scan_edge _P((EdgeXing *, EdgeXing *));
84 void xing_error _P((const char *, int, int, int, EdgeXing *));
85 void scan _P((double, double, double, double));
86 void get_scanbits _P((int));
87
88 static int double_comp _P((const void *, const void *));
89 static int scanbit_comp _P((const void *, const void *));
90 static int orth_edgexing_comp _P((const void *, const void *));
91 static int merc_edgexing_comp _P((const void *, const void *));
92 static int cyl_edgexing_comp _P((const void *, const void *));
93
94 ViewPosInfo view_pos_info;
95 ProjInfo proj_info;
96
97 int first_scan = 1;
98 ExtArr scanbits;
99 ExtArr edgexings;
100 int min_y, max_y;
101 ExtArr *scanbuf;
102
103
104 static int double_comp(a, b)
105 const void *a;
106 const void *b;
107 {
108 double val_a;
109 double val_b;
110 int rslt;
111
112 val_a = *((const double *) a);
113 val_b = *((const double *) b);
114
115 if (val_a < val_b)
116 rslt = -1;
117 else if (val_a > val_b)
118 rslt = 1;
119 else
120 rslt = 0;
121
122 return rslt;
123 }
124
125
126 static int scanbit_comp(a, b)
127 const void *a;
128 const void *b;
129 {
130 return (((const ScanBit *) a)->y - ((const ScanBit *) b)->y);
131 }
132
133
134 static int orth_edgexing_comp(a, b)
135 const void *a;
136 const void *b;
137 {
138 double angle_a;
139 double angle_b;
140 int rslt;
141
142 angle_a = ((const EdgeXing *) a)->angle;
143 angle_b = ((const EdgeXing *) b)->angle;
144
145 if (angle_a < angle_b)
146 rslt = -1;
147 else if (angle_a > angle_b)
148 rslt = 1;
149 else
150 rslt = 0;
151
152 return rslt;
153 }
154
155
156 static int merc_edgexing_comp(a, b)
157 const void *a;
158 const void *b;
159 {
160 double val_a;
161 double val_b;
162 int rslt;
163
164 val_a = ((const EdgeXing *) a)->angle;
165 val_b = ((const EdgeXing *) b)->angle;
166
167 if (val_a < val_b)
168 {
169 rslt = -1;
170 }
171 else if (val_a > val_b)
172 {
173 rslt = 1;
174 }
175 else if (val_a == 0)
176 {
177 val_a = ((const EdgeXing *) a)->y;
178 val_b = ((const EdgeXing *) b)->y;
179
180 if (val_a < val_b)
181 rslt = -1;
182 else if (val_a > val_b)
183 rslt = 1;
184 else
185 rslt = 0;
186 }
187 else if (val_a == 2)
188 {
189 val_a = ((const EdgeXing *) a)->y;
190 val_b = ((const EdgeXing *) b)->y;
191
192 if (val_a > val_b)
193 rslt = -1;
194 else if (val_a < val_b)
195 rslt = 1;
196 else
197 rslt = 0;
198 }
199 else
200 {
201 /* keep lint happy */
202 rslt = 0;
203 assert(0);
204 }
205
206 return rslt;
207 }
208
209
210 static int cyl_edgexing_comp(a, b)
211 const void *a;
212 const void *b;
213 {
214 double val_a;
215 double val_b;
216 int rslt;
217
218 val_a = ((const EdgeXing *) a)->angle;
219 val_b = ((const EdgeXing *) b)->angle;
220
221 if (val_a < val_b)
222 {
223 rslt = -1;
224 }
225 else if (val_a > val_b)
226 {
227 rslt = 1;
228 }
229 else if (val_a == 0)
230 {
231 val_a = ((const EdgeXing *) a)->y;
232 val_b = ((const EdgeXing *) b)->y;
233
234 if (val_a < val_b)
235 rslt = -1;
236 else if (val_a > val_b)
237 rslt = 1;
238 else
239 rslt = 0;
240 }
241 else if (val_a == 2)
242 {
243 val_a = ((const EdgeXing *) a)->y;
244 val_b = ((const EdgeXing *) b)->y;
245
246 if (val_a > val_b)
247 rslt = -1;
248 else if (val_a < val_b)
249 rslt = 1;
250 else
251 rslt = 0;
252 }
253 else
254 {
255 /* keep lint happy */
256 rslt = 0;
257 assert(0);
258 }
259
260 return rslt;
261 }
262
263
264 void scan_map()
265 {
266 int i;
267 ViewPosInfo *vpi;
268 ProjInfo *pi;
269
270 vpi = &view_pos_info;
271 vpi->cos_lat = cos(view_lat * (M_PI/180));
272 vpi->sin_lat = sin(view_lat * (M_PI/180));
273 vpi->cos_lon = cos(view_lon * (M_PI/180));
274 vpi->sin_lon = sin(view_lon * (M_PI/180));
275 vpi->cos_rot = cos(view_rot * (M_PI/180));
276 vpi->sin_rot = sin(view_rot * (M_PI/180));
277
278 pi = &proj_info;
279 if (proj_type == ProjTypeOrthographic)
280 {
281 pi->proj_scale = ((hght < wdth) ? hght : wdth) * (view_mag / 2) * 0.99;
282 }
283 else
284 {
285 /* proj_type is either ProjTypeMercator or ProjTypeCylindrical
286 */
287 pi->proj_scale = (view_mag * wdth) / (2 * M_PI);
288 }
289
290 pi->proj_xofs = (double) wdth / 2 + shift_x;
291 pi->proj_yofs = (double) hght / 2 + shift_y;
292 pi->inv_proj_scale = 1 / pi->proj_scale;
293
294 /* the first time through, allocate scanbits and edgexings;
295 * on subsequent passes, simply reset them.
296 */
297 if (first_scan)
298 {
299 scanbits = extarr_alloc(sizeof(ScanBit));
300 edgexings = extarr_alloc(sizeof(EdgeXing));
301 }
302 else
303 {
304 scanbits->count = 0;
305 edgexings->count = 0;
306 }
307
308 /* maybe only allocate these once and reset them on
309 * subsequent passes (like scanbits and edgexings)?
310 */
311 scanbuf = (ExtArr *) malloc((unsigned) sizeof(ExtArr) * hght);
312 assert(scanbuf != NULL);
313 for (i=0; i<hght; i++)
314 scanbuf[i] = extarr_alloc(sizeof(double));
315
316 if (proj_type == ProjTypeOrthographic)
317 {
318 orth_scan_outline();
319 orth_scan_curves();
320 }
321 else if (proj_type == ProjTypeMercator)
322 {
323 merc_scan_outline();
324 merc_scan_curves();
325 }
326 else /* (proj_type == ProjTypeCylindrical) */
327 {
328 cyl_scan_outline();
329 cyl_scan_curves();
330 }
331
332 for (i=0; i<hght; i++)
333 extarr_free(scanbuf[i]);
334 free(scanbuf);
335
336 qsort(scanbits->body, scanbits->count, sizeof(ScanBit), scanbit_comp);
337
338 first_scan = 0;
339 }
340
341
342 void orth_scan_outline()
343 {
344 min_y = hght;
345 max_y = -1;
346
347 orth_scan_arc(1.0, 0.0, 0.0, 1.0, 0.0, (2*M_PI));
348
349 get_scanbits(64);
350 }
351
352
353 void orth_scan_curves()
354 {
355 int i;
356 int cidx;
357 int npts;
358 int val;
359 short *raw;
360 double *pos;
361 double *prev;
362 double *curr;
363
364 cidx = 0;
365 raw = map_data;
366 while (1)
367 {
368 npts = raw[0];
369 if (npts == 0) break;
370 val = raw[1];
371 raw += 2;
372
373 pos = orth_extract_curve(npts, raw);
374 prev = pos + (npts-1)*3;
375 curr = pos;
376 min_y = hght;
377 max_y = -1;
378
379 for (i=0; i<npts; i++)
380 {
381 orth_scan_along_curve(prev, curr, cidx);
382 prev = curr;
383 curr += 3;
384 }
385
386 free(pos);
387 if (edgexings->count > 0)
388 orth_handle_xings();
389 if (min_y <= max_y)
390 get_scanbits(val);
391
392 cidx += 1;
393 raw += 3*npts;
394 }
395 }
396
397
398 double *orth_extract_curve(npts, data)
399 int npts;
400 short *data;
401 {
402 int i;
403 int x, y, z;
404 double scale;
405 double *pos;
406 double *rslt;
407
408 rslt = (double *) malloc((unsigned) sizeof(double) * 3 * npts);
409 assert(rslt != NULL);
410
411 x = 0;
412 y = 0;
413 z = 0;
414 scale = 1.0 / MAP_DATA_SCALE;
415 pos = rslt;
416
417 for (i=0; i<npts; i++)
418 {
419 x += data[0];
420 y += data[1];
421 z += data[2];
422
423 pos[0] = x * scale;
424 pos[1] = y * scale;
425 pos[2] = z * scale;
426
427 XFORM_ROTATE(pos, view_pos_info);
428
429 data += 3;
430 pos += 3;
431 }
432
433 return rslt;
434 }
435
436
437 void orth_scan_along_curve(prev, curr, cidx)
438 double *prev;
439 double *curr;
440 int cidx;
441 {
442 double extra[3];
443 EdgeXing *xing;
444
445 if (prev[2] <= 0) /* prev not visible */
446 {
447 if (curr[2] <= 0)
448 return; /* neither point visible */
449
450 orth_find_edge_xing(prev, curr, extra);
451
452 /* extra[] is an edge crossing (entry point) */
453 xing = (EdgeXing *) extarr_next(edgexings);
454 xing->type = XingTypeEntry;
455 xing->cidx = cidx;
456 xing->x = extra[0];
457 xing->y = extra[1];
458 xing->angle = atan2(extra[1], extra[0]);
459
460 prev = extra;
461 }
462 else if (curr[2] <= 0) /* curr not visible */
463 {
464 orth_find_edge_xing(prev, curr, extra);
465
466 /* extra[] is an edge crossing (exit point) */
467 xing = (EdgeXing *) extarr_next(edgexings);
468 xing->type = XingTypeExit;
469 xing->cidx = cidx;
470 xing->x = extra[0];
471 xing->y = extra[1];
472 xing->angle = atan2(extra[1], extra[0]);
473
474 curr = extra;
475 }
476
477 scan(XPROJECT(prev[0]), YPROJECT(prev[1]),
478 XPROJECT(curr[0]), YPROJECT(curr[1]));
479 }
480
481
482 void orth_find_edge_xing(prev, curr, rslt)
483 double *prev;
484 double *curr;
485 double *rslt;
486 {
487 double tmp;
488 double r0, r1;
489
490 tmp = curr[2] / (curr[2] - prev[2]);
491 r0 = curr[0] - tmp * (curr[0] - prev[0]);
492 r1 = curr[1] - tmp * (curr[1] - prev[1]);
493
494 tmp = sqrt((r0*r0) + (r1*r1));
495 rslt[0] = r0 / tmp;
496 rslt[1] = r1 / tmp;
497 rslt[2] = 0;
498 }
499
500
501 void orth_handle_xings()
502 {
503 int i;
504 int nxings;
505 EdgeXing *xings;
506 EdgeXing *from;
507 EdgeXing *to;
508
509 xings = (EdgeXing *) edgexings->body;
510 nxings = edgexings->count;
511
512 assert((nxings % 2) == 0);
513 qsort(xings, (unsigned) nxings, sizeof(EdgeXing), orth_edgexing_comp);
514
515 if (xings[0].type == XingTypeExit)
516 {
517 for (i=0; i<nxings; i+=2)
518 {
519 from = &(xings[i]);
520 to = &(xings[i+1]);
521
522 if ((from->type != XingTypeExit) ||
523 (to->type != XingTypeEntry))
524 xing_error(__FILE__, __LINE__, i, nxings, xings);
525
526 orth_scan_arc(from->x, from->y, from->angle,
527 to->x, to->y, to->angle);
528 }
529 }
530 else
531 {
532 from = &(xings[nxings-1]);
533 to = &(xings[0]);
534
535 if ((from->type != XingTypeExit) ||
536 (to->type != XingTypeEntry) ||
537 (from->angle < to->angle))
538 xing_error(__FILE__, __LINE__, nxings-1, nxings, xings);
539
540 orth_scan_arc(from->x, from->y, from->angle,
541 to->x, to->y, to->angle+(2*M_PI));
542
543 for (i=1; i<(nxings-1); i+=2)
544 {
545 from = &(xings[i]);
546 to = &(xings[i+1]);
547
548 if ((from->type != XingTypeExit) ||
549 (to->type != XingTypeEntry))
550 xing_error(__FILE__, __LINE__, i, nxings, xings);
551
552 orth_scan_arc(from->x, from->y, from->angle,
553 to->x, to->y, to->angle);
554 }
555 }
556
557 edgexings->count = 0;
558 }
559
560
561 void orth_scan_arc(x_0, y_0, a_0, x_1, y_1, a_1)
562 double x_0, y_0, a_0;
563 double x_1, y_1, a_1;
564 {
565 int i;
566 int lo, hi;
567 double angle, step;
568 double prev_x, prev_y;
569 double curr_x, curr_y;
570 double c_step, s_step;
571 double arc_x, arc_y;
572 double tmp;
573
574 assert(a_0 < a_1);
575
576 step = proj_info.inv_proj_scale * 10;
577 if (step > 0.05) step = 0.05;
578 lo = ceil(a_0 / step);
579 hi = floor(a_1 / step);
580
581 prev_x = XPROJECT(x_0);
582 prev_y = YPROJECT(y_0);
583
584 if (lo <= hi)
585 {
586 c_step = cos(step);
587 s_step = sin(step);
588
589 angle = lo * step;
590 arc_x = cos(angle);
591 arc_y = sin(angle);
592
593 for (i=lo; i<=hi; i++)
594 {
595 curr_x = XPROJECT(arc_x);
596 curr_y = YPROJECT(arc_y);
597 scan(prev_x, prev_y, curr_x, curr_y);
598
599 /* instead of repeatedly calling cos() and sin() to get the next
600 * values for arc_x and arc_y, simply rotate the existing values
601 */
602 tmp = (c_step * arc_x) - (s_step * arc_y);
603 arc_y = (s_step * arc_x) + (c_step * arc_y);
604 arc_x = tmp;
605
606 prev_x = curr_x;
607 prev_y = curr_y;
608 }
609 }
610
611 curr_x = XPROJECT(x_1);
612 curr_y = YPROJECT(y_1);
613 scan(prev_x, prev_y, curr_x, curr_y);
614 }
615
616
617 void merc_scan_outline()
618 {
619 double left, right;
620 double top, bottom;
621
622 min_y = hght;
623 max_y = -1;
624
625 left = XPROJECT(-M_PI);
626 right = XPROJECT(M_PI);
627 top = YPROJECT(BigNumber);
628 bottom = YPROJECT(-BigNumber);
629
630 scan(right, top, left, top);
631 scan(left, top, left, bottom);
632 scan(left, bottom, right, bottom);
633 scan(right, bottom, right, top);
634
635 get_scanbits(64);
636 }
637
638
639 void merc_scan_curves()
640 {
641 int i;
642 int cidx;
643 int npts;
644 int val;
645 short *raw;
646 double *pos;
647 double *prev;
648 double *curr;
649
650 cidx = 0;
651 raw = map_data;
652 while (1)
653 {
654 npts = raw[0];
655 if (npts == 0) break;
656 val = raw[1];
657 raw += 2;
658
659 pos = merc_extract_curve(npts, raw);
660 prev = pos + (npts-1)*5;
661 curr = pos;
662 min_y = hght;
663 max_y = -1;
664
665 for (i=0; i<npts; i++)
666 {
667 merc_scan_along_curve(prev, curr, cidx);
668 prev = curr;
669 curr += 5;
670 }
671
672 free(pos);
673 if (edgexings->count > 0)
674 merc_handle_xings();
675 if (min_y <= max_y)
676 get_scanbits(val);
677
678 cidx += 1;
679 raw += 3*npts;
680 }
681 }
682
683
684 double *merc_extract_curve(npts, data)
685 int npts;
686 short *data;
687 {
688 int i;
689 int x, y, z;
690 double scale;
691 double *pos;
692 double *rslt;
693
694 rslt = (double *) malloc((unsigned) sizeof(double) * 5 * npts);
695 assert(rslt != NULL);
696
697 x = 0;
698 y = 0;
699 z = 0;
700 scale = 1.0 / MAP_DATA_SCALE;
701 pos = rslt;
702
703 for (i=0; i<npts; i++)
704 {
705 x += data[0];
706 y += data[1];
707 z += data[2];
708
709 pos[0] = x * scale;
710 pos[1] = y * scale;
711 pos[2] = z * scale;
712
713 XFORM_ROTATE(pos, view_pos_info);
714
715 /* apply mercator projection
716 */
717 pos[3] = MERCATOR_X(pos[0], pos[2]);
718 pos[4] = MERCATOR_Y(pos[1]);
719
720 data += 3;
721 pos += 5;
722 }
723
724 return rslt;
725 }
726
727
728 void merc_scan_along_curve(prev, curr, cidx)
729 double *prev;
730 double *curr;
731 int cidx;
732 {
733 double px, py;
734 double cx, cy;
735 double dx;
736 double mx, my;
737 EdgeXing *xing;
738
739 px = prev[3];
740 cx = curr[3];
741 py = prev[4];
742 cy = curr[4];
743 dx = cx - px;
744
745 if (dx > 0)
746 {
747 /* curr to the right of prev
748 */
749
750 if (dx > ((2*M_PI) - dx))
751 {
752 /* vertical edge crossing to the left of prev
753 */
754
755 /* find exit point (left edge) */
756 mx = - M_PI;
757 my = merc_find_edge_xing(prev, curr);
758
759 /* scan from prev to exit point */
760 scan(XPROJECT(px), YPROJECT(py), XPROJECT(mx), YPROJECT(my));
761
762 /* (mx, my) is an edge crossing (exit point) */
763 xing = (EdgeXing *) extarr_next(edgexings);
764 xing->type = XingTypeExit;
765 xing->cidx = cidx;
766 xing->x = mx;
767 xing->y = my;
768 xing->angle = 2; /* left edge */
769
770 /* scan from entry point (right edge) to curr */
771 mx = M_PI;
772 scan(XPROJECT(mx), YPROJECT(my), XPROJECT(cx), YPROJECT(cy));
773
774 /* (mx, my) is an edge crossing (entry point) */
775 xing = (EdgeXing *) extarr_next(edgexings);
776 xing->type = XingTypeEntry;
777 xing->cidx = cidx;
778 xing->x = mx;
779 xing->y = my;
780 xing->angle = 0; /* right edge */
781 }
782 else
783 {
784 /* no vertical edge crossing
785 */
786 scan(XPROJECT(px), YPROJECT(py), XPROJECT(cx), YPROJECT(cy));
787 }
788 }
789 else
790 {
791 /* curr to the left of prev
792 */
793 dx = - dx;
794
795 if (dx > ((2*M_PI) - dx))
796 {
797 /* vertical edge crossing to the right of prev
798 */
799
800 /* find exit point (right edge) */
801 mx = M_PI;
802 my = merc_find_edge_xing(prev, curr);
803
804 /* scan from prev to exit point */
805 scan(XPROJECT(px), YPROJECT(py), XPROJECT(mx), YPROJECT(my));
806
807 /* (mx, my) is an edge crossing (exit point) */
808 xing = (EdgeXing *) extarr_next(edgexings);
809 xing->type = XingTypeExit;
810 xing->cidx = cidx;
811 xing->x = mx;
812 xing->y = my;
813 xing->angle = 0; /* right edge */
814
815 /* scan from entry point (left edge) to curr */
816 mx = - M_PI;
817 scan(XPROJECT(mx), YPROJECT(my), XPROJECT(cx), YPROJECT(cy));
818
819 /* (mx, my) is an edge crossing (entry point) */
820 xing = (EdgeXing *) extarr_next(edgexings);
821 xing->type = XingTypeEntry;
822 xing->cidx = cidx;
823 xing->x = mx;
824 xing->y = my;
825 xing->angle = 2; /* left edge */
826 }
827 else
828 {
829 /* no vertical edge crossing
830 */
831 scan(XPROJECT(px), YPROJECT(py), XPROJECT(cx), YPROJECT(cy));
832 }
833 }
834 }
835
836
837 double merc_find_edge_xing(prev, curr)
838 double *prev;
839 double *curr;
840 {
841 double ratio;
842 double scale;
843 double z1, z2;
844 double rslt;
845
846 if (curr[0] != 0)
847 {
848 ratio = (prev[0] / curr[0]);
849 z1 = prev[1] - (ratio * curr[1]);
850 z2 = prev[2] - (ratio * curr[2]);
851 }
852 else
853 {
854 z1 = curr[1];
855 z2 = curr[2];
856 }
857
858 scale = ((z2 > 0) ? -1 : 1) / sqrt((z1*z1) + (z2*z2));
859 z1 *= scale;
860
861 rslt = MERCATOR_Y(z1);
862
863 return rslt;
864 }
865
866
867 void merc_handle_xings()
868 {
869 int i;
870 int nxings;
871 EdgeXing *xings;
872 EdgeXing *from;
873 EdgeXing *to;
874
875 xings = (EdgeXing *) edgexings->body;
876 nxings = edgexings->count;
877
878 assert((nxings % 2) == 0);
879 qsort(xings, (unsigned) nxings, sizeof(EdgeXing), merc_edgexing_comp);
880
881 if (xings[0].type == XingTypeExit)
882 {
883 for (i=0; i<nxings; i+=2)
884 {
885 from = &(xings[i]);
886 to = &(xings[i+1]);
887
888 if ((from->type != XingTypeExit) ||
889 (to->type != XingTypeEntry))
890 xing_error(__FILE__, __LINE__, i, nxings, xings);
891
892 merc_scan_edge(from, to);
893 }
894 }
895 else
896 {
897 from = &(xings[nxings-1]);
898 to = &(xings[0]);
899
900 if ((from->type != XingTypeExit) ||
901 (to->type != XingTypeEntry) ||
902 (from->angle < to->angle))
903 xing_error(__FILE__, __LINE__, nxings-1, nxings, xings);
904
905 merc_scan_edge(from, to);
906
907 for (i=1; i<(nxings-1); i+=2)
908 {
909 from = &(xings[i]);
910 to = &(xings[i+1]);
911
912 if ((from->type != XingTypeExit) ||
913 (to->type != XingTypeEntry))
914 xing_error(__FILE__, __LINE__, i, nxings, xings);
915
916 merc_scan_edge(from, to);
917 }
918 }
919
920 edgexings->count = 0;
921 }
922
923
924 void merc_scan_edge(from, to)
925 EdgeXing *from;
926 EdgeXing *to;
927 {
928 int s0, s1, s_new;
929 double x_0, x_1, x_new;
930 double y_0, y_1, y_new;
931
932 s0 = from->angle;
933 x_0 = XPROJECT(from->x);
934 y_0 = YPROJECT(from->y);
935
936 s1 = to->angle;
937 x_1 = XPROJECT(to->x);
938 y_1 = YPROJECT(to->y);
939
940 while (s0 != s1)
941 {
942 switch (s0)
943 {
944 case 0:
945 x_new = XPROJECT(M_PI);
946 y_new = YPROJECT(BigNumber);
947 s_new = 1;
948 break;
949
950 case 1:
951 x_new = XPROJECT(-M_PI);
952 y_new = YPROJECT(BigNumber);
953 s_new = 2;
954 break;
955
956 case 2:
957 x_new = XPROJECT(-M_PI);
958 y_new = YPROJECT(-BigNumber);
959 s_new = 3;
960 break;
961
962 case 3:
963 x_new = XPROJECT(M_PI);
964 y_new = YPROJECT(-BigNumber);
965 s_new = 0;
966 break;
967
968 default:
969 /* keep lint happy */
970 x_new = 0;
971 y_new = 0;
972 s_new = 0;
973 assert(0);
974 }
975
976 scan(x_0, y_0, x_new, y_new);
977 x_0 = x_new;
978 y_0 = y_new;
979 s0 = s_new;
980 }
981
982 scan(x_0, y_0, x_1, y_1);
983 }
984
985
986 void cyl_scan_outline()
987 {
988 double left, right;
989 double top, bottom;
990
991 min_y = hght;
992 max_y = -1;
993
994 left = XPROJECT(-M_PI);
995 right = XPROJECT(M_PI);
996 top = YPROJECT(BigNumber);
997 bottom = YPROJECT(-BigNumber);
998
999 scan(right, top, left, top);
1000 scan(left, top, left, bottom);
1001 scan(left, bottom, right, bottom);
1002 scan(right, bottom, right, top);
1003
1004 get_scanbits(64);
1005 }
1006
1007
1008 void cyl_scan_curves()
1009 {
1010 int i;
1011 int cidx;
1012 int npts;
1013 int val;
1014 short *raw;
1015 double *pos;
1016 double *prev;
1017 double *curr;
1018
1019 cidx = 0;
1020 raw = map_data;
1021 while (1)
1022 {
1023 npts = raw[0];
1024 if (npts == 0) break;
1025 val = raw[1];
1026 raw += 2;
1027
1028 pos = cyl_extract_curve(npts, raw);
1029 prev = pos + (npts-1)*5;
1030 curr = pos;
1031 min_y = hght;
1032 max_y = -1;
1033
1034 for (i=0; i<npts; i++)
1035 {
1036 cyl_scan_along_curve(prev, curr, cidx);
1037 prev = curr;
1038 curr += 5;
1039 }
1040
1041 free(pos);
1042 if (edgexings->count > 0)
1043 cyl_handle_xings();
1044 if (min_y <= max_y)
1045 get_scanbits(val);
1046
1047 cidx += 1;
1048 raw += 3*npts;
1049 }
1050 }
1051
1052
1053 double *cyl_extract_curve(npts, data)
1054 int npts;
1055 short *data;
1056 {
1057 int i;
1058 int x, y, z;
1059 double scale;
1060 double *pos;
1061 double *rslt;
1062
1063 rslt = (double *) malloc((unsigned) sizeof(double) * 5 * npts);
1064 assert(rslt != NULL);
1065
1066 x = 0;
1067 y = 0;
1068 z = 0;
1069 scale = 1.0 / MAP_DATA_SCALE;
1070 pos = rslt;
1071
1072 for (i=0; i<npts; i++)
1073 {
1074 x += data[0];
1075 y += data[1];
1076 z += data[2];
1077
1078 pos[0] = x * scale;
1079 pos[1] = y * scale;
1080 pos[2] = z * scale;
1081
1082 XFORM_ROTATE(pos, view_pos_info);
1083
1084 /* apply cylindrical projection
1085 */
1086 pos[3] = CYLINDRICAL_X(pos[0], pos[2]);
1087 pos[4] = CYLINDRICAL_Y(pos[1]);
1088
1089 data += 3;
1090 pos += 5;
1091 }
1092
1093 return rslt;
1094 }
1095
1096
1097 void cyl_scan_along_curve(prev, curr, cidx)
1098 double *prev;
1099 double *curr;
1100 int cidx;
1101 {
1102 double px, py;
1103 double cx, cy;
1104 double dx;
1105 double mx, my;
1106 EdgeXing *xing;
1107
1108 px = prev[3];
1109 cx = curr[3];
1110 py = prev[4];
1111 cy = curr[4];
1112 dx = cx - px;
1113
1114 if (dx > 0)
1115 {
1116 /* curr to the right of prev
1117 */
1118
1119 if (dx > ((2*M_PI) - dx))
1120 {
1121 /* vertical edge crossing to the left of prev
1122 */
1123
1124 /* find exit point (left edge) */
1125 mx = - M_PI;
1126 my = cyl_find_edge_xing(prev, curr);
1127
1128 /* scan from prev to exit point */
1129 scan(XPROJECT(px), YPROJECT(py), XPROJECT(mx), YPROJECT(my));
1130
1131 /* (mx, my) is an edge crossing (exit point) */
1132 xing = (EdgeXing *) extarr_next(edgexings);
1133 xing->type = XingTypeExit;
1134 xing->cidx = cidx;
1135 xing->x = mx;
1136 xing->y = my;
1137 xing->angle = 2; /* left edge */
1138
1139 /* scan from entry point (right edge) to curr */
1140 mx = M_PI;
1141 scan(XPROJECT(mx), YPROJECT(my), XPROJECT(cx), YPROJECT(cy));
1142
1143 /* (mx, my) is an edge crossing (entry point) */
1144 xing = (EdgeXing *) extarr_next(edgexings);
1145 xing->type = XingTypeEntry;
1146 xing->cidx = cidx;
1147 xing->x = mx;
1148 xing->y = my;
1149 xing->angle = 0; /* right edge */
1150 }
1151 else
1152 {
1153 /* no vertical edge crossing
1154 */
1155 scan(XPROJECT(px), YPROJECT(py), XPROJECT(cx), YPROJECT(cy));
1156 }
1157 }
1158 else
1159 {
1160 /* curr to the left of prev
1161 */
1162 dx = - dx;
1163
1164 if (dx > ((2*M_PI) - dx))
1165 {
1166 /* vertical edge crossing to the right of prev
1167 */
1168
1169 /* find exit point (right edge) */
1170 mx = M_PI;
1171 my = cyl_find_edge_xing(prev, curr);
1172
1173 /* scan from prev to exit point */
1174 scan(XPROJECT(px), YPROJECT(py), XPROJECT(mx), YPROJECT(my));
1175
1176 /* (mx, my) is an edge crossing (exit point) */
1177 xing = (EdgeXing *) extarr_next(edgexings);
1178 xing->type = XingTypeExit;
1179 xing->cidx = cidx;
1180 xing->x = mx;
1181 xing->y = my;
1182 xing->angle = 0; /* right edge */
1183
1184 /* scan from entry point (left edge) to curr */
1185 mx = - M_PI;
1186 scan(XPROJECT(mx), YPROJECT(my), XPROJECT(cx), YPROJECT(cy));
1187
1188 /* (mx, my) is an edge crossing (entry point) */
1189 xing = (EdgeXing *) extarr_next(edgexings);
1190 xing->type = XingTypeEntry;
1191 xing->cidx = cidx;
1192 xing->x = mx;
1193 xing->y = my;
1194 xing->angle = 2; /* left edge */
1195 }
1196 else
1197 {
1198 /* no vertical edge crossing
1199 */
1200 scan(XPROJECT(px), YPROJECT(py), XPROJECT(cx), YPROJECT(cy));
1201 }
1202 }
1203 }
1204
1205
1206 double cyl_find_edge_xing(prev, curr)
1207 double *prev;
1208 double *curr;
1209 {
1210 double ratio;
1211 double scale;
1212 double z1, z2;
1213 double rslt;
1214
1215 if (curr[0] != 0)
1216 {
1217 ratio = (prev[0] / curr[0]);
1218 z1 = prev[1] - (ratio * curr[1]);
1219 z2 = prev[2] - (ratio * curr[2]);
1220 }
1221 else
1222 {
1223 z1 = curr[1];
1224 z2 = curr[2];
1225 }
1226
1227 scale = ((z2 > 0) ? -1 : 1) / sqrt((z1*z1) + (z2*z2));
1228 z1 *= scale;
1229
1230 rslt = CYLINDRICAL_Y(z1);
1231
1232 return rslt;
1233 }
1234
1235
1236 void cyl_handle_xings()
1237 {
1238 int i;
1239 int nxings;
1240 EdgeXing *xings;
1241 EdgeXing *from;
1242 EdgeXing *to;
1243
1244 xings = (EdgeXing *) edgexings->body;
1245 nxings = edgexings->count;
1246
1247 assert((nxings % 2) == 0);
1248 qsort(xings, (unsigned) nxings, sizeof(EdgeXing), cyl_edgexing_comp);
1249
1250 if (xings[0].type == XingTypeExit)
1251 {
1252 for (i=0; i<nxings; i+=2)
1253 {
1254 from = &(xings[i]);
1255 to = &(xings[i+1]);
1256
1257 if ((from->type != XingTypeExit) ||
1258 (to->type != XingTypeEntry))
1259 xing_error(__FILE__, __LINE__, i, nxings, xings);
1260
1261 cyl_scan_edge(from, to);
1262 }
1263 }
1264 else
1265 {
1266 from = &(xings[nxings-1]);
1267 to = &(xings[0]);
1268
1269 if ((from->type != XingTypeExit) ||
1270 (to->type != XingTypeEntry) ||
1271 (from->angle < to->angle))
1272 xing_error(__FILE__, __LINE__, nxings-1, nxings, xings);
1273
1274 cyl_scan_edge(from, to);
1275
1276 for (i=1; i<(nxings-1); i+=2)
1277 {
1278 from = &(xings[i]);
1279 to = &(xings[i+1]);
1280
1281 if ((from->type != XingTypeExit) ||
1282 (to->type != XingTypeEntry))
1283 xing_error(__FILE__, __LINE__, i, nxings, xings);
1284
1285 cyl_scan_edge(from, to);
1286 }
1287 }
1288
1289 edgexings->count = 0;
1290 }
1291
1292
1293 void cyl_scan_edge(from, to)
1294 EdgeXing *from;
1295 EdgeXing *to;
1296 {
1297 int s0, s1, s_new;
1298 double x_0, x_1, x_new;
1299 double y_0, y_1, y_new;
1300
1301 s0 = from->angle;
1302 x_0 = XPROJECT(from->x);
1303 y_0 = YPROJECT(from->y);
1304
1305 s1 = to->angle;
1306 x_1 = XPROJECT(to->x);
1307 y_1 = YPROJECT(to->y);
1308
1309 while (s0 != s1)
1310 {
1311 switch (s0)
1312 {
1313 case 0:
1314 x_new = XPROJECT(M_PI);
1315 y_new = YPROJECT(BigNumber);
1316 s_new = 1;
1317 break;
1318
1319 case 1:
1320 x_new = XPROJECT(-M_PI);
1321 y_new = YPROJECT(BigNumber);
1322 s_new = 2;
1323 break;
1324
1325 case 2:
1326 x_new = XPROJECT(-M_PI);
1327 y_new = YPROJECT(-BigNumber);
1328 s_new = 3;
1329 break;
1330
1331 case 3:
1332 x_new = XPROJECT(M_PI);
1333 y_new = YPROJECT(-BigNumber);
1334 s_new = 0;
1335 break;
1336
1337 default:
1338 /* keep lint happy */
1339 x_new = 0;
1340 y_new = 0;
1341 s_new = 0;
1342 assert(0);
1343 }
1344
1345 scan(x_0, y_0, x_new, y_new);
1346 x_0 = x_new;
1347 y_0 = y_new;
1348 s0 = s_new;
1349 }
1350
1351 scan(x_0, y_0, x_1, y_1);
1352 }
1353
1354
1355 void xing_error(file, line, idx, nxings, xings)
1356 const char *file;
1357 int line;
1358 int idx;
1359 int nxings;
1360 EdgeXing *xings;
1361 {
1362 fflush(stdout);
1363 fprintf(stderr, "xearth %s: incorrect edgexing sequence (%s:%d)\n",
1364 VersionString, file, line);
1365 fprintf(stderr, " (cidx %d) (view_lat %.16f) (view_lon %.16f)\n",
1366 xings[idx].cidx, view_lat, view_lon);
1367 fprintf(stderr, "\n");
1368 exit(1);
1369 }
1370
1371
1372 void scan(x_0, y_0, x_1, y_1)
1373 double x_0, y_0;
1374 double x_1, y_1;
1375 {
1376 int i;
1377 int lo_y, hi_y;
1378 double x_value;
1379 double x_delta;
1380
1381 if (y_0 < y_1)
1382 {
1383 lo_y = ceil(y_0 - 0.5);
1384 hi_y = floor(y_1 - 0.5);
1385
1386 if (hi_y == (y_1 - 0.5))
1387 hi_y -= 1;
1388 }
1389 else
1390 {
1391 lo_y = ceil(y_1 - 0.5);
1392 hi_y = floor(y_0 - 0.5);
1393
1394 if (hi_y == (y_0 - 0.5))
1395 hi_y -= 1;
1396 }
1397
1398 if (lo_y < 0) lo_y = 0;
1399 if (hi_y >= hght) hi_y = hght-1;
1400
1401 if (lo_y > hi_y)
1402 return; /* no scan lines crossed */
1403
1404 if (lo_y < min_y) min_y = lo_y;
1405 if (hi_y > max_y) max_y = hi_y;
1406
1407 x_delta = (x_1 - x_0) / (y_1 - y_0);
1408 x_value = x_0 + x_delta * ((lo_y + 0.5) - y_0);
1409
1410 for (i=lo_y; i<=hi_y; i++)
1411 {
1412 *((double *) extarr_next(scanbuf[i])) = x_value;
1413 x_value += x_delta;
1414 }
1415 }
1416
1417
1418 void get_scanbits(val)
1419 int val;
1420 {
1421 int i, j;
1422 int lo_x, hi_x;
1423 unsigned nvals;
1424 double *vals;
1425 ScanBit *scanbit;
1426
1427 for (i=min_y; i<=max_y; i++)
1428 {
1429 vals = (double *) scanbuf[i]->body;
1430 nvals = scanbuf[i]->count;
1431 assert((nvals % 2) == 0);
1432 qsort(vals, nvals, sizeof(double), double_comp);
1433
1434 for (j=0; j<nvals; j+=2)
1435 {
1436 lo_x = ceil(vals[j] - 0.5);
1437 hi_x = floor(vals[j+1] - 0.5);
1438
1439 if (lo_x < 0) lo_x = 0;
1440 if (hi_x >= wdth) hi_x = wdth-1;
1441
1442 if (lo_x <= hi_x)
1443 {
1444 scanbit = (ScanBit *) extarr_next(scanbits);
1445 scanbit->y = i;
1446 scanbit->lo_x = lo_x;
1447 scanbit->hi_x = hi_x;
1448 scanbit->val = val;
1449 }
1450 }
1451
1452 scanbuf[i]->count = 0;
1453 }
1454 }