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

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

save

File size: 11.7 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 public Conv conv;
99 public 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 if (feature.objs.get(feature.type) == null) {
363 feature.objs.put(feature.type, new ObjTab());
364 }
365 } else {
366 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
367 if (att != Att.UNKATT) {
368 AttVal attval = S57val.convertValue(val, att);
369 if (attval.val != null)
370 feature.atts.put(att, new AttItem(attval.conv, attval.val));
371 }
372 }
373 }
374 }
375 }
376
377 public void tagsDone(long id) {
378 switch (feature.flag) {
379 case POINT:
380 Snode node = nodes.get(id);
381 if (node.flg != Nflag.CONN) {
382 node.flg = Nflag.ISOL;
383 }
384 feature.length = 0;
385 feature.area = 0;
386 break;
387 case LINE:
388 edges.put(id, edge);
389 nodes.get(edge.first).flg = Nflag.CONN;
390 nodes.get(edge.last).flg = Nflag.CONN;
391 Bound ebound = (new Bound(new Side(edge, edge.forward), true));
392 feature.length = calcLength(ebound);
393 if (edge.first == edge.last) {
394 feature.flag = Fflag.AREA;
395 Area area = new Area();
396 area.add(ebound);
397 feature.area = calcArea(ebound);
398 areas.put(id, area);
399 } else {
400 feature.area = 0;
401 }
402 break;
403 case AREA:
404 Bound bound = null;
405 Area area = new Area();
406 ArrayList<Long> role = outers;
407 while (role != null) {
408 while (!role.isEmpty()) {
409 Edge edge = edges.get(role.remove(0));
410 long node1 = edge.first;
411 long node2 = edge.last;
412 bound = new Bound(new Side(edge, edge.forward), (role == outers));
413 if (node1 != node2) {
414 for (ListIterator<Long> it = role.listIterator(0); it.hasNext();) {
415 Edge nedge = edges.get(it.next());
416 if (nedge.first == node2) {
417 bound.sides.add(new Side(nedge, true));
418 it.remove();
419 if (nedge.last == node2)
420 break;
421 } else if (nedge.last == node2) {
422 bound.sides.add(new Side(nedge, false));
423 it.remove();
424 if (nedge.first == node2)
425 break;
426 }
427 }
428 }
429 area.add(bound);
430 }
431 if (role == outers) {
432 feature.length = calcLength(bound);
433 feature.area = calcArea(bound);
434 role = inners;
435 } else {
436 role = null;
437 }
438 }
439 areas.put(id, area);
440 break;
441 }
442 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
443 index.put(id, feature);
444 if (features.get(feature.type) == null) {
445 features.put(feature.type, new ArrayList<Feature>());
446 }
447 feature.centre = findCentroid(feature);
448 features.get(feature.type).add(feature);
449 }
450 }
451
452 double signedArea(Bound bound) {
453 Snode node;
454 double lat, lon, llon, llat;
455 lat = lon = llon = llat = 0;
456 double sigma = 0;
457 BoundIterator it = new BoundIterator(bound);
458 while (it.hasNext()) {
459 llon = lon;
460 llat = lat;
461 node = it.next();
462 lat = node.lat;
463 lon = node.lon;
464 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
465 }
466 return sigma / 2.0;
467 }
468
469 public boolean handOfArea(Bound bound) {
470 return (signedArea(bound) < 0);
471 }
472
473 public double calcArea(Bound bound) {
474 return Math.abs(signedArea(bound)) * 3444 * 3444;
475 }
476
477 public double calcLength(Bound bound) {
478 Snode node;
479 double lat, lon, llon, llat;
480 lat = lon = llon = llat = 0;
481 double sigma = 0;
482 BoundIterator it = new BoundIterator(bound);
483 if (it.hasNext()) {
484 node = it.next();
485 lat = node.lat;
486 lon = node.lon;
487 while (it.hasNext()) {
488 llon = lon;
489 llat = lat;
490 node = it.next();
491 lat = node.lat;
492 lon = node.lon;
493 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
494 }
495 }
496 return sigma * 3444;
497 }
498
499 public Snode findCentroid(Feature feature) {
500 double lat, lon, slat, slon, llat, llon;
501 llat = llon = lat = lon = slat = slon = 0;
502 double sarc = 0;
503 boolean first = true;
504 switch (feature.flag) {
505 case POINT:
506 return nodes.get(feature.refs);
507 case LINE:
508 Edge edge = edges.get(feature.refs);
509 EdgeIterator eit = new EdgeIterator(edge, true);
510 while (eit.hasNext()) {
511 Snode node = eit.next();
512 lat = node.lat;
513 lon = node.lon;
514 if (first) {
515 first = false;
516 } else {
517 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
518 }
519 llat = lat;
520 llon = lon;
521 }
522 double harc = sarc / 2;
523 sarc = 0;
524 first = true;
525 eit = new EdgeIterator(edge, true);
526 while (eit.hasNext()) {
527 Snode node = eit.next();
528 lat = node.lat;
529 lon = node.lon;
530 if (first) {
531 first = false;
532 } else {
533 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
534 if (sarc > harc)
535 break;
536 }
537 harc -= sarc;
538 llat = lat;
539 llon = lon;
540 }
541 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
542 case AREA:
543 Bound bound = areas.get(feature.refs).get(0);
544 BoundIterator bit = new BoundIterator(bound);
545 while (bit.hasNext()) {
546 Snode node = bit.next();
547 lat = node.lat;
548 lon = node.lon;
549 if (first) {
550 first = false;
551 } else {
552 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
553 slat += (lat * arc);
554 slon += (lon * arc);
555 sarc += arc;
556 }
557 llon = lon;
558 llat = lat;
559 }
560 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
561 }
562 return null;
563 }
564
565}
Note: See TracBrowser for help on using the repository browser.