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

Last change on this file since 29266 was 29266, checked in by malcolmh, 12 years ago

save

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