// Create a new point with the appropriate lat and long, with no altitude
double pX = xRange.getMinimum() + j * xStep;
DataPoint point = new DataPoint(
- new Latitude(MapUtils.getLatitudeFromY(pY), Coordinate.FORMAT_NONE),
- new Longitude(MapUtils.getLongitudeFromX(pX), Coordinate.FORMAT_NONE),
+ new Latitude(MapUtils.getLatitudeFromY(pY), Coordinate.FORMAT_DECIMAL_FORCE_POINT),
+ new Longitude(MapUtils.getLongitudeFromX(pX), Coordinate.FORMAT_DECIMAL_FORCE_POINT),
null);
//System.out.println("Created point at " + point.getLatitude().output(Coordinate.FORMAT_DEG_MIN_SEC)
// + ", " + point.getLongitude().output(Coordinate.FORMAT_DEG_MIN_SEC));
{
int numVoids = countVoids(inTerrainTrack);
if (numVoids == 0) {return;}
- // System.out.println("Starting to fix, num voids = " + numVoids);
+ //System.out.println("Starting to fix, num voids = " + numVoids);
// Fix the holes which are surrounded on all four sides by non-holes
fixSingleHoles(inTerrainTrack);
- // System.out.println("Fixed single holes, now num voids = " + countVoids(inTerrainTrack));
+ //System.out.println("Fixed single holes, now num voids = " + countVoids(inTerrainTrack));
// Maybe there is something to do in the corners?
- fixCorners(inTerrainTrack);
+ fixCornersAndEdges(inTerrainTrack);
+ //System.out.println("Fixed corners, now num voids = " + countVoids(inTerrainTrack));
// Now fix the bigger holes, which should fix everything left
fixBiggerHoles(inTerrainTrack);
final int numHolesLeft = countVoids(inTerrainTrack);
*/
private static int countVoids(Track inTerrainTrack)
{
+ // DEBUG: Show state of voids first
+// final int gridSize = (int) Math.sqrt(inTerrainTrack.getNumPoints());
+// StringBuilder sb = new StringBuilder();
+// for (int i=0; i<inTerrainTrack.getNumPoints(); i++)
+// {
+// if ((i%gridSize) == 0) sb.append('\n');
+// if (inTerrainTrack.getPoint(i).hasAltitude()) {
+// sb.append('A');
+// } else {
+// sb.append(' ');
+// }
+// }
+// System.out.println("Voids:" + sb.toString());
+ // END DEBUG
+
int numVoids = 0;
if (inTerrainTrack != null)
{
double altitude = 0.0;
if (pll != null && pll.hasAltitude() && prr != null && prr.hasAltitude()
- && puu != null && puu.hasAltitude() && pdd != null & pdd.hasAltitude())
+ && puu != null && puu.hasAltitude() && pdd != null && pdd.hasAltitude())
{
// Use the double-neighbours too to take into account the gradients
altitude = (
}
/**
- * Try to fix the corners, if they're blank
+ * Try to fix the corners and edges, if they're blank
* @param inTerrainTrack terrain track
*/
- private void fixCorners(Track inTerrainTrack)
+ private void fixCornersAndEdges(Track inTerrainTrack)
{
fixCorner(inTerrainTrack, 0, 1, 1);
fixCorner(inTerrainTrack, _gridSize-1, -1, 1);
fixCorner(inTerrainTrack, (_gridSize-1)*_gridSize, 1, -1);
fixCorner(inTerrainTrack, _gridSize*_gridSize-1, -1, -1);
+ fixEdge(inTerrainTrack, 0, 1);
+ fixEdge(inTerrainTrack, _gridSize-1, _gridSize);
+ fixEdge(inTerrainTrack, (_gridSize-1)*_gridSize, -_gridSize);
+ fixEdge(inTerrainTrack, _gridSize*_gridSize-1, -1);
}
/**
// System.out.println("Averaging values " + alt1.getMetricValue() + " and " + alt2.getMetricValue());
int newAltitude = (int) ((alt1.getMetricValue() + alt2.getMetricValue()) / 2.0);
corner.setFieldValue(Field.ALTITUDE, "" + newAltitude, false);
+ // TODO: Check forcing metres? Is there a nicer way?
+ }
+ }
+ }
+
+ /**
+ * Fix any holes found in the specified edge
+ * @param inTerrainTrack terrain track
+ * @param inCornerIndex index of corner to start from
+ * @param inInc increment along edge
+ */
+ private void fixEdge(Track inTerrainTrack, int inCornerIndex, int inInc)
+ {
+ int prevIndexWithAlt = -1;
+ int sIndex = inCornerIndex;
+ if (inTerrainTrack.getPoint(sIndex).hasAltitude()) {prevIndexWithAlt = 0;}
+ for (int i=1; i<_gridSize; i++)
+ {
+ sIndex += inInc;
+ if (inTerrainTrack.getPoint(sIndex).hasAltitude())
+ {
+ if (prevIndexWithAlt >= 0 && prevIndexWithAlt < (i-1))
+ {
+ final int gapLen = i - prevIndexWithAlt;
+ final int cellIndex1 = inCornerIndex + prevIndexWithAlt * inInc;
+ final double alt1 = inTerrainTrack.getPoint(cellIndex1).getAltitude().getMetricValue();
+ final int cellIndex2 = inCornerIndex + i * inInc;
+ final double alt2 = inTerrainTrack.getPoint(cellIndex2).getAltitude().getMetricValue();
+ //System.out.println("Altitude along edge goes from " + alt1 + " (at " + prevIndexWithAlt + ") to " +
+ // alt2 + " (at " + i + ")");
+ for (int j = 1; j < gapLen; j++)
+ {
+ final double alt = alt1 + (alt2-alt1) * j / gapLen;
+ //System.out.println("Fill in " + (prevIndexWithAlt + j) + "(" + (inCornerIndex + (prevIndexWithAlt + j) * inInc) + ") with alt " + (int) alt);
+ final DataPoint p = inTerrainTrack.getPoint(inCornerIndex + (prevIndexWithAlt + j) * inInc);
+ p.setFieldValue(Field.ALTITUDE, "" + (int) alt, false);
+ // TODO: Check forcing metres?
+ }
+ }
+ prevIndexWithAlt = i;
}
}
}
*/
private void fixBiggerHoles(Track inTerrainTrack)
{
- double[] altitudes = new double[inTerrainTrack.getNumPoints()];
+ TerrainPatch patch = new TerrainPatch(_gridSize);
for (int i=0; i<_gridSize; i++)
{
int prevHoriz = -1, prevVert = -1;
{
if (prevHoriz > -1 && prevHoriz != (j-1))
{
-// System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
+ //System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
double startVal = inTerrainTrack.getPoint(i * _gridSize + prevHoriz).getAltitude().getMetricValue();
double endVal = inTerrainTrack.getPoint(i * _gridSize + j).getAltitude().getMetricValue();
for (int k=prevHoriz + 1; k< j; k++)
{
double val = startVal + (k-prevHoriz) * (endVal-startVal) / (j-prevHoriz);
- if (altitudes[i * _gridSize + k] > 0.0) {
- altitudes[i * _gridSize + k] = (altitudes[i * _gridSize + k] + val) / 2.0;
- }
- else {
- altitudes[i * _gridSize + k] = val;
- }
+ patch.addAltitude(i * _gridSize + k, val, k-prevHoriz, j-prevHoriz);
}
}
prevHoriz = j;
{
if (prevVert > -1 && prevVert != (j-1))
{
-// System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
+ //System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
double startVal = inTerrainTrack.getPoint(prevVert * _gridSize + i).getAltitude().getMetricValue();
double endVal = inTerrainTrack.getPoint(j * _gridSize + i).getAltitude().getMetricValue();
for (int k=prevVert + 1; k< j; k++)
{
double val = startVal + (k-prevVert) * (endVal-startVal) / (j-prevVert);
- if (altitudes[k * _gridSize + i] > 0.0) {
- altitudes[k * _gridSize + i] = (altitudes[k * _gridSize + i] + val) / 2.0;
- }
- else {
- altitudes[k * _gridSize + i] = val;
- }
+ patch.addAltitude(k * _gridSize + i, val, k-prevVert, j-prevVert);
}
}
prevVert = j;
}
}
}
- // Now the doubles have been set and/or averaged, we can set the values in the points
+ // Smooth the patch to reduce the blocky effect from the voids
+ patch.smooth();
+
+ // Now the doubles have been set and averaged, we can set the values in the points
for (int i=0; i<inTerrainTrack.getNumPoints(); i++)
{
DataPoint p = inTerrainTrack.getPoint(i);
- if (!p.hasAltitude() && altitudes[i] > 0.0)
+ if (!p.hasAltitude())
{
- p.setFieldValue(Field.ALTITUDE, "" + altitudes[i], false);
- p.getAltitude().reset(new Altitude((int) altitudes[i], UnitSetLibrary.UNITS_METRES));
+ final double altitude = patch.getAltitude(i);
+ p.setFieldValue(Field.ALTITUDE, "" + altitude, false);
+ p.getAltitude().reset(new Altitude((int) altitude, UnitSetLibrary.UNITS_METRES));
}
}
}