1+ package gov .nasa .worldwind .layer .mercator ;
2+
3+ import android .graphics .Bitmap ;
4+
5+ import java .util .Collection ;
6+
7+ import gov .nasa .worldwind .render .ImageSource ;
8+ import gov .nasa .worldwind .render .ImageTile ;
9+ import gov .nasa .worldwind .util .Level ;
10+ import gov .nasa .worldwind .util .LevelSet ;
11+ import gov .nasa .worldwind .util .Logger ;
12+ import gov .nasa .worldwind .util .Tile ;
13+ import gov .nasa .worldwind .util .TileFactory ;
14+
15+ class MercatorImageTile extends ImageTile implements ImageSource .DownloadPostprocessor <Bitmap > {
16+
17+ /**
18+ * Constructs a tile with a specified sector, level, row and column.
19+ *
20+ * @param sector the sector spanned by the tile
21+ * @param level the tile's level in a {@link LevelSet}
22+ * @param row the tile's row within the specified level
23+ * @param column the tile's column within the specified level
24+ */
25+ MercatorImageTile (MercatorSector sector , Level level , int row , int column ) {
26+ super (sector , level , row , column );
27+ }
28+
29+ /**
30+ * Creates all Mercator tiles for a specified level within a {@link LevelSet}.
31+ *
32+ * @param level the level to create the tiles for
33+ * @param tileFactory the tile factory to use for creating tiles.
34+ * @param result an pre-allocated Collection in which to store the results
35+ */
36+ static void assembleMercatorTilesForLevel (Level level , TileFactory tileFactory , Collection <Tile > result ) {
37+ if (level == null ) {
38+ throw new IllegalArgumentException (
39+ Logger .logMessage (Logger .ERROR , "Tile" , "assembleTilesForLevel" , "missingLevel" ));
40+ }
41+
42+ if (tileFactory == null ) {
43+ throw new IllegalArgumentException (
44+ Logger .logMessage (Logger .ERROR , "Tile" , "assembleTilesForLevel" , "missingTileFactory" ));
45+ }
46+
47+ if (result == null ) {
48+ throw new IllegalArgumentException (
49+ Logger .logMessage (Logger .ERROR , "Tile" , "assembleTilesForLevel" , "missingResult" ));
50+ }
51+
52+ // NOTE LevelSet.sector is final Sector attribute and thus can not be cast to MercatorSector!
53+ MercatorSector sector = MercatorSector .fromSector (level .parent .sector );
54+ double dLat = level .tileDelta / 2 ;
55+ double dLon = level .tileDelta ;
56+
57+ int firstRow = Tile .computeRow (dLat , sector .minLatitude ());
58+ int lastRow = Tile .computeLastRow (dLat , sector .maxLatitude ());
59+ int firstCol = Tile .computeColumn (dLon , sector .minLongitude ());
60+ int lastCol = Tile .computeLastColumn (dLon , sector .maxLongitude ());
61+
62+ double deltaLat = dLat / 90 ;
63+ double d1 = sector .minLatPercent () + deltaLat * firstRow ;
64+ for (int row = firstRow ; row <= lastRow ; row ++) {
65+ double d2 = d1 + deltaLat ;
66+ double t1 = sector .minLongitude () + (firstCol * dLon );
67+ for (int col = firstCol ; col <= lastCol ; col ++) {
68+ double t2 ;
69+ t2 = t1 + dLon ;
70+ result .add (tileFactory .createTile (MercatorSector .fromDegrees (d1 , d2 , t1 , t2 ), level , row , col ));
71+ t1 = t2 ;
72+ }
73+ d1 = d2 ;
74+ }
75+ }
76+
77+ /**
78+ * Returns the four children formed by subdividing this tile. This tile's sector is subdivided into four quadrants
79+ * as follows: Southwest; Southeast; Northwest; Northeast. A new tile is then constructed for each quadrant and
80+ * configured with the next level within this tile's LevelSet and its corresponding row and column within that
81+ * level. This returns null if this tile's level is the last level within its {@link LevelSet}.
82+ *
83+ * @param tileFactory the tile factory to use to create the children
84+ *
85+ * @return an array containing the four child tiles, or null if this tile's level is the last level
86+ */
87+ @ Override
88+ public Tile [] subdivide (TileFactory tileFactory ) {
89+ if (tileFactory == null ) {
90+ throw new IllegalArgumentException (
91+ Logger .logMessage (Logger .ERROR , "Tile" , "subdivide" , "missingTileFactory" ));
92+ }
93+
94+ Level childLevel = this .level .nextLevel ();
95+ if (childLevel == null ) {
96+ return null ;
97+ }
98+
99+ MercatorSector sector = (MercatorSector ) this .sector ;
100+
101+ double d0 = sector .minLatPercent ();
102+ double d2 = sector .maxLatPercent ();
103+ double d1 = d0 + (d2 - d0 ) / 2.0 ;
104+
105+ double t0 = sector .minLongitude ();
106+ double t2 = sector .maxLongitude ();
107+ double t1 = 0.5 * (t0 + t2 );
108+
109+ int northRow = 2 * this .row ;
110+ int southRow = northRow + 1 ;
111+ int westCol = 2 * this .column ;
112+ int eastCol = westCol + 1 ;
113+
114+ Tile [] children = new Tile [4 ];
115+ children [0 ] = tileFactory .createTile (MercatorSector .fromDegrees (d0 , d1 , t0 , t1 ), childLevel , northRow , westCol );
116+ children [1 ] = tileFactory .createTile (MercatorSector .fromDegrees (d0 , d1 , t1 , t2 ), childLevel , northRow , eastCol );
117+ children [2 ] = tileFactory .createTile (MercatorSector .fromDegrees (d1 , d2 , t0 , t1 ), childLevel , southRow , westCol );
118+ children [3 ] = tileFactory .createTile (MercatorSector .fromDegrees (d1 , d2 , t1 , t2 ), childLevel , southRow , eastCol );
119+
120+ return children ;
121+ }
122+
123+ @ Override
124+ public Bitmap process (Bitmap resource ) {
125+ // Re-project mercator tile to equirectangular
126+ int [] pixels = new int [resource .getWidth () * resource .getHeight ()];
127+ int [] result = new int [resource .getWidth () * resource .getHeight ()];
128+ resource .getPixels (pixels , 0 , resource .getWidth (), 0 , 0 , resource .getWidth (), resource .getHeight ());
129+ double miny = ((MercatorSector ) sector ).minLatPercent ();
130+ double maxy = ((MercatorSector ) sector ).maxLatPercent ();
131+ for (int y = 0 ; y < resource .getHeight (); y ++) {
132+ double sy = 1.0 - y / (double ) (resource .getHeight () - 1 );
133+ double lat = sy * (sector .maxLatitude () - sector .minLatitude ()) + sector .minLatitude ();
134+ double dy = 1.0 - (MercatorSector .gudermannianInverse (lat ) - miny ) / (maxy - miny );
135+ dy = Math .max (0.0 , Math .min (1.0 , dy ));
136+ int iy = (int ) (dy * (resource .getHeight () - 1 ));
137+ for (int x = 0 ; x < resource .getWidth (); x ++) {
138+ result [x + y * resource .getWidth ()] = pixels [x + iy * resource .getWidth ()];
139+ }
140+ }
141+ return Bitmap .createBitmap (result , resource .getWidth (), resource .getHeight (), resource .getConfig ());
142+ }
143+
144+ }
0 commit comments