From a6eed3a1edb9eefddac0e885fa6f4a9d713aaeeb Mon Sep 17 00:00:00 2001 From: Rogier Date: Sat, 14 Feb 2015 21:25:40 +0100 Subject: [PATCH] Add options to specify a custom major and minor interval in the scale(s). --- TileGenerator.cpp | 125 ++++++++++++++++++++++++++++++++++++---------- TileGenerator.h | 6 +++ mapper.cpp | 59 ++++++++++++++++++++++ 3 files changed, 163 insertions(+), 27 deletions(-) diff --git a/TileGenerator.cpp b/TileGenerator.cpp index 6e2cdae..f973a2e 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -152,6 +152,10 @@ TileGenerator::TileGenerator(): m_scaleFactor(1), m_sqliteCacheWorldRow(false), m_chunkSize(0), + m_sideScaleMajor(0), + m_sideScaleMinor(0), + m_heightScaleMajor(0), + m_heightScaleMinor(0), m_image(0), m_xMin(INT_MAX/16-1), m_xMax(INT_MIN/16+1), @@ -319,6 +323,18 @@ void TileGenerator::setDrawHeightScale(int scale) m_drawScale = (scale & DRAWHEIGHTSCALE_MASK) | (m_drawScale & DRAWSCALE_MASK & ((~scale & DRAWHEIGHTSCALE_MASK) >> 4)); } +void TileGenerator::setSideScaleInterval(int major, int minor) +{ + m_sideScaleMajor = major; + m_sideScaleMinor = minor; +} + +void TileGenerator::setHeightScaleInterval(int major, int minor) +{ + m_heightScaleMajor = major; + m_heightScaleMinor = minor; +} + void TileGenerator::setDrawAlpha(bool drawAlpha) { m_drawAlpha = drawAlpha; @@ -1649,40 +1665,82 @@ void TileGenerator::renderScale() { int color = m_scaleColor.to_libgd(); if ((m_drawScale & DRAWSCALE_LEFT) && (m_drawScale & DRAWSCALE_TOP)) { - gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast(const_cast("X")), color); - gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast(const_cast("Z")), color); + gdImageString(m_image, gdFontGetMediumBold(), borderLeft() - 26, 0, reinterpret_cast(const_cast("X")), color); + gdImageString(m_image, gdFontGetMediumBold(), 2, borderTop() - 26, reinterpret_cast(const_cast("Z")), color); } + int major = m_sideScaleMajor ? m_sideScaleMajor : 4 * 16 * m_scaleFactor; + int minor = m_sideScaleMinor; string scaleText; if ((m_drawScale & DRAWSCALE_TOP)) { - for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4 * m_scaleFactor) { - stringstream buf1, buf2; - buf1 << i * 16; - buf2 << "(" << i << ")"; - int xPos = worldX2ImageX(i * 16); + int start; + int extra_left = borderLeft() ? 0 : major; + int extra_right = borderRight() ? 0 : major; + if (m_xMin >= 0) + start = (m_xMin * 16 + m_mapXStartNodeOffset - 1 + major - 1 - extra_left) / major * major; + else + start = (m_xMin * 16 + m_mapXStartNodeOffset - 1 - extra_left) / major * major; + for (int i = start; i <= (m_xMax + 1) * 16 + m_mapXEndNodeOffset + extra_right; i += major) { + stringstream buf; + buf << i; + int xPos = worldX2ImageX(i); - scaleText = buf1.str(); + scaleText = buf.str(); gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, 0, reinterpret_cast(const_cast(scaleText.c_str())), color); - scaleText = buf2.str(); - gdImageString(m_image, gdFontGetTiny(), xPos + 2, 16, reinterpret_cast(const_cast(scaleText.c_str())), color); + if ((major % 16) == 0) { + buf.str(""); + buf << "(" << i / 16 << ")"; + scaleText = buf.str(); + gdImageString(m_image, gdFontGetTiny(), xPos + 2, 16, reinterpret_cast(const_cast(scaleText.c_str())), color); + } gdImageLine(m_image, xPos, 0, xPos, borderTop() - 1, color); } + if (minor) { + if (m_xMin >= 0) + start = (m_xMin * 16 + m_mapXStartNodeOffset + minor - 2) / minor * minor; + else + start = (m_xMin * 16 + m_mapXStartNodeOffset - 1) / minor * minor; + for (int i = start; i <= (m_xMax + 1) * 16 + m_mapXEndNodeOffset; i += minor) { + int xPos = worldX2ImageX(i); + gdImageLine(m_image, xPos, borderTop() - 5, xPos, borderTop() - 1, color); + } + } } if ((m_drawScale & DRAWSCALE_LEFT)) { - for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4 * m_scaleFactor) { - stringstream buf1, buf2; - buf1 << i * 16; - buf2 << "(" << i << ")"; - int yPos = worldZ2ImageY(i * 16); + int start; + int extra_top = borderTop() ? 0 : major; + int extra_bottom = borderBottom() ? 0 : major; + if (m_zMax >= 0) + start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset + extra_top) / major * major; + else + start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset - major + 1 + extra_top) / major * major; + for (int i = start; i >= m_zMin * 16 - m_mapYEndNodeOffset - 1 - extra_bottom; i -= major) { + stringstream buf; + buf << i; + int yPos = worldZ2ImageY(i); - scaleText = buf1.str(); + scaleText = buf.str(); gdImageString(m_image, gdFontGetMediumBold(), 2, yPos, reinterpret_cast(const_cast(scaleText.c_str())), color); - scaleText = buf2.str(); - gdImageString(m_image, gdFontGetTiny(), 2, yPos-10, reinterpret_cast(const_cast(scaleText.c_str())), color); + if ((major % 16) == 0) { + buf.str(""); + buf << "(" << i / 16 << ")"; + scaleText = buf.str(); + gdImageString(m_image, gdFontGetTiny(), 2, yPos-10, reinterpret_cast(const_cast(scaleText.c_str())), color); + } gdImageLine(m_image, 0, yPos, borderLeft() - 1, yPos, color); } + if (minor) { + if (m_zMax >= 0) + start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset) / minor * minor; + else + start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset - minor + 1) / minor * minor; + for (int i = start; i >= m_zMin * 16 - m_mapYEndNodeOffset - 1; i -= minor) { + int yPos = worldZ2ImageY(i); + gdImageLine(m_image, borderLeft() - 5, yPos, borderLeft() - 1, yPos, color); + } + } } // DRAWSCALE_RIGHT and DRAWSCALE_BOTTOM not implemented - getting the text positioned right seems not trivial (??) @@ -1700,11 +1758,18 @@ void TileGenerator::renderHeightScale() if (height_step < 1.0 / 16) { height_step = 1.0 / 16; } - double number_step = 64; - while (number_step / height_step < 48) - number_step *= 2; - while (number_step / height_step > 96) - number_step /= 2; + double major; + int minor = m_heightScaleMinor; + if (m_heightScaleMajor) { + major = m_heightScaleMajor; + } + else { + major = 64; + while (major / height_step / 64 < 0.75) + major *= 2; + while (major / height_step / 64 > 1.5) + major /= 2; + } double height = height_min; for (int x = 0; height < height_limit; x++, height += height_step) { @@ -1712,21 +1777,27 @@ void TileGenerator::renderHeightScale() gdImageLine(m_image, xBorderOffset + x, yBorderOffset + 8, xBorderOffset + x, yBorderOffset + borderBottom() - 20, color.to_libgd()); int iheight = int(height + (height > 0 ? 0.5 : -0.5)); - int iheight64 = int(iheight / number_step + (height > 0 ? 0.5 : -0.5)) * number_step; - if (fabs(height - iheight64) <= height_step / 2 && (height - iheight64) > -height_step / 2) { - if (iheight64 / int(number_step) % 2 == 1 && fabs(height) > 9999 && number_step / height_step < 56) { + int iheightMaj = int(iheight / major + (height > 0 ? 0.5 : -0.5)) * major; + if (fabs(height - iheightMaj) <= height_step / 2 && (height - iheightMaj) > -height_step / 2) { + if (iheightMaj / int(major) % 2 == 1 && fabs(height) > 9999 && major / height_step < 56) { // Maybe not enough room for the number. Draw a tick mark instead gdImageLine(m_image, xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 16, scaleColor); } else { stringstream buf; - buf << iheight64; + buf << iheightMaj; string scaleText = buf.str(); gdImageString(m_image, gdFontGetMediumBold(), xBorderOffset + x + 2, yBorderOffset + borderBottom() - 16, reinterpret_cast(const_cast(scaleText.c_str())), scaleColor); gdImageLine(m_image, xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 1, scaleColor); } } + if (minor) { + int iheightMin = int(iheight / minor + (height > 0 ? 0.5 : -0.5)) * minor; + if (fabs(height - iheightMin) <= height_step / 2 && (height - iheightMin) > -height_step / 2) { + gdImageLine(m_image, xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 16, scaleColor); + } + } } } diff --git a/TileGenerator.h b/TileGenerator.h index 9a071b6..4a18858 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -123,6 +123,8 @@ public: void setDrawPlayers(bool drawPlayers); void setDrawScale(int scale); void setDrawHeightScale(int scale); + void setSideScaleInterval(int major, int minor); + void setHeightScaleInterval(int major, int minor); void setDrawAlpha(bool drawAlpha); void setDrawAir(bool drawAir); void drawObject(const DrawObject &object) { m_drawObjects.push_back(object); } @@ -235,6 +237,10 @@ private: int m_scaleFactor; bool m_sqliteCacheWorldRow; int m_chunkSize; + int m_sideScaleMajor; + int m_sideScaleMinor; + int m_heightScaleMajor; + int m_heightScaleMinor; DB *m_db; gdImagePtr m_image; diff --git a/mapper.cpp b/mapper.cpp index ad25359..cb4a668 100644 --- a/mapper.cpp +++ b/mapper.cpp @@ -38,6 +38,7 @@ using namespace std; #define OPT_HEIGHTMAPCOLORSFILE 0x8c #define OPT_DRAWHEIGHTSCALE 0x8d #define OPT_SCALEFACTOR 0x8e +#define OPT_SCALEINTERVAL 0x8f // Will be replaced with the actual name and location of the executable (if found) string executableName = "minetestmapper"; @@ -87,7 +88,9 @@ void usage() " --origincolor \n" " --tilebordercolor \n" " --drawscale[=left,top]\n" + " --sidescale-interval [[,:]]\n" " --drawheightscale\n" + " --heightscale-interval [[,:]]\n" " --drawplayers\n" " --draworigin\n" " --drawalpha[=cumulative|cumulative-darken|average|none]\n" @@ -555,7 +558,9 @@ int main(int argc, char *argv[]) {"draworigin", no_argument, 0, 'R'}, {"drawplayers", no_argument, 0, 'P'}, {"drawscale", optional_argument, 0, 'S'}, + {"sidescale-interval", required_argument, 0, OPT_SCALEINTERVAL}, {"drawheightscale", no_argument, 0, OPT_DRAWHEIGHTSCALE}, + {"heightscale-interval", required_argument, 0, OPT_SCALEINTERVAL}, {"drawalpha", optional_argument, 0, 'e'}, {"drawair", no_argument, 0, OPT_DRAWAIR}, {"drawpoint", required_argument, 0, OPT_DRAW_OBJECT}, @@ -733,6 +738,60 @@ int main(int argc, char *argv[]) case OPT_DRAWHEIGHTSCALE : generator.setDrawHeightScale(DRAWHEIGHTSCALE_BOTTOM); break; + case OPT_SCALEINTERVAL: { + istringstream arg; + arg.str(optarg); + int major; + int minor; + char sep; + arg >> major; + if (major < 0 || !isdigit(*optarg) || arg.fail()) { + std::cerr << "Invalid parameter to '" << long_options[option_index].name + << "': '" << optarg << "' (expected: [,]" << std::endl; + usage(); + exit(1); + } + arg >> std::ws >> sep >> std::ws; + if (!arg.fail()) { + if ((sep != ',' && sep != ':') || !isdigit(arg.peek())) { + std::cerr << "Invalid parameter to '" << long_options[option_index].name + << "': '" << optarg << "' (expected: [,]" << std::endl; + usage(); + exit(1); + } + arg >> minor; + if (minor < 0) { + std::cerr << "Invalid parameter to '" << long_options[option_index].name + << "': '" << optarg << "' (expected: [,]" << std::endl; + usage(); + exit(1); + } + } + else { + minor = 0; + } + if (minor && sep == ':') { + if (major % minor) { + std::cerr << long_options[option_index].name << ": Cannot divide major interval in " + << minor << " subintervals (not divisible)" << std::endl; + exit(1); + } + minor = major / minor; + } + if ((minor % major) == 0) + minor = 0; + if (long_options[option_index].name[0] == 's') { + generator.setSideScaleInterval(major, minor); + } + else if (long_options[option_index].name[0] == 'h') { + generator.setHeightScaleInterval(major, minor); + } + else { + std::cerr << "Internal error: option " << long_options[option_index].name << " not handled" << std::endl; + exit(1); + } + } + break; case 'v': if (optarg && isdigit(optarg[0]) && optarg[1] == '\0') { if (optarg[0] == '0')