package se.kodapan.osm.city;
import se.kodapan.osm.domain.Node;
import se.kodapan.osm.domain.Way;
import se.kodapan.osm.domain.root.PojoRoot;
import se.kodapan.osm.parser.xml.instantiated.InstantiatedOsmXmlParser;
import se.kodapan.osm.util.distance.ArcDistance;
import se.kodapan.osm.xml.OsmXmlWriter;
import java.io.*;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author kalle
* @since 2015-01-12 03:47
*/
public class Grid {
public static void main(String[] args) throws Exception {
}
private Cell[][] columns;
private double south;
private double west;
private double north;
private double east;
private double gridColumns;
private double gridRows;
private int squarePixelsWidth;
private int squarePixelsHeight;
private double longitudeDegreesDistancePerPixel;
private double latitudeDegreesDistancePerPixel;
private double longitudeMetersDistancePerPixel;
private double latitudeMetersDistancePerPixel;
private double kilometersHeight;
private double kilometersWidth;
private int cellSquareSizeMeters;
public Grid(double south, double west, double north, double east, int imageWidth, int imageHeight, int cellSquareSizeMeters) {
this.south = south;
this.west = west;
this.north = north;
this.east = east;
this.cellSquareSizeMeters = cellSquareSizeMeters;
latitudeDegreesDistancePerPixel = (north - south) / imageHeight;
longitudeDegreesDistancePerPixel = (east - west) / imageWidth;
ArcDistance arcDistance = new ArcDistance();
kilometersHeight = arcDistance.calculate(south, west, north, west);
kilometersWidth = arcDistance.calculate(south, west, south, east);
longitudeMetersDistancePerPixel = imageWidth / kilometersWidth;
latitudeMetersDistancePerPixel = imageHeight / kilometersHeight;
gridColumns = (kilometersWidth * 1000) / cellSquareSizeMeters;
gridRows = (kilometersHeight * 1000) / cellSquareSizeMeters;
squarePixelsWidth = (int) ((double) imageWidth / gridColumns);
squarePixelsHeight = (int) ((double) imageHeight / gridRows);
columns = new Cell[(int) gridColumns][];
for (int x = 0; x < columns.length; x++) {
columns[x] = new Cell[(int) gridRows];
for (int y = 0; y < columns[x].length; y++) {
columns[x][y] = new Cell(x, y);
}
}
}
public void writeOsmXML(File file) throws Exception {
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF8");
writeOsmXML(writer);
writer.close();
}
public void writeOsmXML(Writer writer) throws Exception {
DecimalFormat df = new DecimalFormat("#.##");
long id = -1;
OsmXmlWriter xml = new OsmXmlWriter(writer);
for (int x = 0; x < columns.length; x++) {
for (int y = 0; y < columns[x].length; y++) {
Cell cell = getCell(x, y);
if (cell.getInstance() != null) {
Way way = new Way(id--);
if (cell.getClassification() != null) {
way.setTag("class", cell.getClassification());
}
way.addNode(new Node(id--, cell.getInstance().getSouth(), cell.getInstance().getWest()));
way.addNode(new Node(id--, cell.getInstance().getNorth(), cell.getInstance().getWest()));
way.addNode(new Node(id--, cell.getInstance().getNorth(), cell.getInstance().getEast()));
way.addNode(new Node(id--, cell.getInstance().getSouth(), cell.getInstance().getEast()));
way.addNode(new Node(id--, cell.getInstance().getSouth(), cell.getInstance().getWest()));
way.setTag("type", "bbox");
for (int i = 0; i < cell.getInstance().getHistogramPercent().length; i++) {
way.setTag("color:" + i + ":percent", df.format(100d * cell.getInstance().getHistogramPercent()[i]));
}
xml.write(way);
for (Node node : way.getNodes()) {
xml.write(node);
}
}
}
}
xml.close();
}
public Map<Instance, String> loadTrainingData(InstanceFactory instanceFactory) throws Exception {
PojoRoot root = new PojoRoot();
InstantiatedOsmXmlParser parser = InstantiatedOsmXmlParser.newInstance();
parser.setRoot(root);
parser.parse(new FileInputStream("trainingdata-malmo.osm.xml"));
Map<Instance, String> instances = new HashMap<Instance, String>(root.getWays().size());
for (Way way : root.getWays().values()) {
String classification = way.getTag("class");
if (classification != null) {
double south = way.getNodes().get(0).getLatitude();
double west = way.getNodes().get(0).getLongitude();
double north = way.getNodes().get(1).getLatitude();
double east = way.getNodes().get(2).getLongitude();
instances.put(instanceFactory.newInstance(south, west, north, east), classification);
}
}
return instances;
}
public double getCellSouth(int x, int y) {
return north - (latitudeDegreesDistancePerPixel * squarePixelsHeight * y);
}
public double getCellNorth(int x, int y) {
return getCellSouth(x, y) + (latitudeDegreesDistancePerPixel * squarePixelsHeight);
}
public double getCellWest(int x, int y) {
return east - (longitudeDegreesDistancePerPixel * squarePixelsWidth * x);
}
public double getCellEast(int x, int y) {
return getCellWest(x, y) + (longitudeDegreesDistancePerPixel * squarePixelsWidth);
}
public int getWidth() {
return (int) gridColumns;
}
public int getHeight() {
return (int) gridRows;
}
public Cell getCellByCoordinate(double longitude, double latitude) {
return getCell(
getGridX(getImageX(longitude)), getGridY(getImageY(latitude))
);
}
public Cell getCellByImagePosition(int x, int y) {
return getCell(
getGridX(x), getGridY(y)
);
}
public Cell getCell(int x, int y) {
return columns[x][y];
}
public int getGridX(int imageX) {
return imageX / squarePixelsWidth;
}
public int getGridY(int imageY) {
return imageY / squarePixelsHeight;
}
public int getImageX(double longitude) {
return (int) ((longitude - west) / longitudeDegreesDistancePerPixel);
}
public int getImageY(double latitude) {
return (int) ((north - latitude) / latitudeDegreesDistancePerPixel);
}
public double getLatitudeY(int y) {
return south + (latitudeDegreesDistancePerPixel * y);
}
public double getLongitudeX(int x) {
return west + (longitudeDegreesDistancePerPixel * x);
}
public Cell[][] getColumns() {
return columns;
}
public double getSouth() {
return south;
}
public double getWest() {
return west;
}
public double getNorth() {
return north;
}
public double getEast() {
return east;
}
public double getGridColumns() {
return gridColumns;
}
public double getGridRows() {
return gridRows;
}
public int getSquarePixelsWidth() {
return squarePixelsWidth;
}
public int getSquarePixelsHeight() {
return squarePixelsHeight;
}
public double getLongitudeDegreesDistancePerPixel() {
return longitudeDegreesDistancePerPixel;
}
public double getLatitudeDegreesDistancePerPixel() {
return latitudeDegreesDistancePerPixel;
}
public double getLongitudeMetersDistancePerPixel() {
return longitudeMetersDistancePerPixel;
}
public double getLatitudeMetersDistancePerPixel() {
return latitudeMetersDistancePerPixel;
}
public double getKilometersHeight() {
return kilometersHeight;
}
public double getKilometersWidth() {
return kilometersWidth;
}
public int getCellSquareSizeMeters() {
return cellSquareSizeMeters;
}
}