]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.maps/src/org/simantics/maps/tile/Shp2ImgTileProvider.java
Ensure ITileProviders return BufferedImages with compatible ColorModel
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / tile / Shp2ImgTileProvider.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.maps.tile;
13
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.awt.Image;
17 import java.awt.geom.Rectangle2D;
18 import java.awt.image.BufferedImage;
19 import java.io.File;
20 import java.io.IOException;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import javax.imageio.ImageIO;
27
28 import org.simantics.maps.ProvisionException;
29 import org.simantics.maps.internal.ImageUtil;
30
31 /**
32  * @author Tuukka Lehtonen
33  * @deprecated this is a demo hack, do not use
34  */
35 public class Shp2ImgTileProvider implements ITileProvider {
36
37     private static final String SHP2IMG_EXECUTABLE = "c:\\ms4w\\tools\\mapserv\\shp2img.exe";
38
39     private static final String SCHEME = "shp2img";
40
41     final URI                   source;
42
43     final File                  mapDirectory;
44
45     final String                mapName;
46
47     final int                   tilePixelSize;
48
49     final String                tileSizeString;
50
51     Rectangle2D                 extentDegrees;
52
53     Rectangle2D                 extentMeters;
54
55     double                      deWidthRecip;
56
57     double                      deHeightRecip;
58
59     String[]                    ENVP               = null;
60
61     BufferedImage               outOfBoundsImage;
62
63     public Shp2ImgTileProvider(String mapDirectory, String mapName, int tilePixelSize, Rectangle2D extentDegrees, Rectangle2D extentMeters) {
64         this.mapDirectory = new File(mapDirectory);
65         this.mapName = mapName;
66         this.tilePixelSize = tilePixelSize;
67         this.tileSizeString = String.valueOf(tilePixelSize);
68         this.extentDegrees = extentDegrees;
69         this.extentMeters = extentMeters;
70
71         this.deWidthRecip = 1.0 / extentDegrees.getWidth();
72         this.deHeightRecip = 1.0 / extentDegrees.getHeight();
73
74         if (!this.mapDirectory.exists()) {
75             throw new IllegalArgumentException("Map directory '" + mapDirectory + "' does not exist");
76         }
77
78         StringBuilder host = new StringBuilder();
79         boolean first = true;
80         String[] segments = mapDirectory.split(File.pathSeparator);
81         for (String seg : segments) {
82             if (!first)
83                 host.append('.');
84             first = false;
85             host.append(seg);
86         }
87         host.append('.');
88         host.append(mapName);
89
90         try {
91             source = new URI(SCHEME, host.toString(), null, null);
92         } catch (URISyntaxException e) {
93             throw new RuntimeException("Shp2ImgTileProvider: Problem in URI generation with mapDirectory="
94                     + mapDirectory + ", mapName= " + mapName, e);
95         }
96
97         List<String> envp = new ArrayList<String>();
98         envp.add("GDAL_DATA=c:\\ms4w\\gdaldata");
99         envp.add("GDAL_DRIVER_PATH=c:\\ms4w\\gdalplugins");
100         envp.add("PROJ_LIB=c:\\ms4w\\proj\\nad");
101         envp.add("PATH=c:\\ms4w\\Apache\\cgi-bin;c:\\ms4w\\tools\\gdal-ogr;c:\\ms4w\\tools\\mapserv;c:\\ms4w\\tools\\shapelib;c:\\ms4w\\proj\\bin;c:\\ms4w\\tools\\shp2tile;c:\\ms4w\\tools\\shpdiff;c:\\ms4w\\tools\\avce00;c:\\ms4w\\tools\\demtools;");
102         ENVP = envp.toArray(new String[0]);
103
104 //        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("png");
105 //        ImageReader reader = readers.next();
106     }
107
108     @Override
109     public URI getSource() {
110         return source;
111     }
112
113     @Override
114     public Rectangle2D getExtent() {
115         // FIXME: should return a clone
116         return extentDegrees;
117     }
118
119     @Override
120     public Image get(TileKey key) throws ProvisionException {
121         // TODO: make this code a utility and externalize the remaining logic as a strategy
122         // This very same code is the same in all ITileProvider implementations.
123
124         int level = key.getLevel();
125         int x = key.getX();
126         int y = key.getY();
127
128         double xTiles = Math.pow(2, level + 1);
129         double yTiles = Math.pow(2, level);
130
131         if (level < 0)
132             throw new IllegalArgumentException("invalid tile level " + level + " (tile=" + key +")");
133         if (x < 0 || x >= (int) xTiles)
134             throw new IllegalArgumentException("tile x out of bounds " + x + " (tile=" + key +")");
135         if (y < 0 || y >= (int) yTiles)
136             throw new IllegalArgumentException("tile y out of bounds " + y + " (tile=" + key +")");
137
138         Rectangle2D r = new Rectangle2D.Double();
139
140         double minx = -180;
141         double miny = -90;
142         double w = 360;
143         double h = 180;
144
145         double xdelta = w / xTiles;
146         double ydelta = h / yTiles;
147         double xx = x;
148         double yy = yTiles - y - 1;
149
150         r.setFrame(
151                 minx + xdelta*xx,
152                 miny + ydelta*yy,
153                 xdelta,
154                 ydelta
155         );
156
157         if (r.intersects(extentDegrees)) {
158             Rectangle2D meters = transformDegreesToMeters(r);
159 //            System.out.println("getImage: " + meters.getMinX() + ", " + meters.getMaxX() + ", " + meters.getWidth() + " ... " + meters.getMinY() + ", " + meters.getMaxY() + ", " + meters.getHeight());
160             try {
161                 return getImage(meters);
162             } catch (IOException e) {
163                 throw new ProvisionException(e);
164             }
165         }
166
167         return getOutOfBoundsImage();
168     }
169
170     private Image getOutOfBoundsImage() {
171         if (outOfBoundsImage != null)
172             return outOfBoundsImage;
173
174         final int outOfBoundsImageSize = 1;
175         BufferedImage image = ImageUtil.createScreenCompatibleImage(outOfBoundsImageSize, outOfBoundsImageSize, BufferedImage.OPAQUE);
176         Graphics2D g = image.createGraphics();
177         try {
178             g.setColor(Color.PINK);
179             g.fillRect(0, 0, outOfBoundsImageSize, outOfBoundsImageSize);
180             outOfBoundsImage = image;
181             return image;
182         } finally {
183             g.dispose();
184         }
185     }
186
187     private Rectangle2D transformDegreesToMeters(Rectangle2D r) {
188         double nx1 = (r.getMinX() - extentDegrees.getMinX()) * deWidthRecip;
189         double ny1 = (r.getMinY() - extentDegrees.getMinY()) * deHeightRecip;
190         double nx2 = (r.getMaxX() - extentDegrees.getMinX()) * deWidthRecip;
191         double ny2 = (r.getMaxY() - extentDegrees.getMinY()) * deHeightRecip;
192         double dw = extentMeters.getWidth();
193         double dh = extentMeters.getHeight();
194         Rectangle2D result = new Rectangle2D.Double();
195         result.setFrameFromDiagonal(
196                 extentMeters.getMinX() + nx1 * dw,
197                 extentMeters.getMinY() + ny1 * dh,
198                 extentMeters.getMinX() + nx2 * dw,
199                 extentMeters.getMinY() + ny2 * dh
200         );
201         return result;
202     }
203
204     private BufferedImage getImage(Rectangle2D r) throws IOException {
205         double w = r.getWidth();
206         double h = r.getHeight();
207         String tileSizeStringX;
208         String tileSizeStringY;
209         if (w > h) {
210             tileSizeStringX = tileSizeString;
211             tileSizeStringY = "" + (int) Math.round(((double)tilePixelSize) * (h/w));
212         } else {
213             tileSizeStringX = "" + (int) Math.round(((double)tilePixelSize) * (w/h));
214             tileSizeStringY = tileSizeString;
215         }
216
217         File tempFile = File.createTempFile("map", ".png");
218         String[] cmd = new String[] {
219                 SHP2IMG_EXECUTABLE,
220 //                "-all_debug",
221 //                "5",
222                 "-m",
223                 mapName,
224                 "-o",
225                 tempFile.getAbsolutePath(),
226                 "-s",
227                 tileSizeStringX,
228                 tileSizeStringY,
229                 "-e",
230                 String.valueOf(r.getMinX()),
231                 String.valueOf(r.getMinY()),
232                 String.valueOf(r.getMaxX()),
233                 String.valueOf(r.getMaxY())
234         };
235         try {
236             try {
237 //                System.out.println(System.currentTimeMillis() + " TEMP FILE: " + tempFile);
238 //                System.out.println(System.currentTimeMillis() + " EXEC: " + Arrays.toString(cmd));
239 //                System.out.println(System.currentTimeMillis() + " EXEC: " + Arrays.toString(ENVP));
240 //                System.out.println(System.currentTimeMillis() + " EXEC: " + mapDirectory);
241                 Process p = Runtime.getRuntime().exec(cmd, ENVP, mapDirectory);
242                 int result = p.waitFor();
243 //                System.out.println(System.currentTimeMillis() + " PROCESS EXITED: " + result);
244                 if (result != 0)
245                     throw new ProvisionException(SHP2IMG_EXECUTABLE + " returned error code: " + result);
246                 //Thread.sleep(500);
247                 BufferedImage img = ImageIO.read(tempFile);
248                 //System.out.println("img = " + img);
249                 if (img == null)
250                     throw new ProvisionException("Failed to provide image for rectangle: " + r);
251                 return ImageUtil.toScreenCompatibleImage(img);
252             } finally {
253                 if (tempFile.exists()) {
254 //                    System.out.println("DELETING TEMP FILE: " + tempFile);
255                     tempFile.delete();
256                 }
257             }
258         } catch (IOException e) {
259             throw new ProvisionException(e);
260         } catch (InterruptedException e) {
261             throw new ProvisionException(e);
262         }
263     }
264
265     public static void main(String[] args) {
266         try {
267             Rectangle2D degreeExtent = new Rectangle2D.Double();
268             Rectangle2D meterExtent = new Rectangle2D.Double();
269             degreeExtent.setFrameFromDiagonal(24.8, 60.175, 24.84, 60.195);
270             meterExtent.setFrameFromDiagonal(2544800, 6674000, 2546842.4, 6676000);
271
272             Shp2ImgTileProvider p = new Shp2ImgTileProvider("d:/TerrasolidOtaniemiMalli/ortho", "global.map", 512, degreeExtent, meterExtent);
273
274             BufferedImage buf = p.getImage(meterExtent);
275             ImageIO.write(buf, "png", new File("d:\\temp\\test.png"));
276         } catch (Throwable e) {
277             e.printStackTrace();
278         }
279     }
280
281 }