Add --buildpyramid, to build a full zoom pyramid for leaflet.

This commit is contained in:
Martijn Versteegh 2018-11-15 12:42:05 +01:00
parent f84828b0bf
commit 90e7228bb9
7 changed files with 153 additions and 11 deletions

View File

@ -103,6 +103,13 @@ tilesize:
a multiple of 16. The filenames will be created in the form <x>_<y>_<filename>, where <x> and <y>
are the tile numbers and <filename> is the name specified with -o. Skip empty tiles by also specifying --noemptyimage.
leaflet:
Together with --tilesize, output tiles in a leaflet-compaitble numbering and also output a html file to display the map.
Copy the files in the Leaflet subfolder to the same folder as your map.
buildpyramid:
Together with --leaflet, build a zoom pyramid for faster zooming/loading of the generated map.
zoom:
Apply zoom to drawn nodes by enlarging them to n*n squares, e.g. ``--zoom 4``

View File

@ -7,6 +7,7 @@
#include <stdexcept>
#include <cstring>
#include <vector>
#include <math.h>
#include "TileGenerator.h"
#include "config.h"
@ -81,6 +82,7 @@ TileGenerator::TileGenerator():
m_shading(true),
m_leaflet(false),
m_dontWriteEmpty(false),
m_buildPyramid(false),
m_backend(""),
m_xBorder(0),
m_yBorder(0),
@ -185,6 +187,11 @@ void TileGenerator::setLeaflet(bool leaflet)
m_leaflet = leaflet;
}
void TileGenerator::setBuildPyramid(bool pyramid)
{
m_buildPyramid = pyramid;
}
void TileGenerator::setBackend(std::string backend)
{
m_backend = backend;
@ -251,10 +258,6 @@ void TileGenerator::setDontWriteEmpty(bool f)
void TileGenerator::generate(const std::string &input, const std::string &output)
{
if (m_leaflet)
{
outputLeafletCode(output);
}
string input_path = input;
if (input_path[input.length() - 1] != PATH_SEPARATOR) {
@ -294,6 +297,22 @@ void TileGenerator::generate(const std::string &input, const std::string &output
tilePositions();
// round xMax/zMax tot integer number of tiles
m_xMax = m_xMin + m_numTilesX * m_tileW;
m_zMax = m_zMin + m_numTilesY * m_tileH;
int maxZoomLevel = 0;
if (m_buildPyramid)
{
int maxDimX = m_xMax > -m_xMin ? m_xMax : -m_xMin;
int maxDimY = m_zMax > -m_zMin ? m_zMax : -m_zMin;
int maxDim = maxDimX > maxDimY ? maxDimX : maxDimY;
maxZoomLevel = static_cast<int>(log2(maxDim / m_tileW)) + 1;
}
int trueXMin = m_xMin;
int trueZMin = m_zMin;
@ -322,8 +341,16 @@ void TileGenerator::generate(const std::string &input, const std::string &output
renderPlayers(input_path);
}
ostringstream fn;
if (m_leaflet)
{
fn << maxZoomLevel << "_";
}
fn << x + minTileX << '_' << (flipY * (y + minTileZ)) << '_' << output;
writeImage(fn.str());
if (m_buildPyramid)
{
m_availableTiles.insert(Coords(x + minTileX,(flipY * (y + minTileZ))));
}
}
}
}
@ -334,6 +361,15 @@ void TileGenerator::generate(const std::string &input, const std::string &output
m_image->fill(m_bgColor);
writeImage(fn.str());
}
if (m_buildPyramid)
{
buildPyramid(output, maxZoomLevel);
}
if (m_leaflet)
{
outputLeafletCode(output, maxZoomLevel);
}
}
else
{
@ -843,12 +879,12 @@ static char const *leafletMapHtml =
"<script>\n"
" var MineTestMap = L.map('mapid', {\n"
" crs: L.CRS.Simple,\n"
"// minZoom: -3,\n"
"// minZoom: 0,\n"
" });\n"
" MineTestMap.setView([0.0, 0.0], 0);\n"
" L.tileLayer('{x}_{y}_%s', {\n"
" MineTestMap.setView([0.0, 0.0], %d);\n"
" L.tileLayer('{z}_{x}_{y}_%s', {\n"
" minNativeZoom: 0,\n"
" maxNativeZoom: 0,\n"
" maxNativeZoom: %d,\n"
" attribution: 'Minetest World',\n"
" tileSize: %d,\n"
" errorTileUrl: \"empty_tile_%s\",\n"
@ -866,7 +902,7 @@ static char const *leafletMapHtml =
"</html>\n";
void TileGenerator::outputLeafletCode(std::string const &output)
void TileGenerator::outputLeafletCode(std::string const &output, int maxLevel)
{
if (m_tileH != m_tileW)
{
@ -874,6 +910,12 @@ void TileGenerator::outputLeafletCode(std::string const &output)
return;
}
if (m_tileH == INT_MAX)
{
throw std::runtime_error("Can only use --leaflet with --tilesize!");
return;
}
ostringstream fn;
fn << output << ".html";
@ -888,9 +930,73 @@ void TileGenerator::outputLeafletCode(std::string const &output)
return;
}
fprintf(out, leafletMapHtml, output.c_str(), m_tileW, output.c_str());
fprintf(out, leafletMapHtml, maxLevel, output.c_str(), maxLevel, m_tileW*16, output.c_str());
fclose(out);
}
void TileGenerator::buildPyramid(std::string const &fileName, int startLevel)
{
TileSet tilesToGenerate;
int level = startLevel;
while (true)
{
for (TileSet::iterator t = m_availableTiles.begin(); t != m_availableTiles.end(); t++)
{
int x = t->first;
int y = t->second;
if (x >=0)
x++;
if (y >=0)
y++;
x = round_multiple_nosign(x, 2) / 2;
y = round_multiple_nosign(y, 2) / 2;
if (x > 0)
x--;
if (y > 0)
y--;
tilesToGenerate.insert(Coords(x, y));
}
int halfW = m_mapWidth/2;
int halfH = m_mapHeight/2;
for (TileSet::iterator g = tilesToGenerate.begin(); g != tilesToGenerate.end(); g++)
{
m_image->fill(m_bgColor);
int x = g->first;
int y = g->second;
for (int i = 0; i < 2 ; i++)
{
for (int j = 0; j < 2; j++)
{
if (m_availableTiles.find(Coords(2*x+i, 2*y+j)) != m_availableTiles.end())
{
std::ostringstream f;
f << level << "_" << (2*x+i) << "_" << (2*y+j) << "_" << fileName;
Image src(f.str());
src.scaleBlit(m_image, i*halfW, j*halfH, halfW, halfH);
}
}
}
std::ostringstream f;
f << (level-1) << "_" << x << "_" << y << "_" << fileName;
m_image->save(f.str());
cout << "Wrote image " << f.str() << endl;
}
std::cout << "generated pyramid level " << (level -1) << endl;
level--;
if (!level)
{
return; // we're done
}
m_availableTiles = tilesToGenerate;
tilesToGenerate.clear();
}
}

View File

@ -57,7 +57,13 @@ struct BitmapThing { // 16x16 bitmap
};
typedef std::list<std::pair<int, int> > PositionsList;
typedef std::pair<int16_t, int16_t> Coords;
struct Coords_hash {
inline std::size_t operator()(const Coords &v) const {
return std::hash<int>()((static_cast<int>(v.first) << 16) + static_cast<int>(v.second));
}
};
class TileGenerator
{
@ -65,10 +71,12 @@ private:
#if __cplusplus >= 201103L
typedef std::unordered_map<std::string, ColorEntry> ColorMap;
typedef std::unordered_set<std::string> NameSet;
typedef std::unordered_set<Coords, Coords_hash> TileSet;
typedef std::unordered_map<int, PositionsList> TileMap;
#else
typedef std::map<std::string, ColorEntry> ColorMap;
typedef std::set<std::string> NameSet;
typedef std::set<Coords, Coords_hash> TileSet;
typedef std::map<int, PositionsList> TileMap;
#endif
@ -85,6 +93,7 @@ public:
void setDrawAlpha(bool drawAlpha);
void setShading(bool shading);
void setLeaflet(bool leaflet);
void setBuildPyramid(bool pyramid);
void setGeometry(int x, int y, int w, int h);
void setTileSize(int w, int h);
void setMinY(int y);
@ -119,7 +128,8 @@ private:
void setZoomed(int x, int y, Color color);
private:
void outputLeafletCode(std::string const &output);
void outputLeafletCode(std::string const &output, int maxZoomLevel);
void buildPyramid(std::string const &baseName, int startLevel);
Color m_bgColor;
Color m_scaleColor;
Color m_originColor;
@ -131,6 +141,7 @@ private:
bool m_shading;
bool m_leaflet;
bool m_dontWriteEmpty;
bool m_buildPyramid;
std::string m_backend;
int m_xBorder, m_yBorder;
@ -167,6 +178,9 @@ private:
int m_zoom;
uint m_scales;
// stuff for pyramid building
TileSet m_availableTiles;
}; // class TileGenerator
#endif // TILEGENERATOR_HEADER

View File

@ -31,6 +31,7 @@ void usage()
" --geometry x:y+w+h\n"
" --tilesize wxh\n"
" --leaflet\n"
" --buildpyramid\n"
" --extent\n"
" --zoom <zoomlevel>\n"
" --colors <colors.txt>\n"
@ -93,6 +94,7 @@ int main(int argc, char *argv[])
{"scales", required_argument, 0, 'f'},
{"noemptyimage", no_argument, 0, 'n'},
{"leaflet", no_argument, 0, 'l'},
{"buildpyramid", no_argument, 0, 'B'},
{0, 0, 0, 0}
};
@ -152,6 +154,9 @@ int main(int argc, char *argv[])
case 'l':
generator.setLeaflet(true);
break;
case 'B':
generator.setBuildPyramid(true);
break;
case 'd':
generator.setBackend(optarg);
break;

View File

@ -82,6 +82,16 @@ Don't output one big image, but output tiles of the specified size, e.g. "--tile
a multiple of 16. The filenames will be created in the form <x>_<y>_<filename>, where <x> and <y>
are the tile numbers and <filename> is the name specified with -o. Skip empty tiles by also specifying --noemptyimage.
.TP
.BR \-\-leaflet " " \fIleaflet\fR
Together with --tilesize, output tiles in a leaflet-compaitble numbering and also output a html file to display the map.
Copy the files in the Leaflet subfolder to the same folder as your map.
.TP
.BR \-\-buildpyramid " " \fIbuildpyramid\fR
Together with --leaflet, build a zoom pyramid for faster zooming/loading of the generated map.
.TP
.BR \-\-extent " " \fIextent\fR
Dont render the image, just print the extent of the map that would be generated, in the same format as the geometry above.