/*
* 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.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<>(excSvc
);
String workDirName = args
[0];
System.
out.
println(workDirName
);
File boundaryDir =
new File(workDirName
);
final Set<String> boundsFileNames =
new HashSet<>();
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.
parseInt(parts
[0]);
int lon =
Integer.
parseInt(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<>(boundsFileNames
));
final int adminLevel = adminlevel
;
final Queue<Future<Area>> areas =
new LinkedBlockingQueue<>();
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(() -
> {
String filename =
"bounds_" + fLat +
"_" + fLon +
".bnd";
if (!boundaryFileNames.
contains(filename
)) {
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<>();
for (int i =
0; i
< maxSteps
* 2 && !areas.
isEmpty(); i++
) {
toMerge.
add(areas.
poll());
}
mergeSteps.
incrementAndGet();
areas.
add(executor.
submit(() -
> {
Area a =
new Area();
ListIterator<Future<Area>> mergeAreas = toMerge.
listIterator();
while (mergeAreas.
hasNext()) {
try {
a.
add(mergeAreas.
next().
get());
} catch (InterruptedException exp1
) {
System.
err.
println(exp1
);
} catch (ExecutionException exp2
) {
System.
err.
println(exp2
);
}
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();
}
}