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

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

[seachart] bug fixes

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