Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial support for output to SVG image format #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace config {
unsigned int seed = 0;
double resolution = 0.08;
std::string outfileExt = ".png";
std::string outfile = "output" + outfileExt;
std::string outfile = "output";
double erosionAmount = -1.0;
int erosionIterations = 3;
int numCities = -1;
Expand All @@ -23,6 +23,8 @@ bool enableCities = true;
bool enableTowns = true;
bool enableLabels = true;
bool enableAreaLabels = true;
bool withSvgOutput = false;
bool enableSvgColors = false;
bool verbose = false;

void print(std::string msg) {
Expand Down Expand Up @@ -55,6 +57,8 @@ bool parseOptions(int argc, char **argv) {
opts.nolabels = arg_litn(NULL, "no-labels", 0, 1, "disable label drawing"),
opts.noarealabels = arg_litn(NULL, "no-arealabels", 0, 1, "disable area label drawing"),
opts.drawinfo = arg_litn(NULL, "drawing-supported", 0, 1, "display whether drawing is supported and exit"),
opts.withsvg = arg_litn(NULL, "with-svg", 0, 1, "additional output in svg format"),
opts.svgcolors = arg_litn(NULL, "svg-colors", 0, 1, "enable colors in svg output"),
opts.verbose = arg_litn("v", "verbose", 0, 1, "output additional information to stdout"),
opts.end = arg_end(20)
};
Expand Down Expand Up @@ -138,6 +142,8 @@ bool _setOptions(OptionArgs opts) {
if (!_disableTowns(opts.notowns)) { return false; }
if (!_disableLabels(opts.nolabels)) { return false; }
if (!_disableAreaLabels(opts.noarealabels)) { return false; }
if (!_enableWithSvg(opts.withsvg)) { return false; }
if (!_enableSvgColors(opts.svgcolors)) { return false; }
if (!_setVerbosity(opts.verbose)) { return false; }

return true;
Expand Down Expand Up @@ -377,6 +383,22 @@ bool _disableAreaLabels(arg_lit *noarealabels) {
return true;
}

bool _enableWithSvg(arg_lit *withsvg) {
if (withsvg->count > 0) {
gen::config::withSvgOutput = true;
}

return true;
}

bool _enableSvgColors(arg_lit *svgcolors) {
if (svgcolors->count > 0) {
gen::config::enableSvgColors = true;
}

return true;
}

bool _setVerbosity(arg_lit *verbose) {
if (verbose->count > 0) {
gen::config::verbose = true;
Expand All @@ -386,4 +408,4 @@ bool _setVerbosity(arg_lit *verbose) {
}

}
}
}
8 changes: 7 additions & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct OptionArgs {
struct arg_lit *nolabels;
struct arg_lit *noarealabels;
struct arg_lit *drawinfo;
struct arg_lit *withsvg;
struct arg_lit *svgcolors;
struct arg_lit *verbose;
struct arg_end *end;
};
Expand All @@ -56,6 +58,8 @@ extern bool enableCities;
extern bool enableTowns;
extern bool enableLabels;
extern bool enableAreaLabels;
extern bool withSvgOutput;
extern bool enableSvgColors;
extern bool verbose;

template<class T>
Expand Down Expand Up @@ -88,9 +92,11 @@ bool _disableCities(arg_lit *nocities);
bool _disableTowns(arg_lit *notowns);
bool _disableLabels(arg_lit *nolabels);
bool _disableAreaLabels(arg_lit *noarealabels);
bool _enableWithSvg(arg_lit *withsvg);
bool _enableSvgColors(arg_lit *svgcolors);
bool _setVerbosity(arg_lit *verbose);

}
}

#endif
#endif
24 changes: 16 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,30 @@ void outputMap(gen::MapGenerator &map) {
gen::config::print("Finished Generating map draw data in " +
gen::config::toString(timer.getTime()) + " seconds.\n");

std::string outfile = gen::config::outfile;
std::string outfileExt = gen::config::outfileExt;
if (gen::config::withSvgOutput)
{
std::string svg_outfile = gen::config::outfile + ".svg";
timer.reset();
timer.start();
gen::config::print("Exporting map as svg...");
map.outputSvgData(svg_outfile);
timer.stop();
gen::config::print("Finished exporting to svg in " +
gen::config::toString(timer.getTime()) + " seconds.\n");

gen::config::print("Wrote svg to file: " + svg_outfile);
}
#ifdef PYTHON_RENDERING_SUPPORTED
if (outfileExt != std::string(".png")) {
outfile += ".png";
}

std::string png_outfile = gen::config::outfile + ".png";
timer.reset();
timer.start();
gen::config::print("Drawing map...");
gen::render::drawMap(drawdata, outfile);
gen::render::drawMap(drawdata, png_outfile);
timer.stop();
gen::config::print("Finished drawing map in " +
gen::config::toString(timer.getTime()) + " seconds.\n");

gen::config::print("Wrote map to image: " + outfile);
gen::config::print("Wrote map to image: " + png_outfile);
#else
if (outfileExt != std::string(".json")) {
outfile += ".json";
Expand Down
230 changes: 229 additions & 1 deletion src/mapgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,204 @@ std::vector<char> gen::MapGenerator::getDrawData() {
return charvect;
}

void gen::MapGenerator::outputSvgData(std::string filename) {
if (!_isInitialized) {
throw std::runtime_error("MapGenerator must be initialized.");
}

if (!_isHeightMapEroded) {
erode(0.0);
}

std::vector<std::vector<double> > contourData;
if (_isContourEnabled) {
_getContourDrawData(contourData);
_contourData = contourData;
}

std::vector<std::vector<double> > riverData;
if (_isRiversEnabled) {
_getRiverDrawData(riverData);
_riverData = riverData;
}

std::vector<double> slopeData;
if (_isSlopesEnabled) {
_getSlopeDrawData(slopeData);
}

std::vector<double> cityData;
if (_isCitiesEnabled) {
_getCityDrawData(cityData);
}

std::vector<double> townData;
if (_isTownsEnabled) {
_getTownDrawData(townData);
}

std::vector<std::vector<double> > territoryData;
_getTerritoryDrawData(territoryData);
_borderData = territoryData;
if (!_isBordersEnabled) {
territoryData.clear();
}

std::vector<Label> labelData;
if (_isLabelsEnabled) {
_getLabelSvgData(labelData);
}

std::ofstream file(filename);

file << "<svg version='1.1' baseProfile='full' width='" << _imgwidth
<< "' height='" << _imgheight
<< "' xmlns='http://www.w3.org/2000/svg'>";

file << "<defs>";
file << "<filter x='0' y='0' width='1' height='1' id='solid'>";
file << "<feFlood flood-color='white' flood-opacity='0.7'/>";
file << "<feComposite in='SourceGraphic'/>";
file << "</filter>";
file << "</defs>";

if (slopeData.size() > 0)
{
file << "<path d='";
for (std::vector<double>::iterator it = slopeData.begin();
it != slopeData.end();
it+=4)
{
file << "M " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
file << "L " << (*(it+2) * _imgwidth) << " " << (_imgheight - *(it+3) * _imgheight) << " ";
}
file << "' id='slope' stroke='grey' stroke-width='1' stroke-linecap='butt' fill='none' />";
}

if (territoryData.size() > 0)
{
for (std::vector<std::vector<double> >::iterator it_path = territoryData.begin();
it_path != territoryData.end();
it_path++)
{
if (it_path->size() > 0)
{
file << "<path d='";
bool first = true;
for (std::vector<double>::iterator it = it_path->begin();
it != it_path->end();
it+=2)
{
if (first)
{
file << "M " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
first = false;
}
else
{
file << "L " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
}
}
file << "' id='territory" << (it_path - territoryData.begin()) << "' "
<< "stroke='" << (gen::config::enableSvgColors ? "red" : "black") << "'"
<< " stroke-width='2' stroke-linecap='round' stroke-dasharray='3,4' fill='none' />";
}
}
}

if (riverData.size() > 0)
{
for (std::vector<std::vector<double> >::iterator it_path = riverData.begin();
it_path != riverData.end();
it_path++)
{
if (it_path->size() > 0)
{
file << "<path d='";
bool first = true;
for (std::vector<double>::iterator it = it_path->begin();
it != it_path->end();
it+=2)
{
if (first)
{
file << "M " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
first = false;
}
else
{
file << "L " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
}
}
file << "' id='river" << (it_path - riverData.begin()) << "' "
<< "stroke='" << (gen::config::enableSvgColors ? "blue" : "black") << "'"
<< " stroke-width='2' stroke-linecap='round' fill='none' />";
}
}
}

if (contourData.size() > 0)
{
for (std::vector<std::vector<double> >::iterator it_path = contourData.begin();
it_path != contourData.end();
it_path++)
{
if (it_path->size() > 0)
{
file << "<path d='";
bool first = true;
for (std::vector<double>::iterator it = it_path->begin();
it != it_path->end();
it+=2)
{
if (first)
{
file << "M " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
first = false;
}
else
{
file << "L " << (*it * _imgwidth) << " " << (_imgheight - *(it+1) * _imgheight) << " ";
}
}
file << "' id='territory" << (it_path - contourData.begin()) << "' "
<< "stroke='black' stroke-width='3' stroke-linecap='round' fill='none' />";
}
}
}

for (std::vector<double>::iterator it = cityData.begin();
it != cityData.end();
it+=2)
{
file << "<circle id='city" << (it - cityData.begin())/2
<< "' cx='" << (*it * _imgwidth) << "' cy='" << (_imgheight - *(it+1) * _imgheight)
<< "' r='" << _cityMarkerRadius << "' stroke='black' stroke-width='5' fill='white' />";
}

for (std::vector<double>::iterator it = townData.begin();
it != townData.end();
it+=2)
{
file << "<circle id='town" << (it - townData.begin())/2
<< "' cx='" << (*it * _imgwidth) << "' cy='" << (_imgheight - *(it+1) * _imgheight)
<< "' r='" << _townMarkerRadius << "' stroke='black' stroke-width='1' fill='black' />";
}

for (std::vector<Label>::iterator it = labelData.begin();
it != labelData.end();
it++)
{
file << "<text filter='url(#solid)' id='label" << (it - labelData.begin())
<< "' x='" << (it->position.x * _imgwidth) << "' y='" << ((1 - it->position.y) * _imgheight)
<< "' font-family='" << it->fontface << "' font-size='" << it->fontsize << "' fill='black'>";
file << it->text;
file << "</text>";
}
file << "</svg>";
file.close();
}

Extents2d gen::MapGenerator::getExtents() {
return _extents;
}
Expand Down Expand Up @@ -1948,6 +2146,23 @@ void gen::MapGenerator::_getLabelDrawData(std::vector<jsoncons::json> &data) {
}
}

void gen::MapGenerator::_getLabelSvgData(std::vector<Label> &data) {
std::vector<Label> labels;
_initializeLabels(labels);
if (labels.size() == 0) {
return;
}

_generateLabelPlacements(labels);

std::vector<jsoncons::json> jsondata;
for (unsigned int i = 0; i < labels.size(); i++) {
LabelCandidate label = labels[i].candidates[labels[i].candidateIdx];
label.baseScore = labels[i].score;
data.push_back(_getLabelSvg(label));
}
}

void gen::MapGenerator::_initializeLabels(std::vector<Label> &labels) {
std::vector<Label> markerLabels;
std::vector<Label> areaLabels;
Expand Down Expand Up @@ -2213,6 +2428,19 @@ jsoncons::json gen::MapGenerator::_getLabelJSON(LabelCandidate &label) {
return json;
}

gen::MapGenerator::Label gen::MapGenerator::_getLabelSvg(LabelCandidate &label)
{
dcel::Point npos = _normalizeMapCoordinate(label.position);

Label result;
result.text = label.text;
result.fontface = label.fontface;
result.fontsize = label.fontsize;
result.position = npos;

return result;
}

dcel::Point gen::MapGenerator::_normalizeMapCoordinate(double x, double y) {
return dcel::Point((x - _extents.minx) / (_extents.maxx - _extents.minx),
(y - _extents.miny) / (_extents.maxy - _extents.miny));
Expand Down Expand Up @@ -2788,4 +3016,4 @@ bool gen::MapGenerator::_isLabelOverlapping(LabelCandidate &label1,
bool gen::MapGenerator::_isExtentsOverlapping(Extents2d &e1, Extents2d &e2) {
return e1.minx < e2.maxx && e1.maxx > e2.minx &&
e1.miny < e2.maxy && e1.maxy > e2.miny;
}
}
Loading