001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.demos.mediaeval13.placing; 031 032import gnu.trove.list.array.TLongArrayList; 033 034import java.io.File; 035import java.io.FileNotFoundException; 036import java.io.IOException; 037import java.util.List; 038 039import org.apache.batik.transcoder.TranscoderException; 040import org.apache.fop.svg.PDFTranscoder; 041import org.geotools.geometry.DirectPosition2D; 042import org.geotools.referencing.operation.DefaultMathTransformFactory; 043import org.geotools.referencing.operation.projection.HotineObliqueMercator; 044import org.opengis.geometry.DirectPosition; 045import org.opengis.parameter.ParameterValueGroup; 046import org.opengis.referencing.FactoryException; 047import org.opengis.referencing.operation.MathTransformFactory; 048import org.opengis.referencing.operation.TransformException; 049import org.openimaj.image.FImage; 050import org.openimaj.image.SVGImage; 051import org.openimaj.image.VectorImageUtilities; 052import org.openimaj.image.renderer.ImageRenderer; 053import org.openimaj.image.renderer.RenderHints; 054import org.openimaj.math.geometry.line.Line2d; 055import org.openimaj.math.geometry.point.Point2d; 056import org.openimaj.math.geometry.point.Point2dImpl; 057import org.openimaj.math.geometry.shape.Polygon; 058import org.openimaj.math.geometry.shape.Shape; 059import org.openimaj.vis.world.WorldPlace; 060import org.openimaj.vis.world.WorldPolygons; 061 062public class DrawMap { 063 064 private static final File BASE = new File("/Users/ss/Experiments/placing"); 065 private static final File DEFAULT_LAT_LNG_FILE = new File(BASE, "training_latlng"); 066 067 private static final int GRID_WIDTH = 5; 068 private static final int BORDER_WIDTH = 4; 069 private static final Float[] BG_COLOUR = new Float[] { 30 / 255f, 32 / 255f, 78 / 255f }; 070 private static final Float[] COUNTRY_BORDER_COLOUR = new Float[] { 90 / 255f, 90 / 255f, 140 / 255f }; 071 private static final Float[] GRID_COLOUR = new Float[] { 70 / 255f, 70 / 255f, 78 / 255f }; 072 073 public static void main(String[] args) throws FileNotFoundException, IOException, TransformException, 074 FactoryException, TranscoderException 075 { 076 System.out.println("Reading latlong"); 077 final List<GeoLocation> lls = Utils.readLatLng(DEFAULT_LAT_LNG_FILE, new TLongArrayList()); 078 System.out.println("...done"); 079 080 final MathTransformFactory fact = new DefaultMathTransformFactory(); 081 final ParameterValueGroup params = fact.getDefaultParameters("Hotine Oblique Mercator"); 082 params.parameter("semi_major").setValue(6377397.155); 083 params.parameter("semi_minor").setValue(6356078.963); 084 params.parameter("longitude_of_center").setValue(7.439583333333333); 085 params.parameter("latitude_of_center").setValue(46.952405555555565); 086 params.parameter("azimuth").setValue(90.0); 087 params.parameter("scale_factor").setValue(1); 088 params.parameter("false_easting").setValue(600000.0); 089 params.parameter("false_northing").setValue(200000.0); 090 params.parameter("rectified_grid_angle").setValue(0.0); // 45 091 092 final HotineObliqueMercator transform = (HotineObliqueMercator) fact.createParameterizedTransform(params); 093 094 double minx = 0; 095 double maxx = 0; 096 double miny = 0; 097 double maxy = 0; 098 for (int y = -90; y <= 90; y += 10) { 099 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}