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

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

add base map rendering

File size: 24.2 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 public NodeTab nodes;
236 public EdgeTab edges;
237
238 public FtrMap features;
239 public FtrTab index;
240
241 public MapBounds bounds;
242
243 public long cref;
244 public long xref;
245 private Feature feature;
246 private Edge edge;
247
248 public S57map() {
249 nodes = new NodeTab(); // All nodes in map
250 edges = new EdgeTab(); // All edges in map
251 feature = new Feature(); // Current feature being built
252 features = new FtrMap(); // All features in map, grouped by type
253 index = new FtrTab(); // Feature look-up table
254 bounds = new MapBounds();
255 cref = 0x0000ffffffff0000L;// Compound reference generator
256 xref = 0x0fff000000000000L;// Extras reference generator
257 }
258
259 // S57 map building methods
260
261 public void newNode(long id, double lat, double lon, Nflag flag) {
262 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon), flag));
263 if (flag == Nflag.ANON) {
264 edge.nodes.add(id);
265 }
266 }
267
268 public void newNode(long id, double lat, double lon, double depth) {
269 nodes.put(id, new Dnode(Math.toRadians(lat), Math.toRadians(lon), depth));
270 }
271
272 public void newFeature(long id, Pflag p, long objl) {
273 feature = new Feature();
274 Obj obj = S57obj.decodeType(objl);
275 if (obj == Obj.BCNWTW)
276 obj = Obj.BCNLAT;
277 if (obj == Obj.BOYWTW)
278 obj = Obj.BOYLAT;
279 if (obj == Obj.C_AGGR)
280 feature.reln = Rflag.UNKN;
281 feature.geom = new Geom(p);
282 feature.type = obj;
283 if (obj != Obj.UNKOBJ) {
284 index.put(id, feature);
285 }
286 }
287
288 public void newObj(long id, int rind) {
289 Rflag r = Rflag.UNKN;
290 switch (rind) {
291 case 1:
292 r = Rflag.MASTER;
293 break;
294 case 2:
295 r = Rflag.SLAVE;
296 break;
297 case 3:
298 r = Rflag.UNKN;
299 break;
300 }
301 feature.rels.add(new Reln(id, r));
302 }
303
304 public void endFeature() {
305
306 }
307
308 public void newAtt(long attl, String atvl) {
309 Att att = S57att.decodeAttribute(attl);
310 AttVal<?> val = S57val.decodeValue(atvl, att);
311 feature.atts.put(att, val);
312 }
313
314 public void newPrim(long id, long ornt, long usag) {
315 feature.geom.elems.add(new Prim(id, (ornt != 2), (usag != 2)));
316 }
317
318 public void addConn(long id, int topi) {
319 if (topi == 1) {
320 edge.first = id;
321 } else {
322 edge.last = id;
323 }
324 }
325
326 public void newEdge(long id) {
327 edge = new Edge();
328 edges.put(id, edge);
329 }
330
331 public void endFile() {
332 for (long id : index.keySet()) {
333 Feature feature = index.get(id);
334 sortGeom(feature);
335 for (Reln reln : feature.rels) {
336 Feature rel = index.get(reln.id);
337 if (cmpGeoms(feature.geom, rel.geom)) {
338 switch (reln.reln) {
339 case SLAVE:
340 feature.reln = Rflag.MASTER;
341 break;
342 default:
343 feature.reln = Rflag.UNKN;
344 break;
345 }
346 rel.reln = reln.reln;
347 } else {
348 reln.reln = Rflag.UNKN;
349 }
350 }
351 }
352 for (long id : index.keySet()) {
353 Feature feature = index.get(id);
354 if (feature.reln == Rflag.UNKN) {
355 feature.reln = Rflag.MASTER;
356 }
357 if ((feature.type != Obj.UNKOBJ) && (feature.reln == Rflag.MASTER)) {
358 if (features.get(feature.type) == null) {
359 features.put(feature.type, new ArrayList<Feature>());
360 }
361 features.get(feature.type).add(feature);
362 }
363 }
364 for (long id : index.keySet()) {
365 Feature feature = index.get(id);
366 for (Reln reln : feature.rels) {
367 Feature rel = index.get(reln.id);
368 if (rel.reln == Rflag.SLAVE) {
369 if (feature.objs.get(rel.type) == null) {
370 feature.objs.put(rel.type, new ObjTab());
371 }
372 ObjTab tab = feature.objs.get(rel.type);
373 int ix = tab.size();
374 tab.put(ix, rel.atts);
375 }
376 }
377 }
378 }
379
380 // OSM map building methods
381
382 public void addNode(long id, double lat, double lon) {
383 Snode node = new Snode(Math.toRadians(lat), Math.toRadians(lon));
384 nodes.put(id, node);
385 feature = new Feature();
386 feature.reln = Rflag.UNKN;
387 feature.geom.prim = Pflag.POINT;
388 feature.geom.elems.add(new Prim(id));
389 edge = null;
390 }
391
392 public void addEdge(long id) {
393 feature = new Feature();
394 feature.reln = Rflag.UNKN;
395 feature.geom.prim = Pflag.LINE;
396 feature.geom.elems.add(new Prim(id));
397 edge = new Edge();
398 }
399
400 public void addToEdge(long node) {
401 if (edge.first == 0) {
402 edge.first = node;
403 nodes.get(node).flg = Nflag.CONN;
404 } else {
405 if (edge.last != 0) {
406 edge.nodes.add(edge.last);
407 }
408 edge.last = node;
409 }
410 }
411
412 public void addArea(long id) {
413 feature = new Feature();
414 feature.reln = Rflag.UNKN;
415 feature.geom.prim = Pflag.AREA;
416 edge = null;
417 }
418
419 public void addToArea(long id, boolean outer) {
420 feature.geom.elems.add(new Prim(id, outer));
421 }
422
423 public void addTag(String key, String val) {
424 feature.reln = Rflag.MASTER;
425 String subkeys[] = key.split(":");
426 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
427 Obj obj = S57obj.enumType(subkeys[1]);
428 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
429 int idx = 0;
430 Att att = Att.UNKATT;
431 try {
432 idx = Integer.parseInt(subkeys[2]);
433 if (subkeys.length == 4) {
434 att = s57.S57att.enumAttribute(subkeys[3], obj);
435 }
436 } catch (Exception e) {
437 att = S57att.enumAttribute(subkeys[2], obj);
438 }
439 ObjTab objs = feature.objs.get(obj);
440 if (objs == null) {
441 objs = new ObjTab();
442 feature.objs.put(obj, objs);
443 }
444 AttMap atts = objs.get(idx);
445 if (atts == null) {
446 atts = new AttMap();
447 objs.put(idx, atts);
448 }
449 AttVal<?> attval = S57val.convertValue(val, att);
450 if (attval.val != null)
451 atts.put(att, attval);
452 } else {
453 if (subkeys[1].equals("type")) {
454 obj = S57obj.enumType(val);
455 feature.type = obj;
456 ObjTab objs = feature.objs.get(obj);
457 if (objs == null) {
458 objs = new ObjTab();
459 feature.objs.put(obj, objs);
460 }
461 AttMap atts = objs.get(0);
462 if (atts == null) {
463 atts = new AttMap();
464 objs.put(0, atts);
465 }
466 } else {
467 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
468 if (att != Att.UNKATT) {
469 AttVal<?> attval = S57val.convertValue(val, att);
470 if (attval.val != null)
471 feature.atts.put(att, attval);
472 }
473 }
474 }
475 } else {
476 KeyVal kv = S57osm.OSMtag(key, val);
477 if (kv.obj != Obj.UNKOBJ) {
478 if (feature.type == Obj.UNKOBJ) {
479 feature.type = kv.obj;
480 }
481 ObjTab objs = feature.objs.get(kv.obj);
482 if (objs == null) {
483 objs = new ObjTab();
484 feature.objs.put(kv.obj, objs);
485 }
486 AttMap atts = objs.get(0);
487 if (atts == null) {
488 atts = new AttMap();
489 objs.put(0, atts);
490 }
491 if (kv.att != Att.UNKATT) {
492 atts.put(kv.att, new AttVal(kv.att, kv.conv, kv.val));
493 }
494 }
495 }
496 }
497
498 public void tagsDone(long id) {
499 switch (feature.geom.prim) {
500 case POINT:
501 Snode node = nodes.get(id);
502 if (node.flg != Nflag.CONN) {
503 node.flg = Nflag.ISOL;
504 }
505 break;
506 case LINE:
507 edges.put(id, edge);
508 nodes.get(edge.first).flg = Nflag.CONN;
509 nodes.get(edge.last).flg = Nflag.CONN;
510 if (edge.first == edge.last) {
511 feature.geom.prim = Pflag.AREA;
512 }
513 break;
514 case AREA:
515 break;
516 default:
517 break;
518 }
519 if ((sortGeom(feature)) && (feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
520 index.put(id, feature);
521 if (features.get(feature.type) == null) {
522 features.put(feature.type, new ArrayList<Feature>());
523 }
524 features.get(feature.type).add(feature);
525 feature.geom.centre = findCentroid(feature);
526 }
527 }
528
529 public void mapDone() {
530 ArrayList<Feature> coasts = new ArrayList<Feature>();
531 ArrayList<Feature> lands = new ArrayList<Feature>();
532 if (features.get(Obj.LNDARE) == null) {
533 features.put(Obj.LNDARE, new ArrayList<Feature>());
534 }
535 for (Feature feature : features.get(Obj.COALNE)) {
536 Feature land = new Feature();
537 land.type = Obj.LNDARE;
538 land.reln = Rflag.MASTER;
539 land.objs.put(Obj.LNDARE, new ObjTab());
540 if (feature.geom.prim == Pflag.AREA) {
541 land.geom = feature.geom;
542 features.get(Obj.LNDARE).add(land);
543 } else if (feature.geom.prim == Pflag.LINE) {
544 land.geom.prim = Pflag.LINE;
545 for (int i = 0; i < feature.geom.elems.size(); i++) {
546 land.geom.elems.add(feature.geom.elems.get(i));
547 }
548 coasts.add(land);
549 }
550 }
551 while (coasts.size() > 0) {
552 Feature land = coasts.remove(0);
553 Edge fedge = edges.get(land.geom.elems.get(0).id);
554 long first = fedge.first;
555 long last = edges.get(land.geom.elems.get(land.geom.elems.size() - 1).id).last;
556 if (coasts.size() > 0) {
557 boolean added = true;
558 while (added) {
559 added = false;
560 for (int i = 0; i < coasts.size(); i++) {
561 Feature coast = coasts.get(i);
562 Edge edge = edges.get(coast.geom.elems.get(0).id);
563 if (edge.first == last) {
564 land.geom.elems.add(coast.geom.elems.get(0));
565 last = edge.last;
566 coasts.remove(i--);
567 added = true;
568 } else if (edge.last == first) {
569 land.geom.elems.add(0, coast.geom.elems.get(0));
570 first = edge.first;
571 coasts.remove(i--);
572 added = true;
573 }
574 }
575 }
576 }
577 lands.add(land);
578 }
579 for (Feature land : lands) {
580 long first = edges.get(land.geom.elems.get(0).id).first;
581 long last = edges.get(land.geom.elems.get(land.geom.elems.size()-1).id).last;
582 Ext fext = outsideBounds(first);
583 Ext lext = outsideBounds(last);
584 Edge nedge = new Edge();
585 nedge.first = last;
586 nedge.last = first;
587 switch (lext) {
588 case N:
589 if ((lext == fext) || (fext != Ext.N)) {
590 nedge.nodes.add(1L);
591 if ((fext != Ext.W)) {
592 nedge.nodes.add(2L);
593 if ((fext != Ext.S)) {
594 nedge.nodes.add(3L);
595 if ((fext != Ext.W)) {
596 nedge.nodes.add(4L);
597 }
598 }
599 }
600 }
601 break;
602 case W:
603 if ((lext == fext) || (fext != Ext.W)) {
604 nedge.nodes.add(2L);
605 if ((fext != Ext.S)) {
606 nedge.nodes.add(3L);
607 if ((fext != Ext.E)) {
608 nedge.nodes.add(4L);
609 if ( (fext != Ext.N)) {
610 nedge.nodes.add(1L);
611 }
612 }
613 }
614 }
615 break;
616 case S:
617 if ((lext == fext) || (fext != Ext.S)) {
618 nedge.nodes.add(3L);
619 if ((fext != Ext.E)) {
620 nedge.nodes.add(4L);
621 if ((fext != Ext.N)) {
622 nedge.nodes.add(1L);
623 if ((fext != Ext.W)) {
624 nedge.nodes.add(2L);
625 }
626 }
627 }
628 }
629 break;
630 case E:
631 if ((lext == fext) || (fext != Ext.E)) {
632 nedge.nodes.add(4L);
633 if ((fext != Ext.N)) {
634 nedge.nodes.add(1L);
635 if ((fext != Ext.W)) {
636 nedge.nodes.add(2L);
637 if ((fext != Ext.S)) {
638 nedge.nodes.add(3L);
639 }
640 }
641 }
642 }
643 break;
644 default:
645 }
646 edges.put(++xref, nedge);
647 land.geom.elems.add(new Prim(xref));
648 sortGeom(land);
649 features.get(Obj.LNDARE).add(land);
650 }
651 return;
652 }
653
654 // Utility methods
655
656 enum Ext {I, N, W, S, E }
657 class Xnode {
658 double lat;
659 double lon;
660 Ext ext;
661 }
662 Ext outsideBounds(long ref) {
663 Snode node = nodes.get(ref);
664 if (node.lat >= bounds.maxlat) {
665 return Ext.N;
666 }
667 if (node.lat <= bounds.minlat) {
668 return Ext.S;
669 }
670 if (node.lon >= bounds.maxlon) {
671 return Ext.E;
672 }
673 if (node.lon <= bounds.minlon) {
674 return Ext.W;
675 }
676 return Ext.I;
677 }
678
679 public boolean sortGeom(Feature feature) {
680 Geom sort = new Geom(feature.geom.prim);
681 long first = 0;
682 long last = 0;
683 Comp comp = null;
684 boolean next = true;
685 feature.geom.length = 0;
686 feature.geom.area = 0;
687 if (feature.geom.prim == Pflag.POINT) {
688 return true;
689 } else {
690 int sweep = feature.geom.elems.size();
691 while (!feature.geom.elems.isEmpty()) {
692 Prim prim = feature.geom.elems.remove(0);
693 Edge edge = edges.get(prim.id);
694 if (edge == null) {
695 return false;
696 }
697 if (next == true) {
698 next = false;
699 if (prim.forward) {
700 first = edge.first;
701 last = edge.last;
702 } else {
703 first = edge.last;
704 last = edge.first;
705 }
706 sort.elems.add(prim);
707 if (prim.outer) {
708 sort.outers++;
709 } else {
710 sort.inners++;
711 }
712 comp = new Comp(cref++, 1);
713 sort.refs.add(comp);
714 } else {
715 if (prim.forward) {
716 if (edge.first == last) {
717 sort.elems.add(prim);
718 last = edge.last;
719 comp.size++;
720 } else if (edge.last == first) {
721 sort.elems.add(0, prim);
722 first = edge.first;
723 comp.size++;
724 } else {
725 feature.geom.elems.add(prim);
726 }
727 } else {
728 if (edge.last == last) {
729 sort.elems.add(prim);
730 last = edge.first;
731 comp.size++;
732 } else if (edge.first == first) {
733 sort.elems.add(0, prim);
734 first = edge.last;
735 comp.size++;
736 } else {
737 feature.geom.elems.add(prim);
738 }
739 }
740 }
741 if (--sweep == 0) {
742 next = true;
743 sweep = feature.geom.elems.size();
744 }
745 }
746 if ((sort.prim == Pflag.LINE) && (sort.outers == 1) && (sort.inners == 0) && (first == last)) {
747 sort.prim = Pflag.AREA;
748 }
749 feature.geom = sort;
750 }
751 if (feature.geom.prim == Pflag.AREA) {
752 ArrayList<Prim> outers = new ArrayList<Prim>();
753 ArrayList<Prim> inners = new ArrayList<Prim>();
754 for (Prim prim : feature.geom.elems) {
755 if (prim.outer) {
756 outers.add(prim);
757 } else {
758 inners.add(prim);
759 }
760 }
761 ArrayList<Prim> sorting = outers.size() > 0 ? outers : inners;
762 ArrayList<Prim> closed = null;
763 sort = new Geom(feature.geom.prim);
764 sort.outers = feature.geom.outers;
765 sort.inners = feature.geom.inners;
766 sort.refs = feature.geom.refs;
767 next = true;
768 while (!sorting.isEmpty()) {
769 Prim prim = sorting.remove(0);
770 Edge edge = edges.get(prim.id);
771 if (next == true) {
772 next = false;
773 closed = new ArrayList<Prim>();
774 closed.add(prim);
775 if (prim.forward) {
776 first = edge.first;
777 last = edge.last;
778 } else {
779 first = edge.last;
780 last = edge.first;
781 }
782 } else {
783 if (prim.forward) {
784 if (edge.first == last) {
785 last = edge.last;
786 closed.add(prim);
787 } else {
788 sorting.add(0, prim);
789 next = true;
790 }
791 } else {
792 if (edge.last == last) {
793 last = edge.first;
794 closed.add(prim);
795 } else {
796 sorting.add(0, prim);
797 next = true;
798 }
799 }
800 }
801 if (first == last) {
802 sort.elems.addAll(closed);
803 next = true;
804 }
805 if (sorting.isEmpty() && sorting == outers) {
806 sorting = inners;
807 next = true;
808 }
809 }
810 feature.geom = sort;
811 }
812 feature.geom.length = calcLength(feature.geom);
813 feature.geom.area = calcArea(feature.geom);
814 return true;
815 }
816
817 public boolean cmpGeoms (Geom g1, Geom g2) {
818 return ((g1.prim == g2.prim) && (g1.outers == g2.outers) && (g1.inners == g2.inners) && (g1.elems.size() == g2.elems.size()));
819 }
820
821 public class EdgeIterator {
822 Edge edge;
823 boolean forward;
824 ListIterator<Long> it;
825
826 public EdgeIterator(Edge e, boolean dir) {
827 edge = e;
828 forward = dir;
829 it = null;
830 }
831
832 public boolean hasNext() {
833 return (edge != null);
834 }
835
836 public long nextRef() {
837 long ref = 0;
838 if (forward) {
839 if (it == null) {
840 ref = edge.first;
841 it = edge.nodes.listIterator();
842 } else {
843 if (it.hasNext()) {
844 ref = it.next();
845 } else {
846 ref = edge.last;
847 edge = null;
848 }
849 }
850 } else {
851 if (it == null) {
852 ref = edge.last;
853 it = edge.nodes.listIterator(edge.nodes.size());
854 } else {
855 if (it.hasPrevious()) {
856 ref = it.previous();
857 } else {
858 ref = edge.first;
859 edge = null;
860 }
861 }
862 }
863 return ref;
864 }
865
866 public Snode next() {
867 return nodes.get(nextRef());
868 }
869 }
870
871 public class GeomIterator {
872 Geom geom;
873 Prim prim;
874 EdgeIterator eit;
875 ListIterator<S57map.Prim> ite;
876 ListIterator<Comp> itc;
877 Comp comp;
878 int ec;
879 long lastref;
880
881 public GeomIterator(Geom g) {
882 geom = g;
883 lastref = 0;
884 ite = geom.elems.listIterator();
885 itc = geom.refs.listIterator();
886 }
887
888 public boolean hasComp() {
889 return (itc.hasNext());
890 }
891
892 public long nextComp() {
893 comp = itc.next();
894 ec = comp.size;
895 lastref = 0;
896 return comp.ref;
897 }
898
899 public boolean hasEdge() {
900 return (ec > 0) && ite.hasNext();
901 }
902
903 public long nextEdge() {
904 prim = ite.next();
905 eit = new EdgeIterator(edges.get(prim.id), prim.forward);
906 ec--;
907 return prim.id;
908 }
909
910 public boolean hasNode() {
911 return (eit.hasNext());
912 }
913
914 public long nextRef(boolean all) {
915 long ref = eit.nextRef();
916 if (!all && (ref == lastref)) {
917 ref = eit.nextRef();
918 }
919 lastref = ref;
920 return ref;
921 }
922
923 public long nextRef() {
924 return nextRef(false);
925 }
926
927 public Snode next() {
928 return nodes.get(nextRef());
929 }
930 }
931
932 double signedArea(Geom geom) {
933 Snode node;
934 double lat, lon, llon, llat;
935 lat = lon = llon = llat = 0;
936 double sigma = 0;
937 GeomIterator git = new GeomIterator(geom);
938 if (git.hasComp()) {
939 git.nextComp();
940 while (git.hasEdge()) {
941 git.nextEdge();
942 while (git.hasNode()) {
943 node = git.next();
944 if (node != null) {
945 llon = lon;
946 llat = lat;
947 lat = node.lat;
948 lon = node.lon;
949 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
950 }
951 }
952 }
953 }
954 return sigma / 2.0;
955 }
956
957 public boolean handOfArea(Geom geom) {
958 return (signedArea(geom) < 0);
959 }
960
961 public double calcArea(Geom geom) {
962 return Math.abs(signedArea(geom)) * 3444 * 3444;
963 }
964
965 public double calcLength(Geom geom) {
966 Snode node;
967 double lat, lon, llon, llat;
968 lat = lon = llon = llat = 0;
969 double sigma = 0;
970 boolean first = true;
971 GeomIterator git = new GeomIterator(geom);
972 while (git.hasComp()) {
973 git.nextComp();
974 while (git.hasEdge()) {
975 git.nextEdge();
976 while (git.hasNode()) {
977 node = git.next();
978 if (first) {
979 first = false;
980 lat = node.lat;
981 lon = node.lon;
982 } else if (node != null) {
983 llat = lat;
984 llon = lon;
985 lat = node.lat;
986 lon = node.lon;
987 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
988 }
989 }
990 }
991 }
992 return sigma * 3444;
993 }
994
995 public Snode findCentroid(Feature feature) {
996 double lat, lon, slat, slon, llat, llon;
997 llat = llon = lat = lon = slat = slon = 0;
998 double sarc = 0;
999 boolean first = true;
1000 switch (feature.geom.prim) {
1001 case POINT:
1002 return nodes.get(feature.geom.elems.get(0).id);
1003 case LINE:
1004 GeomIterator git = new GeomIterator(feature.geom);
1005 while (git.hasComp()) {
1006 git.nextComp();
1007 while (git.hasEdge()) {
1008 git.nextEdge();
1009 while (git.hasNode()) {
1010 Snode node = git.next();
1011 lat = node.lat;
1012 lon = node.lon;
1013 if (first) {
1014 first = false;
1015 } else {
1016 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1017 }
1018 llat = lat;
1019 llon = lon;
1020 }
1021 }
1022 }
1023 double harc = sarc / 2;
1024 sarc = 0;
1025 first = true;
1026 git = new GeomIterator(feature.geom);
1027 while (git.hasComp()) {
1028 git.nextComp();
1029 while (git.hasEdge()) {
1030 git.nextEdge();
1031 while (git.hasNode()) {
1032 Snode node = git.next();
1033 lat = node.lat;
1034 lon = node.lon;
1035 if (first) {
1036 first = false;
1037 } else {
1038 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1039 if (sarc > harc)
1040 break;
1041 }
1042 harc -= sarc;
1043 llat = lat;
1044 llon = lon;
1045 }
1046 }
1047 }
1048 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
1049 case AREA:
1050 git = new GeomIterator(feature.geom);
1051 while (git.hasComp()) {
1052 git.nextComp();
1053 while (git.hasEdge()) {
1054 git.nextEdge();
1055 while (git.hasNode()) {
1056 Snode node = git.next();
1057 lat = node.lat;
1058 lon = node.lon;
1059 if (first) {
1060 first = false;
1061 } else {
1062 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
1063 slat += ((lat + llat) / 2 * arc);
1064 slon += ((lon + llon) / 2 * arc);
1065 sarc += arc;
1066 }
1067 llon = lon;
1068 llat = lat;
1069 }
1070 }
1071 }
1072 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
1073 default:
1074 }
1075 return null;
1076 }
1077
1078}
Note: See TracBrowser for help on using the repository browser.