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

Last change on this file since 31014 was 31014, checked in by malcolmh, 10 years ago

coast/land processing

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