/*
* 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.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
/**
* The class merges two directories with precompiled bounds files. Both directory may contain files covering
* the same area. These files are merged so that the resulting file contains all boundaries of both
* files. Boundaries with the same OSM-id that are contained in both files are merged with a union of its covered area.
* <br/><br/>
* Using this merger it is possible to create several smaller bounds compilations (e.g. one country only) and merge
* these compilations together afterwards.
*
* @author WanMil
*/
public class BoundaryMerger {
public BoundaryMerger() {
}
private void copy(File file, File to) {
String filename = file.getName();
try (FileChannel in = (new FileInputStream(file)).getChannel();
FileChannel out = (new FileOutputStream(new File(to, filename))).getChannel()) {
in.transferTo(0, file.length(), out);
in.close();
out.close();
} catch (IOException exp) {
System.err.println(exp);
}
}
public void merge(File dir1, File dir2, File targetDir) throws IOException {
List<String> fl1 = BoundaryUtil.getBoundaryDirContent(dir1.getAbsolutePath());
List<String> fl2 = BoundaryUtil.getBoundaryDirContent(dir2.getAbsolutePath());
Collections.sort(fl1);
Collections.sort(fl2);
ListIterator<String> fl1Iter = fl1.listIterator();
ListIterator<String> fl2Iter = fl2.listIterator();
BoundarySaver bSave = new BoundarySaver(targetDir, BoundarySaver.QUADTREE_DATA_FORMAT);
bSave.setCreateEmptyFiles(false);
List<File> copy = new ArrayList<File>();
int processed = 0;
int all = fl1.size()+fl2.size();
while (fl1Iter.hasNext() || fl2Iter.hasNext()) {
String f1 = (fl1Iter.hasNext() ? fl1Iter.next(): null);
String f2 = (fl2Iter.hasNext() ? fl2Iter.next(): null);
if (f1 == null) {
copy.add(new File(dir2,f2));
} else if (f2 == null) {
copy.add(new File(dir1,f1));
} else {
int cmp = f1.compareTo(f2);
if (cmp < 0) {
copy.add(new File(dir1,f1));
fl2Iter.previous();
} else if (cmp > 0) {
copy.add(new File(dir2,f2));
fl1Iter.previous();
} else {
BoundaryQuadTree bqt1 = BoundaryUtil.loadQuadTree(dir1.getAbsolutePath(), f1);
if (bqt1 == null){
System.err.println("Failed to load quadtree for " + dir1.getAbsolutePath() + f1);
System.exit(-1);
}
BoundaryQuadTree bqt2 = BoundaryUtil.loadQuadTree(dir2.getAbsolutePath(), f2);
if (bqt2 == null){
System.err.println("Failed to load quadtree for " + dir2.getAbsolutePath() + f2);
System.exit(-1);
}
bqt1.merge(bqt2);
bSave.saveQuadTree(bqt1, f1);
processed += 2;
System.out.println(processed+"/"+all+" processed");
}
}
}
bSave.end();
for (File f: copy) {
copy(f, targetDir);
processed++;
System.out.println(processed+"/"+all+" processed");
}
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
if (args.length != 3) {
System.err.println("java uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryMerger <bounds1> <bounds2> <merge>");
System.err.println("<bounds1> <bounds2> : directories with *.bnd files to merge");
System.err.println("<merge> target directory, is created if it doesn't exist");
return;
}
File b1 = new File(args[0]);
File b2 = new File(args[1]);
File merge = new File(args[2]);
// TODO: maybe allow zip as input
if (b1.exists() == false || b1.isDirectory() == false) {
System.err.println(b1 + " does not exist or is not a directory");
return;
}
if (b2.exists() == false || b2.isDirectory() == false) {
System.err.println(b2 + " does not exist or is not a directory");
return;
}
if (merge.exists() && merge.isDirectory() == false) {
System.err.println(merge + " is not a directory");
}
if (merge.exists() == false) {
merge.mkdirs();
}
BoundaryMerger merger = new BoundaryMerger();
merger.merge(b1, b2, merge);
}
}