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

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

[seachart] bug fix

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