use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class Way method toString.
/**
* A simple representation of this way.
* @return A string with the name and start point
*/
public String toString() {
if (points.isEmpty())
return "Way: empty";
Coord coord = points.get(0);
StringBuilder sb = new StringBuilder();
sb.append("WAY: ").append(getId()).append(" ");
sb.append(getName());
sb.append('(');
sb.append(Utils.toDegrees(coord.getLatitude()));
sb.append('/');
sb.append(Utils.toDegrees(coord.getLongitude()));
sb.append(')');
sb.append(' ');
sb.append(toTagString());
return sb.toString();
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class LinePreparer method calcDeltas.
/**
* Calculate the deltas of one point to the other. While we are doing
* this we must save more information about the maximum sizes, if they
* are all the same sign etc. This must be done separately for both
* the lat and long values.
*/
private void calcDeltas() {
Subdivision subdiv = polyline.getSubdiv();
if (log.isDebugEnabled())
log.debug("label offset", polyline.getLabel().getOffset());
List<Coord> points = polyline.getPoints();
// Space to hold the deltas
int numPointsToUse = points.size();
if (polyline instanceof Polygon) {
if (points.get(0).equals(points.get(points.size() - 1)))
// no need to write the closing point
--numPointsToUse;
}
deltas = new int[2 * (numPointsToUse - 1)];
if (extraBit)
nodes = new boolean[numPointsToUse];
boolean first = true;
// OK go through the points
int lastLat = 0;
int lastLong = 0;
int minDx = Integer.MAX_VALUE, maxDx = 0;
int minDy = Integer.MAX_VALUE, maxDy = 0;
// index of first point in a series of identical coords (after shift)
int firstsame = 0;
for (int i = 0; i < numPointsToUse; i++) {
Coord co = points.get(i);
int lat = subdiv.roundLatToLocalShifted(co.getLatitude());
int lon = subdiv.roundLonToLocalShifted(co.getLongitude());
if (log.isDebugEnabled())
log.debug("shifted pos", lat, lon);
if (first) {
lastLat = lat;
lastLong = lon;
first = false;
continue;
}
int dx = lon - lastLong;
int dy = lat - lastLat;
lastLong = lon;
lastLat = lat;
boolean isSpecialNode = false;
if (co.getId() > 0 || (co.isNumberNode() && ignoreNumberOnlyNodes == false))
isSpecialNode = true;
if (dx != 0 || dy != 0 || extraBit && isSpecialNode)
firstsame = i;
/*
* Current thought is that the node indicator is set when
* the point is a routing node or a house number node.
* There's a separate first extra bit
* that always appears to be false. The last points' extra bit
* is set if the point is a node and this is not the last
* polyline making up the road.
*/
if (extraBit) {
boolean extra = false;
if (isSpecialNode) {
if (i < nodes.length - 1)
// inner node of polyline
extra = true;
else
// end node of polyline: set if inner
// node of road
extra = !polyline.isLastSegment();
}
/*
* Only the first among a range of equal points
* is written, so set the bit if any of the points
* is a node.
* Since we only write extra bits at level 0 now,
* this can only happen when points in the input
* data round to the same point in map units, so
* it may be better to handle this in the
* reader.
*/
nodes[firstsame] = nodes[firstsame] || extra;
}
// find largest delta values
if (dx < minDx)
minDx = dx;
if (dx > maxDx)
maxDx = dx;
if (dy < minDy)
minDy = dy;
if (dy > maxDy)
maxDy = dy;
// Save the deltas
deltas[2 * (i - 1)] = dx;
deltas[2 * (i - 1) + 1] = dy;
}
// Find the maximum number of bits required to hold the delta values.
int xBits = Math.max(bitsNeeded(minDx), bitsNeeded(maxDx));
int yBits = Math.max(bitsNeeded(minDy), bitsNeeded(maxDy));
if (log.isDebugEnabled())
log.debug("initial xBits, yBits", xBits, yBits);
this.xBase = bits2Base(xBits);
this.yBase = bits2Base(yBits);
if (log.isDebugEnabled())
log.debug("initial xBase, yBase", xBase, yBase);
// Set flags for same sign etc.
this.xSameSign = !(minDx < 0 && maxDx > 0);
this.ySameSign = !(minDy < 0 && maxDy > 0);
if (this.xSameSign)
this.xSignNegative = minDx < 0;
if (this.ySameSign)
this.ySignNegative = minDy < 0;
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class RoadNetwork method addRoad.
public void addRoad(RoadDef roadDef, List<Coord> coordList) {
roadDefs.add(roadDef);
CoordNode lastCoord = null;
int lastIndex = 0;
double roadLength = 0;
double arcLength = 0;
int pointsHash = 0;
int npoints = coordList.size();
int numCoordNodes = 0;
boolean hasInternalNodes = false;
int numNumberNodes = 0;
BitSet nodeFlags = new BitSet();
for (int index = 0; index < npoints; index++) {
Coord co = coordList.get(index);
int id = co.getId();
if (id != 0) {
nodeFlags.set(numNumberNodes);
++numCoordNodes;
if (index > 0 && index < npoints - 1)
hasInternalNodes = true;
}
if (co.isNumberNode())
++numNumberNodes;
if (index == 0) {
if (id == 0)
roadDef.setStartsWithNode(false);
} else {
double d = co.distance(coordList.get(index - 1));
arcLength += d;
roadLength += d;
}
if (roadDef.skipAddToNOD())
continue;
pointsHash += co.hashCode();
if (id == 0)
// not a routing node
continue;
// the previous node to this one (and back again).
if (lastCoord != null) {
int lastId = lastCoord.getId();
if (log.isDebugEnabled()) {
log.debug("lastId = " + lastId + " curId = " + id);
log.debug("from " + lastCoord.toDegreeString() + " to " + co.toDegreeString());
log.debug("arclength=" + arcLength + " roadlength=" + roadLength);
}
RouteNode node1 = getOrAddNode(lastId, lastCoord);
RouteNode node2 = getOrAddNode(id, co);
if (node1 == node2)
log.error("Road " + roadDef + " contains consecutive identical nodes at " + co.toOSMURL() + " - routing will be broken");
else if (arcLength == 0)
log.warn("Road " + roadDef + " contains zero length arc at " + co.toOSMURL());
Coord forwardBearingPoint = coordList.get(lastIndex + 1);
if (lastCoord.equals(forwardBearingPoint) || forwardBearingPoint.isAddedNumberNode()) {
// useful - try some more points
for (int bi = lastIndex + 2; bi <= index; ++bi) {
Coord coTest = coordList.get(bi);
if (coTest.isAddedNumberNode() || lastCoord.equals(coTest))
continue;
forwardBearingPoint = coTest;
break;
}
}
Coord reverseBearingPoint = coordList.get(index - 1);
if (co.equals(reverseBearingPoint) || reverseBearingPoint.isAddedNumberNode()) {
// useful - try some more points
for (int bi = index - 2; bi >= lastIndex; --bi) {
Coord coTest = coordList.get(bi);
if (coTest.isAddedNumberNode() || co.equals(coTest))
continue;
reverseBearingPoint = coTest;
break;
}
}
double forwardInitialBearing = lastCoord.bearingTo(forwardBearingPoint);
double forwardDirectBearing = (co == forwardBearingPoint) ? forwardInitialBearing : lastCoord.bearingTo(co);
double reverseInitialBearing = co.bearingTo(reverseBearingPoint);
double directLength = (lastIndex + 1 == index) ? arcLength : lastCoord.distance(co);
double reverseDirectBearing = 0;
if (directLength > 0) {
// bearing on rhumb line is a constant, so we can simply revert
reverseDirectBearing = (forwardDirectBearing <= 0) ? 180 + forwardDirectBearing : -(180 - forwardDirectBearing) % 180.0;
}
// Create forward arc from node1 to node2
RouteArc arc = new RouteArc(roadDef, node1, node2, forwardInitialBearing, forwardDirectBearing, arcLength, arcLength, directLength, pointsHash);
arc.setForward();
node1.addArc(arc);
// Create the reverse arc
RouteArc reverseArc = new RouteArc(roadDef, node2, node1, reverseInitialBearing, reverseDirectBearing, arcLength, arcLength, directLength, pointsHash);
node2.addArc(reverseArc);
// link the two arcs
arc.setReverseArc(reverseArc);
reverseArc.setReverseArc(arc);
} else {
// This is the first node in the road
roadDef.setNode(getOrAddNode(id, co));
}
lastCoord = (CoordNode) co;
lastIndex = index;
arcLength = 0;
pointsHash = co.hashCode();
}
if (roadDef.hasHouseNumbers()) {
// we ignore number nodes when we have no house numbers
if (numCoordNodes < numNumberNodes)
hasInternalNodes = true;
roadDef.setNumNodes(numNumberNodes);
roadDef.setNod2BitSet(nodeFlags);
} else {
roadDef.setNumNodes(numCoordNodes);
}
if (hasInternalNodes)
roadDef.setInternalNodes(true);
roadDef.setLength(roadLength);
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class RouteNode method checkRoundabouts.
public void checkRoundabouts() {
List<RouteArc> roundaboutArcs = new ArrayList<>();
List<RouteArc> nonRoundaboutArcs = new ArrayList<>();
int countNonRoundaboutRoads = 0;
int countNonRoundaboutOtherHighways = 0;
int countHighwaysInsideRoundabout = 0;
for (RouteArc ra : arcs) {
if (ra.isDirect()) {
// ignore ways that have been synthesised by mkgmap
RoadDef rd = ra.getRoadDef();
if (!rd.isSynthesised()) {
if (rd.isRoundabout())
roundaboutArcs.add(ra);
else
nonRoundaboutArcs.add(ra);
}
}
}
if (roundaboutArcs.size() > 0) {
// get the coordinates of a box bounding the junctions of the roundabout
int minRoundaboutLat = coord.getHighPrecLat();
int maxRoundaboutLat = minRoundaboutLat;
int minRoundaboutLon = coord.getHighPrecLon();
int maxRoundaboutLon = minRoundaboutLon;
List<RouteNode> processedNodes = new ArrayList<>();
processedNodes.add(this);
for (RouteArc ra : roundaboutArcs) {
if (ra.isForward()) {
for (RouteArc ra1 : nonRoundaboutArcs) {
if ((ra1.getDirectHeading() == ra.getDirectHeading()) && (ra1.getInitialHeading() == ra.getInitialHeading()) && (ra1.getFinalHeading() == ra.getFinalHeading()) && (ra1.getLengthInMeter() == ra.getLengthInMeter())) {
// non roundabout highway overlaps roundabout
nonRoundaboutArcs.remove(ra1);
if (!ra.getRoadDef().messagePreviouslyIssued("roundabout forks/overlaps"))
log.warn("Highway", ra1.getRoadDef(), "overlaps roundabout", ra.getRoadDef(), "at", coord.toOSMURL());
break;
}
}
RouteNode rn = ra.getDest();
while (rn != null && !processedNodes.contains(rn)) {
processedNodes.add(rn);
int lat = rn.coord.getHighPrecLat();
int lon = rn.coord.getHighPrecLon();
minRoundaboutLat = Math.min(minRoundaboutLat, lat);
maxRoundaboutLat = Math.max(maxRoundaboutLat, lat);
minRoundaboutLon = Math.min(minRoundaboutLon, lon);
maxRoundaboutLon = Math.max(maxRoundaboutLon, lon);
RouteNode nrn = null;
for (RouteArc nra : rn.arcs) {
if (nra.isDirect() && nra.isForward()) {
RoadDef nrd = nra.getRoadDef();
if (nrd.isRoundabout() && !nrd.isSynthesised())
nrn = nra.getDest();
}
}
rn = nrn;
}
}
}
if (nonRoundaboutArcs.size() > 1) {
// get an approximate centre of the roundabout
Coord roundaboutCentre = Coord.makeHighPrecCoord((minRoundaboutLat + maxRoundaboutLat) / 2, (minRoundaboutLon + maxRoundaboutLon) / 2);
for (RouteArc ra : nonRoundaboutArcs) {
double distanceToCentre = roundaboutCentre.distance(coord);
RoadDef rd = ra.getRoadDef();
// ignore footpaths and ways with no access
byte access = rd.getAccess();
if (access != 0 && (access != AccessTagsAndBits.FOOT)) {
// check whether the way is inside the roundabout by seeing if the next point is nearer to the centre of the bounding box than this
RouteNode nextNode = ra.getSource().coord == coord ? ra.getDest() : ra.getSource();
Coord nextCoord = nextNode.coord;
for (RouteNode roundaboutNode : processedNodes) {
if (roundaboutNode.coord.equals(nextCoord)) {
// arc rejoins roundabout, so calculate another point to use half the distance away at the initial bearing
double heading1 = ra.getSource().coord == coord ? ra.getInitialHeading() : 180 + ra.getFinalHeading();
double distance = coord.distance(nextCoord) / 2;
Coord nextCoord1 = coord.offset(heading1, distance);
// now calculate a point the same distance away from the end point 180 degrees from the final bearing
double heading2 = ra.getSource().coord == coord ? 180 + ra.getFinalHeading() : ra.getInitialHeading();
Coord nextCoord2 = nextCoord.offset(heading2, distance);
double distanceToCentreOfNextCoord = roundaboutCentre.distance(nextCoord);
// use the point which has a bigger difference in distance from the centre to increase accuracy
if (Math.abs(distanceToCentre - roundaboutCentre.distance(nextCoord1)) >= Math.abs(distanceToCentreOfNextCoord - roundaboutCentre.distance(nextCoord2)))
nextCoord = nextCoord1;
else {
distanceToCentre = distanceToCentreOfNextCoord;
nextCoord = nextCoord2;
}
break;
}
}
double nextDistanceToCentre = roundaboutCentre.distance(nextCoord);
if (Math.abs(nextDistanceToCentre - distanceToCentre) < 2)
log.info("Way", rd, "unable to accurately determine whether", nextCoord.toOSMURL(), " is inside roundabout");
if (nextDistanceToCentre < distanceToCentre)
countHighwaysInsideRoundabout++;
else {
if ((access & AccessTagsAndBits.CAR) != 0)
countNonRoundaboutRoads++;
else if ((access & (AccessTagsAndBits.BIKE | AccessTagsAndBits.BUS | AccessTagsAndBits.TAXI | AccessTagsAndBits.TRUCK)) != 0)
countNonRoundaboutOtherHighways++;
}
}
}
RouteArc roundaboutArc = roundaboutArcs.get(0);
if (arcs.size() > 1 && roundaboutArcs.size() == 1)
log.warn("Roundabout", roundaboutArc.getRoadDef(), roundaboutArc.isForward() ? "starts at" : "ends at", coord.toOSMURL());
if (countNonRoundaboutRoads > 1)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to more than one road at", coord.toOSMURL());
else if (countNonRoundaboutRoads == 1) {
if (countNonRoundaboutOtherHighways > 0) {
if (countHighwaysInsideRoundabout > 0)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road", countNonRoundaboutOtherHighways, "other highway(s) and", countHighwaysInsideRoundabout, "highways inside the roundabout at", coord.toOSMURL());
else
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road and", countNonRoundaboutOtherHighways, "other highway(s) at", coord.toOSMURL());
} else if (countHighwaysInsideRoundabout > 0)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to a road and", countHighwaysInsideRoundabout, "highway(s) inside the roundabout at", coord.toOSMURL());
} else if (countNonRoundaboutOtherHighways > 0) {
if (countHighwaysInsideRoundabout > 0)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countNonRoundaboutOtherHighways, "highway(s) and", countHighwaysInsideRoundabout, "inside the roundabout at", coord.toOSMURL());
else if (countNonRoundaboutOtherHighways > 1)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countNonRoundaboutOtherHighways, "highways at", coord.toOSMURL());
} else if (countHighwaysInsideRoundabout > 1)
log.warn("Roundabout", roundaboutArc.getRoadDef(), "is connected to", countHighwaysInsideRoundabout, "highways inside the roundabout at", coord.toOSMURL());
if (roundaboutArcs.size() > 2) {
for (RouteArc fa : roundaboutArcs) {
if (fa.isForward()) {
RoadDef rd = fa.getRoadDef();
for (RouteArc fb : roundaboutArcs) {
if (fb != fa) {
if (fa.getPointsHash() == fb.getPointsHash() && ((fb.isForward() && fb.getDest() == fa.getDest()) || (!fb.isForward() && fb.getSource() == fa.getDest()))) {
if (!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
log.warn("Roundabout " + rd + " overlaps " + fb.getRoadDef() + " at " + coord.toOSMURL());
}
} else if (fb.isForward()) {
if (!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
log.warn("Roundabout " + rd + " forks at " + coord.toOSMURL());
}
}
}
}
}
}
}
}
}
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class Point method getLocation.
public Coord getLocation() {
int shift = getSubdiv().getShift();
Coord co = new Coord(getSubdiv().getLatitude() + (getDeltaLat() << shift), getSubdiv().getLongitude() + (getDeltaLong() << shift));
return co;
}
Aggregations