mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
Enhance population counting accuracy and add comprehensive geoJSON exports
Population System Fixes: - Fix province, culture, and religion population calculations to exclude rural population from cells without burgs - Burgs now represent ALL population for their cells (both urban and rural components) - Eliminate double-counting where cell populations were incorrectly added to burg populations Export Enhancements: - Add complete geoJSON export for burgs with all settlement properties - Enhance routes geoJSON export to include type and feature metadata - Add missing length and width properties to rivers geoJSON export - Fix burg coordinate system to match CSV export format with xWorld/yWorld fields UI Improvements: - Add burgs export button to geoJSON export interface - Fix vite module loading issue by adding type="module" to notes-editor.js script tag Documentation: - Create comprehensive QGIS Style Conversion guide with route types, burg features, and relief rendering methods - Add WKT coordinate reference system definition for Fantasy Map Cartesian CRS - Include rule-based styling examples and data processing workflows
This commit is contained in:
parent
9e8bc6e689
commit
83573c8936
6 changed files with 695 additions and 13 deletions
622
QGIS Style Conversion from Fantasy Map.md
Normal file
622
QGIS Style Conversion from Fantasy Map.md
Normal file
|
|
@ -0,0 +1,622 @@
|
|||
# QGIS Style Conversion from Fantasy Map JSON
|
||||
|
||||
## Overview
|
||||
|
||||
This document converts the fantasy map styling JSON to QGIS-compatible styles. The original JSON contains SVG/CSS-style properties that need to be translated to QGIS symbology.
|
||||
|
||||
## Layer Style Conversions
|
||||
|
||||
### Water Bodies
|
||||
|
||||
#### Rivers (`#rivers`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Rivers -->
|
||||
<symbol alpha="1" type="line" name="rivers">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="0,137,202,255"/>
|
||||
<prop k="width" v="0.8"/>
|
||||
<prop k="capstyle" v="round"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Freshwater Lakes (`#freshwater`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Freshwater -->
|
||||
<symbol alpha="1" type="fill" name="freshwater">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="202,227,247,255"/>
|
||||
<prop k="outline_color" v="0,137,202,255"/>
|
||||
<prop k="outline_width" v="1.01"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Ocean Base (`#oceanBase`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Ocean -->
|
||||
<symbol alpha="1" type="fill" name="ocean">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="180,210,243,255"/>
|
||||
<prop k="outline_style" v="no"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
### Landmass and Terrain
|
||||
|
||||
#### Landmass (`#landmass`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Landmass -->
|
||||
<symbol alpha="1" type="fill" name="landmass">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="238,246,251,255"/>
|
||||
<prop k="outline_style" v="no"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Ice (`#ice`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Ice -->
|
||||
<symbol alpha="0.9" type="fill" name="ice">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="232,240,246,255"/>
|
||||
<prop k="outline_color" v="232,240,246,255"/>
|
||||
<prop k="outline_width" v="1"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
### Relief and Terrain
|
||||
|
||||
The Fantasy Map Generator uses SVG icons placed based on elevation to create relief effects. QGIS can replicate this using several approaches:
|
||||
|
||||
#### Method 1: Hillshade from Elevation Data
|
||||
|
||||
Create a Digital Elevation Model (DEM) from the cells GeoJSON data:
|
||||
|
||||
1. **Import cells GeoJSON** with elevation data in the `height` property
|
||||
2. **Convert to raster**: Vector → Conversion Tools → Rasterize
|
||||
- Use `height` field for raster values
|
||||
- Set appropriate resolution (e.g., 100m)
|
||||
3. **Generate hillshade**: Raster → Analysis → Hillshade
|
||||
- Z factor: 1.0
|
||||
- Azimuth: 315° (northwest)
|
||||
- Altitude: 45°
|
||||
|
||||
```xml
|
||||
<!-- Hillshade Layer Style -->
|
||||
<rasterrenderer opacity="0.6" type="hillshade">
|
||||
<rasterproperties>
|
||||
<mDrawingStyle>SingleBandGray</mDrawingStyle>
|
||||
<mColorShadingAlgorithm>0</mColorShadingAlgorithm>
|
||||
<mInvertColor>false</mInvertColor>
|
||||
<mGrayBand>1</mGrayBand>
|
||||
</rasterproperties>
|
||||
</rasterrenderer>
|
||||
```
|
||||
|
||||
#### Method 2: Icon-Based Relief (Fantasy Map Style)
|
||||
|
||||
Replicate the original icon-based relief using rule-based point symbols:
|
||||
|
||||
**Step 1**: Create point layer from cell centroids
|
||||
- Vector → Geometry Tools → Centroids
|
||||
- Filter: `"height" >= 50` (land areas only)
|
||||
|
||||
**Step 2**: Configure rule-based symbology
|
||||
|
||||
```xml
|
||||
<!-- Mountain Icons (height > 70) -->
|
||||
<symbol alpha="1" type="marker" name="mountains">
|
||||
<layer class="SvgMarker" enabled="1">
|
||||
<prop k="size" v="8"/>
|
||||
<prop k="name" v="mountain.svg"/>
|
||||
<prop k="color" v="139,69,19,255"/>
|
||||
<prop k="angle" v="0"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
|
||||
<!-- Hill Icons (height 50-70) -->
|
||||
<symbol alpha="1" type="marker" name="hills">
|
||||
<layer class="SvgMarker" enabled="1">
|
||||
<prop k="size" v="5"/>
|
||||
<prop k="name" v="hill.svg"/>
|
||||
<prop k="color" v="101,67,33,255"/>
|
||||
<prop k="angle" v="0"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
**Step 3**: Rule expressions
|
||||
- Mountains: `"height" > 70`
|
||||
- Hills: `"height" >= 50 AND "height" <= 70`
|
||||
|
||||
#### Method 3: Density-Controlled Relief Points
|
||||
|
||||
For scattered relief icons (matching FMG's Poisson distribution):
|
||||
|
||||
**Step 1**: Use Geometry Generator with point symbols
|
||||
- Symbol type: Point
|
||||
- Geometry type: Point
|
||||
- Expression for scattered points:
|
||||
|
||||
```sql
|
||||
-- Generate multiple points per cell based on elevation
|
||||
CASE
|
||||
WHEN "height" > 70 THEN
|
||||
-- Mountains: 2-4 points per cell
|
||||
array_to_string(
|
||||
array_foreach(
|
||||
generate_series(1, floor("height"/30)),
|
||||
point_on_surface(
|
||||
translate($geometry,
|
||||
rand(-50,50),
|
||||
rand(-50,50)
|
||||
)
|
||||
)
|
||||
), ','
|
||||
)
|
||||
WHEN "height" >= 50 THEN
|
||||
-- Hills: 1-2 points per cell
|
||||
point_on_surface($geometry)
|
||||
ELSE
|
||||
NULL
|
||||
END
|
||||
```
|
||||
|
||||
#### Method 4: Hybrid Approach (Recommended)
|
||||
|
||||
Combine multiple techniques for best results:
|
||||
|
||||
1. **Base layer**: Hillshade raster (opacity 30%)
|
||||
2. **Mid layer**: Graduated cell polygons by elevation
|
||||
3. **Top layer**: Scattered point symbols for major peaks
|
||||
|
||||
**Graduated Elevation Symbology**:
|
||||
```xml
|
||||
<!-- Low elevation -->
|
||||
<symbol alpha="0.3" type="fill" name="low">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="144,238,144,76"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
|
||||
<!-- High elevation -->
|
||||
<symbol alpha="0.5" type="fill" name="high">
|
||||
<layer class="SimpleFill" enabled="1">
|
||||
<prop k="color" v="139,69,19,127"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Relief Color Ramps
|
||||
|
||||
For elevation-based coloring:
|
||||
|
||||
**Height Classes**:
|
||||
- 0-20: Ocean (blue tones)
|
||||
- 20-40: Lowlands (green tones)
|
||||
- 40-60: Hills (yellow-brown tones)
|
||||
- 60-80: Mountains (brown tones)
|
||||
- 80+: High peaks (gray-white tones)
|
||||
|
||||
```xml
|
||||
<!-- Elevation Color Ramp -->
|
||||
<colorrampshader colorRampType="INTERPOLATED">
|
||||
<item alpha="255" value="0" color="#4A90E2" label="Ocean"/>
|
||||
<item alpha="255" value="20" color="#90EE90" label="Coast"/>
|
||||
<item alpha="255" value="40" color="#F4A460" label="Hills"/>
|
||||
<item alpha="255" value="60" color="#8B4513" label="Mountains"/>
|
||||
<item alpha="255" value="80" color="#696969" label="High Peaks"/>
|
||||
</colorrampshader>
|
||||
```
|
||||
|
||||
### Political Boundaries
|
||||
|
||||
#### State Borders (`#stateBorders`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for State Borders -->
|
||||
<symbol alpha="1" type="line" name="state_borders">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="0,0,0,255"/>
|
||||
<prop k="width" v="1.01"/>
|
||||
<prop k="capstyle" v="flat"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Province Borders (`#provinceBorders`)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Province Borders -->
|
||||
<symbol alpha="0.8" type="line" name="province_borders">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="0,0,0,255"/>
|
||||
<prop k="width" v="0.69"/>
|
||||
<prop k="capstyle" v="round"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
### Transportation
|
||||
|
||||
Routes can be styled based on their `type` property using QGIS rule-based styling. The available route types are:
|
||||
|
||||
- **royal**: Major roads connecting capitals and important cities
|
||||
- **market**: Trade routes connecting market towns
|
||||
- **local**: Secondary roads for regional connectivity
|
||||
- **footpath**: Walking trails and paths
|
||||
- **majorSea**: Major shipping routes between ports
|
||||
|
||||
#### Royal Roads (type = 'royal')
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Royal Roads -->
|
||||
<symbol alpha="1" type="line" name="royal_roads">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="255,44,44,255"/>
|
||||
<prop k="width" v="1.2"/>
|
||||
<prop k="capstyle" v="flat"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Market Roads (type = 'market')
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Market Roads -->
|
||||
<symbol alpha="1" type="line" name="market_roads">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="255,100,44,255"/>
|
||||
<prop k="width" v="0.9"/>
|
||||
<prop k="capstyle" v="flat"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Local Roads (type = 'local')
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Local Roads -->
|
||||
<symbol alpha="1" type="line" name="local_roads">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="200,100,50,255"/>
|
||||
<prop k="width" v="0.6"/>
|
||||
<prop k="capstyle" v="flat"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Footpaths (type = 'footpath')
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Footpaths -->
|
||||
<symbol alpha="1" type="line" name="footpaths">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="159,81,34,255"/>
|
||||
<prop k="width" v="0.43"/>
|
||||
<prop k="capstyle" v="flat"/>
|
||||
<prop k="customdash" v="2;1"/>
|
||||
<prop k="use_custom_dash" v="1"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Major Sea Routes (type = 'majorSea')
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Major Sea Routes -->
|
||||
<symbol alpha="1" type="line" name="major_searoutes">
|
||||
<layer class="SimpleLine" enabled="1">
|
||||
<prop k="color" v="0,137,202,255"/>
|
||||
<prop k="width" v="0.6"/>
|
||||
<prop k="capstyle" v="round"/>
|
||||
<prop k="customdash" v="1;2"/>
|
||||
<prop k="use_custom_dash" v="1"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Legacy Route Groups
|
||||
|
||||
For backward compatibility, routes can also be styled by `group` property:
|
||||
|
||||
- **roads**: All land-based routes (royal, market, local)
|
||||
- **trails**: Walking paths (footpath)
|
||||
- **searoutes**: All sea-based routes (majorSea)
|
||||
|
||||
### Settlements
|
||||
|
||||
Burgs can be styled based on their boolean properties using QGIS rule-based styling. The available burg feature types are:
|
||||
|
||||
- **capital**: State capitals (administrative centers)
|
||||
- **port**: Coastal settlements with harbors
|
||||
- **citadel**: Fortified settlements with citadels
|
||||
- **walls**: Settlements with defensive walls
|
||||
- **plaza**: Settlements with central plazas
|
||||
- **temple**: Settlements with religious temples
|
||||
- **shanty**: Settlements with shanty town districts
|
||||
|
||||
#### Capital Cities (capital = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Capital Cities -->
|
||||
<symbol alpha="1" type="marker" name="capitals">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="255,215,0,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.4"/>
|
||||
<prop k="size" v="5"/>
|
||||
<prop k="name" v="star"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Port Cities (port = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Port Cities -->
|
||||
<symbol alpha="1" type="marker" name="ports">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="0,137,202,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.3"/>
|
||||
<prop k="size" v="4"/>
|
||||
<prop k="name" v="diamond"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Fortified Cities (citadel = true OR walls = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Fortified Cities -->
|
||||
<symbol alpha="1" type="marker" name="fortified">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="139,69,19,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.3"/>
|
||||
<prop k="size" v="4"/>
|
||||
<prop k="name" v="square"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Religious Centers (temple = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Religious Centers -->
|
||||
<symbol alpha="1" type="marker" name="religious">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="128,0,128,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.3"/>
|
||||
<prop k="size" v="4"/>
|
||||
<prop k="name" v="cross"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Trading Centers (plaza = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Trading Centers -->
|
||||
<symbol alpha="1" type="marker" name="trading">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="255,165,0,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.3"/>
|
||||
<prop k="size" v="3.5"/>
|
||||
<prop k="name" v="pentagon"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Shanty Towns (shanty = true)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Shanty Towns -->
|
||||
<symbol alpha="0.8" type="marker" name="shanty">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="139,131,120,255"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.2"/>
|
||||
<prop k="size" v="2.5"/>
|
||||
<prop k="name" v="triangle"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Regular Settlements (default)
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Regular Settlements -->
|
||||
<symbol alpha="0.7" type="marker" name="settlements">
|
||||
<layer class="SimpleMarker" enabled="1">
|
||||
<prop k="color" v="0,0,0,179"/>
|
||||
<prop k="outline_color" v="0,0,0,255"/>
|
||||
<prop k="outline_width" v="0.24"/>
|
||||
<prop k="size" v="3"/>
|
||||
<prop k="name" v="circle"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
```
|
||||
|
||||
#### Settlement Labels
|
||||
|
||||
```xml
|
||||
<!-- QML Style for Settlement Labels -->
|
||||
<text-style fontFamily="Arial" fontSize="5" fontSizeUnit="Point">
|
||||
<text-color alpha="255" r="0" g="0" b="0"/>
|
||||
<text-buffer bufferDraw="1" bufferSize="1" bufferSizeUnits="Point">
|
||||
<buffer-color alpha="255" r="255" g="255" b="255"/>
|
||||
</text-buffer>
|
||||
</text-style>
|
||||
```
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### 1. Create Layer Structure
|
||||
|
||||
```
|
||||
Project Root/
|
||||
├── Water Bodies/
|
||||
│ ├── Rivers
|
||||
│ ├── Lakes
|
||||
│ └── Ocean
|
||||
├── Landmass/
|
||||
│ ├── Base Land
|
||||
│ └── Ice
|
||||
├── Relief & Terrain/
|
||||
│ ├── Elevation DEM (raster)
|
||||
│ ├── Hillshade (raster)
|
||||
│ ├── Relief Icons (points)
|
||||
│ └── Elevation Polygons
|
||||
├── Political/
|
||||
│ ├── State Borders
|
||||
│ └── Province Borders
|
||||
├── Transportation/
|
||||
│ ├── Routes (by type)
|
||||
│ └── Routes (by group)
|
||||
└── Settlements/
|
||||
├── Burgs (by feature type)
|
||||
└── Settlement Labels
|
||||
```
|
||||
|
||||
### 2. Apply Styles in QGIS
|
||||
|
||||
1. **Load your vector layers** into QGIS
|
||||
2. **Right-click layer** → Properties → Symbology
|
||||
3. **Copy the XML** from above into a text editor
|
||||
4. **Save as .qml file** (e.g., `rivers.qml`)
|
||||
5. **Load style** in layer properties → Style → Load Style
|
||||
|
||||
### 3. Color Reference Table
|
||||
|
||||
|Original Color|RGB Values|QGIS Color Code|
|
||||
|---|---|---|
|
||||
|`#000000`|0,0,0|`0,0,0,255`|
|
||||
|`#0089ca`|0,137,202|`0,137,202,255`|
|
||||
|`#cae3f7`|202,227,247|`202,227,247,255`|
|
||||
|`#eef6fb`|238,246,251|`238,246,251,255`|
|
||||
|`#ff2c2c`|255,44,44|`255,44,44,255`|
|
||||
|`#9f5122`|159,81,34|`159,81,34,255`|
|
||||
|`#b4d2f3`|180,210,243|`180,210,243,255`|
|
||||
|
||||
### 4. Layer Ordering (Bottom to Top)
|
||||
|
||||
1. Ocean Base
|
||||
2. Landmass
|
||||
3. Elevation DEM (raster)
|
||||
4. Hillshade (30% opacity)
|
||||
5. Elevation Polygons (graduated colors)
|
||||
6. Freshwater Bodies
|
||||
7. Ice
|
||||
8. Province Borders
|
||||
9. State Borders
|
||||
10. Transportation Routes (by type or group)
|
||||
11. Relief Icons (mountains/hills)
|
||||
12. Settlement Icons (by feature type)
|
||||
13. Settlement Labels
|
||||
|
||||
## Notes
|
||||
|
||||
- **Opacity values** from the JSON (like 0.8, 0.9) translate to QGIS alpha values
|
||||
- **Stroke-dasharray** properties become custom dash patterns in QGIS
|
||||
- **Filter effects** like blur and drop shadows need to be recreated using QGIS effects
|
||||
- **Font families** may need substitution if not available in your system
|
||||
- **Coordinate system** should be set to the Fantasy Map Cartesian CRS (WKT format below)
|
||||
|
||||
## Coordinate Reference System (CRS)
|
||||
|
||||
The Fantasy Map Generator uses a custom Cartesian coordinate system. Use this WKT definition in QGIS:
|
||||
|
||||
```
|
||||
ENGCRS["Fantasy Map Cartesian (meters)",
|
||||
EDATUM["Fantasy Map Datum"],
|
||||
CS[Cartesian,2],
|
||||
AXIS["easting (X)",east,
|
||||
ORDER[1],
|
||||
LENGTHUNIT["metre",1]],
|
||||
AXIS["northing (Y)",north,
|
||||
ORDER[2],
|
||||
LENGTHUNIT["metre",1]]]
|
||||
```
|
||||
|
||||
### Setting up the CRS in QGIS:
|
||||
1. Go to **Settings** → **Custom Projections**
|
||||
2. Click **+** to add a new CRS
|
||||
3. Set **Name**: `Fantasy Map Cartesian`
|
||||
4. Set **Format**: `WKT (Recommended)`
|
||||
5. Paste the WKT definition above
|
||||
6. Click **OK** and **Apply**
|
||||
|
||||
## Data Requirements for Relief
|
||||
|
||||
### Essential GeoJSON Exports
|
||||
|
||||
To implement relief rendering, you need these exports from Fantasy Map Generator:
|
||||
|
||||
1. **Cells GeoJSON** (`cells.geojson`)
|
||||
- Contains elevation data in `height` property
|
||||
- Provides cell polygons for DEM generation
|
||||
- Includes biome information for terrain variation
|
||||
|
||||
2. **Burgs GeoJSON** (`burgs.geojson`)
|
||||
- Settlement locations for reference
|
||||
- Population data for symbol sizing
|
||||
|
||||
### Processing Workflow
|
||||
|
||||
1. **Import cells.geojson** into QGIS
|
||||
2. **Create DEM raster**: Vector → Conversion Tools → Rasterize
|
||||
- Field: `height`
|
||||
- Resolution: 50-200m (depending on map detail)
|
||||
- Output extent: Use layer extent
|
||||
3. **Generate hillshade**: Raster → Analysis → Hillshade
|
||||
4. **Create relief points**: Vector → Geometry Tools → Centroids
|
||||
5. **Apply symbology** using the styles below
|
||||
|
||||
## Rule-Based Styling
|
||||
|
||||
### Route Styling by Type
|
||||
To style routes by their `type` property:
|
||||
1. Right-click route layer → Properties → Symbology
|
||||
2. Change from "Single Symbol" to "Rule-based"
|
||||
3. Add rules with expressions like: `"type" = 'royal'`
|
||||
4. Apply the corresponding symbol for each type
|
||||
|
||||
### Burg Styling by Features
|
||||
To style burgs by their feature properties:
|
||||
1. Right-click burg layer → Properties → Symbology
|
||||
2. Change to "Rule-based" styling
|
||||
3. Create rules with expressions like:
|
||||
- `"capital" = 1` for capitals
|
||||
- `"port" = 1` for ports
|
||||
- `"citadel" = 1 OR "walls" = 1` for fortified cities
|
||||
4. Set priority order (capitals first, then ports, etc.)
|
||||
|
||||
### Graduated Symbols by Population
|
||||
To size burg symbols by population:
|
||||
1. Right-click burg layer → Properties → Symbology
|
||||
2. Change to "Graduated"
|
||||
3. Set **Value**: `population`
|
||||
4. Choose appropriate **Method** and **Classes**
|
||||
5. Adjust symbol sizes in the range
|
||||
|
||||
## Advanced Features
|
||||
|
||||
For complex effects like the texture overlay (`#texture`) and fogging (`#fogging`), consider:
|
||||
|
||||
- Using **Raster layers** with blend modes
|
||||
- **Layer effects** in symbology
|
||||
- **Custom SVG symbols** for complex markers
|
||||
- **Expression-based styling** for dynamic effects
|
||||
|
|
@ -6051,6 +6051,7 @@
|
|||
<button onclick="saveGeoJsonRoutes()" data-tip="Download routes data in GeoJSON format">routes</button>
|
||||
<button onclick="saveGeoJsonRivers()" data-tip="Download rivers data in GeoJSON format">rivers</button>
|
||||
<button onclick="saveGeoJsonMarkers()" data-tip="Download markers data in GeoJSON format">markers</button>
|
||||
<button onclick="saveGeoJsonBurgs()" data-tip="Download burgs data in GeoJSON format">burgs</button>
|
||||
</div>
|
||||
<p>
|
||||
GeoJSON format is used in GIS tools such as QGIS. Check out
|
||||
|
|
|
|||
|
|
@ -113,10 +113,8 @@ function culturesCollectStatistics() {
|
|||
if (burgId) {
|
||||
// Burg represents ALL population for this cell (stored in thousands)
|
||||
cultures[cultureId].urban += burgs[burgId].population;
|
||||
} else {
|
||||
// Only count cells.pop for unsettled areas (no burg present)
|
||||
cultures[cultureId].rural += cells.pop[i];
|
||||
}
|
||||
// No population in cells without burgs - all population is in burgs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,10 +123,8 @@ function religionsCollectStatistics() {
|
|||
if (burgId) {
|
||||
// Burg represents ALL population for this cell (stored in thousands)
|
||||
religions[religionId].urban += burgs[burgId].population;
|
||||
} else {
|
||||
// Only count cells.pop for unsettled areas (no burg present)
|
||||
religions[religionId].rural += cells.pop[i];
|
||||
}
|
||||
// No population in cells without burgs - all population is in burgs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -652,12 +652,12 @@ function saveGeoJsonCells() {
|
|||
|
||||
function saveGeoJsonRoutes() {
|
||||
const metersPerPixel = getMetersPerPixel();
|
||||
const features = pack.routes.map(({i, points, group, name = null}) => {
|
||||
const features = pack.routes.map(({i, points, group, name = null, type, feature}) => {
|
||||
const coordinates = points.map(([x, y]) => getFantasyCoordinates(x, y, 2));
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {type: "LineString", coordinates},
|
||||
properties: {id: i, group, name}
|
||||
properties: {id: i, group, name, type, feature}
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -682,14 +682,14 @@ function saveGeoJsonRoutes() {
|
|||
function saveGeoJsonRivers() {
|
||||
const metersPerPixel = getMetersPerPixel();
|
||||
const features = pack.rivers.map(
|
||||
({i, cells, points, source, mouth, parent, basin, widthFactor, sourceWidth, discharge, name, type}) => {
|
||||
({i, cells, points, source, mouth, parent, basin, widthFactor, sourceWidth, discharge, length, width, name, type}) => {
|
||||
if (!cells || cells.length < 2) return;
|
||||
const meanderedPoints = Rivers.addMeandering(cells, points);
|
||||
const coordinates = meanderedPoints.map(([x, y]) => getFantasyCoordinates(x, y, 2));
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {type: "LineString", coordinates},
|
||||
properties: {id: i, source, mouth, parent, basin, widthFactor, sourceWidth, discharge, name, type}
|
||||
properties: {id: i, source, mouth, parent, basin, widthFactor, sourceWidth, discharge, length, width, name, type}
|
||||
};
|
||||
}
|
||||
).filter(f => f); // Remove undefined entries
|
||||
|
|
@ -750,3 +750,68 @@ function saveGeoJsonMarkers() {
|
|||
const fileName = getFileName("Markers") + ".geojson";
|
||||
downloadFile(JSON.stringify(json), fileName, "application/json");
|
||||
}
|
||||
|
||||
function saveGeoJsonBurgs() {
|
||||
const metersPerPixel = getMetersPerPixel();
|
||||
const valid = pack.burgs.filter(b => b.i && !b.removed);
|
||||
|
||||
const features = valid.map(b => {
|
||||
const coordinates = getFantasyCoordinates(b.x, b.y, 2);
|
||||
const province = pack.cells.province[b.cell];
|
||||
const temperature = grid.cells.temp[pack.cells.g[b.cell]];
|
||||
|
||||
// Calculate world coordinates same as CSV export
|
||||
const xWorld = b.x * metersPerPixel;
|
||||
const yWorld = -b.y * metersPerPixel;
|
||||
|
||||
return {
|
||||
type: "Feature",
|
||||
geometry: {type: "Point", coordinates},
|
||||
properties: {
|
||||
id: b.i,
|
||||
name: b.name,
|
||||
province: province ? pack.provinces[province].name : null,
|
||||
provinceFull: province ? pack.provinces[province].fullName : null,
|
||||
state: pack.states[b.state].name,
|
||||
stateFull: pack.states[b.state].fullName,
|
||||
culture: pack.cultures[b.culture].name,
|
||||
religion: pack.religions[pack.cells.religion[b.cell]].name,
|
||||
population: rn(b.population * populationRate * urbanization),
|
||||
populationRaw: b.population,
|
||||
xWorld: rn(xWorld, 2),
|
||||
yWorld: rn(yWorld, 2),
|
||||
xPixel: b.x,
|
||||
yPixel: b.y,
|
||||
elevation: parseInt(getHeight(pack.cells.h[b.cell])),
|
||||
temperature: convertTemperature(temperature),
|
||||
temperatureLikeness: getTemperatureLikeness(temperature),
|
||||
capital: !!b.capital,
|
||||
port: !!b.port,
|
||||
citadel: !!b.citadel,
|
||||
walls: !!b.walls,
|
||||
plaza: !!b.plaza,
|
||||
temple: !!b.temple,
|
||||
shanty: !!b.shanty,
|
||||
emblem: b.coa || null,
|
||||
cell: b.cell
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const json = {
|
||||
type: "FeatureCollection",
|
||||
features,
|
||||
metadata: {
|
||||
crs: "Fantasy Map Cartesian (meters)",
|
||||
mapName: mapName.value,
|
||||
scale: {
|
||||
distance: distanceScale,
|
||||
unit: distanceUnitInput.value,
|
||||
meters_per_pixel: metersPerPixel
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const fileName = getFileName("Burgs") + ".geojson";
|
||||
downloadFile(JSON.stringify(json), fileName, "application/json");
|
||||
}
|
||||
|
|
@ -91,10 +91,8 @@ function editProvinces() {
|
|||
// Burg represents ALL population for this cell (stored in thousands)
|
||||
provinces[p].urban += burgs[cells.burg[i]].population;
|
||||
provinces[p].burgs.push(cells.burg[i]);
|
||||
} else {
|
||||
// Only count cells.pop for unsettled areas (no burg present)
|
||||
provinces[p].rural += cells.pop[i];
|
||||
}
|
||||
// No population in cells without burgs - all population is in burgs
|
||||
}
|
||||
|
||||
provinces.forEach(p => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue