source: osm/applications/editors/josm/plugins/smed2/src/s57/S57map.java@ 30215

Last change on this file since 30215 was 30215, checked in by malcolmh, 11 years ago

new model structure

File size: 14.5 KB
Line 
1/* Copyright 2013 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 enum Nflag {
24 ANON, // Edge inner nodes
25 ISOL, // Node not part of Edge
26 CONN, // Edge first and last nodes
27 DPTH // Sounding nodes
28 }
29
30 public class Snode { // All coordinates in map
31 public double lat; // Latitude
32 public double lon; // Longitude
33 public Nflag flg; // Role of node
34
35 public Snode() {
36 flg = Nflag.ANON;
37 lat = 0;
38 lon = 0;
39 }
40 public Snode(double ilat, double ilon) {
41 flg = Nflag.ANON;
42 lat = ilat;
43 lon = ilon;
44 }
45 public Snode(double ilat, double ilon, Nflag iflg) {
46 lat = ilat;
47 lon = ilon;
48 flg = iflg;
49 }
50 }
51
52 public class Dnode extends Snode { // All depth soundings
53 public double val; // Sounding value
54
55 public Dnode() {
56 flg = Nflag.DPTH;
57 lat = 0;
58 lon = 0;
59 val = 0;
60 }
61 public Dnode(double ilat, double ilon, double ival) {
62 flg = Nflag.DPTH;
63 lat = ilat;
64 lon = ilon;
65 val = ival;
66 }
67 }
68
69 public class Edge { // A polyline segment
70 public long first; // First CONN node
71 public long last; // Last CONN node
72 public ArrayList<Long> nodes; // Inner ANON nodes
73
74 public Edge() {
75 first = 0;
76 last = 0;
77 nodes = new ArrayList<Long>();
78 }
79 }
80
81 public enum Rflag {
82 UNKN, AGGR, MASTER, SLAVE, PEER
83 }
84
85 public class Reln {
86 public long id;
87 public Rflag reln;
88 public Reln(long i, Rflag r) {
89 id = i;
90 reln = r;
91 }
92 }
93
94 public class AttMap extends HashMap<Att, AttVal<?>> {
95 public AttMap() {
96 super();
97 }
98 }
99
100 public class RelTab extends ArrayList<Reln> {
101 public RelTab() {
102 super();
103 }
104 }
105
106 public class ObjTab extends HashMap<Integer, AttMap> {
107 public ObjTab() {
108 super();
109 }
110 }
111
112 public class ObjMap extends EnumMap<Obj, ObjTab> {
113 public ObjMap() {
114 super(Obj.class);
115 }
116 }
117
118 public class NodeTab extends HashMap<Long, Snode> {
119 public NodeTab() {
120 super();
121 }
122 }
123
124 public class EdgeTab extends HashMap<Long, Edge> {
125 public EdgeTab() {
126 super();
127 }
128 }
129
130 public class FtrMap extends EnumMap<Obj, ArrayList<Feature>> {
131 public FtrMap() {
132 super(Obj.class);
133 }
134 }
135
136 public class FtrTab extends HashMap<Long, Feature> {
137 public FtrTab() {
138 super();
139 }
140 }
141
142 public class Prim { // Spatial element
143 public long id; // ID
144 public boolean forward; // Direction of vector used (LINEs & AREAs)
145 public boolean outer; // Exterior/Interior boundary (AREAs)
146 public Prim() {
147 id = 0; forward = true; outer = true;
148 }
149 public Prim(long i) {
150 id = i; forward = true; outer = true;
151 }
152 public Prim(long i, boolean o) {
153 id = i; forward = true; outer = o;
154 }
155 public Prim(long i, boolean f, boolean o) {
156 id = i; forward = f; outer = o;
157 }
158 }
159
160 public enum Pflag {
161 NOSP, POINT, LINE, AREA
162 }
163
164 public class Geom { // Geometric structure of feature
165 public Pflag prim; // Geometry type
166 public ArrayList<Prim> elems; // Ordered list of elements
167 public Geom(Pflag p) {
168 prim = p;
169 elems = new ArrayList<Prim>();
170 }
171 }
172
173 public class Feature {
174 public Rflag reln; // Relationship status
175 public Geom geom; // Geometry data
176 public Obj type; // Feature type
177 public AttMap atts; // Feature attributes
178 public RelTab rels; // Related objects
179 public ObjMap objs; // Slave objects
180 public double area; // Area of feature
181 public double length; // Length of feature
182 public Snode centre; // Centre of feature
183
184 Feature() {
185 reln = Rflag.UNKN;
186 geom = new Geom(Pflag.NOSP);
187 type = Obj.C_AGGR;
188 atts = new AttMap();
189 rels = new RelTab();
190 objs = new ObjMap();
191 area = 0;
192 length = 0;
193 centre = new Snode();
194 }
195 }
196
197 public NodeTab nodes;
198 public EdgeTab edges;
199
200 public FtrMap features;
201 public FtrTab index;
202
203 private Feature feature;
204 private Edge edge;
205
206 public S57map() {
207 nodes = new NodeTab(); // All nodes in map
208 edges = new EdgeTab(); // All edges in map
209 feature = new Feature(); // Current feature being built
210 features = new FtrMap(); // All features in map, grouped by type
211 index = new FtrTab(); // Feature look-up table
212 }
213
214 // S57 map building methods
215
216 public void newNode(long id, double lat, double lon, Nflag flag) {
217 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon), flag));
218 if (flag == Nflag.ANON) {
219 edge.nodes.add(id);
220 }
221 }
222
223 public void newNode(long id, double lat, double lon, double depth) {
224 nodes.put(id, new Dnode(Math.toRadians(lat), Math.toRadians(lon), depth));
225 }
226
227 public void newFeature(long id, Pflag p, long objl) {
228 feature = new Feature();
229 Obj obj = S57obj.decodeType(objl);
230 if (obj == Obj.C_AGGR) {
231 feature.reln = Rflag.AGGR;
232 }
233 feature.geom = new Geom(p);
234 feature.type = obj;
235 index.put(id, feature);
236 }
237
238 public void newObj(long id, int rind) {
239 Rflag r = Rflag.AGGR;
240 switch (rind) {
241 case 1:
242 r = Rflag.MASTER;
243 break;
244 case 2:
245 r = Rflag.SLAVE;
246 break;
247 case 3:
248 r = Rflag.PEER;
249 break;
250 }
251 feature.rels.add(new Reln(id, r));
252 }
253
254 public void endFeature() {
255
256 }
257
258 public void newAtt(long attl, String atvl) {
259 Att att = S57att.decodeAttribute(attl);
260 AttVal<?> val = S57val.decodeValue(atvl, att);
261 feature.atts.put(att, val);
262 }
263
264 public void newPrim(long id, long ornt, long usag) {
265 feature.geom.elems.add(new Prim(id, (ornt != 2), (usag != 2)));
266 }
267
268 public void addConn(long id, int topi) {
269 if (topi == 1) {
270 edge.first = id;
271 } else {
272 edge.last = id;
273 }
274 }
275
276 public void newEdge(long id) {
277 edge = new Edge();
278 edges.put(id, edge);
279 }
280
281 public void endFile() {
282 for (long id : index.keySet()) {
283 Feature feature = index.get(id);
284 for (Reln rel : feature.rels) {
285 Feature reln = index.get(rel.id);
286 reln.reln = rel.reln;
287 if (feature.reln == Rflag.UNKN) {
288 switch (rel.reln) {
289 case MASTER:
290 feature.reln = Rflag.AGGR;
291 break;
292 case SLAVE:
293 feature.reln = Rflag.MASTER;
294 case PEER:
295 feature.reln = Rflag.PEER;
296 break;
297 default:
298 break;
299 }
300 }
301 ObjTab tab = feature.objs.get(reln.type);
302 if (tab == null) {
303 tab = new ObjTab();
304 feature.objs.put(reln.type, tab);
305 }
306 tab.put(tab.size(), reln.atts);
307 }
308 }
309 for (long id : index.keySet()) {
310 Feature feature = index.get(id);
311 if (feature.reln == Rflag.UNKN) {
312 feature.reln = Rflag.MASTER;
313 }
314 if ((feature.type != Obj.UNKOBJ) && ((feature.reln == Rflag.MASTER) || (feature.reln == Rflag.PEER))) {
315 if (features.get(feature.type) == null) {
316 features.put(feature.type, new ArrayList<Feature>());
317 }
318 features.get(feature.type).add(feature);
319 }
320 }
321 }
322
323 // OSM map building methods
324
325 public void addNode(long id, double lat, double lon) {
326 Snode node = new Snode(Math.toRadians(lat), Math.toRadians(lon));
327 nodes.put(id, node);
328 feature = new Feature();
329 feature.reln = Rflag.AGGR;
330 feature.geom.prim = Pflag.POINT;
331 feature.geom.elems.add(new Prim(id));
332 edge = null;
333 }
334
335 public void addEdge(long id) {
336 feature = new Feature();
337 feature.reln = Rflag.AGGR;
338 feature.geom.prim = Pflag.LINE;
339 feature.geom.elems.add(new Prim(id));
340 edge = new Edge();
341 }
342
343 public void addToEdge(long node) {
344 if (edge.first == 0) {
345 edge.first = node;
346 nodes.get(node).flg = Nflag.CONN;
347 } else {
348 if (edge.last != 0) {
349 edge.nodes.add(edge.last);
350 }
351 edge.last = node;
352 }
353 }
354
355 public void addArea(long id) {
356 feature = new Feature();
357 feature.reln = Rflag.AGGR;
358 feature.geom.prim = Pflag.AREA;
359 feature.geom.elems.add(new Prim(id));
360 edge = null;
361 }
362
363 public void addToArea(long id, boolean outer) {
364 feature.geom.elems.add(new Prim(id, outer));
365 }
366
367 public void addTag(String key, String val) {
368 String subkeys[] = key.split(":");
369 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
370 Obj obj = S57obj.enumType(subkeys[1]);
371 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
372 int idx = 0;
373 Att att = Att.UNKATT;
374 try {
375 idx = Integer.parseInt(subkeys[2]);
376 if (subkeys.length == 4) {
377 att = s57.S57att.enumAttribute(subkeys[3], obj);
378 }
379 } catch (Exception e) {
380 att = S57att.enumAttribute(subkeys[2], obj);
381 }
382 ObjTab items = feature.objs.get(obj);
383 if (items == null) {
384 items = new ObjTab();
385 feature.objs.put(obj, items);
386 }
387 AttMap atts = items.get(idx);
388 if (atts == null) {
389 atts = new AttMap();
390 items.put(idx, atts);
391 }
392 AttVal<?> attval = S57val.convertValue(val, att);
393 if (attval.val != null)
394 atts.put(att, attval);
395 } else {
396 if (subkeys[1].equals("type")) {
397 feature.type = S57obj.enumType(val);
398 if (feature.objs.get(feature.type) == null) {
399 feature.objs.put(feature.type, new ObjTab());
400 }
401 } else {
402 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
403 if (att != Att.UNKATT) {
404 AttVal<?> attval = S57val.convertValue(val, att);
405 if (attval.val != null)
406 feature.atts.put(att, attval);
407 }
408 }
409 }
410 }
411 }
412
413 public void tagsDone(long id) {
414 switch (feature.geom.prim) {
415 case POINT:
416 Snode node = nodes.get(id);
417 if (node.flg != Nflag.CONN) {
418 node.flg = Nflag.ISOL;
419 }
420 feature.length = 0;
421 feature.area = 0;
422 break;
423 case LINE:
424 edges.put(id, edge);
425 nodes.get(edge.first).flg = Nflag.CONN;
426 nodes.get(edge.last).flg = Nflag.CONN;
427 feature.length = calcLength(feature.geom);
428 if (edge.first == edge.last) {
429 feature.geom.prim = Pflag.AREA;
430 feature.area = calcArea(feature.geom);
431 } else {
432 feature.area = 0;
433 }
434 break;
435 case AREA:
436 break;
437 default:
438 break;
439 }
440 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
441 index.put(id, feature);
442 if (features.get(feature.type) == null) {
443 features.put(feature.type, new ArrayList<Feature>());
444 }
445 feature.centre = findCentroid(feature);
446 features.get(feature.type).add(feature);
447 }
448 }
449
450 // Utility methods
451
452 public class EdgeIterator {
453 Edge edge;
454 boolean forward;
455 ListIterator<Long> it;
456
457 public EdgeIterator(Edge e, boolean dir) {
458 edge = e;
459 forward = dir;
460 it = null;
461 }
462
463 public boolean hasNext() {
464 return (edge != null);
465 }
466
467 public Snode next() {
468 long ref = 0;
469 if (forward) {
470 if (it == null) {
471 ref = edge.first;
472 it = edge.nodes.listIterator();
473 } else {
474 if (it.hasNext()) {
475 ref = it.next();
476 } else {
477 ref = edge.last;
478 edge = null;
479 }
480 }
481 } else {
482 if (it == null) {
483 ref = edge.last;
484 it = edge.nodes.listIterator(edge.nodes.size());
485 } else {
486 if (it.hasPrevious()) {
487 ref = it.previous();
488 } else {
489 ref = edge.first;
490 edge = null;
491 }
492 }
493 }
494 return nodes.get(ref);
495 }
496 }
497
498 public class GeomIterator {
499 Geom geom;
500 Prim prim;
501 EdgeIterator eit;
502 ListIterator<S57map.Prim> it;
503 Snode first;
504 Snode last;
505
506 public GeomIterator(Geom g) {
507 geom = g;
508 eit = null;
509 first = last = null;
510 if ((geom.prim != Pflag.NOSP) && (geom.prim != Pflag.POINT)) {
511 it = geom.elems.listIterator();
512 } else {
513 it = null;
514 }
515 }
516
517 public boolean hasMore() {
518 return (it != null) && it.hasNext();
519 }
520
521 public boolean more() {
522 if ((it != null) && it.hasNext()) {
523 prim = it.next();
524 return prim.outer;
525 }
526 return false;
527 }
528
529 public boolean hasNext() {
530 return (first != last) && (eit.hasNext() || it.hasNext());
531 }
532
533 public Snode next() {
534 if (!eit.hasNext()) {
535 if (it.hasNext()) {
536 prim = it.next();
537 eit = new EdgeIterator(edges.get(prim.id), prim.forward);
538 } else {
539 return null;
540 }
541 }
542 last = eit.next();
543 return last;
544 }
545 }
546
547 double signedArea(Geom geom) {
548 Snode node;
549 double lat, lon, llon, llat;
550 lat = lon = llon = llat = 0;
551 double sigma = 0;
552/* BoundIterator it = new BoundIterator(bound);
553 while (it.hasNext()) {
554 llon = lon;
555 llat = lat;
556 node = it.next();
557 lat = node.lat;
558 lon = node.lon;
559 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
560 }
561*/ return sigma / 2.0;
562 }
563
564 public boolean handOfArea(Geom geom) {
565 return (signedArea(geom) < 0);
566 }
567
568 public double calcArea(Geom geom) {
569 return Math.abs(signedArea(geom)) * 3444 * 3444;
570 }
571
572 public double calcLength(Geom geom) {
573/* Snode node;
574 double lat, lon, llon, llat;
575 lat = lon = llon = llat = 0;
576 double sigma = 0;
577 BoundIterator it = new BoundIterator(bound);
578 if (it.hasNext()) {
579 node = it.next();
580 lat = node.lat;
581 lon = node.lon;
582 while (it.hasNext()) {
583 llon = lon;
584 llat = lat;
585 node = it.next();
586 lat = node.lat;
587 lon = node.lon;
588 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
589 }
590 }
591 return sigma * 3444;
592*/ return 0;
593 }
594
595 public Snode findCentroid(Feature feature) {
596/* double lat, lon, slat, slon, llat, llon;
597 llat = llon = lat = lon = slat = slon = 0;
598 double sarc = 0;
599 boolean first = true;
600 switch (feature.geom.prim) {
601 case POINT:
602 return nodes.get(feature.geom);
603 case LINE:
604 Edge edge = edges.get(feature.geom);
605 EdgeIterator eit = new EdgeIterator(edge, true);
606 while (eit.hasNext()) {
607 Snode node = eit.next();
608 lat = node.lat;
609 lon = node.lon;
610 if (first) {
611 first = false;
612 } else {
613 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
614 }
615 llat = lat;
616 llon = lon;
617 }
618 double harc = sarc / 2;
619 sarc = 0;
620 first = true;
621 eit = new EdgeIterator(edge, true);
622 while (eit.hasNext()) {
623 Snode node = eit.next();
624 lat = node.lat;
625 lon = node.lon;
626 if (first) {
627 first = false;
628 } else {
629 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
630 if (sarc > harc)
631 break;
632 }
633 harc -= sarc;
634 llat = lat;
635 llon = lon;
636 }
637 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
638 case AREA:
639 Bound bound = areas.get(feature.geom).get(0);
640 BoundIterator bit = new BoundIterator(bound);
641 while (bit.hasNext()) {
642 Snode node = bit.next();
643 lat = node.lat;
644 lon = node.lon;
645 if (first) {
646 first = false;
647 } else {
648 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
649 slat += ((lat + llat) / 2 * arc);
650 slon += ((lon + llon) / 2 * arc);
651 sarc += arc;
652 }
653 llon = lon;
654 llat = lat;
655 }
656 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
657 default:
658 }
659*/ return null;
660 }
661
662}
Note: See TracBrowser for help on using the repository browser.