1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.rugged.raster;
18
19 import java.lang.reflect.Array;
20
21 import org.hipparchus.util.FastMath;
22 import org.hipparchus.util.MathUtils;
23 import org.hipparchus.util.Precision;
24 import org.orekit.bodies.GeodeticPoint;
25 import org.orekit.rugged.errors.DumpManager;
26 import org.orekit.rugged.errors.RuggedException;
27 import org.orekit.rugged.errors.RuggedMessages;
28
29
30
31
32
33
34
35
36
37 public class TilesCache<T extends Tile> {
38
39
40 private static double STEP_EQUALITY = 5 * Precision.EPSILON;
41
42
43 private final TileFactory<T> factory;
44
45
46 private final TileUpdater updater;
47
48
49
50 private final boolean isOverlapping;
51
52
53 private final T[] tiles;
54
55
56
57
58
59
60
61
62 public TilesCache(final TileFactory<T> factory, final TileUpdater updater,
63 final int maxTiles, final boolean isOverlappingTiles) {
64 this.factory = factory;
65 this.updater = updater;
66 this.isOverlapping = isOverlappingTiles;
67 @SuppressWarnings("unchecked")
68 final T[] array = (T[]) Array.newInstance(Tile.class, maxTiles);
69 this.tiles = array;
70 }
71
72
73
74
75
76
77 public T getTile(final double latitude, final double longitude) {
78
79
80 for (int i = 0; i < tiles.length; ++i) {
81 final T tile = tiles[i];
82 if (tile != null && tile.getLocation(latitude, longitude) == Tile.Location.HAS_INTERPOLATION_NEIGHBORS) {
83
84
85
86 while (i > 0) {
87 tiles[i] = tiles[i - 1];
88 --i;
89 }
90 tiles[0] = tile;
91 return tile;
92 }
93 }
94
95
96
97
98
99 for (int i = tiles.length - 1; i > 0; --i) {
100 tiles[i] = tiles[i - 1];
101 }
102
103
104 final T tile = createTile(latitude, longitude);
105
106
107
108
109 if ( !isOverlapping ) {
110
111
112
113
114 final Tile.Location pointLocation = tile.getLocation(latitude, longitude);
115
116
117 if (pointLocation != Tile.Location.HAS_INTERPOLATION_NEIGHBORS) {
118
119
120 return createZipperTile(tile, latitude, longitude, pointLocation);
121
122 } else {
123
124 tiles[0] = tile;
125 return tile;
126
127 }
128
129 } else {
130
131
132 if (tile.getLocation(latitude, longitude) != Tile.Location.HAS_INTERPOLATION_NEIGHBORS) {
133
134 throw new RuggedException(RuggedMessages.TILE_WITHOUT_REQUIRED_NEIGHBORS_SELECTED,
135 FastMath.toDegrees(latitude), FastMath.toDegrees(longitude));
136 }
137
138 tiles[0] = tile;
139 return tile;
140
141 }
142 }
143
144
145
146
147
148
149
150 private T createTile(final double latitude, final double longitude) {
151
152
153 final T tile = factory.createTile();
154
155
156
157 final Boolean wasSuspended = DumpManager.suspend();
158
159
160 updater.updateTile(latitude, longitude, tile);
161
162
163 DumpManager.resume(wasSuspended);
164
165
166 tile.tileUpdateCompleted();
167 return tile;
168 }
169
170
171
172
173
174
175
176
177
178 private T createZipperTile(final T currentTile,
179 final double latitude, final double longitude,
180 final Tile.Location pointLocation) {
181
182 T zipperTile = null;
183
184
185
186 switch (pointLocation) {
187
188 case NORTH:
189
190 zipperTile = createZipperNorthOrSouth(EarthHemisphere.NORTH, longitude, currentTile);
191 break;
192
193 case SOUTH:
194
195 zipperTile = createZipperNorthOrSouth(EarthHemisphere.SOUTH, longitude, currentTile);
196 break;
197
198 case WEST:
199
200 zipperTile = createZipperWestOrEast(EarthHemisphere.WEST, latitude, currentTile);
201 break;
202
203 case EAST:
204
205 zipperTile = createZipperWestOrEast(EarthHemisphere.EAST, latitude, currentTile);
206 break;
207
208
209
210 case NORTH_WEST:
211
212 zipperTile = createCornerZipper(EarthHemisphere.NORTH, EarthHemisphere.WEST, latitude, longitude, currentTile);
213 break;
214
215 case NORTH_EAST:
216
217 zipperTile = createCornerZipper(EarthHemisphere.NORTH, EarthHemisphere.EAST, latitude, longitude, currentTile);
218 break;
219
220 case SOUTH_WEST:
221
222 zipperTile = createCornerZipper(EarthHemisphere.SOUTH, EarthHemisphere.WEST, latitude, longitude, currentTile);
223 break;
224
225 case SOUTH_EAST:
226
227 zipperTile = createCornerZipper(EarthHemisphere.SOUTH, EarthHemisphere.EAST, latitude, longitude, currentTile);
228 break;
229
230 default:
231
232 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
233
234 }
235
236
237 for (int i = tiles.length - 1; i > 0; --i) {
238 tiles[i] = tiles[i - 1];
239 }
240
241 tiles[1] = currentTile;
242 tiles[0] = zipperTile;
243
244 return (T) zipperTile;
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258 private T initializeZipperTile(final double zipperLatMin, final double zipperLonMin,
259 final double zipperLatStep, final double zipperLonStep,
260 final int zipperLatRows, final int zipperLonCols,
261 final double[][] zipperElevations) {
262
263
264 final T zipperTile = factory.createTile();
265
266
267 zipperTile.setGeometry(zipperLatMin, zipperLonMin, zipperLatStep, zipperLonStep,
268 zipperLatRows, zipperLonCols);
269
270
271 for (int iLat = 0; iLat < zipperLatRows; iLat++) {
272 for (int jLon = 0; jLon < zipperLonCols; jLon++) {
273 zipperTile.setElevation(iLat, jLon, zipperElevations[iLat][jLon]);
274 }
275 }
276
277
278 zipperTile.tileUpdateCompleted();
279
280 return zipperTile;
281 }
282
283
284
285
286
287
288
289
290
291
292
293 private T createZipperNorthOrSouth(final EarthHemisphere latitudeHemisphere, final double longitude, final T currentTile) {
294
295 final int currentTileLatRows = currentTile.getLatitudeRows();
296 final int currentTileLonCols = currentTile.getLongitudeColumns();
297 final double currentTileLatStep = currentTile.getLatitudeStep();
298 final double currentTileLonStep = currentTile.getLongitudeStep();
299 final double currentTileMinLat = currentTile.getMinimumLatitude();
300 final double currentTileMinLon = currentTile.getMinimumLongitude();
301
302
303 final T tileNorthOrSouth = createNorthOrSouthTile(latitudeHemisphere, longitude, currentTileMinLat, currentTileLatStep, currentTileLatRows);
304
305
306
307
308
309
310
311
312
313
314
315
316 final int zipperLatRows = 4;
317 double zipperLatStep = currentTileLatStep;
318
319
320 boolean isSameStepLat = true;
321 final double northSouthLatitudeStep = tileNorthOrSouth.getLatitudeStep();
322
323 if (!(Math.abs(currentTileLatStep - northSouthLatitudeStep) < STEP_EQUALITY)) {
324
325 isSameStepLat = false;
326
327 if (northSouthLatitudeStep < currentTileLatStep) {
328 zipperLatStep = northSouthLatitudeStep;
329 }
330 }
331
332
333 double zipperLonStep = currentTileLonStep;
334 int zipperLonCols = currentTileLonCols;
335
336
337 boolean isSameStepLon = true;
338 final double northSouthLongitudeStep = tileNorthOrSouth.getLongitudeStep();
339
340 if (!(Math.abs(currentTileLonStep - northSouthLongitudeStep) < STEP_EQUALITY)) {
341
342 isSameStepLon = false;
343
344 if (northSouthLongitudeStep < currentTileLonStep) {
345 zipperLonStep = northSouthLongitudeStep;
346 zipperLonCols = tileNorthOrSouth.getLongitudeColumns();
347 }
348 }
349
350 final double zipperLatMin;
351 final double zipperLonMin;
352 final double[][] elevations;
353
354 switch (latitudeHemisphere) {
355 case NORTH:
356
357
358
359
360 final double currentTileNorthernLatitude = currentTileMinLat - 0.5 * currentTileLatStep + currentTileLatRows * currentTileLatStep;
361
362
363 zipperLatMin = currentTileNorthernLatitude - 2 * zipperLatStep + 0.5 * zipperLatStep;
364
365
366 zipperLonMin = currentTileMinLon;
367
368
369 elevations = getZipperNorthSouthElevations(zipperLonCols, tileNorthOrSouth, currentTile,
370 isSameStepLat, isSameStepLon,
371 zipperLatMin, zipperLonMin, zipperLatStep, zipperLonStep);
372 break;
373
374 case SOUTH:
375
376
377
378
379 final double currentTileSouthernLatitude = currentTileMinLat - 0.5 * currentTileLatStep;
380
381
382 zipperLatMin = currentTileSouthernLatitude - 2 * zipperLatStep + 0.5 * zipperLatStep;
383
384
385 zipperLonMin = currentTileMinLon;
386
387
388 elevations = getZipperNorthSouthElevations(zipperLonCols, currentTile, tileNorthOrSouth,
389 isSameStepLat, isSameStepLon,
390 zipperLatMin, zipperLonMin, zipperLatStep, zipperLonStep);
391 break;
392
393 default:
394
395 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
396 }
397
398 final T zipperNorthOrSouth = initializeZipperTile(zipperLatMin, zipperLonMin,
399 zipperLatStep, zipperLonStep,
400 zipperLatRows, zipperLonCols, elevations);
401 return zipperNorthOrSouth;
402 }
403
404
405
406
407
408
409
410
411
412
413
414 private T createZipperWestOrEast(final EarthHemisphere longitudeHemisphere, final double latitude, final T currentTile) {
415
416 final int currentTileLatRows = currentTile.getLatitudeRows();
417 final int currentTileLonCols = currentTile.getLongitudeColumns();
418 final double currentTileLatStep = currentTile.getLatitudeStep();
419 final double currentTileLonStep = currentTile.getLongitudeStep();
420 final double currentTileMinLon = currentTile.getMinimumLongitude();
421
422
423 final T tileWestOrEast = createEastOrWestTile(longitudeHemisphere, latitude, currentTileMinLon, currentTileLonStep, currentTileLonCols);
424
425 if (!(Math.abs(currentTileLatStep - tileWestOrEast.getLatitudeStep()) < STEP_EQUALITY) ||
426 !(Math.abs(currentTileLonStep - tileWestOrEast.getLongitudeStep()) < STEP_EQUALITY)) {
427
428
429 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
430 }
431
432
433
434
435
436
437
438
439
440
441
442 final double zipperLonStep = currentTileLonStep;
443 final int zipperLatRows = currentTileLatRows;
444 final int zipperLonCols = 4;
445
446 final double zipperLonMin;
447 final double[][] elevations;
448
449 switch (longitudeHemisphere) {
450 case WEST:
451 zipperLonMin = currentTileMinLon - 2 * currentTileLonStep;
452 elevations = getZipperEastWestElevations(zipperLatRows, currentTile, tileWestOrEast);
453 break;
454
455 case EAST:
456 zipperLonMin = currentTileMinLon + (currentTileLonCols - 2) * currentTileLonStep;
457 elevations = getZipperEastWestElevations(zipperLatRows, tileWestOrEast, currentTile);
458 break;
459
460 default:
461
462 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
463 }
464
465 final T zipperWestOrEast = initializeZipperTile(currentTile.getMinimumLatitude(), zipperLonMin,
466 currentTileLatStep, zipperLonStep,
467 zipperLatRows, zipperLonCols, elevations);
468 return zipperWestOrEast;
469 }
470
471
472
473
474
475
476
477
478
479 private int computeLatitudeIndex(final double latitude, final double latitudeMin, final double latitudeStep, final int latitudeRows) {
480
481
482 final double doubleLatitudeIndex = (latitude - (latitudeMin - 0.5 * latitudeStep)) / latitudeStep;
483 return FastMath.max(0, FastMath.min(latitudeRows - 1, (int) FastMath.floor(doubleLatitudeIndex)));
484 }
485
486
487
488
489
490
491
492
493
494 private int computeLongitudeIndex(final double longitude, final double longitudeMin, final double longitudeStep, final int longitudeColumns) {
495
496
497 final double doubleLongitudeIndex = (longitude - (longitudeMin - 0.5 * longitudeStep)) / longitudeStep;
498 return FastMath.max(0, FastMath.min(longitudeColumns - 1, (int) FastMath.floor(doubleLongitudeIndex)));
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514 private double[][] getZipperNorthSouthElevations(final int zipperLonCols,
515 final T northernTile, final T southernTile,
516 final boolean isSameStepLat, final boolean isSameStepLon,
517 final double zipperLatMin, final double zipperLonMin,
518 final double zipperLatStep, final double zipperLonStep) {
519
520 final double[][] elevations = new double[4][zipperLonCols];
521
522 if (isSameStepLat && isSameStepLon) {
523
524 for (int jLon = 0; jLon < zipperLonCols; jLon++) {
525
526 final int lat3 = 1;
527 elevations[3][jLon] = northernTile.getElevationAtIndices(lat3, jLon);
528 final int lat2 = 0;
529 elevations[2][jLon] = northernTile.getElevationAtIndices(lat2, jLon);
530
531
532 final int lat1 = southernTile.getLatitudeRows() - 1;
533 elevations[1][jLon] = southernTile.getElevationAtIndices(lat1, jLon);
534 final int lat0 = southernTile.getLatitudeRows() - 2;
535 elevations[0][jLon] = southernTile.getElevationAtIndices(lat0, jLon);
536 }
537
538 } else {
539
540
541
542
543
544
545 final double deltaLon = 0.1 * zipperLonStep;
546 double zipperLonCurrent = zipperLonMin + deltaLon;
547
548
549 final double zipperLonMax = MathUtils.normalizeAngle(zipperLonMin + (zipperLonCols - 1) * zipperLonStep, 0.0);
550
551
552 final double northernMinLat = northernTile.getMinimumLatitude();
553 final double northernLatStep = northernTile.getLatitudeStep();
554 final int northernLatRows = northernTile.getLatitudeRows();
555 final double northernMinLon = northernTile.getMinimumLongitude();
556 final double northernLonStep = northernTile.getLongitudeStep();
557 final int northernLonCols = northernTile.getLongitudeColumns();
558
559
560 final double southernMinLat = southernTile.getMinimumLatitude();
561 final double southernLatStep = southernTile.getLatitudeStep();
562 final int southernLatRows = southernTile.getLatitudeRows();
563 final double southernMinLon = southernTile.getMinimumLongitude();
564 final double southernLonStep = southernTile.getLongitudeStep();
565 final int southernLonCols = southernTile.getLongitudeColumns();
566
567 while (zipperLonCurrent <= zipperLonMax + 2 * deltaLon) {
568
569
570 final int zipperLonIndex = computeLongitudeIndex(zipperLonCurrent, zipperLonMin, zipperLonStep, zipperLonCols);
571
572
573
574
575 final int northenLongitudeIndex = computeLongitudeIndex(zipperLonCurrent, northernMinLon, northernLonStep, northernLonCols);
576
577 final double zipperLat3 = zipperLatMin + (3 + 0.1) * zipperLatStep;
578
579 final int lat3Index = computeLatitudeIndex(zipperLat3, northernMinLat, northernLatStep, northernLatRows);
580 elevations[3][zipperLonIndex] = northernTile.getElevationAtIndices(lat3Index, northenLongitudeIndex);
581
582
583 final int lat2Index = 0;
584 elevations[2][zipperLonIndex] = northernTile.getElevationAtIndices(lat2Index, northenLongitudeIndex);
585
586
587
588
589 final int southernLongitudeIndex = computeLongitudeIndex(zipperLonCurrent, southernMinLon, southernLonStep, southernLonCols);
590
591
592 final int lat1Index = southernTile.getLatitudeRows() - 1;
593 elevations[1][zipperLonIndex] = southernTile.getElevationAtIndices(lat1Index, southernLongitudeIndex);
594
595 final double zipperLat0 = zipperLatMin + 0.1 * zipperLatStep;
596
597 final int lat0Index = computeLatitudeIndex(zipperLat0, southernMinLat, southernLatStep, southernLatRows);
598 elevations[0][zipperLonIndex] = southernTile.getElevationAtIndices(lat0Index, southernLongitudeIndex);
599
600
601
602 zipperLonCurrent += zipperLonStep;
603
604 }
605 }
606 return elevations;
607 }
608
609
610
611
612
613
614
615
616 private double[][] getZipperEastWestElevations(final int zipperLatRows,
617 final T easternTile, final T westernTile) {
618
619 final double[][] elevations = new double[zipperLatRows][4];
620
621 for (int iLat = 0; iLat < zipperLatRows; iLat++) {
622
623 final int lon3 = 1;
624 elevations[iLat][3] = easternTile.getElevationAtIndices(iLat, lon3);
625 final int lon2 = 0;
626 elevations[iLat][2] = easternTile.getElevationAtIndices(iLat, lon2);
627
628
629 final int lon1 = westernTile.getLongitudeColumns() - 1;
630 elevations[iLat][1] = westernTile.getElevationAtIndices(iLat, lon1);
631 final int lon0 = westernTile.getLongitudeColumns() - 2;
632 elevations[iLat][0] = westernTile.getElevationAtIndices(iLat, lon0);
633 }
634 return elevations;
635 }
636
637
638
639
640
641
642
643
644
645
646
647 private T createCornerZipper(final EarthHemisphere latitudeHemisphere, final EarthHemisphere longitudeHemisphere,
648 final double latitude, final double longitude, final T currentTile) {
649
650 final int currentTileLatRows = currentTile.getLatitudeRows();
651 final int currentTileLonCols = currentTile.getLongitudeColumns();
652 final double currentTileLatStep = currentTile.getLatitudeStep();
653 final double currentTileLonStep = currentTile.getLongitudeStep();
654 final double currentTileLonMin = currentTile.getMinimumLongitude();
655 final double currentTileLatMin = currentTile.getMinimumLatitude();
656
657 final T belowLeftTile;
658 final T belowRightTile;
659 final T aboveLeftTile;
660 final T aboveRightTile;
661
662 switch (latitudeHemisphere) {
663 case NORTH:
664
665 switch (longitudeHemisphere) {
666 case WEST:
667
668
669 final T tileWest = createEastOrWestTile(EarthHemisphere.WEST, latitude,
670 currentTileLonMin, currentTileLonStep, currentTileLonCols);
671
672 T tileNorth = createNorthOrSouthTile(EarthHemisphere.NORTH, longitude,
673 currentTileLatMin, currentTileLatStep, currentTileLatRows);
674
675 final T tileNorthWest = createIntercardinalTile(EarthHemisphere.NORTH,
676 currentTileLatMin, currentTileLatStep, currentTileLatRows,
677 EarthHemisphere.WEST,
678 currentTileLonMin, currentTileLonStep, currentTileLonCols);
679 belowLeftTile = tileWest;
680 belowRightTile = currentTile;
681 aboveLeftTile = tileNorthWest;
682 aboveRightTile = tileNorth;
683
684 break;
685
686 case EAST:
687
688
689 final T tileEast = createEastOrWestTile(EarthHemisphere.EAST, latitude,
690 currentTileLonMin, currentTileLonStep, currentTileLonCols);
691
692 tileNorth = createNorthOrSouthTile(EarthHemisphere.NORTH, longitude,
693 currentTileLatMin, currentTileLatStep, currentTileLatRows);
694
695 final T tileNorthEast = createIntercardinalTile(EarthHemisphere.NORTH,
696 currentTileLatMin, currentTileLatStep, currentTileLatRows,
697 EarthHemisphere.EAST,
698 currentTileLonMin, currentTileLonStep, currentTileLonCols);
699 belowLeftTile = currentTile;
700 belowRightTile = tileEast;
701 aboveLeftTile = tileNorth;
702 aboveRightTile = tileNorthEast;
703
704 break;
705
706 default:
707
708 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
709 }
710
711 break;
712
713 case SOUTH:
714
715 switch (longitudeHemisphere) {
716 case WEST:
717
718
719 final T tileWest = createEastOrWestTile(EarthHemisphere.WEST, latitude,
720 currentTileLonMin, currentTileLonStep, currentTileLonCols);
721
722 T tileSouth = createNorthOrSouthTile(EarthHemisphere.SOUTH, longitude,
723 currentTileLatMin, currentTileLatStep, currentTileLatRows);
724
725 final T tileSouthhWest = createIntercardinalTile(EarthHemisphere.SOUTH,
726 currentTileLatMin, currentTileLatStep, currentTileLatRows,
727 EarthHemisphere.WEST,
728 currentTileLonMin, currentTileLonStep, currentTileLonCols);
729 belowLeftTile = tileSouthhWest;
730 belowRightTile = tileSouth;
731 aboveLeftTile = tileWest;
732 aboveRightTile = currentTile;
733
734 break;
735
736 case EAST:
737
738
739 final T tileEast = createEastOrWestTile(EarthHemisphere.EAST, latitude,
740 currentTileLonMin, currentTileLonStep, currentTileLonCols);
741
742 tileSouth = createNorthOrSouthTile(EarthHemisphere.SOUTH, longitude,
743 currentTileLatMin, currentTileLatStep, currentTileLatRows);
744
745 final T tileSouthhEast = createIntercardinalTile(EarthHemisphere.SOUTH,
746 currentTileLatMin, currentTileLatStep, currentTileLatRows,
747 EarthHemisphere.EAST,
748 currentTileLonMin, currentTileLonStep, currentTileLonCols);
749 belowLeftTile = tileSouth;
750 belowRightTile = tileSouthhEast;
751 aboveLeftTile = currentTile;
752 aboveRightTile = tileEast;
753
754 break;
755
756 default:
757
758 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
759 }
760
761 break;
762
763 default:
764
765 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
766 }
767
768
769
770
771 if (!(Math.abs(belowLeftTile.getLatitudeStep() - belowRightTile.getLatitudeStep()) < STEP_EQUALITY) ||
772 !(Math.abs(belowLeftTile.getLongitudeStep() - belowRightTile.getLongitudeStep()) < STEP_EQUALITY) ||
773 !(Math.abs(aboveLeftTile.getLatitudeStep() - aboveRightTile.getLatitudeStep()) < STEP_EQUALITY) ||
774 !(Math.abs(aboveLeftTile.getLongitudeStep() - aboveRightTile.getLongitudeStep()) < STEP_EQUALITY)) {
775
776 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
777 }
778
779
780
781
782
783
784 final double belowLatitudeStep = belowRightTile.getLatitudeStep();
785 final double aboveLatitudeStep = aboveRightTile.getLatitudeStep();
786
787
788 double zipperLatStep = belowLatitudeStep;
789
790
791 boolean isSameStepLat = true;
792
793 if (!(Math.abs(belowLatitudeStep - aboveLatitudeStep) < STEP_EQUALITY)) {
794
795
796 isSameStepLat = false;
797
798
799 if (aboveLatitudeStep < belowLatitudeStep) {
800 zipperLatStep = aboveLatitudeStep;
801 }
802 }
803
804
805 final double belowLongitudeStep = belowRightTile.getLongitudeStep();
806 final double aboveLongitudeStep = aboveRightTile.getLongitudeStep();
807
808
809 double zipperLonStep = belowLongitudeStep;
810
811
812 boolean isSameStepLon = true;
813
814 if (!(Math.abs(belowLongitudeStep - aboveLongitudeStep) < STEP_EQUALITY)) {
815
816
817 isSameStepLon = false;
818
819
820 if (aboveLongitudeStep < belowLongitudeStep) {
821 zipperLonStep = aboveLongitudeStep;
822 }
823 }
824
825
826
827
828
829
830 final GeodeticPoint zipperCorner = computeCornerZipperOrigin(zipperLatStep, zipperLonStep,
831 latitudeHemisphere, currentTileLatMin,
832 currentTileLatStep, currentTileLatRows,
833 longitudeHemisphere, currentTileLonMin,
834 currentTileLonStep, currentTileLonCols);
835
836
837 return initializeCornerZipperTile(zipperCorner.getLatitude(), zipperCorner.getLongitude(), zipperLatStep, zipperLonStep,
838 belowLeftTile, aboveLeftTile, belowRightTile, aboveRightTile,
839 isSameStepLat, isSameStepLon);
840
841 }
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857 private T initializeCornerZipperTile(final double zipperLatMin, final double zipperLonMin,
858 final double zipperLatStep, final double zipperLonStep,
859 final T belowLeftTile, final T aboveLeftTile, final T belowRightTile, final T aboveRightTile,
860 final boolean isSameStepLat, final boolean isSameStepLon) {
861
862
863 final int zipperLatRows = 4;
864 final int zipperLonCols = 4;
865 final double[][] elevations = new double[zipperLatRows][zipperLonCols];
866
867 if (isSameStepLat && isSameStepLon) {
868
869
870
871
872
873 elevations[0][0] = belowLeftTile.getElevationAtIndices(belowLeftTile.getLatitudeRows() - 2, belowLeftTile.getLongitudeColumns() - 2);
874 elevations[0][1] = belowLeftTile.getElevationAtIndices(belowLeftTile.getLatitudeRows() - 2, belowLeftTile.getLongitudeColumns() - 1);
875
876 elevations[0][2] = belowRightTile.getElevationAtIndices(belowRightTile.getLatitudeRows() - 2, 0);
877 elevations[0][3] = belowRightTile.getElevationAtIndices(belowRightTile.getLatitudeRows() - 2, 1);
878
879
880 elevations[1][0] = belowLeftTile.getElevationAtIndices(belowLeftTile.getLatitudeRows() - 1, belowLeftTile.getLongitudeColumns() - 2);
881 elevations[1][1] = belowLeftTile.getElevationAtIndices(belowLeftTile.getLatitudeRows() - 1, belowLeftTile.getLongitudeColumns() - 1);
882
883 elevations[1][2] = belowRightTile.getElevationAtIndices(belowRightTile.getLatitudeRows() - 1, 0);
884 elevations[1][3] = belowRightTile.getElevationAtIndices(belowRightTile.getLatitudeRows() - 1, 1);
885
886
887
888
889
890 elevations[2][0] = aboveLeftTile.getElevationAtIndices(0, aboveLeftTile.getLongitudeColumns() - 2);
891 elevations[2][1] = aboveLeftTile.getElevationAtIndices(0, aboveLeftTile.getLongitudeColumns() - 1);
892
893 elevations[2][2] = aboveRightTile.getElevationAtIndices(0, 0);
894 elevations[2][3] = aboveRightTile.getElevationAtIndices(0, 1);
895
896
897 elevations[3][0] = aboveLeftTile.getElevationAtIndices(1, aboveLeftTile.getLongitudeColumns() - 2);
898 elevations[3][1] = aboveLeftTile.getElevationAtIndices(1, aboveLeftTile.getLongitudeColumns() - 1);
899
900 elevations[3][2] = aboveRightTile.getElevationAtIndices(1, 0);
901 elevations[3][3] = aboveRightTile.getElevationAtIndices(1, 1);
902
903
904 } else {
905
906
907
908
909
910
911
912
913 final double zipperLat0 = zipperLatMin + 0.1 * zipperLatStep;
914 final double zipperLat1 = zipperLat0 + zipperLatStep;
915 final double zipperLat2 = zipperLat1 + zipperLatStep;
916 final double zipperLat3 = zipperLat2 + zipperLatStep;
917
918 final double zipperLon0 = zipperLonMin + 0.1 * zipperLonStep;
919 final double zipperLon1 = zipperLon0 + zipperLonStep;
920 final double zipperLon2 = zipperLon1 + zipperLonStep;
921 final double zipperLon3 = zipperLon2 + zipperLonStep;
922
923
924 final int belowLeftLatitudeIndex0 = computeLatitudeIndex(zipperLat0, belowLeftTile.getMinimumLatitude(), belowLeftTile.getLatitudeStep(), belowLeftTile.getLatitudeRows());
925 final int belowLeftLatitudeIndex1 = computeLatitudeIndex(zipperLat1, belowLeftTile.getMinimumLatitude(), belowLeftTile.getLatitudeStep(), belowLeftTile.getLatitudeRows());
926
927 final int belowRightLatitudeIndex0 = computeLatitudeIndex(zipperLat0, belowRightTile.getMinimumLatitude(), belowRightTile.getLatitudeStep(), belowRightTile.getLatitudeRows());
928 final int belowRightLatitudeIndex1 = computeLatitudeIndex(zipperLat1, belowRightTile.getMinimumLatitude(), belowRightTile.getLatitudeStep(), belowRightTile.getLatitudeRows());
929
930 final int aboveLeftLatitudeIndex2 = computeLatitudeIndex(zipperLat2, aboveLeftTile.getMinimumLatitude(), aboveLeftTile.getLatitudeStep(), aboveLeftTile.getLatitudeRows());
931 final int aboveLeftLatitudeIndex3 = computeLatitudeIndex(zipperLat3, aboveLeftTile.getMinimumLatitude(), aboveLeftTile.getLatitudeStep(), aboveLeftTile.getLatitudeRows());
932
933 final int aboveRightLatitudeIndex2 = computeLatitudeIndex(zipperLat2, aboveRightTile.getMinimumLatitude(), aboveRightTile.getLatitudeStep(), aboveRightTile.getLatitudeRows());
934 final int aboveRightLatitudeIndex3 = computeLatitudeIndex(zipperLat3, aboveRightTile.getMinimumLatitude(), aboveRightTile.getLatitudeStep(), aboveRightTile.getLatitudeRows());
935
936
937 final int belowLeftLongitudeIndex0 = computeLongitudeIndex(zipperLon0, belowLeftTile.getMinimumLongitude(), belowLeftTile.getLongitudeStep(), belowLeftTile.getLongitudeColumns());
938 final int belowLeftLongitudeIndex1 = computeLongitudeIndex(zipperLon1, belowLeftTile.getMinimumLongitude(), belowLeftTile.getLongitudeStep(), belowLeftTile.getLongitudeColumns());
939
940 final int belowRightLongitudeIndex2 = computeLongitudeIndex(zipperLon2, belowRightTile.getMinimumLongitude(), belowRightTile.getLongitudeStep(), belowRightTile.getLongitudeColumns());
941 final int belowRightLongitudeIndex3 = computeLongitudeIndex(zipperLon3, belowRightTile.getMinimumLongitude(), belowRightTile.getLongitudeStep(), belowRightTile.getLongitudeColumns());
942
943 final int aboveLeftLongitudeIndex0 = computeLongitudeIndex(zipperLon0, aboveLeftTile.getMinimumLongitude(), aboveLeftTile.getLongitudeStep(), aboveLeftTile.getLongitudeColumns());
944 final int aboveLeftLongitudeIndex1 = computeLongitudeIndex(zipperLon1, aboveLeftTile.getMinimumLongitude(), aboveLeftTile.getLongitudeStep(), aboveLeftTile.getLongitudeColumns());
945
946 final int aboveRightLongitudeIndex2 = computeLongitudeIndex(zipperLon2, aboveRightTile.getMinimumLongitude(), aboveRightTile.getLongitudeStep(), aboveRightTile.getLongitudeColumns());
947 final int aboveRightLongitudeIndex3 = computeLongitudeIndex(zipperLon3, aboveRightTile.getMinimumLongitude(), aboveRightTile.getLongitudeStep(), aboveRightTile.getLongitudeColumns());
948
949
950
951
952
953 elevations[0][0] = belowLeftTile.getElevationAtIndices(belowLeftLatitudeIndex0, belowLeftLongitudeIndex0);
954 elevations[0][1] = belowLeftTile.getElevationAtIndices(belowLeftLatitudeIndex0, belowLeftLongitudeIndex1);
955
956 elevations[0][2] = belowRightTile.getElevationAtIndices(belowRightLatitudeIndex0, belowRightLongitudeIndex2);
957 elevations[0][3] = belowRightTile.getElevationAtIndices(belowRightLatitudeIndex0, belowRightLongitudeIndex3);
958
959
960 elevations[1][0] = belowLeftTile.getElevationAtIndices(belowLeftLatitudeIndex1, belowLeftLongitudeIndex0);
961 elevations[1][1] = belowLeftTile.getElevationAtIndices(belowLeftLatitudeIndex1, belowLeftLongitudeIndex1);
962
963 elevations[1][2] = belowRightTile.getElevationAtIndices(belowRightLatitudeIndex1, belowRightLongitudeIndex2);
964 elevations[1][3] = belowRightTile.getElevationAtIndices(belowRightLatitudeIndex1, belowRightLongitudeIndex3);
965
966
967
968
969
970 elevations[2][0] = aboveLeftTile.getElevationAtIndices(aboveLeftLatitudeIndex2, aboveLeftLongitudeIndex0);
971 elevations[2][1] = aboveLeftTile.getElevationAtIndices(aboveLeftLatitudeIndex2, aboveLeftLongitudeIndex1);
972
973 elevations[2][2] = aboveRightTile.getElevationAtIndices(aboveRightLatitudeIndex2, aboveRightLongitudeIndex2);
974 elevations[2][3] = aboveRightTile.getElevationAtIndices(aboveRightLatitudeIndex2, aboveRightLongitudeIndex3);
975
976
977 elevations[3][0] = aboveLeftTile.getElevationAtIndices(aboveLeftLatitudeIndex3, aboveLeftLongitudeIndex0);
978 elevations[3][1] = aboveLeftTile.getElevationAtIndices(aboveLeftLatitudeIndex3, aboveLeftLongitudeIndex1);
979
980 elevations[3][2] = aboveRightTile.getElevationAtIndices(aboveRightLatitudeIndex3, aboveRightLongitudeIndex2);
981 elevations[3][3] = aboveRightTile.getElevationAtIndices(aboveRightLatitudeIndex3, aboveRightLongitudeIndex3);
982
983 }
984
985
986 final T cornerZipperTile = initializeZipperTile(zipperLatMin, zipperLonMin,
987 zipperLatStep, zipperLonStep,
988 zipperLatRows, zipperLonCols, elevations);
989
990 return cornerZipperTile;
991 }
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 private T createIntercardinalTile(final EarthHemisphere latitudeHemisphere,
1007 final double latitudeMin, final double latitudeStep, final int latitudeRows,
1008 final EarthHemisphere longitudeHemisphere,
1009 final double longitudeMin, final double longitudeStep, final int longitudeCols) {
1010
1011
1012 final int lonHemisphere;
1013 switch (longitudeHemisphere) {
1014 case EAST:
1015 lonHemisphere = +1;
1016 break;
1017 case WEST:
1018 lonHemisphere = -1;
1019 break;
1020 default:
1021
1022 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1023 }
1024
1025
1026 final int latHemisphere;
1027 switch (latitudeHemisphere) {
1028 case NORTH:
1029 latHemisphere = +1;
1030 break;
1031 case SOUTH:
1032 latHemisphere = -1;
1033 break;
1034 default:
1035
1036 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1037 }
1038
1039 final double latToGetIntercardinalTile = latitudeMin + latHemisphere * latitudeRows * latitudeStep;
1040 final double lonToGetIntercardinalTile = longitudeMin + lonHemisphere * longitudeCols * longitudeStep;
1041 final T intercardinalTile = createTile(latToGetIntercardinalTile, lonToGetIntercardinalTile);
1042 return intercardinalTile;
1043 }
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 private GeodeticPoint computeCornerZipperOrigin(final double zipperLatStep, final double zipperLonStep,
1060 final EarthHemisphere latitudeHemisphere,
1061 final double currentTileLatMin, final double currentTileLatStep, final int currentTileLatRows,
1062 final EarthHemisphere longitudeHemisphere,
1063 final double currentTileLonMin, final double currentTileLonStep, final int currentTileLonCols) {
1064 final double zipperLatMin;
1065 final double zipperLonMin;
1066
1067
1068
1069
1070
1071
1072 switch (latitudeHemisphere) {
1073 case NORTH:
1074
1075 switch (longitudeHemisphere) {
1076 case WEST:
1077 zipperLatMin = currentTileLatMin + currentTileLatRows * currentTileLatStep - 2 * zipperLatStep;
1078 zipperLonMin = currentTileLonMin - 2 * zipperLonStep;
1079 break;
1080
1081 case EAST:
1082 zipperLatMin = currentTileLatMin + currentTileLatRows * currentTileLatStep - 2 * zipperLatStep;
1083 zipperLonMin = currentTileLonMin + currentTileLonCols * currentTileLonStep - 2 * zipperLonStep;
1084 break;
1085
1086 default:
1087
1088 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1089 }
1090
1091 break;
1092
1093 case SOUTH:
1094
1095 switch (longitudeHemisphere) {
1096 case WEST:
1097 zipperLatMin = currentTileLatMin - 2 * zipperLatStep;
1098 zipperLonMin = currentTileLonMin - 2 * zipperLonStep;
1099 break;
1100
1101 case EAST:
1102 zipperLatMin = currentTileLatMin - 2 * zipperLatStep;
1103 zipperLonMin = currentTileLonMin + currentTileLonCols * currentTileLonStep - 2 * zipperLonStep;
1104 break;
1105
1106 default:
1107
1108 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1109 }
1110
1111 break;
1112
1113 default:
1114
1115 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1116 }
1117
1118 return new GeodeticPoint(zipperLatMin, zipperLonMin, 0);
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131 private T createNorthOrSouthTile(final EarthHemisphere latitudeHemisphere, final double longitude,
1132 final double latitudeMin, final double latitudeStep, final int latitudeRows) {
1133
1134 final int hemisphere;
1135 switch (latitudeHemisphere) {
1136 case NORTH:
1137 hemisphere = +1;
1138 break;
1139 case SOUTH:
1140 hemisphere = -1;
1141 break;
1142 default:
1143
1144 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1145 }
1146
1147 final double latToGetNewTile = latitudeMin + hemisphere * latitudeRows * latitudeStep;
1148 return createTile(latToGetNewTile, longitude);
1149 }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 private T createEastOrWestTile(final EarthHemisphere longitudeHemisphere, final double latitude,
1162 final double longitudeMin, final double longitudeStep, final int longitudeCols) {
1163
1164 final int hemisphere;
1165 switch (longitudeHemisphere) {
1166 case EAST:
1167 hemisphere = +1;
1168 break;
1169 case WEST:
1170 hemisphere = -1;
1171 break;
1172 default:
1173
1174 throw new RuggedException(RuggedMessages.INTERNAL_ERROR);
1175 }
1176
1177 final double lonToGetNewTile = longitudeMin + hemisphere * longitudeCols * longitudeStep;
1178 return createTile(latitude, lonToGetNewTile);
1179 }
1180 }