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

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

save

File size: 10.8 KB
Line 
1/* Copyright 2012 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 long area;
166 public Snode centre;
167
168 Feature() {
169 flag = Fflag.UNKN;
170 refs = 0;
171 type = Obj.UNKOBJ;
172 atts = new AttMap();
173 objs = new ObjMap();
174 area = 0;
175 centre = new Snode();
176 }
177 }
178
179 public NodeTab nodes;
180 public EdgeTab edges;
181 public AreaTab areas;
182
183 public FtrMap features;
184 public FtrTab index;
185
186 private Feature feature;
187 private Edge edge;
188 private ArrayList<Long> outers;
189 private ArrayList<Long> inners;
190
191 public class EdgeIterator {
192 Edge edge;
193 boolean forward;
194 ListIterator<Long> it;
195
196 public EdgeIterator(Edge iedge, boolean dir) {
197 edge = iedge;
198 forward = dir;
199 it = null;
200 }
201
202 public boolean hasNext() {
203 return (edge != null) && ((it == null) || (forward && it.hasNext()) || (!forward && it.hasPrevious()));
204 }
205
206 public Snode next() {
207 long ref = 0;
208 if (forward) {
209 if (it == null) {
210 ref = edge.first;
211 it = edge.nodes.listIterator();
212 } else {
213 if (it.hasNext()) {
214 ref = it.next();
215 } else {
216 ref = edge.last;
217 edge = null;
218 }
219 }
220 } else {
221 if (it == null) {
222 ref = edge.last;
223 it = edge.nodes.listIterator(edge.nodes.size());
224 } else {
225 if (it.hasPrevious()) {
226 ref = it.previous();
227 } else {
228 ref = edge.first;
229 edge = null;
230 }
231 }
232 }
233 return nodes.get(ref);
234 }
235 }
236
237 public class BoundIterator {
238 Bound bound;
239 Side side;
240 ListIterator<Side> sit;
241 EdgeIterator eit;
242
243 public BoundIterator(Bound ibound) {
244 bound = ibound;
245 sit = bound.sides.listIterator();
246 if (sit.hasNext()) {
247 side = sit.next();
248 eit = new EdgeIterator(side.edge, side.forward);
249 } else {
250 side = null;
251 }
252 }
253
254 public boolean hasNext() {
255 return side != null;
256 }
257
258 public Snode next() {
259 Snode node = null;
260 if (side != null) {
261 if (eit.hasNext()) {
262 node = eit.next();
263 } else {
264 if (sit.hasNext()) {
265 side = sit.next();
266 eit = new EdgeIterator(side.edge, side.forward);
267 node = eit.next();
268 } else {
269 side = null;
270 }
271 }
272 }
273 return node;
274 }
275 }
276
277 public class AreaIterator {
278 Area area;
279 }
280
281 public class FeatureIterator {
282 Feature feature;
283 }
284
285 public SeaMap() {
286 nodes = new NodeTab();
287 edges = new EdgeTab();
288 areas = new AreaTab();
289 feature = new Feature();
290 features = new FtrMap();
291 index = new FtrTab();
292 }
293
294 public void addNode(long id, double lat, double lon) {
295 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon)));
296 feature = new Feature();
297 feature.refs = id;
298 feature.flag = Fflag.POINT;
299 edge = null;
300 }
301
302 public void addEdge(long id) {
303 feature = new Feature();
304 feature.refs = id;
305 feature.flag = Fflag.LINE;
306 edge = new Edge();
307 }
308
309 public void addToEdge(long node) {
310 if (edge.first == 0) {
311 edge.first = node;
312 } else {
313 if (edge.last != 0) {
314 edge.nodes.add(edge.last);
315 }
316 edge.last = node;
317 }
318 }
319
320 public void addArea(long id) {
321 feature = new Feature();
322 feature.refs = id;
323 feature.flag = Fflag.AREA;
324 outers = new ArrayList<Long>();
325 inners = new ArrayList<Long>();
326 edge = null;
327 }
328
329 public void addToArea(long id, boolean outer) {
330 if (outer) {
331 outers.add(id);
332 } else {
333 inners.add(id);
334 }
335 }
336
337 public void addTag(String key, String val) {
338 String subkeys[] = key.split(":");
339 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
340 Obj obj = S57obj.enumType(subkeys[1]);
341 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
342 int idx = 0;
343 Att att = Att.UNKATT;
344 try {
345 idx = Integer.parseInt(subkeys[2]);
346 if (subkeys.length == 4) {
347 att = s57.S57att.enumAttribute(subkeys[3], obj);
348 }
349 } catch (Exception e) {
350 att = S57att.enumAttribute(subkeys[2], obj);
351 }
352 ObjTab items = feature.objs.get(obj);
353 if (items == null) {
354 items = new ObjTab();
355 feature.objs.put(obj, items);
356 }
357 AttMap atts = items.get(idx);
358 if (atts == null) {
359 atts = new AttMap();
360 items.put(idx, atts);
361 }
362 AttVal attval = S57val.convertValue(val, att);
363 if (attval.val != null)
364 atts.put(att, new AttItem(attval.conv, attval.val));
365 } else {
366 if (subkeys[1].equals("type")) {
367 feature.type = S57obj.enumType(val);
368 } else {
369 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
370 if (att != Att.UNKATT) {
371 AttVal attval = S57val.convertValue(val, att);
372 if (attval.val != null)
373 feature.atts.put(att, new AttItem(attval.conv, attval.val));
374 }
375 }
376 }
377 }
378 }
379
380 public void tagsDone(long id) {
381 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
382 index.put(id, feature);
383 if (features.get(feature.type) == null) {
384 features.put(feature.type, new ArrayList<Feature>());
385 }
386 features.get(feature.type).add(feature);
387 }
388 switch (feature.flag) {
389 case POINT:
390 Snode node = nodes.get(id);
391 if (node.flg != Nflag.CONN) {
392 node.flg = Nflag.ISOL;
393 }
394 break;
395 case LINE:
396 edges.put(id, edge);
397 nodes.get(edge.first).flg = Nflag.CONN;
398 nodes.get(edge.last).flg = Nflag.CONN;
399 if (edge.first == edge.last) {
400 feature.flag = Fflag.AREA;
401 Area area = new Area();
402 area.add(new Bound(new Side(edge, edge.forward), true));
403 areas.put(id, area);
404 }
405 break;
406 case AREA:
407 Area area = new Area();
408 for (ArrayList<Long> role = outers; role != null; role = inners) {
409 while (!role.isEmpty()) {
410 Edge edge = edges.get(role.remove(0));
411 long node1 = edge.first;
412 long node2 = edge.last;
413 Bound bound = new Bound(new Side(edge, edge.forward), (role == outers));
414 if (node1 != node2) {
415 for (ListIterator<Long> it = role.listIterator(0); it.hasNext();) {
416 Edge nedge = edges.get(it.next());
417 if (nedge.first == node2) {
418 bound.sides.add(new Side(nedge, true));
419 it.remove();
420 if (nedge.last == node2)
421 break;
422 } else if (nedge.last == node2) {
423 bound.sides.add(new Side(nedge, false));
424 it.remove();
425 if (nedge.first == node2)
426 break;
427 }
428 }
429 }
430 area.add(bound);
431 }
432 if (role == outers) {
433 if (area.isEmpty()) {
434 role = null;
435 } else {
436 areas.put(id, area);
437 }
438 }
439 }
440 break;
441 }
442 feature.centre = findCentroid(feature);
443 }
444
445 public double signedArea(Bound bound) {
446 Snode node;
447 double lat, lon, llon, llat;
448 lat = lon = llon = llat = 0;
449 double sigma = 0;
450 BoundIterator it = new BoundIterator(bound);
451 while (it.hasNext()) {
452 llon = lon;
453 llat = lat;
454 node = it.next();
455 lat = node.lat;
456 lon = node.lon;
457 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
458 }
459 return sigma;
460 }
461
462 public boolean handOfArea(Bound bound) {
463 return (signedArea(bound) < 0);
464 }
465
466 public double calcArea(Bound bound) {
467 return Math.abs(signedArea(bound)) * 3444 * 3444 / 2.0;
468 }
469
470 public Snode findCentroid(Feature feature) {
471 double lat, lon, slat, slon, sarc, llat, llon;
472 lat = lon = slat = slon = sarc = llat = llon = 0;
473 switch (feature.flag) {
474 case POINT:
475 return nodes.get(feature.refs);
476 case LINE:
477 Edge edge = edges.get(feature.refs);
478 EdgeIterator eit = new EdgeIterator(edge, true);
479 while (eit.hasNext()) {
480 Snode node = eit.next();
481 lat = node.lat;
482 lon = node.lon;
483 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
484 llat = lat;
485 llon = lon;
486 }
487 double harc = sarc / 2;
488 sarc = 0;
489 eit = new EdgeIterator(edge, true);
490 while (eit.hasNext()) {
491 Snode node = eit.next();
492 lat = node.lat;
493 lon = node.lon;
494 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
495 if (sarc > harc)
496 break;
497 harc -= sarc;
498 llat = lat;
499 llon = lon;
500 }
501 double frac = harc / sarc;
502 return new Snode(llat + ((lat - llat) / frac), llon + ((lon - llon) / frac));
503 case AREA:
504 Bound bound = areas.get(feature.refs).get(0);
505 BoundIterator bit = new BoundIterator(bound);
506 while (bit.hasNext()) {
507 llon = lon;
508 llat = lat;
509 Snode node = bit.next();
510 lat = node.lat;
511 lon = node.lon;
512 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
513 slat += (lat * arc);
514 slon += (lon * arc);
515 sarc += arc;
516 }
517 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
518 }
519 return null;
520 }
521
522}
Note: See TracBrowser for help on using the repository browser.