Subversion Repositories mkgmap

Rev

Rev 4544 | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

}