/*
* 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();
}
}