Rev 4507 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* Copyright (C) 2017.
*
* 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.osmstyle.NameFinder;
import uk.me.parabola.mkgmap.reader.osm.boundary.Boundary;
import uk.me.parabola.mkgmap.reader.osm.boundary.BoundaryQuadTree;
import uk.me.parabola.util.EnhancedProperties;
import uk.me.parabola.util.Java2DConverter;
/**
* Hook to add tag mkgmap:residential to elements that lie within a landuse=residential area.
* @author Gerd Petermann
*
*/
public class ResidentialHook implements OsmReadingHooks {
private static final Logger log = Logger.getLogger(ResidentialHook.class);
private BoundaryQuadTree residentialBoundaries;
private ElementSaver saver;
private NameFinder nameFinder;
@Override
public boolean init(ElementSaver saver, EnhancedProperties props, Style style) {
if (!props.getProperty("residential-hook", true))
return false;
this.nameFinder = new NameFinder(props);
this.saver = saver;
return true;
}
@Override
public void end() {
log.info("Starting with residential hook");
long t1 = System.currentTimeMillis();
residentialBoundaries = buildResidentialBoundaryTree();
long t2 = System.currentTimeMillis();
log.info("Creating residential bounds took", (t2 - t1), "ms");
// process all nodes that might be converted to a garmin node (tagcount > 0)
for (Node node : saver.getNodes().values()) {
if (node.getTagCount() > 0 && saver.getBoundingBox().contains(node.getLocation())) {
processElem(node);
}
}
// process all ways that might be converted to a garmin way (tagcount > 0)
for (Way way : saver.getWays().values()) {
if (way.getTagCount() > 0) {
processElem(way);
}
}
long t3 = System.currentTimeMillis();
log.info("Using residential bounds took", (t3 - t2), "ms");
// free memory
residentialBoundaries = null;
}
private static final short TK_LANDUSE = TagDict.getInstance().xlate("landuse");
private static final short TK_NAME = TagDict.getInstance().xlate("name");
private static final short TKM_STYLEFILTER = TagDict.getInstance().xlate("mkgmap:stylefilter");
private static final short TKM_OTHER = TagDict.getInstance().xlate("mkgmap:other");
private BoundaryQuadTree buildResidentialBoundaryTree() {
List<Boundary> residentials = new ArrayList<>();
Tags tags = new Tags();
for (Way way : saver.getWays().values()) {
if (way.hasIdenticalEndPoints() && "residential".equals(way.getTag(TK_LANDUSE))) {
if ("polyline".equals(way.getTag(TKM_STYLEFILTER)))
continue;
String name = nameFinder.getName(way);
tags.put(TK_NAME, name == null ? "yes": name);
Boundary b = new Boundary(Java2DConverter.createArea(way.getPoints()), tags, "w"+way.getId());
residentials.add(b);
}
}
return new BoundaryQuadTree(saver.getBoundingBox(), residentials, null);
}
/**
* Extract the location info and perform a test
* against the BoundaryQuadTree. If found, assign the tag.
* @param elem A way or Node
*/
private void processElem(Element elem){
Tags residentialTags = null;
if (elem instanceof Node){
Node node = (Node) elem;
residentialTags = residentialBoundaries.get(node.getLocation());
} else if (elem instanceof Way){
Way way = (Way) elem;
// try the mid point of the way first
int middle = way.getPoints().size() / 2;
Coord loc = way.hasIdenticalEndPoints() ? way.getCofG() : way.getPoints().get(middle);
if (! "residential".equals(way.getTag(TK_LANDUSE)))
residentialTags = residentialBoundaries.get(loc);
}
if (residentialTags != null) {
elem.addTag("mkgmap:residential", residentialTags.get(TKM_OTHER));
}
}
@Override
public Set<String> getUsedTags() {
return new HashSet<>(Arrays.asList("landuse", "name"));
}
}