source: osm/applications/editors/josm/plugins/smed2/src/seamap/SeaMap.java@ 29826

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

save

File size: 11.6 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 seamap;
11
12import java.util.*;
13
14import s57.S57att;
15import s57.S57att.Att;
16import s57.S57obj;
17import s57.S57obj.*;
18import s57.S57val;
19import s57.S57val.*;
20
21public class SeaMap {
22
23 public enum Nflag {
24 ANON, ISOL, CONN
25 }
26
27 public class Snode {
28 public double lat;
29 public double lon;
30 public Nflag flg;
31
32 public Snode() {
33 flg = Nflag.ANON;
34 lat = 0;
35 lon = 0;
36 }
37
38 public Snode(double ilat, double ilon) {
39 flg = Nflag.ANON;
40 lat = ilat;
41 lon = ilon;
42 }
43
44 public Snode(double ilat, double ilon, Nflag iflg) {
45 lat = ilat;
46 lon = ilon;
47 flg = iflg;
48 }
49 }
50
51 public class Edge {
52 public boolean forward;
53 public long first;
54 public long last;
55 public ArrayList<Long> nodes;
56
57 public Edge() {
58 forward = true;
59 first = 0;
60 last = 0;
61 nodes = new ArrayList<Long>();
62 }
63 }
64
65 public class Side {
66 Edge edge;
67 boolean forward;
68
69 public Side(Edge iedge, boolean ifwd) {
70 edge = iedge;
71 forward = ifwd;
72 }
73 }
74
75 public class Bound {
76 public boolean outer;
77 ArrayList<Side> sides;
78
79 public Bound() {
80 outer = true;
81 sides = new ArrayList<Side>();
82 }
83
84 public Bound(Side iside, boolean irole) {
85 outer = irole;
86 sides = new ArrayList<Side>();
87 sides.add(iside);
88 }
89 }
90
91 public class Area extends ArrayList<Bound> {
92 public Area() {
93 super();
94 }
95 }
96
97 public class AttItem {
98 Conv conv;
99 Object val;
100
101 AttItem(Conv iconv, Object ival) {
102 conv = iconv;
103 val = ival;
104 }
105 }
106
107 public class AttMap extends EnumMap<Att, AttItem> {
108 public AttMap() {
109 super(Att.class);
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 NodeTab extends HashMap<Long, Snode> {
126 public NodeTab() {
127 super();
128 }
129 }
130
131 public class EdgeTab extends HashMap<Long, Edge> {
132 public EdgeTab() {
133 super();
134 }
135 }
136
137 public class AreaTab extends HashMap<Long, Area> {
138 public AreaTab() {
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 enum Fflag {
156 UNKN, POINT, LINE, AREA
157 }
158
159 public class Feature {
160 public Fflag flag;
161 public long refs;
162 public Obj type;
163 public AttMap atts;
164 public ObjMap objs;
165 public double area;
166 public double length;
167 public Snode centre;
168
169 Feature() {
170 flag = Fflag.UNKN;
171 refs = 0;
172 type = Obj.UNKOBJ;
173 atts = new AttMap();
174 objs = new ObjMap();
175 area = 0;
176 length = 0;
177 centre = new Snode();
178 }
179 }
180
181 public NodeTab nodes;
182 public EdgeTab edges;
183 public AreaTab areas;
184
185 public FtrMap features;
186 public FtrTab index;
187
188 private Feature feature;
189 private Edge edge;
190 private ArrayList<Long> outers;
191 private ArrayList<Long> inners;
192
193 public class EdgeIterator {
194 Edge edge;
195 boolean forward;
196 ListIterator<Long> it;
197
198 public EdgeIterator(Edge iedge, boolean dir) {
199 edge = iedge;
200 forward = dir;
201 it = null;
202 }
203
204 public boolean hasNext() {
205 return (edge != null);
206 }
207
208 public Snode next() {
209 long ref = 0;
210 if (forward) {
211 if (it == null) {
212 ref = edge.first;
213 it = edge.nodes.listIterator();
214 } else {
215 if (it.hasNext()) {
216 ref = it.next();
217 } else {
218 ref = edge.last;
219 edge = null;
220 }
221 }
222 } else {
223 if (it == null) {
224 ref = edge.last;
225 it = edge.nodes.listIterator(edge.nodes.size());
226 } else {
227 if (it.hasPrevious()) {
228 ref = it.previous();
229 } else {
230 ref = edge.first;
231 edge = null;
232 }
233 }
234 }
235 return nodes.get(ref);
236 }
237 }
238
239 public class BoundIterator {
240 Bound bound;
241 Side side;
242 ListIterator<Side> sit;
243 EdgeIterator eit;
244
245 public BoundIterator(Bound ibound) {
246 bound = ibound;
247 sit = bound.sides.listIterator();
248 if (sit.hasNext()) {
249 side = sit.next();
250 eit = new EdgeIterator(side.edge, side.forward);
251 } else {
252 side = null;
253 }
254 }
255
256 public boolean hasNext() {
257 return (side != null) && ((sit.hasNext()) || (eit.hasNext()));
258 }
259
260 public Snode next() {
261 Snode node = null;
262 if (side != null) {
263 if (eit.hasNext()) {
264 node = eit.next();
265 } else {
266 if (sit.hasNext()) {
267 side = sit.next();
268 eit = new EdgeIterator(side.edge, side.forward);
269 node = eit.next();
270 } else {
271 side = null;
272 }
273 }
274 }
275 return node;
276 }
277 }
278
279 public SeaMap() {
280 nodes = new NodeTab();
281 edges = new EdgeTab();
282 areas = new AreaTab();
283 feature = new Feature();
284 features = new FtrMap();
285 index = new FtrTab();
286 }
287
288 public void addNode(long id, double lat, double lon) {
289 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon)));
290 feature = new Feature();
291 feature.refs = id;
292 feature.flag = Fflag.POINT;
293 edge = null;
294 }
295
296 public void addEdge(long id) {
297 feature = new Feature();
298 feature.refs = id;
299 feature.flag = Fflag.LINE;
300 edge = new Edge();
301 }
302
303 public void addToEdge(long node) {
304 if (edge.first == 0) {
305 edge.first = node;
306 } else {
307 if (edge.last != 0) {
308 edge.nodes.add(edge.last);
309 }
310 edge.last = node;
311 }
312 }
313
314 public void addArea(long id) {
315 feature = new Feature();
316 feature.refs = id;
317 feature.flag = Fflag.AREA;
318 outers = new ArrayList<Long>();
319 inners = new ArrayList<Long>();
320 edge = null;
321 }
322
323 public void addToArea(long id, boolean outer) {
324 if (outer) {
325 outers.add(id);
326 } else {
327 inners.add(id);
328 }
329 }
330
331 public void addTag(String key, String val) {
332 String subkeys[] = key.split(":");
333 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
334 Obj obj = S57obj.enumType(subkeys[1]);
335 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
336 int idx = 0;
337 Att att = Att.UNKATT;
338 try {
339 idx = Integer.parseInt(subkeys[2]);
340 if (subkeys.length == 4) {
341 att = s57.S57att.enumAttribute(subkeys[3], obj);
342 }
343 } catch (Exception e) {
344 att = S57att.enumAttribute(subkeys[2], obj);
345 }
346 ObjTab items = feature.objs.get(obj);
347 if (items == null) {
348 items = new ObjTab();
349 feature.objs.put(obj, items);
350 }
351 AttMap atts = items.get(idx);
352 if (atts == null) {
353 atts = new AttMap();
354 items.put(idx, atts);
355 }
356 AttVal attval = S57val.convertValue(val, att);
357 if (attval.val != null)
358 atts.put(att, new AttItem(attval.conv, attval.val));
359 } else {
360 if (subkeys[1].equals("type")) {
361 feature.type = S57obj.enumType(val);
362 } else {
363 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
364 if (att != Att.UNKATT) {
365 AttVal attval = S57val.convertValue(val, att);
366 if (attval.val != null)
367 feature.atts.put(att, new AttItem(attval.conv, attval.val));
368 }
369 }
370 }
371 }
372 }
373
374 public void tagsDone(long id) {
375 switch (feature.flag) {
376 case POINT:
377 Snode node = nodes.get(id);
378 if (node.flg != Nflag.CONN) {
379 node.flg = Nflag.ISOL;
380 }
381 feature.length = 0;
382 feature.area = 0;
383 break;
384 case LINE:
385 edges.put(id, edge);
386 nodes.get(edge.first).flg = Nflag.CONN;
387 nodes.get(edge.last).flg = Nflag.CONN;
388 Bound ebound = (new Bound(new Side(edge, edge.forward), true));
389 feature.length = calcLength(ebound);
390 if (edge.first == edge.last) {
391 feature.flag = Fflag.AREA;
392 Area area = new Area();
393 area.add(ebound);
394 feature.area = calcArea(ebound);
395 areas.put(id, area);
396 } else {
397 feature.area = 0;
398 }
399 break;
400 case AREA:
401 Bound bound = null;
402 Area area = new Area();
403 ArrayList<Long> role = outers;
404 while (role != null) {
405 while (!role.isEmpty()) {
406 Edge edge = edges.get(role.remove(0));
407 long node1 = edge.first;
408 long node2 = edge.last;
409 bound = new Bound(new Side(edge, edge.forward), (role == outers));
410 if (node1 != node2) {
411 for (ListIterator<Long> it = role.listIterator(0); it.hasNext();) {
412 Edge nedge = edges.get(it.next());
413 if (nedge.first == node2) {
414 bound.sides.add(new Side(nedge, true));
415 it.remove();
416 if (nedge.last == node2)
417 break;
418 } else if (nedge.last == node2) {
419 bound.sides.add(new Side(nedge, false));
420 it.remove();
421 if (nedge.first == node2)
422 break;
423 }
424 }
425 }
426 area.add(bound);
427 }
428 if (role == outers) {
429 feature.length = calcLength(bound);
430 feature.area = calcArea(bound);
431 role = inners;
432 } else {
433 role = null;
434 }
435 }
436 areas.put(id, area);
437 break;
438 }
439 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
440 index.put(id, feature);
441 if (features.get(feature.type) == null) {
442 features.put(feature.type, new ArrayList<Feature>());
443 }
444 feature.centre = findCentroid(feature);
445 features.get(feature.type).add(feature);
446 }
447 }
448
449 double signedArea(Bound bound) {
450 Snode node;
451 double lat, lon, llon, llat;
452 lat = lon = llon = llat = 0;
453 double sigma = 0;
454 BoundIterator it = new BoundIterator(bound);
455 while (it.hasNext()) {
456 llon = lon;
457 llat = lat;
458 node = it.next();
459 lat = node.lat;
460 lon = node.lon;
461 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
462 }
463 return sigma / 2.0;
464 }
465
466 public boolean handOfArea(Bound bound) {
467 return (signedArea(bound) < 0);
468 }
469
470 public double calcArea(Bound bound) {
471 return Math.abs(signedArea(bound)) * 3444 * 3444;
472 }
473
474 public double calcLength(Bound bound) {
475 Snode node;
476 double lat, lon, llon, llat;
477 lat = lon = llon = llat = 0;
478 double sigma = 0;
479 BoundIterator it = new BoundIterator(bound);
480 if (it.hasNext()) {
481 node = it.next();
482 lat = node.lat;
483 lon = node.lon;
484 while (it.hasNext()) {
485 llon = lon;
486 llat = lat;
487 node = it.next();
488 lat = node.lat;
489 lon = node.lon;
490 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
491 }
492 }
493 return sigma * 3444;
494 }
495
496 public Snode findCentroid(Feature feature) {
497 double lat, lon, slat, slon, llat, llon;
498 llat = llon = lat = lon = slat = slon = 0;
499 double sarc = 0;
500 boolean first = true;
501 switch (feature.flag) {
502 case POINT:
503 return nodes.get(feature.refs);
504 case LINE:
505 Edge edge = edges.get(feature.refs);
506 EdgeIterator eit = new EdgeIterator(edge, true);
507 while (eit.hasNext()) {
508 Snode node = eit.next();
509 lat = node.lat;
510 lon = node.lon;
511 if (first) {
512 first = false;
513 } else {
514 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
515 }
516 llat = lat;
517 llon = lon;
518 }
519 double harc = sarc / 2;
520 sarc = 0;
521 first = true;
522 eit = new EdgeIterator(edge, true);
523 while (eit.hasNext()) {
524 Snode node = eit.next();
525 lat = node.lat;
526 lon = node.lon;
527 if (first) {
528 first = false;
529 } else {
530 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
531 if (sarc > harc)
532 break;
533 }
534 harc -= sarc;
535 llat = lat;
536 llon = lon;
537 }
538 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
539 case AREA:
540 Bound bound = areas.get(feature.refs).get(0);
541 BoundIterator bit = new BoundIterator(bound);
542 while (bit.hasNext()) {
543 Snode node = bit.next();
544 lat = node.lat;
545 lon = node.lon;
546 if (first) {
547 first = false;
548 } else {
549 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
550 slat += (lat * arc);
551 slon += (lon * arc);
552 sarc += arc;
553 }
554 llon = lon;
555 llat = lat;
556 }
557 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
558 }
559 return null;
560 }
561
562}
Note: See TracBrowser for help on using the repository browser.