/*
* KMLRenderer.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.geo;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.util.ArrayList;
/**
* @author Alexei Drummond
*/
public class KMLRenderer implements Lattice {
BufferedImage image;
int[][] lattice;
Rectangle2D bounds;
java.util.List<AbstractPolygon2D> polygons;
java.util.List<Shape> shapes;
ViewTransform viewTransform;
Color shapeColor;
Color background;
public KMLRenderer(String kmlFileName, Color shapeColor, Color background) {
polygons = Polygon2D.readKMLFile(kmlFileName);
this.shapeColor = shapeColor;
this.background = background;
System.out.println("Read " + polygons.size() + " polygons");
System.out.println("Converting polygons to shapes");
double minX = Double.MAX_VALUE, maxX = -Double.MAX_VALUE, minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
shapes = new ArrayList<Shape>();
for (AbstractPolygon2D p : polygons) {
Shape shape = p.getShape();
bounds = shape.getBounds();
if (bounds.getMinX() < minX) minX = bounds.getMinX();
if (bounds.getMaxX() > maxX) maxX = bounds.getMaxX();
if (bounds.getMinY() < minY) minY = bounds.getMinY();
if (bounds.getMaxY() > maxY) maxY = bounds.getMaxY();
shapes.add(shape);
System.out.print(".");
System.out.flush();
}
bounds = new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
System.out.println();
}
public Rectangle2D getBounds() {
return bounds;
}
public BufferedImage render(int size) {
int width;
int height;
if (bounds.getHeight() > bounds.getWidth()) {
height = size;
width = (int) (height * bounds.getWidth() / bounds.getHeight());
} else {
width = size;
height = (int) (width * bounds.getHeight() / bounds.getWidth());
}
return render(width, height);
}
public BufferedImage render(int width, int height) {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
render(image);
Raster raster = image.getData();
lattice = new int[width][height];
int[] pixel = new int[4];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
raster.getPixel(i, j, pixel);
if (colorDistanceSquared(pixel, shapeColor) < colorDistanceSquared(pixel, background)) {
lattice[i][j] = 1;
} else {
lattice[i][j] = 0;
}
}
}
return image;
}
private double colorDistanceSquared(int[] pixel, Color color) {
double[] argb = new double[4];
argb[0] = Math.abs(pixel[0] - color.getAlpha());
argb[1] = Math.abs(pixel[1] - color.getRed());
argb[2] = Math.abs(pixel[2] - color.getGreen());
argb[3] = Math.abs(pixel[3] - color.getBlue());
double dist = 0;
for (double a : argb) {
dist += a * a;
}
return dist;
}
public void render(BufferedImage image) {
Graphics2D g2d = image.createGraphics();
g2d.setColor(background);
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
viewTransform = new ViewTransform(bounds, image.getWidth(), image.getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(shapeColor);
AffineTransform transform = viewTransform.getTransform();
for (Shape s : shapes) {
GeneralPath path = new GeneralPath(s);
path.transform(transform);
g2d.fill(path);
}
}
public int latticeWidth() {
return lattice.length;
}
public int latticeHeight() {
return lattice[0].length;
}
public void setState(int i, int j, int state) {
lattice[i][j] = state;
}
public int getState(int i, int j) {
return lattice[i][j];
}
public void paintLattice(Graphics g) {
g.drawImage(image, 0, 0, null);
}
public void setBounds(Rectangle2D bounds) {
this.bounds = bounds;
}
}