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

Last change on this file since 31063 was 31063, checked in by malcolmh, 9 years ago

[SeaChart] update

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