fixed projection problems in export

added cell -> geojson export
added a QGIS example style
This commit is contained in:
Tom Vogt 2019-09-01 20:26:33 +02:00
parent 2df9f02440
commit a0df54bb21
8 changed files with 623 additions and 151 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

361
QGIS/Style_Biomes.qml Normal file
View file

@ -0,0 +1,361 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis styleCategories="Symbology" version="3.8.2-Zanzibar">
<renderer-v2 enableorderby="0" forceraster="0" attr="biome" symbollevels="0" type="categorizedSymbol">
<categories>
<category label="Marine" value="0" symbol="0" render="true"/>
<category label="Hot Desert" value="1" symbol="1" render="true"/>
<category label="Tundra" value="10" symbol="2" render="true"/>
<category label="Glacier" value="11" symbol="3" render="true"/>
<category label="Wetland" value="12" symbol="4" render="true"/>
<category label="Cold Desert" value="2" symbol="5" render="true"/>
<category label="Savanna" value="3" symbol="6" render="true"/>
<category label="Grassland" value="4" symbol="7" render="true"/>
<category label="Tropical Seasonal Forest" value="5" symbol="8" render="true"/>
<category label="Temperate Deciduous Forest" value="6" symbol="9" render="true"/>
<category label="Tropical Rainforest" value="7" symbol="10" render="true"/>
<category label="Temperate Rainforest" value="8" symbol="11" render="true"/>
<category label="Taiga" value="9" symbol="12" render="true"/>
<category label="" value="" symbol="13" render="true"/>
</categories>
<symbols>
<symbol name="0" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="31,120,180,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="31,120,180,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="1" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="254,239,124,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="254,239,124,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="10" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="44,156,102,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="44,156,102,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="11" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="81,155,119,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="81,155,119,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="12" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="203,227,81,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="203,227,81,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="13" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="58,205,107,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="35,35,35,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="2" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="210,220,60,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="210,220,60,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="3" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="247,252,255,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="247,252,255,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="4" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="135,143,97,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="135,143,97,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="5" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="244,228,104,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="244,228,104,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="6" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="253,191,111,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="253,191,111,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.36"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="7" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="178,223,138,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="178,223,138,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="8" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="31,114,13,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="31,114,13,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
<symbol name="9" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="51,160,44,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="51,160,44,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</symbols>
<source-symbol>
<symbol name="0" alpha="1" clip_to_extent="1" force_rhr="0" type="fill">
<layer locked="0" pass="0" enabled="1" class="SimpleFill">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="229,182,54,255"/>
<prop k="joinstyle" v="bevel"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="35,35,35,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0.26"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option value="" name="name" type="QString"/>
<Option name="properties"/>
<Option value="collection" name="type" type="QString"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</source-symbol>
<colorramp name="[source]" type="randomcolors"/>
<rotation/>
<sizescale/>
</renderer-v2>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerGeometryType>2</layerGeometryType>
</qgis>

32
README-GIS.md Normal file
View file

@ -0,0 +1,32 @@
# GIS Support
There is simple GIS support in this release, allowing the export to tools like Quantum GIS (https://qgis.org).
## Burg Data
This version exports position information (longitude, latitude and height) for burgs. These can be imported into QGIS by choosing Layer -> Add Layer... -> Add Delimited Text Layer...
Choose the exported .csv file. It should all be set up correctly automatically, so just check that x and y are correctly set to the longitude and latitude fields.
## Cell Data
In the Save... menu is a new option ".json" to save the cell data into a GeoJSON file. These can be imported into QGIS by choosing Layer -> Add Layer... -> Add Vector Layer...
Choose the saved .geojson file. It should be set up correctly as well, but doesn't show much. For the biomes, a prepared style can be found in the QGIS subdirectory here. Load it for the new layer you just created and the biomes should show up.
There is additional cell information such as population, height (for a heightmap), but also states, provinces, culture, etc. exported, all of which can be used in QGIS to render this information
## Rivers, Roads, Borders etc.
Not yet supported, planned.
## Questions, etc.
Make a pull request:
https://github.com/tvogt/Fantasy-Map-Generator

View file

@ -1819,6 +1819,7 @@
<div id="saveMap" data-tip="Save as fully functional map in .map format. Shortcut: Ctrl + M">.map</div> <div id="saveMap" data-tip="Save as fully functional map in .map format. Shortcut: Ctrl + M">.map</div>
<div id="saveSVG" data-tip="Download the map as .svg image (open in browser or Inkscape). Shortcut: Ctrl + S">.svg</div> <div id="saveSVG" data-tip="Download the map as .svg image (open in browser or Inkscape). Shortcut: Ctrl + S">.svg</div>
<div id="savePNG" data-tip="Download visible part of the map as image. Texture will not be shown. Shortcut: Ctrl + P">.png</div> <div id="savePNG" data-tip="Download visible part of the map as image. Texture will not be shown. Shortcut: Ctrl + P">.png</div>
<div id="saveGeo" data-tip="Download cell data as GeoJSON (for use in GIS tools such as QGIS).">.json</div>
</div> </div>
<button id="loadMap" data-tip="Load fully functional map in a .map format. Shortcut: Ctrl + L">Load</button> <button id="loadMap" data-tip="Load fully functional map in a .map format. Shortcut: Ctrl + L">Load</button>
<button id="zoomReset" data-tip="Reset map zoom. Shortcut: 0">Reset Zoom</button> <button id="zoomReset" data-tip="Reset map zoom. Shortcut: 0">Reset Zoom</button>

View file

@ -1,6 +1,83 @@
// Functions to save and load the map // Functions to save and load the map
"use strict"; "use strict";
// download map data as GeoJSON
function saveGeoJSON() {
let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n";
const cells = pack.cells;
const v = pack.vertices;
/*
my guesses on the cells structure:
cells.h = height
cells.p = coordinates of center point (of the voronoi cell)
cells.pop = population
// from voronoi.js:
const cells = {v: [], c: [], b: []}; // voronoi cells: v = cell vertices, c = adjacent cells, b = near-border cell
const vertices = {p: [], v: [], c: []}; // cells vertices: p = vertex coordinates, v = neighboring vertices, c = adjacent cells
*/
cells.i.forEach(i => {
data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [[";
cells.v[i].forEach(n => {
let x = mapCoordinates.lonW + (v.p[n][0] / graphWidth) * mapCoordinates.lonT;
let y = mapCoordinates.latN - (v.p[n][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise
data += "["+x+","+y+"],";
});
// close the ring
let x = mapCoordinates.lonW + (v.p[cells.v[i][0]][0] / graphWidth) * mapCoordinates.lonT;
let y = mapCoordinates.latN - (v.p[cells.v[i][0]][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise
data += "["+x+","+y+"]";
data += "]] },\n \"properties\": {\n";
let height = parseInt(getFriendlyHeight(cells.h[i]));
data += " \"id\": \""+i+"\",\n";
data += " \"height\": \""+height+"\",\n";
data += " \"biome\": \""+cells.biome[i]+"\",\n";
data += " \"population\": \""+cells.pop[i]+"\",\n";
data += " \"state\": \""+cells.state[i]+"\",\n";
data += " \"province\": \""+cells.province[i]+"\",\n";
data += " \"culture\": \""+cells.culture[i]+"\",\n";
data += " \"religion\": \""+cells.religion[i]+"\"\n";
data +=" }\n},\n";
});
/*
cells.i.forEach(i => {
let x = (cells.p[i][0] / graphWidth) * mapCoordinates.lonT + mapCoordinates.lonW;
let y = mapCoordinates.latN - (cells.p[i][1] / graphHeight) * mapCoordinates.lonT; // inverted in QGIS otherwise
let height = parseInt(getFriendlyHeight(cells.h[i]));
data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Point\", \"coordinates\": ["+x+", "+y+", "+height+"] },\n \"properties\": {\n";
data += " \"id\": \""+i+"\",\n";
data += " \"biome\": \""+cells.biome[i]+"\",\n";
data += " \"height\": \""+cells.h[i]+"\"\n";
data +=" }\n},\n";
});
*/
data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma
data += "]}";
const dataBlob = new Blob([data], {type: "application/json"});
const url = window.URL.createObjectURL(dataBlob);
const link = document.createElement("a");
document.body.appendChild(link);
link.download = "fantasy_map_" + Date.now() + ".geojson";
link.href = url;
link.click();
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
}
// download map as SVG or PNG file // download map as SVG or PNG file
function saveAsImage(type) { function saveAsImage(type) {
console.time("saveAsImage"); console.time("saveAsImage");

View file

@ -265,8 +265,8 @@ function editBurgs() {
data += b.port ? "port," : ","; data += b.port ? "port," : ",";
// add geography data // add geography data
data += (b.x / graphWidth) * mapCoordinates.lonT + mapCoordinates.lonW + ","; data += mapCoordinates.lonW + (b.x / graphWidth) * mapCoordinates.lonT + ",";
data += (b.y / graphHeight) * mapCoordinates.latT + mapCoordinates.latS + ","; data += mapCoordinates.latN - (b.y / graphHeight) * mapCoordinates.latT + ","; // this is inverted in QGIS otherwise
data += parseInt(getFriendlyHeight(pack.cells.h[b.cell])) + "\n"; data += parseInt(getFriendlyHeight(pack.cells.h[b.cell])) + "\n";
}); });

View file

@ -996,7 +996,8 @@ document.getElementById("sticked").addEventListener("click", function(event) {
else if (id === "saveMap") saveMap(); else if (id === "saveMap") saveMap();
else if (id === "saveSVG") saveAsImage("svg"); else if (id === "saveSVG") saveAsImage("svg");
else if (id === "savePNG") saveAsImage("png"); else if (id === "savePNG") saveAsImage("png");
if (id === "saveMap" || id === "saveSVG" || id === "savePNG") toggleSavePane(); else if (id === "saveGeo") saveGeoJSON();
if (id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveGeo") toggleSavePane();
}); });
function regeneratePrompt() { function regeneratePrompt() {