source: osm/applications/editors/josm/plugins/smed2/src/s57/S57map.java@ 30285

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

save

File size: 20.0 KB
Line 
1/* Copyright 2014 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 s57;
11
12import java.util.*;
13
14import s57.S57obj;
15import s57.S57obj.*;
16import s57.S57att;
17import s57.S57att.*;
18import s57.S57val;
19import s57.S57val.*;
20
21public class S57map {
22
23 public class MapBounds {
24 public double minlat;
25 public double minlon;
26 public double maxlat;
27 public double maxlon;
28 public MapBounds() {
29 minlat = 90;
30 minlon = 180;
31 maxlat = -90;
32 maxlon = -180;
33 }
34 }
35
36 public enum Nflag {
37 ANON, // Edge inner nodes
38 ISOL, // Node not part of Edge
39 CONN, // Edge first and last nodes
40 DPTH // Sounding nodes
41 }
42
43 public class Snode { // All coordinates in map
44 public double lat; // Latitude
45 public double lon; // Longitude
46 public Nflag flg; // Role of node
47
48 public Snode() {
49 flg = Nflag.ANON;
50 lat = 0;
51 lon = 0;
52 }
53 public Snode(double ilat, double ilon) {
54 flg = Nflag.ANON;
55 lat = ilat;
56 lon = ilon;
57 }
58 public Snode(double ilat, double ilon, Nflag iflg) {
59 lat = ilat;
60 lon = ilon;
61 flg = iflg;
62 }
63 }
64
65 public class Dnode extends Snode { // All depth soundings
66 public double val; // Sounding value
67
68 public Dnode() {
69 flg = Nflag.DPTH;
70 lat = 0;
71 lon = 0;
72 val = 0;
73 }
74 public Dnode(double ilat, double ilon, double ival) {
75 flg = Nflag.DPTH;
76 lat = ilat;
77 lon = ilon;
78 val = ival;
79 }
80 }
81
82 public class Edge { // A polyline segment
83 public long first; // First CONN node
84 public long last; // Last CONN node
85 public ArrayList<Long> nodes; // Inner ANON nodes
86
87 public Edge() {
88 first = 0;
89 last = 0;
90 nodes = new ArrayList<Long>();
91 }
92 }
93
94 public enum Rflag {
95 UNKN, MASTER, SLAVE
96 }
97
98 public class Reln {
99 public long id;
100 public Rflag reln;
101 public Reln(long i, Rflag r) {
102 id = i;
103 reln = r;
104 }
105 }
106
107 public class RelTab extends ArrayList<Reln> {
108 public RelTab() {
109 super();
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 AttMap extends HashMap<Att, AttVal<?>> {
126 public AttMap() {
127 super();
128 }
129 }
130
131 public class NodeTab extends HashMap<Long, Snode> {
132 public NodeTab() {
133 super();
134 }
135 }
136
137 public class EdgeTab extends HashMap<Long, Edge> {
138 public EdgeTab() {
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 class Prim { // Spatial element
156 public long id; // Snode ID for POINTs, Edge ID for LINEs & AREAs)
157 public boolean forward; // Direction of vector used (LINEs & AREAs)
158 public boolean outer; // Exterior/Interior boundary (AREAs)
159 public Prim() {
160 id = 0; forward = true; outer = true;
161 }
162 public Prim(long i) {
163 id = i; forward = true; outer = true;
164 }
165 public Prim(long i, boolean o) {
166 id = i; forward = true; outer = o;
167 }
168 public Prim(long i, boolean f, boolean o) {
169 id = i; forward = f; outer = o;
170 }
171 }
172
173 public class Comp {
174 public long ref;
175 public int size;
176 public Comp(long r, int s) {
177 ref = r;
178 size = s;
179 }
180 }
181
182 public enum Pflag {
183 NOSP, POINT, LINE, AREA
184 }
185
186 public class Geom { // Geometric structure of feature
187 public Pflag prim; // Geometry type
188 public ArrayList<Prim> elems; // Ordered list of elements
189 public int outers; // Number of outers
190 public int inners; // Number of inners
191 public ArrayList<Comp> refs; // Ordered list of compounds
192 public double area; // Area of feature
193 public double length; // Length of feature
194 public Snode centre; // Centre of feature
195 public Geom(Pflag p) {
196 prim = p;
197 elems = new ArrayList<Prim>();
198 outers = inners = 0;
199 refs = new ArrayList<Comp>();
200 area = 0;
201 length = 0;
202 centre = new Snode();
203 }
204 }
205
206 public class Feature {
207 public Rflag reln; // Relationship status
208 public Geom geom; // Geometry data
209 public Obj type; // Feature type
210 public AttMap atts; // Feature attributes
211 public RelTab rels; // Related objects
212 public ObjMap objs; // Slave object attributes
213
214 Feature() {
215 reln = Rflag.UNKN;
216 geom = new Geom(Pflag.NOSP);
217 type = Obj.UNKOBJ;
218 atts = new AttMap();
219 rels = new RelTab();
220 objs = new ObjMap();
221 }
222 }
223
224 public NodeTab nodes;
225 public EdgeTab edges;
226
227 public FtrMap features;
228 public FtrTab index;
229
230 public long ref;
231 private Feature feature;
232 private Edge edge;
233
234 public S57map() {
235 nodes = new NodeTab(); // All nodes in map
236 edges = new EdgeTab(); // All edges in map
237 feature = new Feature(); // Current feature being built
238 features = new FtrMap(); // All features in map, grouped by type
239 index = new FtrTab(); // Feature look-up table
240 ref = 0x0000ffffffff0000L;// Compound reference generator
241 }
242
243 // S57 map building methods
244
245 public void newNode(long id, double lat, double lon, Nflag flag) {
246 nodes.put(id, new Snode(Math.toRadians(lat), Math.toRadians(lon), flag));
247 if (flag == Nflag.ANON) {
248 edge.nodes.add(id);
249 }
250 }
251
252 public void newNode(long id, double lat, double lon, double depth) {
253 nodes.put(id, new Dnode(Math.toRadians(lat), Math.toRadians(lon), depth));
254 }
255
256 public void newFeature(long id, Pflag p, long objl) {
257 feature = new Feature();
258 Obj obj = S57obj.decodeType(objl);
259 if (obj == Obj.BCNWTW)
260 obj = Obj.BCNLAT;
261 if (obj == Obj.BOYWTW)
262 obj = Obj.BOYLAT;
263 if (obj == Obj.C_AGGR)
264 feature.reln = Rflag.UNKN;
265 feature.geom = new Geom(p);
266 feature.type = obj;
267 if (obj != Obj.UNKOBJ) {
268 index.put(id, feature);
269 }
270 }
271
272 public void newObj(long id, int rind) {
273 Rflag r = Rflag.UNKN;
274 switch (rind) {
275 case 1:
276 r = Rflag.MASTER;
277 break;
278 case 2:
279 r = Rflag.SLAVE;
280 break;
281 case 3:
282 r = Rflag.UNKN;
283 break;
284 }
285 feature.rels.add(new Reln(id, r));
286 }
287
288 public void endFeature() {
289
290 }
291
292 public void newAtt(long attl, String atvl) {
293 Att att = S57att.decodeAttribute(attl);
294 AttVal<?> val = S57val.decodeValue(atvl, att);
295 feature.atts.put(att, val);
296 }
297
298 public void newPrim(long id, long ornt, long usag) {
299 feature.geom.elems.add(new Prim(id, (ornt != 2), (usag != 2)));
300 }
301
302 public void addConn(long id, int topi) {
303 if (topi == 1) {
304 edge.first = id;
305 } else {
306 edge.last = id;
307 }
308 }
309
310 public void newEdge(long id) {
311 edge = new Edge();
312 edges.put(id, edge);
313 }
314
315 public void endFile() {
316 for (long id : index.keySet()) {
317 Feature feature = index.get(id);
318 if ((feature.geom.prim == Pflag.LINE) || (feature.geom.prim == Pflag.AREA)) {
319 feature.geom.outers = 1;
320 feature.geom.inners = 0;
321 feature.geom.refs = new ArrayList<Comp>();
322 Comp comp = new Comp(ref++, 0);
323 feature.geom.refs.add(comp);
324 ListIterator<S57map.Prim> ite = feature.geom.elems.listIterator();
325 long first = 0;
326 while (ite.hasNext()) {
327 Prim prim = ite.next();
328 Edge edge = edges.get(prim.id);
329 if (!prim.outer) {
330 if (first == 0) {
331 feature.geom.inners++;
332 comp = new Comp(ref++, 0);
333 feature.geom.refs.add(comp);
334 first = edge.first;
335 } else {
336 if (edge.last == first) {
337 first = 0;
338 }
339 }
340 }
341 comp.size++;
342 }
343 }
344 }
345 for (long id : index.keySet()) {
346 Feature feature = index.get(id);
347 for (Reln reln : feature.rels) {
348 Feature rel = index.get(reln.id);
349 if (cmpGeoms(feature.geom, rel.geom)) {
350 switch (reln.reln) {
351 case SLAVE:
352 feature.reln = Rflag.MASTER;
353 break;
354 default:
355 feature.reln = Rflag.UNKN;
356 break;
357 }
358 rel.reln = reln.reln;
359 } else {
360 reln.reln = Rflag.UNKN;
361 }
362 }
363 }
364 for (long id : index.keySet()) {
365 Feature feature = index.get(id);
366 if (feature.reln == Rflag.UNKN) {
367 feature.reln = Rflag.MASTER;
368 }
369 if ((feature.type != Obj.UNKOBJ) && (feature.reln == Rflag.MASTER)) {
370 if (features.get(feature.type) == null) {
371 features.put(feature.type, new ArrayList<Feature>());
372 }
373 features.get(feature.type).add(feature);
374 }
375 }
376 for (long id : index.keySet()) {
377 Feature feature = index.get(id);
378 for (Reln reln : feature.rels) {
379 Feature rel = index.get(reln.id);
380 if (rel.reln == Rflag.SLAVE) {
381 if (feature.objs.get(rel.type) == null) {
382 feature.objs.put(rel.type, new ObjTab());
383 }
384 ObjTab tab = feature.objs.get(rel.type);
385 int ix = tab.size();
386 tab.put(ix, rel.atts);
387 }
388 }
389 }
390 }
391
392 // OSM map building methods
393
394 public void addNode(long id, double lat, double lon) {
395 Snode node = new Snode(Math.toRadians(lat), Math.toRadians(lon));
396 nodes.put(id, node);
397 feature = new Feature();
398 feature.reln = Rflag.UNKN;
399 feature.geom.prim = Pflag.POINT;
400 feature.geom.elems.add(new Prim(id));
401 edge = null;
402 }
403
404 public void addEdge(long id) {
405 feature = new Feature();
406 feature.reln = Rflag.UNKN;
407 feature.geom.prim = Pflag.LINE;
408 feature.geom.elems.add(new Prim(id));
409 edge = new Edge();
410 }
411
412 public void addToEdge(long node) {
413 if (edge.first == 0) {
414 edge.first = node;
415 nodes.get(node).flg = Nflag.CONN;
416 } else {
417 if (edge.last != 0) {
418 edge.nodes.add(edge.last);
419 }
420 edge.last = node;
421 }
422 }
423
424 public void addArea(long id) {
425 feature = new Feature();
426 feature.reln = Rflag.UNKN;
427 feature.geom.prim = Pflag.AREA;
428 feature.geom.elems.add(new Prim(id));
429 edge = null;
430 }
431
432 public void addToArea(long id, boolean outer) {
433 feature.geom.elems.add(new Prim(id, outer));
434 }
435
436 public void addTag(String key, String val) {
437 feature.reln = Rflag.MASTER;
438 String subkeys[] = key.split(":");
439 if ((subkeys.length > 1) && subkeys[0].equals("seamark")) {
440 Obj obj = S57obj.enumType(subkeys[1]);
441 if ((subkeys.length > 2) && (obj != Obj.UNKOBJ)) {
442 int idx = 0;
443 Att att = Att.UNKATT;
444 try {
445 idx = Integer.parseInt(subkeys[2]);
446 if (subkeys.length == 4) {
447 att = s57.S57att.enumAttribute(subkeys[3], obj);
448 }
449 } catch (Exception e) {
450 att = S57att.enumAttribute(subkeys[2], obj);
451 }
452 ObjTab objs = feature.objs.get(obj);
453 if (objs == null) {
454 objs = new ObjTab();
455 feature.objs.put(obj, objs);
456 }
457 AttMap atts = objs.get(idx);
458 if (atts == null) {
459 atts = new AttMap();
460 objs.put(idx, atts);
461 }
462 AttVal<?> attval = S57val.convertValue(val, att);
463 if (attval.val != null)
464 atts.put(att, attval);
465 } else {
466 if (subkeys[1].equals("type")) {
467 obj = S57obj.enumType(val);
468 feature.type = obj;
469 ObjTab objs = feature.objs.get(obj);
470 if (objs == null) {
471 objs = new ObjTab();
472 feature.objs.put(obj, objs);
473 }
474 AttMap atts = objs.get(0);
475 if (atts == null) {
476 atts = new AttMap();
477 objs.put(0, atts);
478 }
479 } else {
480 Att att = S57att.enumAttribute(subkeys[1], Obj.UNKOBJ);
481 if (att != Att.UNKATT) {
482 AttVal<?> attval = S57val.convertValue(val, att);
483 if (attval.val != null)
484 feature.atts.put(att, attval);
485 }
486 }
487 }
488 }
489 }
490
491 public void tagsDone(long id) {
492 switch (feature.geom.prim) {
493 case POINT:
494 Snode node = nodes.get(id);
495 if (node.flg != Nflag.CONN) {
496 node.flg = Nflag.ISOL;
497 }
498 feature.geom.length = 0;
499 feature.geom.area = 0;
500 break;
501 case LINE:
502 edges.put(id, edge);
503 nodes.get(edge.first).flg = Nflag.CONN;
504 nodes.get(edge.last).flg = Nflag.CONN;
505 feature.geom.length = calcLength(feature.geom);
506 if (edge.first == edge.last) {
507 feature.geom.prim = Pflag.AREA;
508 feature.geom.area = calcArea(feature.geom);
509 } else {
510 feature.geom.area = 0;
511 }
512 break;
513 case AREA:
514 break;
515 default:
516 break;
517 }
518 if ((feature.type != Obj.UNKOBJ) && !((edge != null) && (edge.last == 0))) {
519 index.put(id, feature);
520 if (features.get(feature.type) == null) {
521 features.put(feature.type, new ArrayList<Feature>());
522 }
523 features.get(feature.type).add(feature);
524 feature.geom.centre = findCentroid(feature);
525 }
526 }
527
528 // Utility methods
529
530 public void sortGeom() {
531 for (long id : index.keySet()) {
532 feature = index.get(id);
533 Geom sort = new Geom(feature.geom.prim);
534 long first = 0;
535 long last = 0;
536 Comp comp = null;
537 boolean next = true;
538 if ((feature.geom.prim == Pflag.LINE) || (feature.geom.prim == Pflag.AREA)) {
539 int sweep = feature.geom.elems.size();
540 while (!feature.geom.elems.isEmpty()) {
541 Prim prim = feature.geom.elems.remove(0);
542 Edge edge = edges.get(prim.id);
543 if (next == true) {
544 next = false;
545 if (prim.forward) {
546 first = edge.first;
547 last = edge.last;
548 } else {
549 first = edge.last;
550 last = edge.first;
551 }
552 sort.elems.add(prim);
553 if (prim.outer) {
554 sort.outers++;
555 } else {
556 sort.inners++;
557 }
558 comp = new Comp(ref++, 1);
559 sort.refs.add(comp);
560 } else {
561 if (prim.forward) {
562 if (edge.first == last) {
563 sort.elems.add(prim);
564 last = edge.last;
565 comp.size++;
566 } else if (edge.last == first) {
567 sort.elems.add(0, prim);
568 first = edge.first;
569 comp.size++;
570 } else {
571 feature.geom.elems.add(prim);
572 }
573 } else {
574 if (edge.last == last) {
575 sort.elems.add(prim);
576 last = edge.first;
577 comp.size++;
578 } else if (edge.first == first) {
579 sort.elems.add(0, prim);
580 first = edge.last;
581 comp.size++;
582 } else {
583 feature.geom.elems.add(prim);
584 }
585 }
586 }
587 if (--sweep == 0) {
588 next = true;
589 sweep = feature.geom.elems.size();
590 }
591 }
592 if ((sort.prim == Pflag.LINE) && (sort.outers == 1) && (sort.inners == 0) && (first == last)) {
593 sort.prim = Pflag.AREA;
594 }
595 feature.geom = sort;
596 }
597 if (feature.geom.prim == Pflag.AREA) {
598 ArrayList<Prim> outers = new ArrayList<Prim>();
599 ArrayList<Prim> inners = new ArrayList<Prim>();
600 for (Prim prim : feature.geom.elems) {
601 if (prim.outer) {
602 outers.add(prim);
603 } else {
604 inners.add(prim);
605 }
606 }
607 ArrayList<Prim> sorting = outers;
608 ArrayList<Prim> closed = null;
609 sort = new Geom(feature.geom.prim);
610 sort.outers = feature.geom.outers;
611 sort.inners = feature.geom.inners;
612 sort.refs = feature.geom.refs;
613 next = true;
614 while (!sorting.isEmpty()) {
615 Prim prim = sorting.remove(0);
616 Edge edge = edges.get(prim.id);
617 if (next == true) {
618 next = false;
619 closed = new ArrayList<Prim>();
620 closed.add(prim);
621 if (prim.forward) {
622 first = edge.first;
623 last = edge.last;
624 } else {
625 first = edge.last;
626 last = edge.first;
627 }
628 } else {
629 if (prim.forward) {
630 if (edge.first == last) {
631 last = edge.last;
632 closed.add(prim);
633 } else {
634 sorting.add(0, prim);
635 next = true;
636 }
637 } else {
638 if (edge.last == last) {
639 last = edge.first;
640 closed.add(prim);
641 } else {
642 sorting.add(0, prim);
643 next = true;
644 }
645 }
646 }
647 if (first == last) {
648 sort.elems.addAll(closed);
649 next = true;
650 }
651 if (sorting.isEmpty() && sorting == outers) {
652 sorting = inners;
653 next = true;
654 }
655 }
656 feature.geom = sort;
657 }
658 }
659 }
660
661 public boolean cmpGeoms (Geom g1, Geom g2) {
662 return ((g1.prim == g2.prim) && (g1.outers == g2.outers) && (g1.inners == g2.inners) && (g1.elems.size() == g2.elems.size()));
663 }
664
665 public class EdgeIterator {
666 Edge edge;
667 boolean forward;
668 ListIterator<Long> it;
669
670 public EdgeIterator(Edge e, boolean dir) {
671 edge = e;
672 forward = dir;
673 it = null;
674 }
675
676 public boolean hasNext() {
677 return (edge != null);
678 }
679
680 public long nextRef() {
681 long ref = 0;
682 if (forward) {
683 if (it == null) {
684 ref = edge.first;
685 it = edge.nodes.listIterator();
686 } else {
687 if (it.hasNext()) {
688 ref = it.next();
689 } else {
690 ref = edge.last;
691 edge = null;
692 }
693 }
694 } else {
695 if (it == null) {
696 ref = edge.last;
697 it = edge.nodes.listIterator(edge.nodes.size());
698 } else {
699 if (it.hasPrevious()) {
700 ref = it.previous();
701 } else {
702 ref = edge.first;
703 edge = null;
704 }
705 }
706 }
707 return ref;
708 }
709
710 public Snode next() {
711 return nodes.get(nextRef());
712 }
713 }
714
715 public class GeomIterator {
716 Geom geom;
717 Prim prim;
718 EdgeIterator eit;
719 ListIterator<S57map.Prim> ite;
720 ListIterator<Comp> itc;
721 Comp comp;
722 int ec;
723 long lastref;
724
725 public GeomIterator(Geom g) {
726 geom = g;
727 lastref = 0;
728 ite = geom.elems.listIterator();
729 itc = geom.refs.listIterator();
730 }
731
732 public boolean hasComp() {
733 return (itc.hasNext());
734 }
735
736 public long nextComp() {
737 comp = itc.next();
738 ec = comp.size;
739 lastref = 0;
740 return comp.ref;
741 }
742
743 public boolean hasEdge() {
744 return (ec > 0) && ite.hasNext();
745 }
746
747 public long nextEdge() {
748 prim = ite.next();
749 eit = new EdgeIterator(edges.get(prim.id), prim.forward);
750 ec--;
751 return prim.id;
752 }
753
754 public boolean hasNode() {
755 return (eit.hasNext());
756 }
757
758 public long nextRef(boolean all) {
759 long ref = eit.nextRef();
760 if (!all && (ref == lastref)) {
761 ref = eit.nextRef();
762 }
763 lastref = ref;
764 return ref;
765 }
766
767 public long nextRef() {
768 return nextRef(false);
769 }
770
771 public Snode next() {
772 return nodes.get(nextRef());
773 }
774 }
775
776 double signedArea(Geom geom) {
777 Snode node;
778 double lat, lon, llon, llat;
779 lat = lon = llon = llat = 0;
780 double sigma = 0;
781 GeomIterator it = new GeomIterator(geom);
782 it.nextComp();
783 while (it.hasNode()) {
784 llon = lon;
785 llat = lat;
786 node = it.next();
787 lat = node.lat;
788 lon = node.lon;
789 sigma += (lon * Math.sin(llat)) - (llon * Math.sin(lat));
790 }
791 return sigma / 2.0;
792 }
793
794 public boolean handOfArea(Geom geom) {
795 return (signedArea(geom) < 0);
796 }
797
798 public double calcArea(Geom geom) {
799 return Math.abs(signedArea(geom)) * 3444 * 3444;
800 }
801
802 public double calcLength(Geom geom) {
803 Snode node;
804 double lat, lon, llon, llat;
805 lat = lon = llon = llat = 0;
806 double sigma = 0;
807 GeomIterator it = new GeomIterator(geom);
808 it.nextComp();
809 if (it.hasNode()) {
810 node = it.next();
811 lat = node.lat;
812 lon = node.lon;
813 while (it.hasNode()) {
814 llon = lon;
815 llat = lat;
816 node = it.next();
817 lat = node.lat;
818 lon = node.lon;
819 sigma += Math.acos(Math.sin(lat) * Math.sin(llat) + Math.cos(lat) * Math.cos(llat) * Math.cos(llon - lon));
820 }
821 }
822 return sigma * 3444;
823 }
824
825 public Snode findCentroid(Feature feature) {
826 double lat, lon, slat, slon, llat, llon;
827 llat = llon = lat = lon = slat = slon = 0;
828 double sarc = 0;
829 boolean first = true;
830 switch (feature.geom.prim) {
831 case POINT:
832 return nodes.get(feature.geom.elems.get(0).id);
833 case LINE:
834 GeomIterator it = new GeomIterator(feature.geom);
835 it.nextComp();
836 while (it.hasNode()) {
837 Snode node = it.next();
838 lat = node.lat;
839 lon = node.lon;
840 if (first) {
841 first = false;
842 } else {
843 sarc += (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
844 }
845 llat = lat;
846 llon = lon;
847 }
848 double harc = sarc / 2;
849 sarc = 0;
850 first = true;
851 it = new GeomIterator(feature.geom);
852 while (it.hasNode()) {
853 it.nextComp();
854 Snode node = it.next();
855 lat = node.lat;
856 lon = node.lon;
857 if (first) {
858 first = false;
859 } else {
860 sarc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
861 if (sarc > harc)
862 break;
863 }
864 harc -= sarc;
865 llat = lat;
866 llon = lon;
867 }
868 return new Snode(llat + ((lat - llat) * harc / sarc), llon + ((lon - llon) * harc / sarc));
869 case AREA:
870 GeomIterator bit = new GeomIterator(feature.geom);
871 bit.nextComp();
872 while (bit.hasNode()) {
873 Snode node = bit.next();
874 lat = node.lat;
875 lon = node.lon;
876 if (first) {
877 first = false;
878 } else {
879 double arc = (Math.acos(Math.cos(lon - llon) * Math.cos(lat - llat)));
880 slat += ((lat + llat) / 2 * arc);
881 slon += ((lon + llon) / 2 * arc);
882 sarc += arc;
883 }
884 llon = lon;
885 llat = lat;
886 }
887 return new Snode((sarc > 0.0 ? slat / sarc : 0.0), (sarc > 0.0 ? slon / sarc : 0.0));
888 default:
889 }
890 return null;
891 }
892
893}
Note: See TracBrowser for help on using the repository browser.