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}