use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class LinkDestinationHook method cutoffWay.
/**
* Cuts off at least minLength meter of the given way and returns the cut off way tagged
* identical to the given way.
* @param w the way to be cut
* @param maxLength the cut off way is no longer than this value
* @return the cut off way or <code>null</code> if cutting not possible
*/
private Way cutoffWay(Way w, double cutLength, double maxLength, Coord c1, Coord c2) {
if (w.getPoints().size() < 2) {
return null;
}
if (w.getPoints().size() >= 3) {
// try to use existing points - that does not deform the way
Coord firstPoint = w.getPoints().get(0);
Coord cutPoint = w.getPoints().get(1);
// check if the maxLength is not exceeded
double dist = firstPoint.distance(cutPoint);
if (dist <= maxLength) {
// create a new way with the first two points and identical tags
Way precedingWay = new Way(w.getOriginalId(), w.getPoints().subList(0, 1 + 1));
precedingWay.setFakeId();
precedingWay.copyTags(w);
saver.addWay(precedingWay);
// remove the points of the new way from the original way
removePointsFromWay(w, 0, 1);
registerPointsOfWay(precedingWay);
// check and update relations so that they use the new way if appropriate
changeWayIdInRelations(w, precedingWay);
log.debug("Cut way", w, "at existing point 1. New way:", precedingWay);
// return the new way
return precedingWay;
} else {
log.debug("Cannot cut way", w, "on existing nodes because the first distance is too big:", dist);
}
}
double startSegmentLength = 0;
Coord lastC = w.getPoints().get(0);
for (int i = 1; i < w.getPoints().size(); i++) {
Coord c = w.getPoints().get(i);
double segmentLength = lastC.distance(c);
if (startSegmentLength + segmentLength >= cutLength) {
double frac = (cutLength - startSegmentLength) / segmentLength;
// insert a new point at the minimum distance
Coord cConnection = lastC.makeBetweenPoint(c, frac);
if (c1 != null && c2 != null && cConnection != null) {
// test if the way using the new point still uses the same
// orientation to the main motorway
double oldAngle = getAngle(c1, c2, c);
double newAngle = getAngle(c1, c2, cConnection);
if (Math.signum(oldAngle) != Math.signum(newAngle)) {
double bestAngleDiff = 180.0d;
Coord bestCoord = cConnection;
for (Coord cNeighbour : getDirectNeighbours(cConnection)) {
double neighbourAngle = getAngle(c1, c2, cNeighbour);
if (Math.signum(oldAngle) == Math.signum(neighbourAngle) && Math.abs(oldAngle - neighbourAngle) < bestAngleDiff) {
bestAngleDiff = Math.abs(oldAngle - neighbourAngle);
bestCoord = cNeighbour;
}
}
if (log.isDebugEnabled()) {
log.debug("Changed orientation:", oldAngle, "to", newAngle);
log.debug("on Link", w);
log.debug("Corrected coord ", cConnection, "to", bestCoord);
}
cConnection = bestCoord;
}
}
// create the new way with identical tags
w.getPoints().add(i, cConnection);
Way precedingWay = new Way(w.getOriginalId(), new ArrayList<Coord>(w.getPoints().subList(0, i + 1)));
precedingWay.setFakeId();
precedingWay.copyTags(w);
saver.addWay(precedingWay);
// remove the points of the new way from the old way
removePointsFromWay(w, 0, i);
registerPointsOfWay(precedingWay);
// check and update relations so that they use the new way if appropriate
changeWayIdInRelations(w, precedingWay);
// return the split way
return precedingWay;
}
lastC = c;
}
// way too short
return null;
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class MultiPolygonRelation method calcAreaSize.
/**
* Calculates a unitless number that gives a value for the size
* of the area. The calculation does not correct to any earth
* coordinate system. It uses the simple rectangular coordinate
* system of garmin coordinates.
*
* @param polygon the points of the area
* @return the size of the area (unitless)
*/
public static double calcAreaSize(List<Coord> polygon) {
if (polygon.size() < 4 || polygon.get(0) != polygon.get(polygon.size() - 1)) {
// line or not closed
return 0;
}
long area = 0;
Iterator<Coord> polyIter = polygon.iterator();
Coord c2 = polyIter.next();
while (polyIter.hasNext()) {
Coord c1 = c2;
c2 = polyIter.next();
area += (long) (c2.getHighPrecLon() + c1.getHighPrecLon()) * (c1.getHighPrecLat() - c2.getHighPrecLat());
}
// convert from high prec to value in map units
double areaSize = (double) area / (2 * (1 << Coord.DELTA_SHIFT) * (1 << Coord.DELTA_SHIFT));
return Math.abs(areaSize);
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class MultiPolygonRelation method connectUnclosedWays.
protected boolean connectUnclosedWays(List<JoinedWay> allWays) {
List<JoinedWay> unclosed = new ArrayList<>();
for (JoinedWay w : allWays) {
if (w.hasIdenticalEndPoints() == false) {
unclosed.add(w);
}
}
// try to connect ways lying outside or on the bbox
if (unclosed.size() >= 2) {
log.debug("Checking", unclosed.size(), "unclosed ways for connections outside the bbox");
Map<Coord, JoinedWay> outOfBboxPoints = new IdentityHashMap<>();
// check all ways for endpoints outside or on the bbox
for (JoinedWay w : unclosed) {
Coord c1 = w.getPoints().get(0);
Coord c2 = w.getPoints().get(w.getPoints().size() - 1);
if (tileBounds.insideBoundary(c1) == false) {
log.debug("Point", c1, "of way", w.getId(), "outside bbox");
outOfBboxPoints.put(c1, w);
}
if (tileBounds.insideBoundary(c2) == false) {
log.debug("Point", c2, "of way", w.getId(), "outside bbox");
outOfBboxPoints.put(c2, w);
}
}
if (outOfBboxPoints.size() < 2) {
log.debug(outOfBboxPoints.size(), "point outside the bbox. No connection possible.");
return false;
}
List<ConnectionData> coordPairs = new ArrayList<>();
ArrayList<Coord> coords = new ArrayList<>(outOfBboxPoints.keySet());
for (int i = 0; i < coords.size(); i++) {
for (int j = i + 1; j < coords.size(); j++) {
ConnectionData cd = new ConnectionData();
cd.c1 = coords.get(i);
cd.c2 = coords.get(j);
cd.w1 = outOfBboxPoints.get(cd.c1);
cd.w2 = outOfBboxPoints.get(cd.c2);
if (lineCutsBbox(cd.c1, cd.c2)) {
// Check if the way can be closed with one additional point
// outside the bounding box.
// The additional point is combination of the coords of both endpoints.
// It works if the lines from the endpoints to the additional point does
// not cut the bounding box.
// This can be removed when the splitter guarantees to provide logical complete
// multi-polygons.
Coord edgePoint1 = new Coord(cd.c1.getLatitude(), cd.c2.getLongitude());
Coord edgePoint2 = new Coord(cd.c2.getLatitude(), cd.c1.getLongitude());
if (lineCutsBbox(cd.c1, edgePoint1) == false && lineCutsBbox(edgePoint1, cd.c2) == false) {
cd.imC = edgePoint1;
} else if (lineCutsBbox(cd.c1, edgePoint2) == false && lineCutsBbox(edgePoint2, cd.c2) == false) {
cd.imC = edgePoint1;
} else {
// automatically closing such points would create wrong polygons in most cases
continue;
}
cd.distance = cd.c1.distance(cd.imC) + cd.imC.distance(cd.c2);
} else {
cd.distance = cd.c1.distance(cd.c2);
}
coordPairs.add(cd);
}
}
if (coordPairs.isEmpty()) {
log.debug("All potential connections cross the bbox. No connection possible.");
return false;
} else {
// retrieve the connection with the minimum distance
ConnectionData minCon = Collections.min(coordPairs, new Comparator<ConnectionData>() {
public int compare(ConnectionData o1, ConnectionData o2) {
return Double.compare(o1.distance, o2.distance);
}
});
if (minCon.w1 == minCon.w2) {
log.debug("Close a gap in way", minCon.w1);
if (minCon.imC != null)
minCon.w1.getPoints().add(minCon.imC);
minCon.w1.closeWayArtificially();
} else {
log.debug("Connect", minCon.w1, "with", minCon.w2);
if (minCon.w1.getPoints().get(0) == minCon.c1) {
Collections.reverse(minCon.w1.getPoints());
}
if (minCon.w2.getPoints().get(0) != minCon.c2) {
Collections.reverse(minCon.w2.getPoints());
}
minCon.w1.getPoints().addAll(minCon.w2.getPoints());
minCon.w1.addWay(minCon.w2);
allWays.remove(minCon.w2);
return true;
}
}
}
return false;
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class MultiPolygonRelation method removeWaysOutsideBbox.
/**
* Removes all ways that are completely outside the bounding box.
* This reduces error messages from problems on the tile bounds.
* @param wayList list of ways
*/
protected void removeWaysOutsideBbox(ArrayList<JoinedWay> wayList) {
ListIterator<JoinedWay> wayIter = wayList.listIterator();
while (wayIter.hasNext()) {
JoinedWay w = wayIter.next();
boolean remove = true;
// check all points
for (Coord c : w.getPoints()) {
if (tileBounds.contains(c)) {
// if one point is in the bounding box the way should not be removed
remove = false;
break;
}
}
if (remove) {
// check if the polygon contains the complete bounding box
if (w.getBounds().contains(tileArea.getBounds())) {
remove = false;
}
}
if (remove) {
if (log.isDebugEnabled()) {
log.debug("Remove way", w.getId(), "because it is completely outside the bounding box.");
}
wayIter.remove();
}
}
}
use of uk.me.parabola.imgfmt.app.Coord in project mkgmap by openstreetmap.
the class MultiPolygonRelation method closeWays.
/**
* Try to close all unclosed ways in the given list of ways.
*
* @param wayList
* a list of ways
*/
protected void closeWays(ArrayList<JoinedWay> wayList, double maxCloseDist) {
for (JoinedWay way : wayList) {
if (way.hasIdenticalEndPoints() || way.getPoints().size() < 3) {
continue;
}
Coord p1 = way.getPoints().get(0);
Coord p2 = way.getPoints().get(way.getPoints().size() - 1);
if (tileBounds.insideBoundary(p1) == false && tileBounds.insideBoundary(p2) == false) {
// check if both points are on the same side of the bounding box
if ((p1.getLatitude() <= tileBounds.getMinLat() && p2.getLatitude() <= tileBounds.getMinLat()) || (p1.getLatitude() >= tileBounds.getMaxLat() && p2.getLatitude() >= tileBounds.getMaxLat()) || (p1.getLongitude() <= tileBounds.getMinLong() && p2.getLongitude() <= tileBounds.getMinLong()) || (p1.getLongitude() >= tileBounds.getMaxLong() && p2.getLongitude() >= tileBounds.getMaxLong())) {
// they are on the same side outside of the bbox
// so just close them without worrying about if
// they intersect itself because the intersection also
// is outside the bbox
way.closeWayArtificially();
log.info("Endpoints of way", way, "are both outside the bbox. Closing it directly.");
continue;
}
}
Line2D closingLine = new Line2D.Float(p1.getLongitude(), p1.getLatitude(), p2.getLongitude(), p2.getLatitude());
boolean intersects = false;
Coord lastPoint = null;
// Both isn't interesting for this check
for (Coord thisPoint : way.getPoints().subList(1, way.getPoints().size() - 1)) {
if (lastPoint != null) {
if (closingLine.intersectsLine(lastPoint.getLongitude(), lastPoint.getLatitude(), thisPoint.getLongitude(), thisPoint.getLatitude())) {
intersects = true;
break;
}
}
lastPoint = thisPoint;
}
if (!intersects) {
// close the polygon
// the new way segment does not intersect the rest of the polygon
boolean doClose = true;
if (maxCloseDist > 0) {
// calc the distance to close
double closeDist = way.getPoints().get(0).distance(way.getPoints().get(way.getPoints().size() - 1));
doClose = closeDist < maxCloseDist;
}
if (doClose) {
log.info("Closing way", way);
log.info("from", way.getPoints().get(0).toOSMURL());
log.info("to", way.getPoints().get(way.getPoints().size() - 1).toOSMURL());
// mark this ways as artificially closed
way.closeWayArtificially();
}
}
}
}
Aggregations