/*
* Copyright (C) 2006, 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* This program 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
* General Public License for more details.
*/
package uk.me.parabola.mkgmap.reader.osm.boundary;
import java.awt.geom.Area;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.reader.osm.Way;
import uk.me.parabola.util.GpxCreator;
import uk.me.parabola.util.Java2DConverter;
public class BoundaryCoverageUtil {
private final BoundaryQuadTree bqt;
public BoundaryCoverageUtil(String boundaryDirName, String boundaryFileName) {
bqt = BoundaryUtil.loadQuadTree(boundaryDirName, boundaryFileName);
}
public Area getCoveredArea(int admLevel) {
return bqt.getCoveredArea(admLevel);
}
private static void saveArea(String attribute, Integer level, Area covered) {
String gpxBasename = "gpx/summary/" + attribute + "/admin_level="
+ level;
List<List<Coord>> coveredPolys = Java2DConverter.areaToShapes(covered);
Collections.reverse(coveredPolys);
int i = 0;
for (List<Coord> coveredPart : coveredPolys) {
String attr = Way.clockwise(coveredPart) ? "o" : "i";
GpxCreator.createGpx(gpxBasename + "/" + i + "_" + attr, coveredPart);
i++;
}
}
public static void main(String[] args) throws InterruptedException {
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService excSvc = Executors.newFixedThreadPool(processors);
ExecutorCompletionService<Area> executor = new ExecutorCompletionService<Area>(
excSvc);
String workDirName = args[0];
System.out.println(workDirName);
File boundaryDir = new File(workDirName);
final Set<String> boundsFileNames = new HashSet<String>();
if (boundaryDir.isFile() && boundaryDir.getName().endsWith(".bnd")) {
workDirName = boundaryDir.getParent();
if (workDirName == null)
workDirName = ".";
boundsFileNames.add(boundaryDir.getName());
} else {
boundsFileNames.addAll(BoundaryUtil
.getBoundaryDirContent(workDirName));
}
int minLat = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int minLon = Integer.MAX_VALUE;
int maxLon = Integer.MIN_VALUE;
for (String fileName : boundsFileNames) {
String[] parts = fileName.substring("bounds_".length(),
fileName.length() - 4).split("_");
int lat = Integer.valueOf(parts[0]);
int lon = Integer.valueOf(parts[1]);
if (lat < minLat)
minLat = lat;
if (lat > maxLat)
maxLat = lat;
if (lon < minLon)
minLon = lon;
if (lon > maxLon)
maxLon = lon;
}
System.out.format("Covered area: (%d,%d)-(%d,%d)\n", minLat, minLon,
maxLat, maxLon);
int maxSteps = 2;
final String boundaryDirName = workDirName;
for (int adminlevel = 2; adminlevel < 12; adminlevel++) {
final Set<String> boundaryFileNames = Collections.synchronizedSet(new HashSet<String>(boundsFileNames));
final int adminLevel = adminlevel;
final Queue<Future<Area>> areas = new LinkedBlockingQueue<Future<Area>>();
for (int lat = minLat; lat <= maxLat; lat += maxSteps
* BoundaryUtil.RASTER) {
for (int lon = minLon; lon <= maxLon; lon += maxSteps
* BoundaryUtil.RASTER) {
for (int latStep = 0; latStep < maxSteps
&& lat + latStep * BoundaryUtil.RASTER <= maxLat; latStep++) {
for (int lonStep = 0; lonStep < maxSteps
&& lon + lonStep * BoundaryUtil.RASTER <= maxLon; lonStep++) {
final int fLat = lat + latStep
* BoundaryUtil.RASTER;
final int fLon = lon + lonStep
* BoundaryUtil.RASTER;
areas.add(executor.submit(new Callable<Area>() {
public Area call() {
String filename = "bounds_" + fLat + "_"
+ fLon + ".bnd";
if (boundaryFileNames.contains(filename) == false) {
return new Area();
}
BoundaryCoverageUtil converter = new BoundaryCoverageUtil(
boundaryDirName, filename);
boundaryFileNames.remove(filename);
System.out.format("%5d bounds files remaining\n", boundaryFileNames.size());
return converter.getCoveredArea(adminLevel);
}
}));
}
}
}
}
final AtomicInteger mergeSteps = new AtomicInteger();
while (areas.size() > 1) {
final List<Future<Area>> toMerge = new ArrayList<Future<Area>>();
for (int i = 0; i < maxSteps * 2 && areas.isEmpty() == false; i++) {
toMerge.add(areas.poll());
}
mergeSteps.incrementAndGet();
areas.add(executor.submit(new Callable<Area>() {
public Area call() {
Area a = new Area();
ListIterator<Future<Area>> mergeAreas = toMerge
.listIterator();
while (mergeAreas.hasNext()) {
try {
a.add(mergeAreas.next().get());
} catch (InterruptedException exp) {
System.err.println(exp);
} catch (ExecutionException exp) {
System.err.println(exp);
}
mergeAreas.remove();
}
System.out.format("%5d merges remaining\n",mergeSteps.decrementAndGet());
return a;
}
}));
}
try {
Area finalArea = areas.poll().get();
System.out.println("Joining finished. Saving results.");
saveArea("covered", adminlevel, finalArea);
} catch (Exception exp) {
System.err.println(exp);
}
// }
}
excSvc.shutdown();
}
}