source: osm/applications/editors/josm/plugins/seachart/src/s57/S57map.java@ 31027

Last change on this file since 31027 was 31027, checked in by malcolmh, 11 years ago

add base map rendering

File size: 24.4 KB
Line 
1/* Copyright 2014 Malcolm Herring
2 *
3 * This is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License.
6 *
7 * For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
8 */
9
10package s57;
11
12import java.util.*;
13
14import s57.S57obj;
15import s57.S57obj.*;
16import s57.S57att;
17import s57.S57att.*;
18import s57.S57val;
19import s57.S57val.*;
20import s57.S57osm;
21import s57.S57osm.*;
22
23public class S57map {
24
25 public class MapBounds {
26 public double minlat;
27 public double minlon;
28 public double maxlat;
29 public double maxlon;
30 public MapBounds() {
31 minlat = Math.toRadians(90);
32 minlon = Math.toRadians(180);
33 maxlat = Math.toRadians(-90);
34 maxlon = Math.toRadians(-180);
35 }
36 }
37
38 public enum Nflag {
39 ANON, // Edge inner nodes
40 ISOL, // Node not part of Edge
41 CONN, // Edge first and last nodes
42 DPTH // Sounding nodes
43 }
44
45 public class Snode { // All coordinates in map
46 public double lat; // Latitude
47 public double lon; // Longitude
48 public Nflag flg; // Role of node
49
50 public Snode() {
51 flg = Nflag.ANON;
52 lat = 0;
53 lon = 0;
54 }
55 public Snode(double ilat, double ilon) {
56 flg = Nflag.ANON;
57 lat = ilat;
58 lon = ilon;
59 }
60 public Snode(double ilat, double ilon, Nflag iflg) {
61 lat = ilat;
62 lon = ilon;
63 flg = iflg;
64 }
65 }
66
67 public class Dnode extends Snode { // All depth soundings
68 public double val; // Sounding value
69
70 public Dnode() {
71 flg = Nflag.DPTH;
72 lat = 0;
73 lon = 0;
74 val = 0;
75 }
76 public Dnode(double ilat, double ilon, double ival) {
77 flg = Nflag.DPTH;
78 lat = ilat;
79 lon = ilon;
80 val = ival;
81 }
82 }
83
84 public class Edge { // A polyline segment
85 public long first; // First CONN node
86 public long last; // Last CONN node
87 public ArrayList<Long> nodes; // Inner ANON nodes
88
89 public Edge() {
90 first = 0;
91 last = 0;
92 nodes = new ArrayList<Long>();
93 }
94 }
95
96 public enum Rflag {
97 UNKN, MASTER, SLAVE
98 }
99
100 public class Reln {
101 public long id;
102 public Rflag reln;
103 public Reln(long i, Rflag r) {
104 id = i;
105 reln = r;
106 }
107 }
108
109 public class RelTab extends ArrayList<Reln> {
110 public RelTab() {
111 super();
112 }
113 }
114
115 public class ObjTab extends HashMap<Integer, AttMap> {
116 public ObjTab() {
117 super();
118 }
119 }
120
121 public class ObjMap extends EnumMap<Obj, ObjTab> {
122 public ObjMap() {
123 super(Obj.class);
124 }
125 }
126
127 public class AttMap extends HashMap<Att, AttVal<?>> {
128 public AttMap() {
129 super();
130 }
131 }
132
133 public class NodeTab extends HashMap<Long, Snode> {
134 public NodeTab() {
135 super();
136 }
137 }
138
139 public class EdgeTab extends HashMap<Long, Edge> {
140 public EdgeTab() {
141 super();
142 }
143 }
144
145 public class FtrMap extends EnumMap<Obj, ArrayList<Feature>> {
146 public FtrMap() {
147 super(Obj.class);
148 }
149 }
150
151 public class FtrTab extends HashMap<Long, Feature> {
152 public FtrTab() {
153 super();
154 }
155 }
156
157 public class Prim { // Spatial element
158 public long id; // Snode ID for POINTs, Edge ID for LINEs & AREAs)
159 public boolean forward; // Direction of vector used (LINEs & AREAs)
160 public boolean outer; // Exterior/Interior boundary (AREAs)
161 public Prim() {
162 id = 0; forward = true; outer = true;
163 }
164 public Prim(long i) {
165 id = i; forward = true; outer = true;
166 }
167 public Prim(long i, boolean o) {
168 id = i; forward = true; outer = o;
169 }
170 public Prim(long i, boolean f, boolean o) {
171 id = i; forward = f; outer = o;
172 }
173 }
174
175 public class Comp { // Composite spatial element
176 public long ref; // ID of Comp
177 public int size; // Number of Prims in this Comp
178 public Comp(long r, int s) {
179 ref = r;
180 size = s;
181 }
182 }
183
184 public enum Pflag {
185 NOSP, POINT, LINE, AREA
186 }
187
188 public class Geom { // Geometric structure of feature
189 public Pflag prim; // Geometry type
190 public ArrayList<Prim> elems; // Ordered list of elements
191 public int outers; // Number of outers
192 public int inners; // Number of inners
193 public ArrayList<Comp> refs; // Ordered list of compounds
194 public double area; // Area of feature
195 public double length; // Length of feature
196 public Snode centre; // Centre of feature
197 public Geom(Pflag p) {
198 prim = p;
199 elems = new ArrayList<Prim>();
200 outers = inners = 0;
201 refs = new ArrayList<Comp>();
202 area = 0;
203 length = 0;
204 centre = new Snode();
205 }
206 }
207
208 public class Feature {
209 public Rflag reln; // Relationship status
210 public Geom geom; // Geometry data
211 public Obj type; // Feature type
212 public AttMap atts; // Feature attributes
213 public RelTab rels; // Related objects
214 public ObjMap objs; // Slave object attributes
215
216 Feature() {
217 reln = Rflag.UNKN;
218 geom = new Geom(Pflag.NOSP);
219 type = Obj.UNKOBJ;
220 atts = new AttMap();
221 rels = new RelTab();
222 objs = new ObjMap();
223 }
224 }
225
226 class OSMtag {
227 String key;
228 String val;
229 OSMtag(String k, String v) {
230 key = k;
231 val = v;
232 }
233 }
234
235 ArrayList<OSMtag> osmtags;
236
237 public NodeTab nodes;
238 public EdgeTab edges;
239
240 public FtrMap features;
241 public FtrTab index;
242
243 public MapBounds bounds;
244
245 public long cref;
246 public long xref;
247 private Feature feature;
248 private Edge edge;
249
250 public S57map() {
251 nodes = new NodeTab(); // All nodes in map
252 edges = new EdgeTab(); // All edges in map
253 feature = new Feature(); // Current feature being built
254 features = new FtrMap(); // All features in map, grouped by type
255 index = new FtrTab(); // Feature look-up table
256 bounds = new MapBounds();
257 cref = 0x0000ffffffff0000L;// Compound reference generator
258 xref = 0x0fff000000000000L;// Extras reference generator
259 }
260
261 // S57 map building methods
262
263 public void newNode(long id, double lat, double lon, Nflag flag) {
264 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon), flag));
265 if (flag == Nflag.ANON) {
266 edge.nodes.add(id);
267 }
268 }
269
270 public void newNode(long id, double lat, double lon, double depth) {
271 nodes.put(id, new Dnode(Math.toRadians(lat), Math.toRadians(lon), depth));
272 }
273
274 public void newFeature(long id, Pflag p, long objl) {
275 feature = new Feature();
276 Obj obj = S57obj.decodeType(objl);
277 if (obj == Obj.BCNWTW)
278 obj = Obj.BCNLAT;
279 if (obj == Obj.BOYWTW)
280 obj = Obj.BOYLAT;
281 if (obj == Obj.C_AGGR)
282 feature.reln = Rflag.UNKN;
283 feature.geom = new Geom(p);
284 feature.type = obj;
285 if (obj != Obj.UNKOBJ) {
286 index.put(id, feature);
287 }
288 }
289
290 public void newObj(long id, int rind) {
291 Rflag r = Rflag.UNKN;
292 switch (rind) {
293 case 1:
294 r = Rflag.MASTER;
295 break;
296 case 2:
297 r = Rflag.SLAVE;
298 break;
299 case 3:
300 r = Rflag.UNKN;
301 break;
302 }
303 feature.rels.add(new Reln(id, r));
304 }
305
306 public void endFeature() {
307
308 }
309
310 public void newAtt(long attl, String atvl) {
311 Att att = S57att.decodeAttribute(attl);
312 AttVal<?> val = S57val.decodeValue(atvl, att);
313 feature.atts.put(att, val);
314 }
315
316 public void newPrim(long id, long ornt, long usag) {
317 feature.geom.elems.add(new Prim(id, (ornt != 2), (usag != 2)));
318 }
319
320 public void addConn(long id, int topi) {
321 if (topi == 1) {
322 edge.first = id;
323 } else {
324 edge.last = id;
325 }
326 }
327
328 public void newEdge(long id) {
329 edge = new Edge();
330 edges.put(id, edge);
331 }
332
333 public void endFile() {
334 for (long id : index.keySet()) {
335 Feature feature = index.get(id);
336 sortGeom(feature);
337 for (Reln reln : feature.rels) {
338 Feature rel = index.get(reln.id);
339 if (cmpGeoms(feature.geom, rel.geom)) {
340 switch (reln.reln) {
341 case SLAVE:
342 feature.reln = Rflag.MASTER;
343 break;
344 default:
345 feature.reln = Rflag.UNKN;
346 break;
347 }
348 rel.reln = reln.reln;
349 } else {
350 reln.reln = Rflag.UNKN;
351 }
352 }
353 }
354 for (long id : index.keySet()) {
355 Feature feature = index.get(id);
356 if (feature.reln == Rflag.UNKN) {
357 feature.reln = Rflag.MASTER;
358 }
359 if ((feature.type != Obj.UNKOBJ) && (feature.reln == Rflag.MASTER)) {
360 if (features.get(feature.type) == null) {
361 features.put(feature.type, new ArrayList<Feature>());
362 }
363 features.get(feature.type).add(feature);
364 }
365 }
366 for (long id : index.keySet()) {
367 Feature feature = index.get(id);
368 for (Reln reln : feature.rels) {
369 Feature rel = index.get(reln.id);
370 if (rel.reln == Rflag.SLAVE) {
371 if (feature.objs.get(rel.type) == null) {
372 feature.objs.put(rel.type, new ObjTab());
373 }
374 ObjTab tab = feature.objs.get(rel.type);
375 int ix = tab.size();
376 tab.put(ix, rel.atts);
377 }
378 }
379 }
380 }
381
382 // OSM map building methods
383
384 public void addNode(long id, double lat, double lon) {
385 Snode node = new Snode(Math.toRadians(lat), Math.toRadians(lon));
386 nodes.put(id, node);
387 feature = new Feature();
388 feature.reln = Rflag.UNKN;
389 feature.geom.prim = Pflag.POINT;
390 feature.geom.elems.add(new Prim(id));
391 osmtags = new ArrayList<OSMtag>();
392 edge = null;
393 }
394
395 public void addEdge(long id) {
396 feature = new Feature();
397 feature.reln = Rflag.UNKN;
398 feature.geom.prim = Pflag.LINE;
399 feature.geom.elems.add(new Prim(id));
400 osmtags = new ArrayList<OSMtag>();
401 edge = new Edge();
402 }
403
404 public void addToEdge(long node) {
405 if (edge.first == 0) {
406 edge.first = node;
407 nodes.get(node).flg = Nflag.CONN;
408 } else {
409 if (edge.last != 0) {
410 edge.nodes.add(edge.last);
411 }
412 edge.last = node;
413 }
414 }
415
416 public void addArea(long id) {
417 feature = new Feature();
418 feature.reln = Rflag.UNKN;
419 feature.geom.prim = Pflag.AREA;
420 osmtags = new ArrayList<OSMtag>();
421 edge = null;
422 }
423
424 public void addToArea(long id, boolean outer) {
425 feature.geom.elems.add(new Prim(id, outer));
426 }
427
428 public void addTag(String key, String val) {
429 feature.reln = Rflag.MASTER;
430 String subkeys[] = key.split(":");
431 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
432 Obj obj = S57obj.enumType(subkeys[1]);
433 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
434 int idx = 0;
435 Att att = Att.UNKATT;
436 try {
437 idx = Integer.parseInt(subkeys[2]);
438 if (subkeys.length == 4) {
439 att = s57.S57att.enumAttribute(subkeys[3], obj);
440 }
441 } catch (Exception e) {
442 att = S57att.enumAttribute(subkeys[2], obj);
443 }
444 ObjTab objs = feature.objs.get(obj);
445 if (objs == null) {
446 objs = new ObjTab();
447 feature.objs.put(obj, objs);
448 }
449 AttMap atts = objs.get(idx);
450 if (atts == null) {
451 atts = new AttMap();
452 objs.put(idx, atts);
453 }
454 AttVal<?> attval = S57val.convertValue(val, att);
455 if (attval.val != null)
456 atts.put(att, attval);
457 } else {
458 if (subkeys[1].equals("type")) {
459 obj = S57obj.enumType(val);
460 feature.type = obj;
461 ObjTab objs = feature.objs.get(obj);
462 if (objs == null) {
463 objs = new ObjTab();
464 feature.objs.put(obj, objs);
465 }
466 AttMap atts = objs.get(0);
467 if (atts == null) {
468 atts = new AttMap();
469 objs.put(0, atts);
470 }
471 } else {
472 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
473 if (att != Att.UNKATT) {
474 AttVal<?> attval = S57val.convertValue(val, att);
475 if (attval.val != null)
476 feature.atts.put(att, attval);
477 }
478 }
479 }
480 } else {
481 osmtags.add(new OSMtag(key, val));
482 }
483 }
484
485 public void tagsDone(long id) {
486 for (OSMtag tag : osmtags) {
487 KeyVal kv = S57osm.OSMtag(tag.key, tag.val);
488 if (kv.obj != Obj.UNKOBJ) {
489 if (feature.type == Obj.UNKOBJ) {
490 feature.type = kv.obj;
491 }
492 ObjTab objs = feature.objs.get(kv.obj);
493 if (objs == null) {
494 objs = new ObjTab();
495 feature.objs.put(kv.obj, objs);
496 }
497 AttMap atts = objs.get(0);
498 if (atts == null) {
499 atts = new AttMap();
500 objs.put(0, atts);
501 }
502 if (kv.att != Att.UNKATT) {
503 atts.put(kv.att, new AttVal(kv.att, kv.conv, kv.val));
504 }
505 break;
506 }
507 }
508 switch (feature.geom.prim) {
509 case POINT:
510 Snode node = nodes.get(id);
511 if (node.flg != Nflag.CONN) {
512 node.flg = Nflag.ISOL;
513 }
514 break;
515 case LINE:
516 edges.put(id, edge);
517 nodes.get(edge.first).flg = Nflag.CONN;
518 nodes.get(edge.last).flg = Nflag.CONN;
519 if (edge.first == edge.last) {
520 feature.geom.prim = Pflag.AREA;
521 }
522 break;
523 case AREA:
524 break;
525 default:
526 break;
527 }
528 if ((sortGeom(feature)) && (feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
529 index.put(id, feature);
530 if (features.get(feature.type) == null) {
531 features.put(feature.type, new ArrayList<Feature>());
532 }
533 features.get(feature.type).add(feature);
534 feature.geom.centre = findCentroid(feature);
535 }
536 }
537
538 public void mapDone() {
539 ArrayList<Feature> coasts = new ArrayList<Feature>();
540 ArrayList<Feature> lands = new ArrayList<Feature>();
541 if (features.get(Obj.LNDARE) == null) {
542 features.put(Obj.LNDARE, new ArrayList<Feature>());
543 }
544 for (Feature feature : features.get(Obj.COALNE)) {
545 Feature land = new Feature();
546 land.type = Obj.LNDARE;
547 land.reln = Rflag.MASTER;
548 land.objs.put(Obj.LNDARE, new ObjTab());
549 if (feature.geom.prim == Pflag.AREA) {
550 land.geom = feature.geom;
551 features.get(Obj.LNDARE).add(land);
552 } else if (feature.geom.prim == Pflag.LINE) {
553 land.geom.prim = Pflag.LINE;
554 for (int i = 0; i < feature.geom.elems.size(); i++) {
555 land.geom.elems.add(feature.geom.elems.get(i));
556 }
557 coasts.add(land);
558 }
559 }
560 while (coasts.size() > 0) {
561 Feature land = coasts.remove(0);
562 Edge fedge = edges.get(land.geom.elems.get(0).id);
563 long first = fedge.first;
564 long last = edges.get(land.geom.elems.get(land.geom.elems.size() - 1).id).last;
565 if (coasts.size() > 0) {
566 boolean added = true;
567 while (added) {
568 added = false;
569 for (int i = 0; i < coasts.size(); i++) {
570 Feature coast = coasts.get(i);
571 Edge edge = edges.get(coast.geom.elems.get(0).id);
572 if (edge.first == last) {
573 land.geom.elems.add(coast.geom.elems.get(0));
574 last = edge.last;
575 coasts.remove(i--);
576 added = true;
577 } else if (edge.last == first) {
578 land.geom.elems.add(0, coast.geom.elems.get(0));
579 first = edge.first;
580 coasts.remove(i--);
581 added = true;
582 }
583 }
584 }
585 }
586 lands.add(land);
587 }
588 for (Feature land : lands) {
589 long first = edges.get(land.geom.elems.get(0).id).first;
590 long last = edges.get(land.geom.elems.get(land.geom.elems.size()-1).id).last;
591 Ext fext = outsideBounds(first);
592 Ext lext = outsideBounds(last);
593 Edge nedge = new Edge();
594 nedge.first = last;
595 nedge.last = first;
596 switch (lext) {
597 case N:
598 if ((lext == fext) || (fext != Ext.N)) {
599 nedge.nodes.add(1L);
600 if ((fext != Ext.W)) {
601 nedge.nodes.add(2L);
602 if ((fext != Ext.S)) {
603 nedge.nodes.add(3L);
604 if ((fext != Ext.W)) {
605 nedge.nodes.add(4L);
606 }
607 }
608 }
609 }
610 break;
611 case W:
612 if ((lext == fext) || (fext != Ext.W)) {
613 nedge.nodes.add(2L);
614 if ((fext != Ext.S)) {
615 nedge.nodes.add(3L);
616 if ((fext != Ext.E)) {
617 nedge.nodes.add(4L);
618 if ( (fext != Ext.N)) {
619 nedge.nodes.add(1L);
620 }
621 }
622 }
623 }
624 break;
625 case S:
626 if ((lext == fext) || (fext != Ext.S)) {
627 nedge.nodes.add(3L);
628 if ((fext != Ext.E)) {
629 nedge.nodes.add(4L);
630 if ((fext != Ext.N)) {
631 nedge.nodes.add(1L);
632 if ((fext != Ext.W)) {
633 nedge.nodes.add(2L);
634 }
635 }
636 }
637 }
638 break;
639 case E:
640 if ((lext == fext) || (fext != Ext.E)) {
641 nedge.nodes.add(4L);
642 if ((fext != Ext.N)) {
643 nedge.nodes.add(1L);
644 if ((fext != Ext.W)) {
645 nedge.nodes.add(2L);
646 if ((fext != Ext.S)) {
647 nedge.nodes.add(3L);
648 }
649 }
650 }
651 }
652 break;
653 default:
654 }
655 edges.put(++xref, nedge);
656 land.geom.elems.add(new Prim(xref));
657 sortGeom(land);
658 features.get(Obj.LNDARE).add(land);
659 }
660 return;
661 }
662
663 // Utility methods
664
665 enum Ext {I, N, W, S, E }
666 class Xnode {
667 double lat;
668 double lon;
669 Ext ext;
670 }
671 Ext outsideBounds(long ref) {
672 Snode node = nodes.get(ref);
673 if (node.lat >= bounds.maxlat) {
674 return Ext.N;
675 }
676 if (node.lat <= bounds.minlat) {
677 return Ext.S;
678 }
679 if (node.lon >= bounds.maxlon) {
680 return Ext.E;
681 }
682 if (node.lon <= bounds.minlon) {
683 return Ext.W;
684 }
685 return Ext.I;
686 }
687
688 public boolean sortGeom(Feature feature) {
689 Geom sort = new Geom(feature.geom.prim);
690 long first = 0;
691 long last = 0;
692 Comp comp = null;
693 boolean next = true;
694 feature.geom.length = 0;
695 feature.geom.area = 0;
696 if (feature.geom.prim == Pflag.POINT) {
697 return true;
698 } else {
699 int sweep = feature.geom.elems.size();
700 while (!feature.geom.elems.isEmpty()) {
701 Prim prim = feature.geom.elems.remove(0);
702 Edge edge = edges.get(prim.id);
703 if (edge == null) {
704 return false;
705 }
706 if (next == true) {
707 next = false;
708 if (prim.forward) {
709 first = edge.first;
710 last = edge.last;
711 } else {
712 first = edge.last;
713 last = edge.first;
714 }
715 sort.elems.add(prim);
716 if (prim.outer) {
717 sort.outers++;
718 } else {
719 sort.inners++;
720 }
721 comp = new Comp(cref++, 1);
722 sort.refs.add(comp);
723 } else {
724 if (prim.forward) {
725 if (edge.first == last) {
726 sort.elems.add(prim);
727 last = edge.last;
728 comp.size++;
729 } else if (edge.last == first) {
730 sort.elems.add(0, prim);
731 first = edge.first;
732 comp.size++;
733 } else {
734 feature.geom.elems.add(prim);
735 }
736 } else {
737 if (edge.last == last) {
738 sort.elems.add(prim);
739 last = edge.first;
740 comp.size++;
741 } else if (edge.first == first) {
742 sort.elems.add(0, prim);
743 first = edge.last;
744 comp.size++;
745 } else {
746 feature.geom.elems.add(prim);
747 }
748 }
749 }
750 if (--sweep == 0) {
751 next = true;
752 sweep = feature.geom.elems.size();
753 }
754 }
755 if ((sort.prim == Pflag.LINE) && (sort.outers == 1) && (sort.inners == 0) && (first == last)) {
756 sort.prim = Pflag.AREA;
757 }
758 feature.geom = sort;
759 }
760 if (feature.geom.prim == Pflag.AREA) {
761 ArrayList<Prim> outers = new ArrayList<Prim>();
762 ArrayList<Prim> inners = new ArrayList<Prim>();
763 for (Prim prim : feature.geom.elems) {
764 if (prim.outer) {
765 outers.add(prim);
766 } else {
767 inners.add(prim);
768 }
769 }
770 ArrayList<Prim> sorting = outers.size() > 0 ? outers : inners;
771 ArrayList<Prim> closed = null;
772 sort = new Geom(feature.geom.prim);
773 sort.outers = feature.geom.outers;
774 sort.inners = feature.geom.inners;
775 sort.refs = feature.geom.refs;
776 next = true;
777 while (!sorting.isEmpty()) {
778 Prim prim = sorting.remove(0);
779 Edge edge = edges.get(prim.id);
780 if (next == true) {
781 next = false;
782 closed = new ArrayList<Prim>();
783 closed.add(prim);
784 if (prim.forward) {
785 first = edge.first;
786 last = edge.last;
787 } else {
788 first = edge.last;
789 last = edge.first;
790 }
791 } else {
792 if (prim.forward) {
793 if (edge.first == last) {
794 last = edge.last;
795 closed.add(prim);
796 } else {
797 sorting.add(0, prim);
798 next = true;
799 }
800 } else {
801 if (edge.last == last) {
802 last = edge.first;
803 closed.add(prim);
804 } else {
805 sorting.add(0, prim);
806 next = true;
807 }
808 }
809 }
810 if (first == last) {
811 sort.elems.addAll(closed);
812 next = true;
813 }
814 if (sorting.isEmpty() && sorting == outers) {
815 sorting = inners;
816 next = true;
817 }
818 }
819 feature.geom = sort;
820 }
821 feature.geom.length = calcLength(feature.geom);
822 feature.geom.area = calcArea(feature.geom);
823 return true;
824 }
825
826 public boolean cmpGeoms (Geom g1, Geom g2) {
827 return ((g1.prim == g2.prim) && (g1.outers == g2.outers) && (g1.inners == g2.inners) && (g1.elems.size() == g2.elems.size()));
828 }
829
830 public class EdgeIterator {
831 Edge edge;
832 boolean forward;
833 ListIterator<Long> it;
834
835 public EdgeIterator(Edge e, boolean dir) {
836 edge = e;
837 forward = dir;
838 it = null;
839 }
840
841 public boolean hasNext() {
842 return (edge != null);
843 }
844
845 public long nextRef() {
846 long ref = 0;
847 if (forward) {
848 if (it == null) {
849 ref = edge.first;
850 it = edge.nodes.listIterator();
851 } else {
852 if (it.hasNext()) {
853 ref = it.next();
854 } else {
855 ref = edge.last;
856 edge = null;
857 }
858 }
859 } else {
860 if (it == null) {
861 ref = edge.last;
862 it = edge.nodes.listIterator(edge.nodes.size());
863 } else {
864 if (it.hasPrevious()) {
865 ref = it.previous();
866 } else {
867 ref = edge.first;
868 edge = null;
869 }
870 }
871 }
872 return ref;
873 }
874
875 public Snode next() {
876 return nodes.get(nextRef());
877 }
878 }
879
880 public class GeomIterator {
881 Geom geom;
882 Prim prim;
883 EdgeIterator eit;
884 ListIterator<S57map.Prim> ite;
885 ListIterator<Comp> itc;
886 Comp comp;
887 int ec;
888 long lastref;
889
890 public GeomIterator(Geom g) {
891 geom = g;
892 lastref = 0;
893 ite = geom.elems.listIterator();
894 itc = geom.refs.listIterator();
895 }
896
897 public boolean hasComp() {
898 return (itc.hasNext());
899 }
900
901 public long nextComp() {
902 comp = itc.next();
903 ec = comp.size;
904 lastref = 0;
905 return comp.ref;
906 }
907
908 public boolean hasEdge() {
909 return (ec > 0) && ite.hasNext();
910 }
911
912 public long nextEdge() {
913 prim = ite.next();
914 eit = new EdgeIterator(edges.get(prim.id), prim.forward);
915 ec--;
916 return prim.id;
917 }
918
919 public boolean hasNode() {
920 return (eit.hasNext());
921 }
922
923 public long nextRef(boolean all) {
924 long ref = eit.nextRef();
925 if (!all && (ref == lastref)) {
926 ref = eit.nextRef();
927 }
928 lastref = ref;
929 return ref;
930 }
931
932 public long nextRef() {
933 return nextRef(false);
934 }
935
936 public Snode next() {
937 return nodes.get(nextRef());
938 }
939 }
940
941 double signedArea(Geom geom) {
942 Snode node;
943 double lat, lon, llon, llat;
944 lat = lon = llon = llat = 0;
945 double sigma = 0;
946 GeomIterator git = new GeomIterator(geom);
947 if (git.hasComp()) {
948 git.nextComp();
949 while (git.hasEdge()) {
950 git.nextEdge();
951 while (git.hasNode()) {
952 node = git.next();
953 if (node != null) {
954 llon = lon;
955 llat = lat;
956 lat = node.lat;
957 lon = node.lon;
958 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
959 }
960 }
961 }
962 }
963 return sigma / 2.0;
964 }
965
966 public boolean handOfArea(Geom geom) {
967 return (signedArea(geom) < 0);
968 }
969
970 public double calcArea(Geom geom) {
971 return Math.abs(signedArea(geom)) * 3444 * 3444;
972 }
973
974 public double calcLength(Geom geom) {
975 Snode node;
976 double lat, lon, llon, llat;
977 lat = lon = llon = llat = 0;
978 double sigma = 0;
979 boolean first = true;
980 GeomIterator git = new GeomIterator(geom);
981 while (git.hasComp()) {
982 git.nextComp();
983 while (git.hasEdge()) {
984 git.nextEdge();
985 while (git.hasNode()) {
986 node = git.next();
987 if (first) {
988 first = false;
989 lat = node.lat;
990 lon = node.lon;
991 } else if (node != null) {
992 llat = lat;
993 llon = lon;
994 lat = node.lat;
995 lon = node.lon;
996 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
997 }
998 }
999 }
1000 }
1001 return sigma * 3444;
1002 }
1003
1004 public Snode findCentroid(Feature feature) {
1005 double lat, lon, slat, slon, llat, llon;
1006 llat = llon = lat = lon = slat = slon = 0;
1007 double sarc = 0;
1008 boolean first = true;
1009 switch (feature.geom.prim) {
1010 case POINT:
1011 return nodes.get(feature.geom.elems.get(0).id);
1012 case LINE:
1013 GeomIterator git = new GeomIterator(feature.geom);
1014 while (git.hasComp()) {
1015 git.nextComp();
1016 while (git.hasEdge()) {
1017 git.nextEdge();
1018 while (git.hasNode()) {
1019 Snode node = git.next();
1020 lat = node.lat;
1021 lon = node.lon;
1022 if (first) {
1023 first = false;
1024 } else {
1025 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1026 }
1027 llat = lat;
1028 llon = lon;
1029 }
1030 }
1031 }
1032 double harc = sarc / 2;
1033 sarc = 0;
1034 first = true;
1035 git = new GeomIterator(feature.geom);
1036 while (git.hasComp()) {
1037 git.nextComp();
1038 while (git.hasEdge()) {
1039 git.nextEdge();
1040 while (git.hasNode()) {
1041 Snode node = git.next();
1042 lat = node.lat;
1043 lon = node.lon;
1044 if (first) {
1045 first = false;
1046 } else {
1047 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1048 if (sarc > harc)
1049 break;
1050 }
1051 harc -= sarc;
1052 llat = lat;
1053 llon = lon;
1054 }
1055 }
1056 }
1057 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
1058 case AREA:
1059 git = new GeomIterator(feature.geom);
1060 while (git.hasComp()) {
1061 git.nextComp();
1062 while (git.hasEdge()) {
1063 git.nextEdge();
1064 while (git.hasNode()) {
1065 Snode node = git.next();
1066 lat = node.lat;
1067 lon = node.lon;
1068 if (first) {
1069 first = false;
1070 } else {
1071 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1072 slat += ((lat + llat) / 2 * arc);
1073 slon += ((lon + llon) / 2 * arc);
1074 sarc += arc;
1075 }
1076 llon = lon;
1077 llat = lat;
1078 }
1079 }
1080 }
1081 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
1082 default:
1083 }
1084 return null;
1085 }
1086
1087}
Note: See TracBrowser for help on using the repository browser.