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

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

Multipolygon processing

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