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

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

save

File size: 10.9 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) || (edge.nodes.isEmpty()) || (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 SeaMap() {
278 nodes = new NodeTab();
279 edges = new EdgeTab();
280 areas = new AreaTab();
281 feature = new Feature();
282 features = new FtrMap();
283 index = new FtrTab();
284 }
285
286 public void addNode(long id, double lat, double lon) {
287 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon)));
288 feature = new Feature();
289 feature.refs = id;
290 feature.flag = Fflag.POINT;
291 edge = null;
292 }
293
294 public void addEdge(long id) {
295 feature = new Feature();
296 feature.refs = id;
297 feature.flag = Fflag.LINE;
298 edge = new Edge();
299 }
300
301 public void addToEdge(long node) {
302 if (edge.first == 0) {
303 edge.first = node;
304 } else {
305 if (edge.last != 0) {
306 edge.nodes.add(edge.last);
307 }
308 edge.last = node;
309 }
310 }
311
312 public void addArea(long id) {
313 feature = new Feature();
314 feature.refs = id;
315 feature.flag = Fflag.AREA;
316 outers = new ArrayList<Long>();
317 inners = new ArrayList<Long>();
318 edge = null;
319 }
320
321 public void addToArea(long id, boolean outer) {
322 if (outer) {
323 outers.add(id);
324 } else {
325 inners.add(id);
326 }
327 }
328
329 public void addTag(String key, String val) {
330 String subkeys[] = key.split(":");
331 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
332 Obj obj = S57obj.enumType(subkeys[1]);
333 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
334 int idx = 0;
335 Att att = Att.UNKATT;
336 try {
337 idx = Integer.parseInt(subkeys[2]);
338 if (subkeys.length == 4) {
339 att = s57.S57att.enumAttribute(subkeys[3], obj);
340 }
341 } catch (Exception e) {
342 att = S57att.enumAttribute(subkeys[2], obj);
343 }
344 ObjTab items = feature.objs.get(obj);
345 if (items == null) {
346 items = new ObjTab();
347 feature.objs.put(obj, items);
348 }
349 AttMap atts = items.get(idx);
350 if (atts == null) {
351 atts = new AttMap();
352 items.put(idx, atts);
353 }
354 AttVal attval = S57val.convertValue(val, att);
355 if (attval.val != null)
356 atts.put(att, new AttItem(attval.conv, attval.val));
357 } else {
358 if (subkeys[1].equals("type")) {
359 feature.type = S57obj.enumType(val);
360 } else {
361 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
362 if (att != Att.UNKATT) {
363 AttVal attval = S57val.convertValue(val, att);
364 if (attval.val != null)
365 feature.atts.put(att, new AttItem(attval.conv, attval.val));
366 }
367 }
368 }
369 }
370 }
371
372 public void tagsDone(long id) {
373 switch (feature.flag) {
374 case POINT:
375 Snode node = nodes.get(id);
376 if (node.flg != Nflag.CONN) {
377 node.flg = Nflag.ISOL;
378 }
379 break;
380 case LINE:
381 edges.put(id, edge);
382 nodes.get(edge.first).flg = Nflag.CONN;
383 nodes.get(edge.last).flg = Nflag.CONN;
384 if (edge.first == edge.last) {
385 feature.flag = Fflag.AREA;
386 Area area = new Area();
387 area.add(new Bound(new Side(edge, edge.forward), true));
388 areas.put(id, area);
389 }
390 break;
391 case AREA:
392 Area area = new Area();
393 for (ArrayList<Long> role = outers; role != null; role = inners) {
394 while (!role.isEmpty()) {
395 Edge edge = edges.get(role.remove(0));
396 long node1 = edge.first;
397 long node2 = edge.last;
398 Bound bound = new Bound(new Side(edge, edge.forward), (role == outers));
399 if (node1 != node2) {
400 for (ListIterator<Long> it = role.listIterator(0); it.hasNext();) {
401 Edge nedge = edges.get(it.next());
402 if (nedge.first == node2) {
403 bound.sides.add(new Side(nedge, true));
404 it.remove();
405 if (nedge.last == node2)
406 break;
407 } else if (nedge.last == node2) {
408 bound.sides.add(new Side(nedge, false));
409 it.remove();
410 if (nedge.first == node2)
411 break;
412 }
413 }
414 }
415 area.add(bound);
416 }
417 if (role == outers) {
418 if (area.isEmpty()) {
419 role = null;
420 } else {
421 areas.put(id, area);
422 }
423 }
424 }
425 break;
426 }
427 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
428 index.put(id, feature);
429 if (features.get(feature.type) == null) {
430 features.put(feature.type, new ArrayList<Feature>());
431 }
432 feature.centre = findCentroid(feature);
433 features.get(feature.type).add(feature);
434 }
435 }
436
437 public double signedArea(Bound bound) {
438 Snode node;
439 double lat, lon, llon, llat;
440 lat = lon = llon = llat = 0;
441 double sigma = 0;
442 BoundIterator it = new BoundIterator(bound);
443 while (it.hasNext()) {
444 llon = lon;
445 llat = lat;
446 node = it.next();
447 lat = node.lat;
448 lon = node.lon;
449 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
450 }
451 return sigma;
452 }
453
454 public boolean handOfArea(Bound bound) {
455 return (signedArea(bound) < 0);
456 }
457
458 public double calcArea(Bound bound) {
459 return Math.abs(signedArea(bound)) * 3444 * 3444 / 2.0;
460 }
461
462 public Snode findCentroid(Feature feature) {
463 double lat, lon, slat, slon, llat, llon;
464 llat = llon = lat = lon = slat = slon = 0;
465 double sarc = 0;
466 boolean first = true;
467 switch (feature.flag) {
468 case POINT:
469 return nodes.get(feature.refs);
470 case LINE:
471 Edge edge = edges.get(feature.refs);
472 EdgeIterator eit = new EdgeIterator(edge, true);
473 while (eit.hasNext()) {
474 Snode node = eit.next();
475 lat = node.lat;
476 lon = node.lon;
477 if (first) {
478 first = false;
479 } else {
480 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
481 }
482 llat = lat;
483 llon = lon;
484 }
485 double harc = sarc / 2;
486 sarc = 0;
487 first = true;
488 eit = new EdgeIterator(edge, true);
489 while (eit.hasNext()) {
490 Snode node = eit.next();
491 lat = node.lat;
492 lon = node.lon;
493 if (first) {
494 first = false;
495 } else {
496 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
497 if (sarc > harc)
498 break;
499 }
500 harc -= sarc;
501 llat = lat;
502 llon = lon;
503 }
504 double frac = harc / sarc;
505 return new Snode(llat + ((lat - llat) / frac), llon + ((lon - llon) / frac));
506 case AREA:
507 Bound bound = areas.get(feature.refs).get(0);
508 BoundIterator bit = new BoundIterator(bound);
509 while (bit.hasNext()) {
510 Snode node = bit.next();
511 lat = node.lat;
512 lon = node.lon;
513 if (first) {
514 first = false;
515 } else {
516 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
517 slat += (lat * arc);
518 slon += (lon * arc);
519 sarc += arc;
520 }
521 llon = lon;
522 llat = lat;
523 }
524 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
525 }
526 return null;
527 }
528
529}
Note: See TracBrowser for help on using the repository browser.