View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.demos.mediaeval13.placing;
31  
32  import gnu.trove.list.array.TLongArrayList;
33  
34  import java.io.File;
35  import java.io.FileNotFoundException;
36  import java.io.IOException;
37  import java.util.List;
38  
39  import org.apache.batik.transcoder.TranscoderException;
40  import org.apache.fop.svg.PDFTranscoder;
41  import org.geotools.geometry.DirectPosition2D;
42  import org.geotools.referencing.operation.DefaultMathTransformFactory;
43  import org.geotools.referencing.operation.projection.HotineObliqueMercator;
44  import org.opengis.geometry.DirectPosition;
45  import org.opengis.parameter.ParameterValueGroup;
46  import org.opengis.referencing.FactoryException;
47  import org.opengis.referencing.operation.MathTransformFactory;
48  import org.opengis.referencing.operation.TransformException;
49  import org.openimaj.image.FImage;
50  import org.openimaj.image.SVGImage;
51  import org.openimaj.image.VectorImageUtilities;
52  import org.openimaj.image.renderer.ImageRenderer;
53  import org.openimaj.image.renderer.RenderHints;
54  import org.openimaj.math.geometry.line.Line2d;
55  import org.openimaj.math.geometry.point.Point2d;
56  import org.openimaj.math.geometry.point.Point2dImpl;
57  import org.openimaj.math.geometry.shape.Polygon;
58  import org.openimaj.math.geometry.shape.Shape;
59  import org.openimaj.vis.world.WorldPlace;
60  import org.openimaj.vis.world.WorldPolygons;
61  
62  public class DrawMap {
63  
64  	private static final File BASE = new File("/Users/ss/Experiments/placing");
65  	private static final File DEFAULT_LAT_LNG_FILE = new File(BASE, "training_latlng");
66  
67  	private static final int GRID_WIDTH = 5;
68  	private static final int BORDER_WIDTH = 4;
69  	private static final Float[] BG_COLOUR = new Float[] { 30 / 255f, 32 / 255f, 78 / 255f };
70  	private static final Float[] COUNTRY_BORDER_COLOUR = new Float[] { 90 / 255f, 90 / 255f, 140 / 255f };
71  	private static final Float[] GRID_COLOUR = new Float[] { 70 / 255f, 70 / 255f, 78 / 255f };
72  
73  	public static void main(String[] args) throws FileNotFoundException, IOException, TransformException,
74  			FactoryException, TranscoderException
75  	{
76  		System.out.println("Reading latlong");
77  		final List<GeoLocation> lls = Utils.readLatLng(DEFAULT_LAT_LNG_FILE, new TLongArrayList());
78  		System.out.println("...done");
79  
80  		final MathTransformFactory fact = new DefaultMathTransformFactory();
81  		final ParameterValueGroup params = fact.getDefaultParameters("Hotine Oblique Mercator");
82  		params.parameter("semi_major").setValue(6377397.155);
83  		params.parameter("semi_minor").setValue(6356078.963);
84  		params.parameter("longitude_of_center").setValue(7.439583333333333);
85  		params.parameter("latitude_of_center").setValue(46.952405555555565);
86  		params.parameter("azimuth").setValue(90.0);
87  		params.parameter("scale_factor").setValue(1);
88  		params.parameter("false_easting").setValue(600000.0);
89  		params.parameter("false_northing").setValue(200000.0);
90  		params.parameter("rectified_grid_angle").setValue(0.0); // 45
91  
92  		final HotineObliqueMercator transform = (HotineObliqueMercator) fact.createParameterizedTransform(params);
93  
94  		double minx = 0;
95  		double maxx = 0;
96  		double miny = 0;
97  		double maxy = 0;
98  		for (int y = -90; y <= 90; y += 10) {
99  			for (int x = -180; x <= 180; x += 10) {
100 				final DirectPosition2D dp = new DirectPosition2D(x, y);
101 				// final DirectPosition dp =null;
102 				final double[] pt = transform.transform(dp, (DirectPosition) null).getCoordinate();
103 				// double[] pt = transform.transform(dp, null);
104 				if (pt[0] > maxx)
105 					maxx = pt[0];
106 				if (pt[0] < minx)
107 					minx = pt[0];
108 				if (pt[1] > maxy)
109 					maxy = pt[1];
110 				if (pt[1] < miny)
111 					miny = pt[1];
112 			}
113 		}
114 
115 		// final MBFImage img = new MBFImage(10000, (int) (10000 * ((maxy -
116 		// miny) / (maxx - minx))), 3);
117 		final SVGImage img = new SVGImage(10000, (int) (10000 * ((maxy - miny) / (maxx - minx))));
118 		img.fill(BG_COLOUR);
119 		final ImageRenderer<Float[], SVGImage> r = img.createRenderer(RenderHints.ANTI_ALIASED);
120 		System.out.println("Rendering world");
121 		final WorldPolygons wp = new WorldPolygons();
122 		for (final WorldPlace place : wp.getShapes()) {
123 			for (final Shape s : place.getShapes()) {
124 				final Polygon p = transform(s.asPolygon(), transform, minx, maxx, miny, maxy, img.getWidth(),
125 						img.getHeight()).asPolygon();
126 
127 				if (p.nVertices() < 2)
128 					return;
129 
130 				Point2d p1, p2;
131 				for (int i = 0; i < p.nVertices() - 1; i++) {
132 					p1 = p.getVertices().get(i);
133 					p2 = p.getVertices().get(i + 1);
134 
135 					if (Line2d.distance(p1, p2) < img.getHeight() / 2)
136 						r.drawLine(p1.getX(), p1.getY(), p2.getX(), p2.getY(), BORDER_WIDTH, COUNTRY_BORDER_COLOUR);
137 				}
138 
139 				p1 = p.getVertices().get(p.nVertices() - 1);
140 				p2 = p.getVertices().get(0);
141 				if (Line2d.distance(p1, p2) < img.getHeight() / 2)
142 					r.drawLine(p1.getX(), p1.getY(), p2.getX(), p2.getY(), BORDER_WIDTH, COUNTRY_BORDER_COLOUR);
143 			}
144 		}
145 		System.out.println("Preparing heatmap");
146 		final FImage heatmap = new FImage(img.getWidth(), img.getHeight());
147 		for (final GeoLocation ll : lls) {
148 			final Point2dImpl pt = new Point2dImpl((float) ll.longitude, (float) ll.latitude);
149 			final Point2dImpl tpt = transform(transform, minx, maxx, miny, maxy, heatmap.width, heatmap.height, pt);
150 
151 			final int tx = (int) tpt.x;
152 			final int ty = (int) tpt.y;
153 
154 			if (tx >= 0 && tx < heatmap.width && ty >= 0 && ty < heatmap.height)
155 				heatmap.pixels[ty][tx]++;
156 		}
157 
158 		for (int y = 0; y < heatmap.height; y++) {
159 			for (int x = 0; x < heatmap.width; x++) {
160 				heatmap.pixels[y][x] = heatmap.pixels[y][x] == 0 ? 0 : (float) Math.log(heatmap.pixels[y][x]);
161 			}
162 		}
163 		// heatmap.processInplace(new FGaussianConvolve(10.0f));
164 		// heatmap.normalise();
165 		//
166 		// System.out.println("Drawing points");
167 		// for (int y = 0; y < heatmap.height; y++) {
168 		// for (int x = 0; x < heatmap.width; x++) {
169 		// float val = heatmap.pixels[y][x];
170 		// if (val > 0) {
171 		// val = 0.5f + 0.5f * val;
172 		// final float red = Interpolation.lerp(val, 0, BG_COLOUR[0], 1, 1);
173 		// final float green = Interpolation.lerp(val, 0, BG_COLOUR[1], 1, 1);
174 		// final float blue = Interpolation.lerp(val, 0, BG_COLOUR[2], 1, 1);
175 		//
176 		// for (int yy = -1; yy <= 1; yy++)
177 		// for (int xx = -1; xx <= 1; xx++)
178 		// img.setPixel(x + xx, y + yy, new Float[] { red, green, blue });
179 		// }
180 		// }
181 		// }
182 		// System.out.println("Drawing grid lines");
183 		// for (int y = -90; y <= 90; y += 15) {
184 		// Point2dImpl last = transform(transform, minx, maxx, miny, maxy,
185 		// img.getWidth(), img.getHeight(),
186 		// new Point2dImpl(-180, y));
187 		//
188 		// for (float x = -180; x <= 180; x += 0.1) {
189 		// final Point2dImpl pt = transform(transform, minx, maxx, miny, maxy,
190 		// img.getWidth(), img.getHeight(),
191 		// new Point2dImpl(x, y));
192 		// if (Line2d.distance(last, pt) < img.getHeight() / 2)
193 		// r.drawLine(last, pt, GRID_WIDTH, GRID_COLOUR);
194 		// last = pt;
195 		// }
196 		// }
197 
198 		// for (int x = -180; x <= 180; x += 15) {
199 		// Point2dImpl last = transform(transform, minx, maxx, miny, maxy,
200 		// img.getWidth(), img.getHeight(),
201 		// new Point2dImpl(x, -90));
202 		//
203 		// for (float y = -90; y <= 90; y += 0.1f) {
204 		// final Point2dImpl pt = transform(transform, minx, maxx, miny, maxy,
205 		// img.getWidth(), img.getHeight(),
206 		// new Point2dImpl(x, y));
207 		// if (Line2d.distance(last, pt) < img.getHeight() / 2)
208 		// r.drawLine(last, pt, GRID_WIDTH, GRID_COLOUR);
209 		// last = pt;
210 		// }
211 		// }
212 		System.out.println("Writing image..");
213 
214 		// MBFImage bigimg = new MBFImage(img.getWidth(), (int) (img.getHeight()
215 		// * 1.5), 3);
216 		// bigimg.drawImage(img, 0, -img.getHeight() / 2);
217 		// bigimg.drawImage(img, 0, img.getHeight() / 2);
218 		//
219 		// bigimg = ProjectionProcessor.project(bigimg,
220 		// TransformUtilities.rotationMatrix(Math.PI / 4), BG_COLOUR);
221 		//
222 		// bigimg = bigimg.extractROI(new Rectangle(
223 		// (int) (bigimg.getWidth() / 3.15),
224 		// (int) (bigimg.getHeight() / 3.5),
225 		// (int) (0.65f * img.getWidth()),
226 		// (int) (0.65f * img.getWidth() * Math.sqrt(2))));
227 
228 		// ImageUtilities.write(bigimg, new File("/Users/jsh2/map.png"));
229 		VectorImageUtilities.write(img, new File("/Users/ss/out.pdf"), new PDFTranscoder());
230 	}
231 
232 	private static Shape transform(Polygon asPolygon, HotineObliqueMercator transform, double minx, double maxx,
233 			double miny, double maxy, int width, int height) throws TransformException
234 	{
235 		final Polygon p = new Polygon();
236 
237 		for (final Point2d pt : asPolygon.points) {
238 			final Point2dImpl pto = transform(transform, minx, maxx, miny, maxy, width, height, pt);
239 
240 			p.points.add(pto);
241 		}
242 
243 		return p;
244 	}
245 
246 	private static Point2dImpl transform(HotineObliqueMercator transform, double minx, double maxx, double miny,
247 			double maxy, int width, int height, final Point2d pt) throws TransformException
248 	{
249 		final float x = pt.getX();
250 		final float y = pt.getY();
251 		final double[] c = transform.transform(new DirectPosition2D(x, y), (DirectPosition) null)
252 				.getCoordinate();
253 
254 		final float px = (float) (width * (c[0] - minx) / (maxx - minx));
255 		final float py = (float) (height - height * (c[1] - miny) / (maxy - miny));
256 		final Point2dImpl pto = new Point2dImpl(px, py);
257 		return pto;
258 	}
259 }