Index: resources/help/en/options =================================================================== --- resources/help/en/options (revision 1580) +++ resources/help/en/options (working copy) @@ -370,11 +370,49 @@ --tdbfile Write a .tdb file. ---show-profiles=1 +--show-profiles=0|1 Sets a flag in tdb file which marks set mapset as having contour lines and allows showing profile in MapSource. Default is 0 which means disabled. - + DON'T use this option when combining separate tiles with contour + lines and real data tiles for the same area. MapSource will crash + on them. + +--contour + Create contour lines. Behaviour is specified by the dem-* options. + +--dem-type=[SRTM|ASTER|CGIAR] + Defines kind of processed data. Default is SRTM. + SRTM data covers earth surface from 60� north to 56� south in 1�x1� + plain data files (1201x1201 short int values). + See http://www2.jpl.nasa.gov/srtm/ + CGIAR contains optimized SRTM to fill missing data areas. + Data is provided as 5�x5� GeoTiff files. + See http://srtm.csi.cgiar.org/ + ASTER data covers earth surface from 83� north to 83� south and is + provided as 1�x1� GeoTiff files. + See http://www.gdem.aster.ersdac.or.jp/ + +--dem-path + Location of DEM source data. Currently mkgmap does not load required + files from the web. + +--dem-increment=10[,0[,0]] + Create contour lines for steps with specified increment in meter. + The really used increment depends on option --dem-maxlevels. + The optional parameters define a factor which contour lines are + marked as major (first parameter) and as medium (second). If both + are omitted all lines are just marked as "contour=elevation". + Example: 20,10,5 results in minor contour every 20 meter, medium + contour every 100 meter and major contour every 200 meter. + +--dem-maxlevels=100 + Defines maximum number of different elevation levels. Increment + will be doubled while maxlevel is exceeded. Using the default + values of 10 for dem-increment and 100 for dem-maxlevels, the + active increment will be set to 20 if lowest point of tile is 0 + and highest point is 1200: 10*100 < 1200 < 20*100 + --draw-priority=25 When two maps cover the same area, this option controls what order they are drawn in and therefore which map is on top of Index: src/uk/me/parabola/mkgmap/reader/dem/DEM.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/dem/DEM.java (revision 1580) +++ src/uk/me/parabola/mkgmap/reader/dem/DEM.java (working copy) @@ -28,6 +28,7 @@ import uk.me.parabola.imgfmt.app.Area; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.imgfmt.app.map.Map; +import uk.me.parabola.log.Logger; import uk.me.parabola.mkgmap.build.MapBuilder; import uk.me.parabola.mkgmap.general.LevelInfo; import uk.me.parabola.mkgmap.general.LoadableMapDataSource; @@ -38,6 +39,7 @@ import uk.me.parabola.mkgmap.reader.osm.OsmConverter; import uk.me.parabola.mkgmap.reader.osm.Style; import uk.me.parabola.mkgmap.reader.osm.Way; +import uk.me.parabola.mkgmap.reader.osm.xml.Osm5XmlHandler; import uk.me.parabola.util.EnhancedProperties; @@ -47,6 +49,8 @@ * Adaptive Grid Contouring Algorithm by Downing and Zoraster. */ public abstract class DEM { + private static final Logger log = Logger.getLogger(DEM.class); + final static double epsilon = 1e-9; final protected static double delta = 1.5; final static int maxPoints = 200000; @@ -104,11 +108,43 @@ } Isolines lines = data.new Isolines(data, minLat, minLon, maxLat, maxLon); - int increment = config.getProperty("dem-increment", 10); + // get base increment between isolines (meter) + int increment = 10; + // which levels are marked as major elevation lines (default is all) + int maj_increment = 0; + // which levels are marked as medium elevation lines (default is all) + int med_increment = 0; + String strInc = config.getProperty("dem-increment", null); + if (strInc != null) { + String steps[] = strInc.split(","); + try { + increment = Integer.parseInt(steps[0]); + } catch (NumberFormatException ex) { + log.error("dem-increment expects list of numerical data"); + } + if (steps.length > 1) { + try { + maj_increment = Integer.parseInt(steps[1]); + } catch (NumberFormatException ex) { + log.error("dem-increment expects list of numerical data"); + } + } + if (steps.length > 2) { + try { + med_increment = Integer.parseInt(steps[1]); + } catch (NumberFormatException ex) { + log.error("dem-increment expects list of numerical data"); + } + } + } double minHeight = lines.getMinHeight(); double maxHeight = lines.getMaxHeight(); + // get maximum number of isolines int maxLevels = config.getProperty("dem-maxlevels", 100); + // adjust increment to ensure no more than maxLevels isolines are created + // e.g. if we have a difference between lowest and highest point of 1980 increment is increased to 20. + // So the only way to ensure fixed increments is to define dem-maxlevels to a value which will be reached never. while ((maxHeight - minHeight) / increment > maxLevels) increment *= 2; @@ -149,6 +185,14 @@ for (Isolines.Isoline line : lines.isolines) { Way way = new Way(id--, line.points); way.addTag("contour", "elevation"); + if (maj_increment != 0) { + if ((level / increment) % maj_increment == 0) + way.addTag("contour_ext", "elevation_major"); + else if (med_increment != 0 && ((level / increment) % med_increment == 0)) + way.addTag("contour_ext", "elevation_medium"); + else + way.addTag("contour_ext", "elevation_minor"); + } way.addTag("ele", String.format("%d", (int) line.level)); converter.convertWay(way); } @@ -687,10 +731,16 @@ // we need some overlap for bicubic interpolation max = -1000; min = 10000; + double e; for (int i = minX; i < maxX; i++) for (int j = minY; j < maxY; j++) { - if (data.elevation(i, j) < min) min = data.elevation(i, j); - if (data.elevation(i, j) > max) max = data.elevation(i, j); + e = data.elevation(i, j); + if (e < - 1000) // SRTM marks invalid values with Short.MIN_VALUE, so don't get confused by this + continue; + if (e < min) + min = e; + if (e > max) + max = e; } debug("min: %f, max: %f\n", min, max); Index: src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java (revision 1580) +++ src/uk/me/parabola/mkgmap/reader/dem/HGTDEM.java (working copy) @@ -22,44 +22,69 @@ import static java.nio.channels.FileChannel.MapMode.READ_ONLY; +import java.util.HashMap; +import java.util.Map; + public class HGTDEM extends DEM { - MappedByteBuffer buffer = null; - + Map buffers = new HashMap(); + + int nLon; // number of touched files in longitude direction + int nLat; // number of touched files in latitude direction + public HGTDEM(String dataPath, double minLat, double minLon, double maxLat, double maxLon) { - this.lat = (int) minLat; - this.lon = (int) minLon; - if (maxLat > lat+1 || maxLon > lon+1) - throw new RuntimeException("Area too large (must not span more than one SRTM file)"); - - String northSouth = lat < 0 ? "S" : "N"; - String eastWest = lon > 0 ? "E" : "W"; - String fileName = String.format("%s/%s%02d%s%03d.hgt", dataPath, - northSouth, lat < 0 ? -lat : lat, - eastWest, lon < 0 ? -lon : lon); - try { - FileInputStream is = new FileInputStream(fileName); - buffer = is.getChannel().map(READ_ONLY, 0, 2*(M+1)*(M+1)); - } - catch (Exception e) { - throw new RuntimeException(e); - } + res = 1.0 / M; + this.lat = (int) minLat; + this.lon = (int) minLon; + nLat = (int)maxLat - this.lat + 1; + nLon = (int)maxLon - this.lon + 1; + if (nLat > nLon) + N = M * nLat; + else + N = M * nLon; + for (int x = 0; x < nLon; ++x) { + String eastWest = "E"; + int actLon = lon + x; + if ((lon + x) < 0) { + actLon = -(lon + x); + eastWest = "W"; + } + for (int y = 0; y < nLat; ++y) { + String northSouth = (lat + y) < 0 ? "S" : "N"; + String fileName = String.format("%s/%s%02d%s%03d.hgt", dataPath, + northSouth, (lat + y) < 0 ? -(lat + y) : (lat + y), + eastWest, actLon); + try { + FileInputStream is = new FileInputStream(fileName); + buffers.put(x * nLat + y, is.getChannel().map(READ_ONLY, 0, 2*(M+1)*(M+1))); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } } - public void read(int minLon, int minLat, int maxLon, int maxLat) + @Override + protected void read(int minLon, int minLat, int maxLon, int maxLat) { } - public double ele(int x, int y) - { - return buffer.getShort(2*((M-y)*(M+1)+x))+delta; - } + @Override + protected double ele(int x, int y) { + int actLon = x / M; + int actLat = y / M; + if (actLon > nLon || actLat > nLat) + throw new IndexOutOfBoundsException("point not inside area"); + MappedByteBuffer buffer = buffers.get(actLon*nLat+actLat); + return buffer.getShort(2*((M-y%M)*(M+1)+x%M))+delta; + } public void serializeCopyRight(Writer out) throws IOException { - out.write(" \n"); - out.write(" Contour lines generated from DEM data by NASA\n"); - out.write(" \n"); + out.write(" \n"); + out.write(" Contour lines generated from DEM data by NASA\n"); + out.write(" \n"); } }