use of uk.me.parabola.imgfmt.app.CoordNode in project mkgmap by openstreetmap.
the class PredictFilterPoints method predictedMaxNumPoints.
public static int predictedMaxNumPoints(List<Coord> points, int resolution, boolean checkPreserved) {
// see RemoveObsoletePointsFilter, RoundCoordsFilter, ... for comments on preserved and resolution
// %%% checkPreserved = config.getLevel() == 0 && config.isRoutable() && line.isRoad()){
// final int shift = 30 - resolution; // NB getting highPrec
// final int half = 1 << (shift - 1); // 0.5 shifted
// final int mask = ~((1 << shift) - 1); // to remove fraction bits
// best use same info as filters
final int shift = 24 - resolution;
int half;
int mask;
if (shift == 0) {
half = 0;
mask = ~0;
} else {
// 0.5 shifted
half = 1 << (shift - 1);
// to remove fraction bits
mask = ~((1 << shift) - 1);
}
int numPoints = 0;
int lastLat = 0, lastLon = 0;
for (Coord p : points) {
// final int lat = (p.getHighPrecLat() + half) & mask;
// final int lon = (p.getHighPrecLon() + half) & mask;
final int lat = (p.getLatitude() + half) & mask;
final int lon = (p.getLongitude() + half) & mask;
if (numPoints == 0)
// always have one/first point
numPoints = 1;
else {
if (lat != lastLat || lon != lastLon || (checkPreserved && (p instanceof CoordNode || p.preserved())))
++numPoints;
}
lastLat = lat;
lastLon = lon;
}
// true shapes will have >3 points, lines >1
return numPoints;
}
use of uk.me.parabola.imgfmt.app.CoordNode in project mkgmap by openstreetmap.
the class StyledConverter method end.
public void end() {
pointMap.clear();
style.reportStats();
driveOnLeft = calcDrivingSide();
setHighwayCounts();
findUnconnectedRoads();
rotateClosedWaysToFirstNode();
filterCoordPOI();
WrongAngleFixer wrongAngleFixer = new WrongAngleFixer(bbox);
wrongAngleFixer.optimizeWays(roads, lines, modifiedRoads, deletedRoads, restrictions);
// make sure that copies of modified roads have equal points
for (ConvertedWay line : lines) {
if (!line.isValid())
continue;
Way way = line.getWay();
if (deletedRoads.contains(way.getId())) {
line.getPoints().clear();
continue;
}
if (!line.isOverlay())
continue;
ConvertedWay modWay = modifiedRoads.get(way.getId());
if (modWay != null) {
List<Coord> points = line.getPoints();
points.clear();
points.addAll(modWay.getPoints());
if (modWay.isReversed() != line.isReversed())
Collections.reverse(points);
}
}
for (Long wayId : deletedRoads) {
if (wayRelMap.containsKey(wayId)) {
// may happen e.g. when very short way is leading to nowhere
log.warn("Way that is used in valid restriction relation was removed, id:", wayId);
}
}
deletedRoads = null;
modifiedRoads = null;
mergeRoads();
resetHighwayCounts();
setHighwayCounts();
for (ConvertedWay cw : lines) {
if (cw.isValid())
addLine(cw.getWay(), cw.getGType());
}
lines = null;
if (roadLog.isInfoEnabled()) {
roadLog.info("Flags: oneway,no-emergency, no-delivery, no-throughroute, no-truck, no-bike, no-foot, carpool, no-taxi, no-bus, no-car");
roadLog.info(String.format("%19s %4s %11s %6s %6s %6s %s", "Road-OSM-Id", "Type", "Flags", "Class", "Speed", "Points", "Labels"));
}
// add the roads after the other lines
for (ConvertedWay cw : roads) {
if (cw.isValid())
addRoad(cw);
}
housenumberGenerator.generate(lineAdder, nextNodeId);
housenumberGenerator = null;
if (routable)
createRouteRestrictionsFromPOI();
poiRestrictions = null;
if (routable) {
for (RestrictionRelation rr : restrictions) {
rr.addRestriction(collector, nodeIdMap);
}
}
roads = null;
if (routable) {
for (Relation relation : throughRouteRelations) {
Node node = null;
Way w1 = null;
Way w2 = null;
for (Map.Entry<String, Element> member : relation.getElements()) {
if (member.getValue() instanceof Node) {
if (node == null)
node = (Node) member.getValue();
else
log.warn("Through route relation", relation.toBrowseURL(), "has more than 1 node");
} else if (member.getValue() instanceof Way) {
Way w = (Way) member.getValue();
if (w1 == null)
w1 = w;
else if (w2 == null)
w2 = w;
else
log.warn("Through route relation", relation.toBrowseURL(), "has more than 2 ways");
}
}
CoordNode coordNode = null;
if (node == null)
log.warn("Through route relation", relation.toBrowseURL(), "is missing the junction node");
else {
Coord junctionPoint = node.getLocation();
if (bbox != null && !bbox.contains(junctionPoint)) {
// junction is outside of the tile - ignore it
continue;
}
coordNode = nodeIdMap.get(junctionPoint);
if (coordNode == null)
log.warn("Through route relation", relation.toBrowseURL(), "junction node at", junctionPoint.toOSMURL(), "is not a routing node");
}
if (w1 == null || w2 == null)
log.warn("Through route relation", relation.toBrowseURL(), "should reference 2 ways that meet at the junction node");
if (coordNode != null && w1 != null && w2 != null)
collector.addThroughRoute(coordNode.getId(), w1.getId(), w2.getId());
}
}
// return memory to GC
nodeIdMap = null;
throughRouteRelations.clear();
restrictions.clear();
}
use of uk.me.parabola.imgfmt.app.CoordNode in project mkgmap by openstreetmap.
the class RoadNetwork method addRestriction.
/**
* One restriction forbids to travel a specific combination of arcs.
* We know two kinds: 3 nodes with two arcs and one via node or 4 nodes with 3 arcs
* and two via nodes. Maybe more nodes are possible, but we don't know for sure how
* to write them (2014-04-02).
* Depending on the data in grr we create one or more such restrictions.
* A restriction with 4 (or more) nodes is added to each via node.
*
* The OSM restriction gives a from way id and a to way id and one or more
* via nodes. It is possible that the to-way is a loop, so we have to identify
* the correct arc.
* @param grr the object that holds the details about the route restriction
*/
public int addRestriction(GeneralRouteRestriction grr) {
if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_NO_TROUGH)
return addNoThroughRoute(grr);
String sourceDesc = grr.getSourceDesc();
List<RouteNode> viaNodes = new ArrayList<>();
for (CoordNode via : grr.getViaNodes()) {
RouteNode vn = nodes.get(via.getId());
if (vn == null) {
log.error(sourceDesc, "can't locate 'via' RouteNode with id", via.getId());
return 0;
}
viaNodes.add(vn);
}
int firstViaId = grr.getViaNodes().get(0).getId();
int lastViaId = grr.getViaNodes().get(grr.getViaNodes().size() - 1).getId();
RouteNode firstViaNode = nodes.get(firstViaId);
RouteNode lastViaNode = nodes.get(lastViaId);
List<List<RouteArc>> viaArcsList = new ArrayList<>();
if (grr.getViaNodes().size() != grr.getViaWayIds().size() + 1) {
log.error(sourceDesc, "internal error: number of via nodes and via ways doesn't fit");
return 0;
}
for (int i = 1; i < grr.getViaNodes().size(); i++) {
RouteNode vn = viaNodes.get(i - 1);
Long viaWayId = grr.getViaWayIds().get(i - 1);
List<RouteArc> viaArcs = vn.getDirectArcsTo(viaNodes.get(i), viaWayId);
if (viaArcs.isEmpty()) {
log.error(sourceDesc, "can't locate arc from 'via' node at", vn.getCoord().toOSMURL(), "to next 'via' node on way", viaWayId);
return 0;
}
viaArcsList.add(viaArcs);
}
// determine the from node and arc(s)
int fromId = 0;
RouteNode fn = null;
if (grr.getFromNode() != null) {
fromId = grr.getFromNode().getId();
// polish input data provides id
fn = nodes.get(fromId);
if (fn == null) {
log.error(sourceDesc, "can't locate 'from' RouteNode with id", fromId);
return 0;
}
} else {
List<RouteArc> possibleFromArcs = firstViaNode.getDirectArcsOnWay(grr.getFromWayId());
for (RouteArc arc : possibleFromArcs) {
if (fn == null)
fn = arc.getDest();
else if (fn != arc.getDest()) {
log.warn(sourceDesc, "found different 'from' arcs for way", grr.getFromWayId(), "restriction is ignored");
return 0;
}
}
if (fn == null) {
log.warn(sourceDesc, "can't locate 'from' RouteNode for 'from' way", grr.getFromWayId());
return 0;
}
fromId = fn.getCoord().getId();
}
List<RouteArc> fromArcs = fn.getDirectArcsTo(firstViaNode, grr.getFromWayId());
if (fromArcs.isEmpty()) {
log.error(sourceDesc, "can't locate arc from 'from' node ", fromId, "to 'via' node", firstViaId, "on way", grr.getFromWayId());
return 0;
}
// a bit more complex: determine the to-node and arc(s)
RouteNode tn = null;
int toId = 0;
List<RouteArc> toArcs = new ArrayList<>();
if (grr.getToNode() != null) {
// polish input data provides id
toId = grr.getToNode().getId();
tn = nodes.get(toId);
if (tn == null) {
log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId);
return 0;
}
} else {
// we can have multiple arcs between last via node and to node. The
// arcs can be on the same OSM way or on different OSM ways.
// We can have multiple arcs with different RoadDef objects that refer to the same
// OSM way id. The direction indicator tells us what arc is probably meant.
List<RouteArc> possibleToArcs = lastViaNode.getDirectArcsOnWay(grr.getToWayId());
RouteArc fromArc = fromArcs.get(0);
boolean ignoreAngle = false;
if (fromArc.getLengthInMeter() <= 0.0001)
ignoreAngle = true;
if (grr.getDirIndicator() == '?')
ignoreAngle = true;
log.info(sourceDesc, "found", possibleToArcs.size(), "candidates for to-arc");
// group the available arcs by angle
Map<Integer, List<RouteArc>> angleMap = new TreeMap<>();
for (RouteArc arc : possibleToArcs) {
if (arc.getLengthInMeter() <= 0.0001)
ignoreAngle = true;
Integer angle = Math.round(getAngle(fromArc, arc));
List<RouteArc> list = angleMap.get(angle);
if (list == null) {
list = new ArrayList<>();
angleMap.put(angle, list);
}
list.add(arc);
}
// find the group that fits best
Iterator<Entry<Integer, List<RouteArc>>> iter = angleMap.entrySet().iterator();
Integer bestAngle = null;
while (iter.hasNext()) {
Entry<Integer, List<RouteArc>> entry = iter.next();
if (ignoreAngle || matchDirectionInfo(entry.getKey(), grr.getDirIndicator())) {
if (bestAngle == null)
bestAngle = entry.getKey();
else {
bestAngle = getBetterAngle(bestAngle, entry.getKey(), grr.getDirIndicator());
}
}
}
if (bestAngle == null) {
log.warn(sourceDesc, "the angle of the from and to way don't match the restriction");
return 0;
}
toArcs = angleMap.get(bestAngle);
}
if (toArcs.isEmpty()) {
log.error(sourceDesc, "can't locate arc from 'via' node ", lastViaId, "to 'to' node", toId, "on way", grr.getToWayId());
return 0;
}
List<RouteArc> badArcs = new ArrayList<>();
if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_NOT) {
for (RouteArc toArc : toArcs) {
badArcs.add(toArc);
}
} else if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_ONLY) {
// this is the inverse logic, grr gives the allowed path, we have to find the others
for (RouteArc badArc : lastViaNode.arcsIteration()) {
if (!badArc.isDirect() || toArcs.contains(badArc))
continue;
badArcs.add(badArc);
}
if (badArcs.isEmpty()) {
log.warn(sourceDesc, "restriction ignored because it has no effect");
return 0;
}
}
// create all possible paths for which the restriction applies
List<List<RouteArc>> arcLists = new ArrayList<>();
arcLists.add(fromArcs);
arcLists.addAll(viaArcsList);
arcLists.add(badArcs);
if (arcLists.size() > MAX_RESTRICTIONS_ARCS) {
log.warn(sourceDesc, "has more than", MAX_RESTRICTIONS_ARCS, "arcs, this is not supported");
return 0;
}
// remove arcs which cannot be travelled by the vehicles listed in the restriction
for (int i = 0; i < arcLists.size(); i++) {
List<RouteArc> arcs = arcLists.get(i);
int countNoEffect = 0;
int countOneway = 0;
for (int j = arcs.size() - 1; j >= 0; --j) {
RouteArc arc = arcs.get(j);
if (isUsable(arc.getRoadDef().getAccess(), grr.getExceptionMask()) == false) {
countNoEffect++;
arcs.remove(j);
} else if (arc.getRoadDef().isOneway()) {
if (!arc.isForward()) {
countOneway++;
arcs.remove(j);
}
}
}
String arcType = null;
if (arcs.isEmpty()) {
if (i == 0)
arcType = "from way is";
else if (i == arcLists.size() - 1) {
if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_ONLY)
arcType = "all possible other ways are";
else
arcType = "to way is";
} else
arcType = "via way is";
String reason;
if (countNoEffect > 0 & countOneway > 0)
reason = "wrong direction in oneway or not accessible for restricted vehicles";
else if (countNoEffect > 0)
reason = "not accessible for restricted vehicles";
else
reason = "wrong direction in oneway";
log.warn(sourceDesc, "restriction ignored because", arcType, reason);
return 0;
}
}
if (viaNodes.contains(fn)) {
log.warn(sourceDesc, "restriction not written because from node appears also as via node");
return 0;
}
// determine all possible combinations of arcs. In most cases,
// this will be 0 or one, but if the style creates multiple roads for one
// OSM way, this can be a larger number
int numCombis = 1;
int[] indexes = new int[arcLists.size()];
for (int i = 0; i < indexes.length; i++) {
List<RouteArc> arcs = arcLists.get(i);
numCombis *= arcs.size();
}
List<RouteArc> path = new ArrayList<>();
int added = 0;
for (int i = 0; i < numCombis; i++) {
for (RouteNode vn : viaNodes) {
path.clear();
boolean viaNodeFound = false;
byte pathNoAccessMask = 0;
for (int j = 0; j < indexes.length; j++) {
RouteArc arc = arcLists.get(j).get(indexes[j]);
if (arc.getDest() == vn || viaNodeFound == false) {
arc = arc.getReverseArc();
}
if (arc.getSource() == vn)
viaNodeFound = true;
if (arc.getDest() == vn) {
if (added > 0)
log.error(sourceDesc, "restriction incompletely written because dest in arc is via node");
else
log.warn(sourceDesc, "restriction not written because dest in arc is via node");
return added;
}
pathNoAccessMask |= ~arc.getRoadDef().getAccess();
path.add(arc);
}
byte pathAccessMask = (byte) ~pathNoAccessMask;
if (isUsable(pathAccessMask, grr.getExceptionMask())) {
vn.addRestriction(new RouteRestriction(vn, path, grr.getExceptionMask()));
++added;
}
}
// get next combination of arcs
++indexes[indexes.length - 1];
for (int j = indexes.length - 1; j > 0; --j) {
if (indexes[j] >= arcLists.get(j).size()) {
indexes[j] = 0;
indexes[j - 1]++;
}
}
}
// double check
if (indexes[0] != arcLists.get(0).size())
log.error(sourceDesc, " failed to generate all possible paths");
log.info(sourceDesc, "added", added, "route restriction(s) to img file");
return added;
}
use of uk.me.parabola.imgfmt.app.CoordNode in project mkgmap by openstreetmap.
the class RGNFileReader method readBitStream.
/**
* Read the bit stream for a single line in the file.
* @param br The bit stream reader.
* @param div The subdivision that the line is in.
* @param line The line itself.
* @param extra True if there is an 'extra' bit in the stream. Used for nodes.
* @param len The length of the stream.
* @param base The base size of the deltas.
*/
private void readBitStream(BitReader br, Subdivision div, Polyline line, boolean extra, int len, int base) {
int currLat = line.getLat();
int currLon = line.getLong();
log.debug(String.format("Start point %.5f,%.5f", Utils.toDegrees(currLat), Utils.toDegrees(currLon)));
if (extra)
line.addCoord(new CoordNode(currLat, currLon, 0, /* XXX */
false));
else
line.addCoord(new Coord(currLat, currLon));
int xbase = 2;
int n = base & 0xf;
if (n <= 9)
xbase += n;
else
xbase += (2 * n) - 9;
n = (base >>> 4) & 0xf;
int ybase = 2;
if (n <= 9)
ybase += n;
else
ybase += (2 * n) - 9;
if (len == 0)
return;
boolean xneg = false;
boolean xsame = br.get1();
if (xsame) {
xneg = br.get1();
} else
xbase++;
boolean ysame = br.get1();
boolean yneg = false;
if (ysame) {
yneg = br.get1();
} else
ybase++;
if (line.hasExtendedType()) {
br.get1();
}
if (extra) {
boolean firstextra = br.get1();
log.debug("the first extra bit is", firstextra);
}
// proper lat/long coords.
while (br.getBitPosition() <= 8 * len - ((extra ? 1 : 0) + xbase + ybase)) {
br.getBitPosition();
int dx;
if (xsame) {
dx = br.get(xbase);
if (xneg)
dx = -dx;
} else {
dx = br.sget2(xbase);
}
int dy;
if (ysame) {
dy = br.get(ybase);
if (yneg)
dy = -dy;
} else {
dy = br.sget2(ybase);
}
boolean isnode = false;
if (extra)
isnode = br.get1();
currLat += dy << (24 - div.getResolution());
currLon += dx << (24 - div.getResolution());
Coord coord;
if (isnode)
coord = new CoordNode(currLat, currLon, 0, /* XXX */
false);
else
coord = new Coord(currLat, currLon);
line.addCoord(coord);
}
if (line instanceof Polygon) {
// make sure that polygon is closed
line.addCoord(line.getPoints().get(0));
}
}
use of uk.me.parabola.imgfmt.app.CoordNode in project mkgmap by openstreetmap.
the class RoundCoordsFilter method doFilter.
/**
* @param element A map element that will be a line or a polygon.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
MapLine line = (MapLine) element;
// 0.5 shifted
int half = 1 << (shift - 1);
// to remove fraction bits
int mask = ~((1 << shift) - 1);
if (shift == 0) {
// do nothing
next.doFilter(line);
} else {
// round lat/lon values to nearest for shift
List<Coord> newPoints = new ArrayList<Coord>(line.getPoints().size());
Coord lastP = null;
for (Coord p : line.getPoints()) {
int lat = (p.getLatitude() + half) & mask;
int lon = (p.getLongitude() + half) & mask;
Coord newP;
if (p instanceof CoordNode && checkRouting)
newP = new CoordNode(lat, lon, p.getId(), p.getOnBoundary());
else
newP = new Coord(lat, lon);
newP.preserved(p.preserved());
// CoordNode and the last point wasn't a CoordNode
if (lastP == null || !lastP.equals(newP) || (newP instanceof CoordNode && !(lastP instanceof CoordNode))) {
newPoints.add(newP);
lastP = newP;
} else if (newP.preserved()) {
// this point is not going to be used because it
// has the same (rounded) coordinates as the last
// node but it has been marked as being "preserved" -
// transfer that property to the previous point so
// that it's not lost
lastP.preserved(true);
}
}
if (newPoints.size() > 1) {
MapLine newLine = line.copy();
newLine.setPoints(newPoints);
next.doFilter(newLine);
}
}
}
Aggregations