mapwright 0.20.0__tar.gz → 0.21.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. {mapwright-0.20.0 → mapwright-0.21.0}/CHANGELOG.md +22 -0
  2. {mapwright-0.20.0 → mapwright-0.21.0}/PKG-INFO +8 -5
  3. {mapwright-0.20.0 → mapwright-0.21.0}/README.md +7 -4
  4. mapwright-0.21.0/docs/gallery/grid-city.png +0 -0
  5. mapwright-0.21.0/docs/gallery/grid-city.svg +1 -0
  6. {mapwright-0.20.0 → mapwright-0.21.0}/examples/gallery.py +1 -0
  7. {mapwright-0.20.0 → mapwright-0.21.0}/pyproject.toml +1 -1
  8. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/__init__.py +1 -1
  9. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/_geometry.py +43 -0
  10. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/settlement.py +204 -28
  11. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_geometry.py +21 -0
  12. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_settlement.py +92 -1
  13. {mapwright-0.20.0 → mapwright-0.21.0}/.github/workflows/ci.yml +0 -0
  14. {mapwright-0.20.0 → mapwright-0.21.0}/.github/workflows/publish.yml +0 -0
  15. {mapwright-0.20.0 → mapwright-0.21.0}/.gitignore +0 -0
  16. {mapwright-0.20.0 → mapwright-0.21.0}/LICENSE +0 -0
  17. {mapwright-0.20.0 → mapwright-0.21.0}/NOTICE +0 -0
  18. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/age-old.png +0 -0
  19. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/age-old.svg +0 -0
  20. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/age-young.png +0 -0
  21. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/age-young.svg +0 -0
  22. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/archipelago.png +0 -0
  23. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/archipelago.svg +0 -0
  24. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/arctic.png +0 -0
  25. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/arctic.svg +0 -0
  26. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas.png +0 -0
  27. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/README.md +0 -0
  28. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/city_castle_1.png +0 -0
  29. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/city_large_1.png +0 -0
  30. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/city_town_1.png +0 -0
  31. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/city_village_1.png +0 -0
  32. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/decoration_compass_1.png +0 -0
  33. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/decoration_creature_1.png +0 -0
  34. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/decoration_ship_1.png +0 -0
  35. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/dune_1.png +0 -0
  36. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/hill_1.png +0 -0
  37. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/hill_2.png +0 -0
  38. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/manifest.json +0 -0
  39. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/mountain_mid_1.png +0 -0
  40. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/mountain_old_1.png +0 -0
  41. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/mountain_old_2.png +0 -0
  42. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/mountain_young_1.png +0 -0
  43. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/mountain_young_2.png +0 -0
  44. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/tree_cactus_1.png +0 -0
  45. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/tree_deciduous_1.png +0 -0
  46. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/tree_deciduous_2.png +0 -0
  47. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/tree_pine_1.png +0 -0
  48. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/atlas_pack/tree_pine_2.png +0 -0
  49. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/citadel.png +0 -0
  50. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/citadel.svg +0 -0
  51. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/continent.png +0 -0
  52. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/continent.svg +0 -0
  53. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/desert.png +0 -0
  54. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/desert.svg +0 -0
  55. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/dungeon.png +0 -0
  56. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/dungeon.svg +0 -0
  57. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/highlands.png +0 -0
  58. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/highlands.svg +0 -0
  59. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/hint.png +0 -0
  60. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/hint.svg +0 -0
  61. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/islands.png +0 -0
  62. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/islands.svg +0 -0
  63. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/metropolis.png +0 -0
  64. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/metropolis.svg +0 -0
  65. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/pangaea.png +0 -0
  66. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/pangaea.svg +0 -0
  67. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/port.png +0 -0
  68. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/port.svg +0 -0
  69. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/regions.png +0 -0
  70. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/regions.svg +0 -0
  71. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/roads.png +0 -0
  72. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/roads.svg +0 -0
  73. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/shantytown.png +0 -0
  74. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/shantytown.svg +0 -0
  75. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/template-atoll.png +0 -0
  76. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/template-atoll.svg +0 -0
  77. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/template-isthmus.png +0 -0
  78. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/template-isthmus.svg +0 -0
  79. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-blueprint.png +0 -0
  80. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-blueprint.svg +0 -0
  81. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-citadel-neon.png +0 -0
  82. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-citadel-neon.svg +0 -0
  83. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-dune.png +0 -0
  84. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-dune.svg +0 -0
  85. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-dungeon-blueprint.png +0 -0
  86. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-dungeon-blueprint.svg +0 -0
  87. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-neon.png +0 -0
  88. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-neon.svg +0 -0
  89. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-parchment.png +0 -0
  90. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/theme-parchment.svg +0 -0
  91. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/town.png +0 -0
  92. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/town.svg +0 -0
  93. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/tropical.png +0 -0
  94. {mapwright-0.20.0 → mapwright-0.21.0}/docs/gallery/tropical.svg +0 -0
  95. {mapwright-0.20.0 → mapwright-0.21.0}/examples/benchmark.py +0 -0
  96. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/_graph.py +0 -0
  97. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/_serde.py +0 -0
  98. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/affordances.py +0 -0
  99. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/atlas_renderer.py +0 -0
  100. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/config.py +0 -0
  101. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/dungeon.py +0 -0
  102. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/dungeon_renderer.py +0 -0
  103. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/names.py +0 -0
  104. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/regions.py +0 -0
  105. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/rng.py +0 -0
  106. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/roads.py +0 -0
  107. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/settlement_renderer.py +0 -0
  108. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/svg_renderer.py +0 -0
  109. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/terrain.py +0 -0
  110. {mapwright-0.20.0 → mapwright-0.21.0}/src/mapwright/themes.py +0 -0
  111. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_affordances.py +0 -0
  112. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_api_contract.py +0 -0
  113. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_atlas_renderer.py +0 -0
  114. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_config.py +0 -0
  115. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_dungeon.py +0 -0
  116. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_dungeon_renderer.py +0 -0
  117. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_graph.py +0 -0
  118. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_names.py +0 -0
  119. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_properties.py +0 -0
  120. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_regions.py +0 -0
  121. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_rng.py +0 -0
  122. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_roads.py +0 -0
  123. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_serialize.py +0 -0
  124. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_svg_renderer.py +0 -0
  125. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_terrain.py +0 -0
  126. {mapwright-0.20.0 → mapwright-0.21.0}/tests/test_themes.py +0 -0
@@ -8,6 +8,28 @@ All notable changes to mapwright are documented here. The format follows
8
8
  `tests/test_api_contract.py`). While the version is `0.x`, minor versions may
9
9
  make breaking changes; these will always be noted here.
10
10
 
11
+ ## [0.21.0] — 2026-06-02
12
+
13
+ ### Added
14
+ - **Grid streets — the organic ↔ planned layout descriptor.** A new
15
+ `SettlementConfig.layout` field (`"organic"` default, or `"grid"`) chooses the
16
+ street pattern. In `"grid"` mode the town gets a geometric street grid aligned
17
+ to its long axis (PCA over the footprint): two families of parallel
18
+ thoroughfares clipped to the footprint, the central line of each marked
19
+ `"main"`, with gates where the mains pierce the perimeter (plus a harbour gate
20
+ when coastal). Building lots are also bisected along the grid axes, so blocks
21
+ come out rectangular and street-aligned. Walls splice grid gates (which land
22
+ mid-edge) into the wall ring as real gatehouse gaps. This is the *Layout &
23
+ Geometry* descriptor from the imaginative-realms taxonomy ("Hyper-Grid Rigid"),
24
+ generalising the `era`/`wealth` shanty↔skyscraper axis.
25
+ - New preset **`grid_city`**; gallery `grid-city` showcase.
26
+ - The default (`layout="organic"`) output is **byte-identical** to before — all
27
+ grid logic is gated behind the new mode.
28
+ - `layout` serialises via `to_dict`/`json_schema` (new enum-field support in
29
+ `SettlementConfig`, via an `_ENUM_SPEC`).
30
+ - New reusable geometry primitive `clip_line_to_convex` (Liang–Barsky line ↔
31
+ convex-polygon clipping) in the internal `_geometry` module.
32
+
11
33
  ## [0.20.0] — 2026-06-02
12
34
 
13
35
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapwright
3
- Version: 0.20.0
3
+ Version: 0.21.0
4
4
  Summary: Domain-neutral procedural fantasy map & world generation: Voronoi terrain, hydraulic erosion, biomes, rivers, Markov place-names, and shaded-relief SVG.
5
5
  Project-URL: Homepage, https://github.com/sligara7/mapwright
6
6
  Project-URL: Repository, https://github.com/sligara7/mapwright
@@ -97,7 +97,7 @@ produced by [`examples/gallery.py`](examples/gallery.py):
97
97
  <tr>
98
98
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/shantytown.png" alt="poor, dense, irregular shantytown"><br><sub><code>wealth=0.08</code> (shantytown)</sub></td>
99
99
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/metropolis.png" alt="rich, modern, grid-block metropolis"><br><sub><code>wealth=0.92, era=0.95</code> (metropolis)</sub></td>
100
- <td align="center"><sub>Same generator, opposite ends of the <b>shanty skyscraper</b> axis: <code>wealth</code> drives plot size + ward mix, <code>era</code> drives organic-vs-grid block regularity.</sub></td>
100
+ <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/grid-city.png" alt="planned town with a geometric street grid"><br><sub><code>layout="grid"</code> (grid_city)</sub></td>
101
101
  </tr>
102
102
  <tr>
103
103
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/roads.png" alt="settlements linked by terrain-routed roads"><br><sub><code>RegionalRoadGenerator</code></sub></td>
@@ -226,8 +226,11 @@ open("town.svg", "w").write(SettlementSVGRenderer().render(town))
226
226
  ```
227
227
 
228
228
  Settlement presets: `hamlet`, `village`, `town`, `city`, `port`, `citadel`,
229
- `shantytown`, `metropolis`. The `wealth` (poor ⇄ rich) and `era` (ancient ⇄ modern)
230
- knobs drive the shanty↔skyscraper axis — plot size, ward-kind mix, and block regularity.
229
+ `shantytown`, `metropolis`, `grid_city`. The `wealth` (poor ⇄ rich) and `era`
230
+ (ancient ⇄ modern) knobs drive the shanty↔skyscraper axis — plot size, ward-kind
231
+ mix, and block regularity. The `layout` knob picks the street pattern: `"organic"`
232
+ (winding ward-to-ward roads, the default) or `"grid"` (a geometric street grid
233
+ aligned to the town's long axis, with grid-aligned lots).
231
234
 
232
235
  ## What's inside
233
236
 
@@ -245,7 +248,7 @@ knobs drive the shanty↔skyscraper axis — plot size, ward-kind mix, and block
245
248
  | `RegionGenerator` | Partitions land into named factions/territories: spread capitals seed a flood fill over the land graph (sea divides them); each `Region` is Markov-named. |
246
249
  | `DungeonGenerator` | BSP-partitioned rooms + minimum-spanning-tree corridors → rooms, corridor cells, and a walkable grid (with `Dungeon.ascii()`). |
247
250
  | `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. Takes a `theme=`. |
248
- | `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (MST over ward adjacency + main roads from gates to the market), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
251
+ | `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (`layout="organic"` → MST over ward adjacency + gate-to-market roads; `layout="grid"` a geometric street grid + grid-aligned lots), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
249
252
  | `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. Takes a `theme=`. |
250
253
 
251
254
  Everything is neutral: `RegionalTerrainGenerator` returns a `TerrainResult` of `TerrainCell`s
@@ -70,7 +70,7 @@ produced by [`examples/gallery.py`](examples/gallery.py):
70
70
  <tr>
71
71
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/shantytown.png" alt="poor, dense, irregular shantytown"><br><sub><code>wealth=0.08</code> (shantytown)</sub></td>
72
72
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/metropolis.png" alt="rich, modern, grid-block metropolis"><br><sub><code>wealth=0.92, era=0.95</code> (metropolis)</sub></td>
73
- <td align="center"><sub>Same generator, opposite ends of the <b>shanty skyscraper</b> axis: <code>wealth</code> drives plot size + ward mix, <code>era</code> drives organic-vs-grid block regularity.</sub></td>
73
+ <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/grid-city.png" alt="planned town with a geometric street grid"><br><sub><code>layout="grid"</code> (grid_city)</sub></td>
74
74
  </tr>
75
75
  <tr>
76
76
  <td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/roads.png" alt="settlements linked by terrain-routed roads"><br><sub><code>RegionalRoadGenerator</code></sub></td>
@@ -199,8 +199,11 @@ open("town.svg", "w").write(SettlementSVGRenderer().render(town))
199
199
  ```
200
200
 
201
201
  Settlement presets: `hamlet`, `village`, `town`, `city`, `port`, `citadel`,
202
- `shantytown`, `metropolis`. The `wealth` (poor ⇄ rich) and `era` (ancient ⇄ modern)
203
- knobs drive the shanty↔skyscraper axis — plot size, ward-kind mix, and block regularity.
202
+ `shantytown`, `metropolis`, `grid_city`. The `wealth` (poor ⇄ rich) and `era`
203
+ (ancient ⇄ modern) knobs drive the shanty↔skyscraper axis — plot size, ward-kind
204
+ mix, and block regularity. The `layout` knob picks the street pattern: `"organic"`
205
+ (winding ward-to-ward roads, the default) or `"grid"` (a geometric street grid
206
+ aligned to the town's long axis, with grid-aligned lots).
204
207
 
205
208
  ## What's inside
206
209
 
@@ -218,7 +221,7 @@ knobs drive the shanty↔skyscraper axis — plot size, ward-kind mix, and block
218
221
  | `RegionGenerator` | Partitions land into named factions/territories: spread capitals seed a flood fill over the land graph (sea divides them); each `Region` is Markov-named. |
219
222
  | `DungeonGenerator` | BSP-partitioned rooms + minimum-spanning-tree corridors → rooms, corridor cells, and a walkable grid (with `Dungeon.ascii()`). |
220
223
  | `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. Takes a `theme=`. |
221
- | `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (MST over ward adjacency + main roads from gates to the market), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
224
+ | `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (`layout="organic"` → MST over ward adjacency + gate-to-market roads; `layout="grid"` a geometric street grid + grid-aligned lots), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
222
225
  | `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. Takes a `theme=`. |
223
226
 
224
227
  Everything is neutral: `RegionalTerrainGenerator` returns a `TerrainResult` of `TerrainCell`s
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="630" height="630" viewBox="0 0 630 630"><rect width="630" height="630" fill="#c9d2bb"/><polygon points="81.8,367.7 85.2,334.2 93.9,300.7 107.5,267.9 125.8,236.4 148.3,206.8 174.7,179.7 204.4,155.7 236.9,135.3 271.5,119.2 307.4,107.7 343.8,101.3 379.7,100.2 414.2,104.5 446.3,114.3 475.2,129.1 500.2,148.6 520.5,172.3 535.8,199.6 545.7,229.7 550.1,261.9 548.9,295.5 542.2,329.7 529.9,363.8 512.4,397.0 490.0,428.6 463.1,457.8 432.1,483.7 397.9,505.7 361.2,523.0 323.0,535.0 284.5,541.3 246.7,541.7 210.8,536.0 177.9,524.6 148.9,507.7 124.5,486.1 105.4,460.5 91.8,431.7 84.0,400.4" fill="#e6dcc0"/><g stroke="#4a4230" stroke-width="1" stroke-linejoin="round"><polygon points="137.2,221.4 148.3,206.8 174.7,179.7 195.1,163.2 204.9,173.1 217.7,215.1 196.3,253.2 192.7,254.4" fill="#d8cdb0"/><polygon points="319.2,444.5 349.3,451.3 361.7,488.1 300.7,496.8" fill="#c2b48f"/><polygon points="435.4,234.2 430.3,235.4 404.9,216.9 403.0,197.8 416.9,189.5 454.6,205.8" fill="#d8cdb0"/><polygon points="387.2,258.5 368.8,303.9 345.0,289.1 339.1,253.5 360.2,235.5 377.5,241.6" fill="#b9a98c"/><polygon points="495.4,144.9 500.2,148.6 520.5,172.3 535.8,199.6 540.4,213.5 494.2,223.6 466.9,200.2 468.2,187.2" fill="#c2b48f"/><polygon points="405.4,356.6 376.6,307.4 420.6,298.3 437.4,319.3 434.0,348.1" fill="#cdbf9e"/><polygon points="549.5,279.5 548.9,295.5 542.2,329.7 531.8,358.4 497.0,341.7 485.1,297.9 488.4,287.3" fill="#d8cdb0"/><polygon points="192.7,254.4 196.3,253.2 240.6,275.4 249.3,301.4 239.0,322.7 204.4,334.3 170.0,314.8 168.9,310.0" fill="#cdbf9e"/><polygon points="247.0,429.8 273.2,435.3 277.2,502.5 216.9,473.7" fill="#b9a98c"/><polygon points="249.3,301.4 240.6,275.4 268.1,244.8 297.0,250.4 298.4,298.9" fill="#c2b48f"/><polygon points="418.4,109.2 419.8,143.9 378.0,160.5 361.2,145.5 364.3,131.3" fill="#d8cdb0"/><polygon points="423.4,414.1 412.5,432.7 400.0,437.6 369.7,428.6 364.2,407.6 392.9,375.1" fill="#b3a684"/><polygon points="445.3,472.6 432.1,483.7 397.9,505.7 388.0,510.3 386.3,507.6 400.0,437.6 412.5,432.7" fill="#c2b48f"/><polygon points="298.4,298.9 297.0,250.4 305.3,244.9 339.1,253.5 345.0,289.1 300.5,300.5" fill="#dfd6c0"/><polygon points="349.3,451.3 319.2,444.5 302.2,422.7 304.1,415.6 334.0,395.0 364.2,407.6 369.7,428.6" fill="#c2b48f"/><polygon points="392.9,375.1 364.2,407.6 334.0,395.0 335.3,352.1 339.9,350.2 393.0,373.0" fill="#c2b48f"/><polygon points="468.2,187.2 466.9,200.2 454.6,205.8 416.9,189.5 428.1,160.2" fill="#dfd6c0"/><polygon points="204.9,476.7 185.3,527.1 177.9,524.6 148.9,507.7 124.5,486.1 111.9,469.3 178.5,449.3" fill="#cdbf9e"/><polygon points="310.1,213.6 305.3,244.9 297.0,250.4 268.1,244.8 256.6,218.1 274.3,191.1" fill="#cdbf9e"/><polygon points="425.2,280.8 415.4,262.1 430.3,235.4 435.4,234.2 476.1,267.0 476.2,267.5" fill="#d8cdb0"/><polygon points="284.0,541.3 246.7,541.7 210.8,536.0 185.3,527.1 204.9,476.7 216.9,473.7 277.2,502.5 284.0,510.5" fill="#dfd6c0"/><polygon points="273.2,435.3 247.0,429.8 230.9,399.3 272.9,365.0 273.8,365.1 304.1,415.6 302.2,422.7" fill="#b3a684"/><polygon points="489.1,139.9 495.4,144.9 468.2,187.2 428.1,160.2 426.6,151.9" fill="#cdbf9e"/><polygon points="504.6,408.1 490.0,428.6 468.9,451.5 444.9,408.0 459.5,391.3" fill="#b9a98c"/><polygon points="300.5,300.5 345.0,289.1 368.8,303.9 369.0,304.4 339.9,350.2 335.3,352.1 309.0,343.2" fill="#d9c08a"/><polygon points="376.6,307.4 405.4,356.6 393.0,373.0 339.9,350.2 369.0,304.4" fill="#cdbf9e"/><polygon points="368.8,303.9 387.2,258.5 415.4,262.1 425.2,280.8 420.6,298.3 376.6,307.4 369.0,304.4" fill="#d8cdb0"/><polygon points="387.2,258.5 377.5,241.6 404.9,216.9 430.3,235.4 415.4,262.1" fill="#cdbf9e"/><polygon points="105.5,272.8 107.5,267.9 125.8,236.4 137.2,221.4 192.7,254.4 168.9,310.0" fill="#d8cdb0"/><polygon points="361.2,145.5 378.0,160.5 380.7,185.9 352.0,205.8 334.3,198.1 324.8,161.6 328.6,155.2" fill="#cdbf9e"/><polygon points="195.1,163.2 204.4,155.7 236.9,135.3 265.4,122.0 274.6,170.2 273.0,173.2 204.9,173.1" fill="#c2b48f"/><polygon points="468.9,451.5 463.1,457.8 445.3,472.6 412.5,432.7 423.4,414.1 444.9,408.0" fill="#d8cdb0"/><polygon points="435.4,234.2 454.6,205.8 466.9,200.2 494.2,223.6 476.1,267.0" fill="#c2b48f"/><polygon points="388.0,510.3 361.2,523.0 323.0,535.0 284.5,541.3 284.0,541.3 284.0,510.5 300.7,496.8 361.7,488.1 386.3,507.6" fill="#c2b48f"/><polygon points="268.1,244.8 240.6,275.4 196.3,253.2 217.7,215.1 256.6,218.1" fill="#cdbf9e"/><polygon points="419.4,106.1 446.3,114.3 475.2,129.1 489.1,139.9 426.6,151.9 419.8,143.9 418.4,109.2" fill="#d8cdb0"/><polygon points="437.4,319.3 420.6,298.3 425.2,280.8 476.2,267.5 488.4,287.3 485.1,297.9" fill="#dfd6c0"/><polygon points="423.4,414.1 392.9,375.1 393.0,373.0 405.4,356.6 434.0,348.1 456.6,364.1 459.5,391.3 444.9,408.0" fill="#b3a684"/><polygon points="360.2,235.5 339.1,253.5 305.3,244.9 310.1,213.6 334.3,198.1 352.0,205.8" fill="#cdbf9e"/><polygon points="306.8,107.9 307.4,107.7 343.8,101.3 354.2,101.0 364.3,131.3 361.2,145.5 328.6,155.2" fill="#d8cdb0"/><polygon points="403.0,197.8 404.9,216.9 377.5,241.6 360.2,235.5 352.0,205.8 380.7,185.9" fill="#cdbf9e"/><polygon points="89.7,316.8 93.9,300.7 105.5,272.8 168.9,310.0 170.0,314.8 137.2,350.1" fill="#cdbf9e"/><polygon points="239.0,322.7 249.3,301.4 298.4,298.9 300.5,300.5 309.0,343.2 273.8,365.1 272.9,365.0" fill="#b3a684"/><polygon points="152.1,392.8 94.0,436.2 91.8,431.7 84.0,400.4 82.5,378.1 136.0,357.8" fill="#cdbf9e"/><polygon points="354.2,101.0 379.7,100.2 414.2,104.5 419.4,106.1 418.4,109.2 364.3,131.3" fill="#d8cdb0"/><polygon points="416.9,189.5 403.0,197.8 380.7,185.9 378.0,160.5 419.8,143.9 426.6,151.9 428.1,160.2" fill="#cdbf9e"/><polygon points="81.8,367.7 85.2,334.2 89.7,316.8 137.2,350.1 136.0,357.8 82.5,378.1" fill="#cdbf9e"/><polygon points="274.3,191.1 256.6,218.1 217.7,215.1 204.9,173.1 273.0,173.2" fill="#c2b48f"/><polygon points="265.4,122.0 271.5,119.2 306.8,107.9 328.6,155.2 324.8,161.6 274.6,170.2" fill="#d8cdb0"/><polygon points="309.0,343.2 335.3,352.1 334.0,395.0 304.1,415.6 273.8,365.1" fill="#cdbf9e"/><polygon points="178.5,449.3 111.9,469.3 105.4,460.5 94.0,436.2 152.1,392.8 179.9,404.4" fill="#c2b48f"/><polygon points="434.0,348.1 437.4,319.3 485.1,297.9 497.0,341.7 456.6,364.1" fill="#b9a98c"/><polygon points="361.7,488.1 349.3,451.3 369.7,428.6 400.0,437.6 386.3,507.6" fill="#d8cdb0"/><polygon points="170.0,314.8 204.4,334.3 204.0,391.3 179.9,404.4 152.1,392.8 136.0,357.8 137.2,350.1" fill="#b9a98c"/><polygon points="230.9,399.3 247.0,429.8 216.9,473.7 204.9,476.7 178.5,449.3 179.9,404.4 204.0,391.3" fill="#c2b48f"/><polygon points="531.8,358.4 529.9,363.8 512.4,397.0 504.6,408.1 459.5,391.3 456.6,364.1 497.0,341.7" fill="#c2b48f"/><polygon points="204.4,334.3 239.0,322.7 272.9,365.0 230.9,399.3 204.0,391.3" fill="#b9a98c"/><polygon points="277.2,502.5 273.2,435.3 302.2,422.7 319.2,444.5 300.7,496.8 284.0,510.5" fill="#b9a98c"/><polygon points="324.8,161.6 334.3,198.1 310.1,213.6 274.3,191.1 273.0,173.2 274.6,170.2" fill="#cdbf9e"/><polygon points="540.4,213.5 545.7,229.7 550.1,261.9 549.5,279.5 488.4,287.3 476.2,267.5 476.1,267.0 494.2,223.6" fill="#c2b48f"/></g><g fill="#7d6c52" stroke="#4a3e2e" stroke-width="0.5" stroke-linejoin="round"><polygon points="143.4,220.2 151.5,209.6 165.4,195.3 182.2,218.1 163.3,232.0"/><polygon points="187.1,224.9 198.6,240.5 193.5,249.7 193.2,249.8 171.1,236.7"/><polygon points="171.3,189.2 177.5,182.8 194.8,168.9 201.2,175.3 207.1,194.6 186.5,209.8"/><polygon points="209.7,203.2 213.2,214.6 203.2,232.5 191.5,216.6"/><polygon points="307.4,486.2 314.7,465.6 321.9,475.5"/><polygon points="331.9,489.3 308.2,492.7 325.2,480.2"/><polygon points="320.6,449.2 332.0,464.7 324.9,469.9 317.1,459.3"/><polygon points="327.4,449.0 347.2,453.5 347.3,453.8 336.6,461.6"/><polygon points="348.7,460.3 351.6,468.9 334.2,481.6 329.1,474.7"/><polygon points="354.2,474.8 357.9,485.7 338.5,488.5 337.5,487.1"/><polygon points="432.9,230.5 431.2,230.8 408.9,214.6 407.4,200.0 417.2,194.2 448.3,207.7"/><polygon points="348.0,281.4 343.6,255.2 349.4,250.2 363.8,269.7"/><polygon points="355.9,244.7 361.1,240.2 374.6,245.0 381.4,256.8 370.6,264.7"/><polygon points="378.2,269.6 366.8,297.7 352.3,288.7"/><polygon points="470.1,195.5 470.8,188.1 478.2,176.7 484.3,185.0"/><polygon points="492.9,197.3 479.6,207.1 472.4,200.9 487.4,189.8"/><polygon points="494.3,168.7 484.2,176.2 480.9,171.8 488.2,160.5"/><polygon points="496.0,148.7 498.3,150.5 506.2,159.7 498.2,165.5 491.3,156.2"/><polygon points="507.7,186.0 497.9,193.3 488.3,180.2 498.1,173.0"/><polygon points="509.6,164.1 518.1,174.0 520.0,177.4 513.0,182.6 502.9,169.0"/><polygon points="489.2,215.7 483.8,211.1 498.6,200.2 502.7,205.7"/><polygon points="511.6,217.3 494.9,221.0 492.9,219.3 506.0,209.7"/><polygon points="519.7,203.1 511.9,208.9 503.2,197.0 511.0,191.3"/><polygon points="523.0,182.3 530.4,195.4 524.2,200.0 515.3,187.9"/><polygon points="533.0,200.6 533.1,200.8 536.6,211.3 517.0,215.6 515.4,213.5"/><polygon points="386.1,318.4 380.8,309.3 399.7,305.4 401.1,307.3"/><polygon points="394.5,331.6 389.6,323.2 404.2,312.4 410.0,320.2"/><polygon points="406.0,304.4 419.4,301.6 425.4,309.2 415.1,316.7"/><polygon points="404.0,347.5 398.0,337.3 411.6,327.3 418.6,336.8"/><polygon points="406.6,353.7 406.3,353.2 422.8,341.0 427.6,347.4"/><polygon points="416.5,323.2 429.2,313.8 434.2,320.2 433.9,323.1 422.6,331.4"/><polygon points="434.1,329.3 432.1,345.8 424.9,336.0"/><polygon points="518.4,311.7 497.4,327.1 489.5,298.0 491.6,291.2 502.3,289.8"/><polygon points="545.1,284.3 544.8,292.2 525.2,306.7 511.9,288.6"/><polygon points="532.2,345.1 529.5,352.6 500.6,338.7 499.8,335.8 516.4,323.6"/><polygon points="542.9,304.0 538.1,328.5 535.6,335.5 523.1,318.6"/><polygon points="186.8,309.2 177.8,315.9 172.5,312.9 171.9,310.2 177.7,296.8"/><polygon points="182.2,293.7 180.0,290.7 186.5,275.5 193.6,285.2"/><polygon points="202.6,297.7 191.5,305.9 185.5,297.9 196.7,289.6"/><polygon points="195.0,256.9 196.1,256.6 208.6,262.9 192.8,274.5 189.4,269.9"/><polygon points="217.2,286.1 207.2,293.5 197.0,279.6 207.0,272.2"/><polygon points="214.9,265.9 233.1,275.0 222.7,282.6 211.9,268.0"/><polygon points="207.7,329.7 204.7,330.7 184.0,319.0 194.2,311.4"/><polygon points="204.8,315.7 198.7,307.4 208.7,300.0 214.8,308.3"/><polygon points="226.2,324.0 214.1,328.0 208.2,320.0 218.0,312.8"/><polygon points="230.8,299.5 220.8,306.9 213.4,296.9 223.4,289.5"/><polygon points="238.6,278.2 242.8,290.9 235.5,296.2 228.0,286.0"/><polygon points="239.1,316.2 237.0,320.5 231.8,322.2 223.9,311.6 231.5,306.0"/><polygon points="244.9,295.6 246.8,301.2 241.8,311.5 235.3,302.7"/><polygon points="249.9,462.3 231.4,475.9 223.1,472.0 239.5,448.1"/><polygon points="248.8,434.4 269.2,438.7 269.8,447.7 256.7,457.3 244.5,440.8"/><polygon points="268.6,494.0 239.5,480.1 251.7,471.1"/><polygon points="270.7,456.8 272.5,486.3 257.8,466.3"/><polygon points="249.0,292.3 243.6,276.1 246.6,272.7 256.8,286.5"/><polygon points="250.6,268.7 255.8,262.8 267.3,278.4 261.1,283.0"/><polygon points="251.8,297.8 270.7,283.9 279.9,296.4"/><polygon points="259.8,258.4 269.1,248.0 270.7,248.3 276.8,256.6 264.9,265.4"/><polygon points="280.3,261.0 285.5,268.1 273.4,277.1 268.2,270.0"/><polygon points="278.7,249.7 294.3,252.7 294.6,261.4 289.9,264.9"/><polygon points="295.0,290.9 295.1,295.9 288.0,296.2 277.2,281.6 284.3,276.4"/><polygon points="295.4,266.8 295.9,283.2 287.9,272.4"/><polygon points="402.1,146.4 378.8,155.7 365.9,144.0 368.0,134.4 387.4,126.4"/><polygon points="414.4,115.4 415.5,141.1 410.2,143.2 395.4,123.2"/><polygon points="370.0,421.7 366.4,408.1 367.9,406.4 376.0,417.3"/><polygon points="371.0,403.4 375.0,398.8 384.0,411.0 379.2,414.6"/><polygon points="377.8,395.3 384.3,387.9 389.4,394.8 381.6,400.5"/><polygon points="391.8,397.9 395.6,403.0 387.6,408.9 383.8,403.8"/><polygon points="387.0,384.8 392.9,378.2 398.1,384.9 390.9,390.2"/><polygon points="400.5,388.1 405.9,395.1 398.7,400.5 393.4,393.3"/><polygon points="384.6,430.8 371.4,426.9 371.2,425.9 379.2,420.1 386.2,429.6"/><polygon points="382.6,417.6 388.1,413.5 395.1,423.1 389.6,427.1"/><polygon points="403.5,434.1 399.9,435.5 389.4,432.4 397.7,426.2"/><polygon points="399.0,420.9 391.7,411.0 397.9,406.5 405.1,416.3"/><polygon points="401.7,403.8 408.5,398.8 415.9,408.3 408.9,413.4"/><polygon points="414.5,424.7 411.0,430.9 407.4,432.3 401.7,424.5 409.9,418.5"/><polygon points="421.5,414.2 417.1,421.7 412.7,415.6 418.9,411.0"/><polygon points="392.2,488.5 395.4,472.4 401.9,481.3"/><polygon points="410.0,494.1 396.3,502.9 390.0,505.9 392.0,495.2 404.2,486.3"/><polygon points="399.0,469.6 396.8,466.7 399.8,451.6 408.1,462.9"/><polygon points="401.0,445.0 402.1,439.3 411.8,435.6 415.7,440.4 403.9,449.0"/><polygon points="418.7,444.4 424.1,450.9 412.1,459.7 407.1,453.0"/><polygon points="424.2,484.6 415.5,490.2 403.4,473.8 411.7,467.6"/><polygon points="422.3,471.3 416.4,463.3 427.4,455.2 433.7,462.9"/><polygon points="441.8,472.3 430.6,481.7 429.9,482.1 425.3,475.7 437.3,466.9"/><polygon points="300.1,275.3 299.6,256.4 308.8,268.9"/><polygon points="301.2,292.7 300.9,281.4 311.5,273.6 317.0,281.1"/><polygon points="304.8,296.9 320.7,285.2 325.4,291.6"/><polygon points="301.3,250.5 305.7,247.5 318.8,250.8 307.6,259.1"/><polygon points="325.1,253.5 336.0,256.3 336.3,257.8 317.9,271.4 311.9,263.2"/><polygon points="339.5,287.4 330.8,289.7 321.3,276.8 328.1,271.8"/><polygon points="338.4,263.3 341.4,281.2 331.8,268.2"/><polygon points="317.0,436.2 305.9,422.0 307.1,417.7 312.7,413.8 324.9,430.3"/><polygon points="317.7,409.8 323.3,405.9 335.8,422.9 330.3,426.9"/><polygon points="335.9,446.0 320.5,442.5 319.5,441.3 327.9,435.1"/><polygon points="348.2,447.9 343.1,446.7 332.7,432.6 339.3,427.8 351.4,444.3"/><polygon points="328.0,402.5 333.1,399.0 345.5,415.9 340.6,419.6"/><polygon points="340.5,400.2 357.8,407.5 350.0,413.2"/><polygon points="361.3,433.4 355.6,439.7 344.2,424.2 350.9,419.2"/><polygon points="362.3,410.2 367.0,427.9 365.4,429.6 355.0,415.5"/><polygon points="336.7,369.2 337.1,354.0 344.2,363.6"/><polygon points="337.4,389.7 337.9,374.7 346.2,368.5 353.3,378.1"/><polygon points="345.1,356.0 369.1,366.3 358.5,374.2"/><polygon points="354.9,401.4 339.4,394.9 346.3,389.8"/><polygon points="371.1,394.6 363.3,403.4 351.6,387.6 360.9,380.7"/><polygon points="388.5,374.9 375.8,389.2 366.5,376.6 376.1,369.6"/><polygon points="425.8,190.7 420.0,188.2 424.9,175.3 432.6,185.7"/><polygon points="427.5,169.9 429.5,164.6 445.6,175.5 436.5,182.2"/><polygon points="451.2,201.4 431.4,192.8 440.2,186.4"/><polygon points="464.6,188.9 463.7,198.0 458.1,200.5 445.5,183.4 450.7,179.5"/><polygon points="126.0,483.2 116.8,470.9 128.2,467.4 135.0,476.6"/><polygon points="133.3,465.4 146.0,461.6 149.6,466.5 139.5,473.9"/><polygon points="139.5,495.7 130.0,487.3 139.9,480.0 147.3,490.0"/><polygon points="144.2,476.7 152.4,470.7 159.9,480.9 151.7,486.9"/><polygon points="152.3,460.6 162.8,457.5 172.6,470.7 164.3,476.8"/><polygon points="168.6,455.1 177.7,452.4 186.2,461.3 177.8,467.6"/><polygon points="158.5,510.1 150.5,505.4 143.8,499.5 152.1,493.4 162.3,507.3"/><polygon points="156.7,490.1 163.3,485.2 173.5,499.0 166.8,503.9"/><polygon points="185.8,516.6 183.3,522.9 179.3,521.5 164.7,513.1 176.8,504.3"/><polygon points="187.3,486.8 177.4,494.1 168.4,481.9 178.3,474.6"/><polygon points="201.1,477.0 192.5,483.3 183.1,470.7 190.1,465.5"/><polygon points="197.6,487.1 188.7,509.7 181.0,499.2"/><polygon points="265.0,230.1 260.0,218.4 265.8,209.5 275.4,222.5"/><polygon points="268.6,204.2 275.0,194.3 283.5,199.7 271.7,208.4"/><polygon points="287.8,203.0 295.4,207.8 280.2,219.1 275.2,212.3"/><polygon points="273.9,242.6 270.4,241.9 267.8,235.9 284.0,223.9 289.3,231.2"/><polygon points="300.3,245.0 296.5,247.6 281.1,244.7 293.4,235.6"/><polygon points="306.9,215.1 306.1,219.8 294.8,228.1 288.9,220.0 300.7,211.2"/><polygon points="306.1,226.1 303.7,241.7 297.1,232.7"/><polygon points="422.7,267.1 420.2,262.2 433.0,239.0 434.4,238.7 447.2,249.1"/><polygon points="427.3,275.9 426.7,274.6 454.0,254.5 467.5,265.4"/><polygon points="201.6,529.3 189.6,525.1 195.9,508.8 207.7,524.8"/><polygon points="198.0,501.6 204.5,485.1 211.9,495.1 199.8,504.1"/><polygon points="214.9,500.4 224.0,512.8 213.1,520.8 204.0,508.5"/><polygon points="207.3,479.2 216.6,476.9 228.6,482.6 216.4,491.6"/><polygon points="238.9,502.0 229.4,509.0 220.2,496.5 229.7,489.5"/><polygon points="234.7,484.9 252.1,493.2 243.9,499.2 233.9,485.6"/><polygon points="221.2,535.6 211.3,534.1 206.4,532.4 214.5,526.5"/><polygon points="227.3,535.3 219.2,524.3 229.3,516.9 237.4,527.9"/><polygon points="247.5,539.7 246.9,539.7 232.8,537.5 241.3,531.3"/><polygon points="238.5,519.8 233.6,513.2 245.8,504.2 250.6,510.8"/><polygon points="246.0,530.1 241.5,524.0 253.8,515.0 258.3,521.1"/><polygon points="249.5,501.0 257.1,495.4 265.0,499.2 254.1,507.2"/><polygon points="269.7,502.1 275.4,504.8 277.2,506.8 262.5,517.6 257.6,511.0"/><polygon points="269.8,538.5 252.7,538.7 249.5,534.3 260.7,526.1"/><polygon points="280.4,537.8 277.3,537.9 266.2,522.8 280.5,512.3"/><polygon points="236.3,406.1 232.9,399.7 237.2,396.2 241.6,402.2"/><polygon points="240.1,394.3 247.5,388.3 251.8,394.2 244.2,399.8"/><polygon points="243.7,418.8 238.6,409.1 244.4,404.8 250.9,413.6"/><polygon points="247.9,402.2 254.1,397.6 260.6,406.5 254.4,411.0"/><polygon points="250.2,385.8 253.6,383.0 260.3,392.0 256.7,394.7"/><polygon points="256.6,380.8 261.2,377.1 267.9,386.2 263.1,389.7"/><polygon points="270.1,389.9 274.6,396.0 264.1,403.6 259.7,397.5"/><polygon points="264.8,374.7 272.9,368.1 278.4,377.3 270.8,382.9"/><polygon points="280.9,381.0 285.3,388.3 278.3,393.5 273.2,386.6"/><polygon points="255.6,429.3 248.4,427.8 245.8,422.8 252.8,417.6 259.3,426.5"/><polygon points="255.6,414.9 258.7,412.7 265.8,422.4 262.8,424.7"/><polygon points="261.6,410.7 265.8,407.7 272.7,417.1 268.6,420.2"/><polygon points="270.2,433.2 259.5,430.9 265.4,426.6"/><polygon points="268.6,425.1 274.9,420.5 281.5,429.4 274.2,432.6"/><polygon points="268.6,405.4 275.7,400.2 279.4,405.3 272.3,410.5"/><polygon points="281.5,408.1 285.3,413.3 278.2,418.5 274.4,413.3"/><polygon points="278.8,398.2 287.5,391.7 290.7,396.9 282.3,403.0"/><polygon points="292.7,400.1 295.9,405.4 288.2,411.1 284.5,406.1"/><polygon points="294.5,423.7 285.5,427.6 280.9,421.4 288.6,415.7"/><polygon points="297.7,408.8 302.0,415.9 300.5,421.3 298.5,422.1 291.9,413.1"/><polygon points="445.2,168.4 430.6,158.5 429.8,154.1 437.8,152.5 448.0,166.4"/><polygon points="444.0,151.5 458.5,148.7 463.2,155.0 452.4,162.9"/><polygon points="468.6,181.8 467.4,183.5 449.9,171.7 457.2,166.3"/><polygon points="475.5,171.2 471.6,177.2 461.3,163.1 466.7,159.2"/><polygon points="481.7,143.6 468.4,153.4 463.7,147.1"/><polygon points="489.7,144.2 491.4,145.6 478.4,165.7 472.1,157.2"/><polygon points="455.9,420.6 449.3,408.5 458.9,397.4 468.9,411.0"/><polygon points="482.6,430.5 469.7,444.4 460.1,427.1 473.1,417.5"/><polygon points="498.1,410.1 488.2,424.0 470.3,399.7"/><polygon points="356.1,351.8 353.4,353.7 343.0,349.2 348.2,341.1"/><polygon points="368.1,341.8 359.7,348.0 351.7,337.2 357.8,327.7"/><polygon points="374.7,309.6 377.5,314.3 362.9,325.0 360.8,322.3 370.1,307.7"/><polygon points="380.1,319.5 385.5,328.8 373.0,338.1 366.6,329.4"/><polygon points="371.6,360.7 359.5,355.5 372.6,345.8 379.3,355.0"/><polygon points="391.6,370.2 376.1,363.5 383.0,358.5"/><polygon points="388.7,334.4 396.0,346.9 386.2,354.1 377.7,342.5"/><polygon points="399.5,351.3 402.5,356.5 394.7,366.9 388.9,359.0"/><polygon points="374.1,301.9 384.6,276.1 400.8,298.1 377.0,303.0"/><polygon points="388.3,267.0 389.9,263.1 412.7,266.0 420.7,281.3 417.2,294.7 409.8,296.2"/><polygon points="387.8,252.6 381.8,242.3 393.7,231.5 401.7,242.4"/><polygon points="393.1,256.4 405.9,247.0 414.3,258.4 413.9,259.1"/><polygon points="398.6,226.9 405.1,221.0 419.2,231.3 407.9,239.6"/><polygon points="424.7,234.6 426.8,236.1 417.3,253.2 411.0,244.7"/><polygon points="110.8,271.0 111.3,269.8 128.5,240.1 150.2,269.5 131.6,283.2"/><polygon points="133.7,233.0 138.3,226.9 176.9,249.9 156.9,264.5"/><polygon points="170.8,294.7 166.9,303.9 139.5,287.8 156.5,275.3"/><polygon points="184.7,254.5 187.4,256.1 174.7,285.8 163.3,270.3"/><polygon points="332.9,179.0 328.5,162.1 330.9,158.1 335.7,156.6 345.4,169.8"/><polygon points="336.2,193.5 334.2,186.0 349.5,174.7 353.8,180.5"/><polygon points="363.5,193.9 351.6,202.2 341.1,197.6 357.4,185.6"/><polygon points="360.6,148.2 361.4,148.9 345.8,160.4 341.1,154.0"/><polygon points="365.0,153.4 372.2,159.8 355.5,172.1 349.9,164.5"/><polygon points="376.1,185.5 368.7,190.6 358.9,177.3 366.1,172.0"/><polygon points="376.2,163.4 377.9,179.6 369.6,168.3"/><polygon points="199.2,163.4 206.0,157.9 208.1,156.6 217.1,168.8 214.9,170.4 206.0,170.4"/><polygon points="213.4,153.8 224.7,146.7 232.3,157.1 221.6,165.0"/><polygon points="236.2,161.3 243.1,170.7 223.5,170.6"/><polygon points="229.2,143.2 238.1,137.6 241.1,136.2 245.7,142.4 234.7,150.6"/><polygon points="248.8,146.4 253.2,152.4 242.0,160.7 237.5,154.7"/><polygon points="247.3,134.3 262.8,127.0 265.7,141.9 257.4,148.1"/><polygon points="264.2,170.4 249.5,170.4 245.4,164.7 254.9,157.7"/><polygon points="267.7,148.2 271.8,169.8 271.4,170.5 271.1,170.5 259.2,154.4"/><polygon points="426.8,443.4 417.6,432.3 426.2,417.7 442.8,412.9 450.1,426.2"/><polygon points="463.7,450.9 460.2,454.7 445.9,466.7 432.1,449.9 454.2,433.7"/><polygon points="440.1,233.5 450.1,218.6 459.9,231.9 448.5,240.3"/><polygon points="453.5,212.6 456.5,208.1 466.4,203.6 472.2,208.5 458.1,218.9"/><polygon points="476.6,212.2 481.7,216.6 465.3,228.7 461.4,223.4"/><polygon points="461.6,251.3 453.4,244.7 467.7,234.2 473.8,242.4"/><polygon points="480.3,250.3 475.1,262.8 465.7,255.3 477.6,246.6"/><polygon points="486.1,220.9 490.3,224.5 482.4,243.4 473.0,230.6"/><polygon points="286.2,533.7 286.2,516.7 294.3,527.7"/><polygon points="288.2,510.8 295.1,505.1 305.2,518.8 298.0,524.1"/><polygon points="315.5,533.1 290.3,537.2 308.6,523.8"/><polygon points="309.3,513.6 300.3,501.5 302.2,500.0 319.9,497.5 323.9,502.9"/><polygon points="316.6,524.6 312.5,519.0 328.1,507.6 332.2,513.2"/><polygon points="341.7,526.1 322.4,532.2 322.3,532.2 320.0,529.2 335.5,517.8"/><polygon points="338.2,511.3 327.1,496.2 339.0,494.5 346.8,505.0"/><polygon points="345.0,493.0 360.9,490.8 363.9,493.1 351.7,502.1"/><polygon points="362.9,518.6 360.0,520.0 347.6,523.9 342.1,516.4 354.5,507.2"/><polygon points="382.8,509.1 368.9,515.6 359.9,503.4 368.1,497.5"/><polygon points="203.8,244.1 212.3,229.1 216.5,234.8"/><polygon points="212.2,257.5 201.8,252.3 218.7,239.9 224.8,248.2"/><polygon points="241.2,270.1 239.9,271.6 218.5,260.8 228.8,253.2"/><polygon points="218.4,229.8 214.9,225.1 219.1,217.6 229.6,218.5 231.1,220.4"/><polygon points="230.1,244.4 222.4,233.9 233.8,225.4 241.6,236.0"/><polygon points="237.0,219.5 254.6,220.9 256.6,225.3 246.7,232.6"/><polygon points="253.3,256.1 245.5,264.9 234.2,249.6 243.5,242.8"/><polygon points="264.5,244.2 258.0,251.5 248.5,238.7 258.8,231.1"/><polygon points="422.5,111.3 444.8,118.0 445.2,118.2 423.5,134.3"/><polygon points="453.3,122.5 473.0,132.6 479.2,137.5 428.2,147.3 424.9,143.4"/><polygon points="428.6,304.2 423.4,297.7 426.5,286.0 435.9,298.9"/><polygon points="430.8,282.4 443.1,279.2 449.7,288.2 440.2,295.2"/><polygon points="438.1,316.1 431.9,308.3 440.7,301.8 448.0,311.7"/><polygon points="445.2,298.8 453.3,292.8 462.3,305.0 452.9,309.3"/><polygon points="449.6,277.7 474.7,271.1 475.4,272.3 456.1,286.5"/><polygon points="475.5,299.3 467.6,302.8 459.2,291.5 466.1,286.4"/><polygon points="478.8,277.2 485.3,287.7 482.8,295.9 480.6,296.8 470.6,283.2"/><polygon points="398.3,378.8 395.0,374.5 395.0,373.7 400.8,366.1 405.9,373.1"/><polygon points="403.6,362.8 406.8,358.6 410.7,357.4 416.4,365.1 409.2,370.4"/><polygon points="408.9,391.9 401.1,381.9 406.6,377.9 414.1,388.1"/><polygon points="409.6,375.2 419.1,368.1 421.8,371.8 412.3,378.9"/><polygon points="424.0,374.8 427.0,379.0 417.6,385.9 414.5,381.8"/><polygon points="415.4,356.1 433.6,350.7 434.7,351.5 420.0,362.4"/><polygon points="425.1,370.0 422.2,366.0 432.1,358.7 435.0,362.7"/><polygon points="440.0,369.4 430.0,376.8 427.3,373.1 437.3,365.7"/><polygon points="438.8,354.1 449.7,361.9 443.1,366.8 435.5,356.5"/><polygon points="417.5,403.6 411.1,395.3 415.7,391.9 421.9,400.3"/><polygon points="418.7,389.7 423.1,386.4 429.4,394.9 424.9,398.2"/><polygon points="424.1,412.1 419.7,406.4 425.0,402.5 430.7,410.2"/><polygon points="427.9,400.4 431.5,397.7 439.0,407.8 434.3,409.1"/><polygon points="426.9,384.4 434.4,378.9 440.9,387.7 433.4,393.2"/><polygon points="443.7,391.5 449.4,399.2 443.6,405.9 442.8,406.1 436.2,397.1"/><polygon points="438.0,376.0 444.5,371.2 450.9,379.9 444.4,384.7"/><polygon points="447.6,368.5 453.4,364.2 454.8,365.1 456.0,376.6 454.4,377.8"/><polygon points="456.3,381.4 457.2,390.6 452.6,395.9 446.9,388.3"/><polygon points="309.1,241.6 313.1,215.8 324.0,230.6"/><polygon points="338.6,249.9 338.3,250.2 315.8,244.5 328.0,235.5"/><polygon points="329.2,226.4 318.7,212.1 328.7,205.7 338.7,219.4"/><polygon points="333.3,201.9 334.5,201.1 349.8,207.7 350.8,211.4 344.0,216.4"/><polygon points="350.0,240.3 343.2,246.1 332.7,231.8 339.8,226.5"/><polygon points="357.2,234.5 354.5,236.9 344.2,222.9 352.3,216.9"/><polygon points="312.9,111.0 344.2,105.5 351.2,105.2 352.2,108.5 322.0,130.8"/><polygon points="355.1,116.9 360.0,131.6 357.7,142.2 330.9,150.1 325.6,138.6"/><polygon points="359.3,221.2 355.3,207.0 362.0,202.4 370.0,213.3"/><polygon points="382.9,231.9 376.7,237.6 363.1,232.8 361.6,227.4 373.3,218.8"/><polygon points="376.0,211.4 366.9,199.2 376.1,192.8 385.0,204.8"/><polygon points="380.0,189.1 380.8,188.5 396.8,197.1 389.7,202.3"/><polygon points="394.8,222.2 388.0,228.4 379.2,216.3 386.5,210.9"/><polygon points="400.6,200.3 402.2,215.8 398.9,218.8 390.7,207.6"/><polygon points="95.8,302.6 96.1,301.5 102.9,285.1 108.8,293.1"/><polygon points="92.5,315.7 94.0,310.0 97.8,307.2 106.4,318.9 101.8,322.3"/><polygon points="102.4,304.4 111.5,297.7 119.5,308.6 110.4,315.3"/><polygon points="104.9,280.0 106.5,276.0 119.2,283.4 111.5,289.0"/><polygon points="123.4,287.1 137.2,295.2 124.3,304.6 115.6,292.8"/><polygon points="118.0,333.4 106.4,325.2 115.7,318.4 123.7,329.2"/><polygon points="120.3,315.2 129.8,308.2 137.6,318.7 128.0,325.7"/><polygon points="139.7,343.6 136.8,346.7 122.5,336.6 130.4,330.9"/><polygon points="149.0,333.6 143.3,339.7 134.5,327.8 141.1,322.9"/><polygon points="143.3,298.6 155.7,305.9 142.7,315.4 134.9,304.8"/><polygon points="161.6,309.3 166.1,312.0 166.5,313.8 152.6,328.9 146.4,320.5"/><polygon points="241.1,322.4 246.7,310.7 251.2,316.7 241.9,323.5"/><polygon points="248.8,307.1 250.6,303.4 256.9,303.1 261.2,308.9 254.1,314.2"/><polygon points="246.7,329.5 244.1,326.3 253.9,319.1 256.3,322.4"/><polygon points="261.5,329.6 252.3,336.3 249.0,332.2 258.3,325.4"/><polygon points="263.7,312.6 270.8,322.2 264.6,326.8 257.4,317.2"/><polygon points="261.5,302.6 276.3,301.9 266.4,309.2"/><polygon points="279.3,305.0 284.5,312.0 274.5,319.3 269.4,312.3"/><polygon points="282.6,301.8 297.7,301.0 298.6,301.7 298.6,302.0 288.3,309.6"/><polygon points="263.3,350.0 254.7,339.3 258.1,336.7 266.3,347.8"/><polygon points="261.5,334.5 266.1,331.1 274.0,341.8 269.3,345.2"/><polygon points="269.4,328.6 279.3,321.3 282.7,325.9 272.8,333.2"/><polygon points="285.2,328.9 287.6,332.1 277.3,339.7 274.9,336.4"/><polygon points="268.8,356.7 265.7,352.9 275.8,345.5 278.7,349.4"/><polygon points="284.0,356.6 273.7,363.0 271.1,359.7 280.9,352.4"/><polygon points="281.8,347.1 278.9,343.2 289.7,335.3 292.5,339.1"/><polygon points="298.5,347.3 287.2,354.3 284.2,350.3 294.9,342.5"/><polygon points="286.4,324.4 282.4,318.9 290.0,313.3 294.0,318.8"/><polygon points="300.5,327.6 293.0,333.2 288.7,327.4 296.2,321.9"/><polygon points="299.5,306.5 303.1,324.3 293.3,311.1"/><polygon points="304.1,330.1 306.5,342.2 302.0,344.9 295.7,336.3"/><polygon points="87.2,402.7 86.5,400.0 85.4,382.3 95.7,396.4"/><polygon points="89.4,378.6 98.0,375.4 107.0,387.7 99.9,392.9"/><polygon points="105.4,423.6 95.3,431.1 95.0,430.5 89.4,408.4 92.5,406.1"/><polygon points="103.2,410.0 97.4,402.1 110.5,392.5 116.3,400.3"/><polygon points="124.1,410.4 110.6,420.5 106.3,414.7 119.9,404.7"/><polygon points="115.2,387.9 104.6,373.5 118.2,368.4 126.5,379.6"/><polygon points="123.7,365.4 134.6,361.2 139.2,371.2 132.0,376.6"/><polygon points="137.2,400.0 128.4,406.5 118.8,393.5 127.6,387.0"/><polygon points="148.4,391.8 142.2,396.5 132.4,383.2 141.4,376.6"/><polygon points="359.9,105.0 379.5,104.4 409.8,108.2 366.9,125.7"/><polygon points="383.5,180.3 381.6,162.8 391.2,159.0 398.6,169.1"/><polygon points="403.5,194.7 402.9,195.0 385.7,185.9 393.1,180.5"/><polygon points="413.6,188.3 407.7,191.8 397.3,177.7 402.8,173.6"/><polygon points="396.8,156.1 406.3,152.3 413.9,162.6 405.9,168.5"/><polygon points="411.0,150.0 419.1,146.7 424.4,152.9 424.8,155.2 418.3,160.0"/><polygon points="424.5,161.8 416.4,182.8 409.2,173.0"/><polygon points="85.8,356.9 88.1,334.7 88.1,334.6 97.9,348.0"/><polygon points="84.0,367.7 84.4,364.3 88.0,361.6 95.0,371.1 84.5,375.0"/><polygon points="92.5,359.2 101.4,352.6 110.2,364.6 99.5,368.6"/><polygon points="89.0,327.6 90.9,320.1 100.5,326.8 92.7,332.5"/><polygon points="104.0,330.3 115.0,338.0 103.8,346.2 96.3,336.0"/><polygon points="125.1,358.8 115.8,362.4 107.3,350.9 115.1,345.2"/><polygon points="120.0,340.9 134.6,351.2 133.9,356.1 130.6,357.4 119.0,341.6"/><polygon points="211.8,187.1 208.3,175.6 223.1,175.7 224.6,177.6"/><polygon points="218.1,208.1 213.1,192.1 215.5,190.3 224.9,203.1"/><polygon points="219.9,187.7 227.5,182.1 236.3,194.1 228.8,199.6"/><polygon points="235.9,214.4 219.3,213.1 219.3,212.8 229.3,205.4"/><polygon points="251.7,214.9 241.9,214.2 233.7,203.0 239.7,198.6"/><polygon points="241.0,189.8 231.4,176.7 258.8,176.7"/><polygon points="262.9,202.5 256.9,211.7 244.9,195.4 253.2,189.3"/><polygon points="271.3,190.3 266.8,197.2 258.0,185.3 270.3,176.3"/><polygon points="270.2,124.4 273.0,123.1 304.5,113.0 308.3,121.1 274.3,146.1"/><polygon points="296.7,162.8 277.5,166.1 275.4,155.0 285.5,147.6"/><polygon points="311.9,128.9 323.9,154.9 322.2,157.8 304.9,160.8 292.1,143.4"/><polygon points="284.0,375.9 278.2,366.2 292.1,357.5 298.1,365.5"/><polygon points="290.6,387.5 286.9,381.3 301.9,370.2 306.2,376.0"/><polygon points="297.3,398.5 293.7,392.5 309.6,380.7 313.7,386.4"/><polygon points="322.5,398.9 305.1,410.9 300.8,403.6 317.1,391.6"/><polygon points="303.2,362.5 296.9,354.0 307.8,347.1 313.6,354.9"/><polygon points="323.0,367.9 312.7,375.4 306.4,366.9 316.7,359.3"/><polygon points="315.6,348.4 332.4,354.1 332.2,361.0 327.5,364.6"/><polygon points="331.3,369.5 330.6,393.1 328.0,394.9 317.0,380.0"/><polygon points="106.5,455.0 98.2,437.3 105.0,432.2 116.4,447.7"/><polygon points="109.5,428.0 124.8,416.6 128.5,421.6 113.1,433.0"/><polygon points="131.7,426.4 136.7,433.2 121.8,444.2 116.8,437.4"/><polygon points="129.5,460.9 113.1,465.9 109.3,460.8 122.3,451.2"/><polygon points="132.4,455.0 127.0,447.7 140.3,437.9 145.7,445.2"/><polygon points="153.4,454.5 135.2,460.0 134.8,459.5 149.3,448.9"/><polygon points="135.3,420.9 129.8,413.4 144.8,402.2 150.4,409.7"/><polygon points="142.2,430.9 138.5,425.9 154.3,414.3 158.0,419.3"/><polygon points="150.2,398.4 152.6,396.7 174.9,406.0 162.5,415.1"/><polygon points="153.6,446.7 145.2,435.3 152.2,430.2 160.5,441.6"/><polygon points="156.1,427.1 161.8,422.9 170.4,434.6 164.7,438.8"/><polygon points="175.9,447.3 158.1,452.7 156.8,450.9 173.2,438.8 176.0,442.6"/><polygon points="166.2,420.1 176.9,412.2 176.2,433.7"/><polygon points="438.4,346.1 441.2,322.2 449.9,318.3 459.2,330.8"/><polygon points="464.1,337.5 473.4,350.1 456.8,359.2 445.5,351.2"/><polygon points="457.5,314.7 482.5,303.5 484.7,311.6 465.5,325.7"/><polygon points="486.9,320.1 492.2,339.6 480.7,346.0 470.5,332.2"/><polygon points="360.5,471.5 354.0,452.3 371.0,433.3 395.1,440.5 393.9,446.9"/><polygon points="365.2,485.5 363.3,479.9 391.5,459.1 383.5,500.0"/><polygon points="168.4,354.1 146.4,370.3 140.4,357.2 141.2,352.0 155.5,336.6"/><polygon points="170.8,320.1 195.5,334.1 175.1,349.1 161.3,330.3"/><polygon points="155.0,389.1 150.0,378.1 174.8,359.8 181.8,369.4"/><polygon points="197.1,390.2 179.6,399.7 163.8,393.1 186.8,376.2"/><polygon points="200.1,341.2 199.9,379.8 181.5,354.9"/><polygon points="181.8,423.4 182.3,405.9 184.1,404.9 192.1,415.8"/><polygon points="192.9,444.8 184.2,451.2 181.3,448.2 181.9,429.9 181.9,429.9"/><polygon points="205.5,435.1 197.5,441.0 186.9,426.7 194.9,420.8"/><polygon points="196.6,411.9 189.9,402.8 204.4,395.0 215.2,398.2"/><polygon points="221.4,423.0 210.7,430.8 200.8,417.4 211.5,409.5"/><polygon points="228.7,401.9 234.8,413.5 227.0,419.3 216.7,405.3 223.4,400.3"/><polygon points="197.4,465.2 187.7,455.2 195.1,449.8 203.3,460.9"/><polygon points="199.9,446.9 210.7,439.0 218.2,449.2 207.5,457.1"/><polygon points="224.1,457.5 214.9,470.9 205.9,473.2 201.9,469.0 221.8,454.3"/><polygon points="233.5,443.8 227.9,451.9 215.8,435.4 223.2,429.9"/><polygon points="237.9,418.8 243.5,429.6 237.3,438.6 228.0,426.1"/><polygon points="460.7,380.0 459.1,365.4 463.0,363.3 470.2,373.0"/><polygon points="469.6,392.1 462.0,389.3 461.6,385.7 473.0,377.4 478.8,385.4"/><polygon points="467.6,361.0 479.2,354.6 484.5,361.7 473.9,369.5"/><polygon points="487.6,366.1 493.7,374.4 483.3,382.1 477.2,373.8"/><polygon points="492.1,400.9 474.9,394.6 483.0,388.6"/><polygon points="494.0,395.0 487.3,385.9 497.0,378.8 503.7,387.9"/><polygon points="510.3,396.1 503.7,405.3 500.0,403.9 496.6,399.4 507.0,391.7"/><polygon points="497.9,369.6 485.1,352.3 493.9,347.4 505.9,363.7"/><polygon points="500.4,346.1 519.2,355.1 511.3,360.9"/><polygon points="519.0,377.5 512.5,389.8 501.8,375.2 511.8,367.8"/><polygon points="528.9,359.6 527.7,362.8 522.5,372.7 515.8,363.7 524.3,357.4"/><polygon points="207.8,376.9 207.9,348.4 221.5,366.8"/><polygon points="237.1,388.8 230.0,394.6 208.2,388.1 208.3,386.3 225.7,373.4"/><polygon points="209.4,337.1 237.5,327.6 244.6,336.4 221.5,353.5"/><polygon points="250.9,377.7 243.6,383.7 226.3,360.2 233.9,354.6"/><polygon points="249.9,343.0 267.1,364.4 257.3,372.4 240.6,349.8"/><polygon points="278.3,468.6 276.9,444.0 289.1,460.6"/><polygon points="280.8,501.1 279.3,476.3 279.6,476.1 294.9,496.8 284.4,505.3"/><polygon points="285.2,471.7 292.8,466.1 303.0,480.0 299.2,490.8"/><polygon points="280.3,436.6 300.9,427.6 307.2,435.7 289.3,448.9"/><polygon points="312.1,442.0 314.7,445.2 305.6,471.0 294.1,455.3"/><polygon points="276.7,186.0 275.8,173.8 276.4,172.7 287.7,170.8 291.1,175.4"/><polygon points="286.8,195.6 279.4,190.9 294.3,179.9 299.1,186.5"/><polygon points="314.1,207.3 310.1,209.9 292.5,198.8 302.4,191.5"/><polygon points="314.9,177.8 305.4,184.8 294.6,170.1 307.6,167.8"/><polygon points="323.3,164.1 325.2,171.5 319.9,175.5 312.8,165.9"/><polygon points="326.2,199.9 319.4,204.2 308.8,189.9 315.3,185.1"/><polygon points="326.2,176.5 331.5,197.0 331.0,197.3 319.4,181.5"/><polygon points="484.1,274.4 479.5,266.9 485.4,252.8 495.3,266.2"/><polygon points="487.4,246.1 494.1,230.0 500.3,238.4 488.2,247.3"/><polygon points="502.9,243.4 511.1,254.5 500.4,262.4 492.2,251.2"/><polygon points="506.0,282.3 489.8,284.4 487.0,279.7 498.1,271.5"/><polygon points="508.1,275.6 502.6,268.2 515.0,259.1 520.4,266.5"/><polygon points="530.3,279.4 512.2,281.7 511.0,280.0 523.8,270.6"/><polygon points="505.0,235.7 497.7,225.9 517.8,221.5 520.1,224.6"/><polygon points="529.1,237.1 514.2,248.1 508.7,240.6 523.6,229.6"/><polygon points="538.4,217.1 541.9,227.8 534.2,233.5 524.3,220.1"/><polygon points="536.1,254.8 525.1,262.9 517.8,253.1 528.8,245.0"/><polygon points="543.6,233.6 545.6,248.3 540.9,251.8 533.2,241.3"/><polygon points="546.7,275.6 546.6,276.9 536.2,278.2 528.6,267.8 536.6,261.9"/><polygon points="546.9,253.1 548.1,262.0 547.9,268.8 540.0,258.2"/></g><g fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M118.4,249.1 L311.4,107.0" stroke="#6c604a" stroke-width="3.4"/><path d="M83.9,347.1 L413.3,104.4" stroke="#6c604a" stroke-width="3.4"/><path d="M88.1,416.6 L476.8,130.3" stroke="#6c604a" stroke-width="3.4"/><path d="M113.0,470.8 L519.6,171.3" stroke="#6c604a" stroke-width="4.8"/><path d="M155.8,511.8 L544.4,225.6" stroke="#6c604a" stroke-width="3.4"/><path d="M219.6,537.4 L549.0,294.8" stroke="#6c604a" stroke-width="3.4"/><path d="M320.9,535.4 L514.8,392.5" stroke="#6c604a" stroke-width="3.4"/><path d="M84.0,400.0 L174.1,522.3" stroke="#6c604a" stroke-width="3.4"/><path d="M91.1,311.2 L260.8,541.5" stroke="#6c604a" stroke-width="3.4"/><path d="M118.2,249.5 L327.5,533.6" stroke="#6c604a" stroke-width="3.4"/><path d="M154.6,200.4 L384.2,512.1" stroke="#6c604a" stroke-width="3.4"/><path d="M198.0,160.8 L434.4,481.8" stroke="#6c604a" stroke-width="4.8"/><path d="M248.0,130.1 L477.7,442.0" stroke="#6c604a" stroke-width="3.4"/><path d="M304.7,108.6 L514.4,393.3" stroke="#6c604a" stroke-width="3.4"/><path d="M371.3,100.4 L541.5,331.5" stroke="#6c604a" stroke-width="3.4"/><path d="M458.7,120.6 L547.3,240.9" stroke="#6c604a" stroke-width="3.4"/><path d="M118.4,249.1 L311.4,107.0" stroke="#e4d9bc" stroke-width="1.8"/><path d="M83.9,347.1 L413.3,104.4" stroke="#e4d9bc" stroke-width="1.8"/><path d="M88.1,416.6 L476.8,130.3" stroke="#e4d9bc" stroke-width="1.8"/><path d="M113.0,470.8 L519.6,171.3" stroke="#e4d9bc" stroke-width="3.2"/><path d="M155.8,511.8 L544.4,225.6" stroke="#e4d9bc" stroke-width="1.8"/><path d="M219.6,537.4 L549.0,294.8" stroke="#e4d9bc" stroke-width="1.8"/><path d="M320.9,535.4 L514.8,392.5" stroke="#e4d9bc" stroke-width="1.8"/><path d="M84.0,400.0 L174.1,522.3" stroke="#e4d9bc" stroke-width="1.8"/><path d="M91.1,311.2 L260.8,541.5" stroke="#e4d9bc" stroke-width="1.8"/><path d="M118.2,249.5 L327.5,533.6" stroke="#e4d9bc" stroke-width="1.8"/><path d="M154.6,200.4 L384.2,512.1" stroke="#e4d9bc" stroke-width="1.8"/><path d="M198.0,160.8 L434.4,481.8" stroke="#e4d9bc" stroke-width="3.2"/><path d="M248.0,130.1 L477.7,442.0" stroke="#e4d9bc" stroke-width="1.8"/><path d="M304.7,108.6 L514.4,393.3" stroke="#e4d9bc" stroke-width="1.8"/><path d="M371.3,100.4 L541.5,331.5" stroke="#e4d9bc" stroke-width="1.8"/><path d="M458.7,120.6 L547.3,240.9" stroke="#e4d9bc" stroke-width="1.8"/></g><polygon points="81.8,367.7 85.2,334.2 93.9,300.7 107.5,267.9 125.8,236.4 148.3,206.8 174.7,179.7 204.4,155.7 236.9,135.3 271.5,119.2 307.4,107.7 343.8,101.3 379.7,100.2 414.2,104.5 446.3,114.3 475.2,129.1 500.2,148.6 520.5,172.3 535.8,199.6 545.7,229.7 550.1,261.9 548.9,295.5 542.2,329.7 529.9,363.8 512.4,397.0 490.0,428.6 463.1,457.8 432.1,483.7 397.9,505.7 361.2,523.0 323.0,535.0 284.5,541.3 246.7,541.7 210.8,536.0 177.9,524.6 148.9,507.7 124.5,486.1 105.4,460.5 91.8,431.7 84.0,400.4" fill="none" stroke="#3c3628" stroke-width="1.5"/><g font-family="Georgia, serif" font-size="8" text-anchor="middle"><text x="183.4" y="214.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="331.3" y="475.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="426.3" y="214.2" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="362.4" y="270.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="501.5" y="193.4" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="411.0" y="328.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="518.8" y="317.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="209.3" y="299.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="253.2" y="467.4" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="272.6" y="278.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="392.9" y="139.4" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="393.0" y="413.8" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Slums</text><text x="411.9" y="474.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="318.4" y="275.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Temple</text><text x="337.3" y="426.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="357.9" y="382.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="442.5" y="188.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Temple</text><text x="164.5" y="487.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="284.0" y="226.2" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="440.6" y="262.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="235.7" y="515.8" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Temple</text><text x="267.9" y="407.9" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Slums</text><text x="462.3" y="163.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="472.3" y="420.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="332.1" y="321.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Market</text><text x="374.2" y="344.9" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="398.1" y="286.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="404.1" y="244.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="150.3" y="267.9" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="352.9" y="177.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="241.4" y="157.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="441.0" y="441.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="466.5" y="234.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="329.2" y="516.2" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="233.7" y="245.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="444.5" y="134.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="453.8" y="295.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Temple</text><text x="428.8" y="382.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Slums</text><text x="332.6" y="230.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="338.2" y="128.9" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="378.6" y="216.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="126.9" y="315.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="276.1" y="330.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Slums</text><text x="113.7" y="396.4" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="381.4" y="115.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="403.4" y="173.6" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="103.7" y="352.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="240.6" y="196.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="295.2" y="143.8" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="309.1" y="379.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="141.5" y="435.5" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="465.1" y="335.2" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="375.8" y="466.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Noble</text><text x="174.0" y="364.1" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="209.2" y="434.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="493.0" y="376.9" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text><text x="231.8" y="364.3" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="293.1" y="465.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Garrison</text><text x="304.8" y="188.7" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Residential</text><text x="515.9" y="256.0" stroke="#f7f3ea" stroke-width="2.5" paint-order="stroke" fill="#23211c">Craftsmen</text></g><text x="315.0" y="20" text-anchor="middle" font-family="Georgia, serif" font-size="16" font-weight="bold" stroke="#f7f3ea" stroke-width="3" paint-order="stroke" fill="#23211c">Pelmoorhill</text></svg>
@@ -214,6 +214,7 @@ def main() -> None:
214
214
  emit("citadel", render_settlement("citadel", seed=3))
215
215
  emit("shantytown", render_settlement("shantytown", seed=5))
216
216
  emit("metropolis", render_settlement("metropolis", seed=5))
217
+ emit("grid-city", render_settlement("grid_city", seed=7))
217
218
  emit("roads", render_roads(seed=7))
218
219
  emit("regions", render_regions(seed=4))
219
220
  emit("template-isthmus", render_template("isthmus", 0.5, seed=5))
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mapwright"
7
- version = "0.20.0"
7
+ version = "0.21.0"
8
8
  description = "Domain-neutral procedural fantasy map & world generation: Voronoi terrain, hydraulic erosion, biomes, rivers, Markov place-names, and shaded-relief SVG."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -60,7 +60,7 @@ from .terrain import (
60
60
  compute_cell_polygons,
61
61
  )
62
62
 
63
- __version__ = "0.20.0"
63
+ __version__ = "0.21.0"
64
64
 
65
65
  __all__ = [
66
66
  "SeededRNG",
@@ -278,3 +278,46 @@ def inset_convex(poly: list[Point], dist: float) -> list[Point]:
278
278
  if polygon_area(out) <= 1e-9:
279
279
  return []
280
280
  return out
281
+
282
+
283
+ def clip_line_to_convex(
284
+ poly: list[Point], px: float, py: float, dx: float, dy: float
285
+ ) -> tuple[Point, Point] | None:
286
+ """Clip the infinite line through ``(px, py)`` with direction ``(dx, dy)`` to a
287
+ convex polygon, returning its ``(entry, exit)`` endpoints — or ``None`` if the
288
+ line misses the polygon (or the inputs are degenerate).
289
+
290
+ Liang–Barsky against each edge's inward half-plane: the line is ``P(t) =
291
+ (px + t·dx, py + t·dy)``; the valid ``t``-interval starts at ``(-inf, +inf)``
292
+ and is narrowed by every edge. ``poly`` must be convex.
293
+ """
294
+ if len(poly) < 3 or (dx == 0.0 and dy == 0.0):
295
+ return None
296
+ cx, cy = polygon_centroid(poly)
297
+ t_lo, t_hi = -math.inf, math.inf
298
+ n = len(poly)
299
+ for i in range(n):
300
+ ax, ay = poly[i]
301
+ bx, by = poly[(i + 1) % n]
302
+ ex, ey = bx - ax, by - ay
303
+ # Inward normal of this edge (oriented toward the centroid).
304
+ nx, ny = ey, -ex
305
+ if (cx - ax) * nx + (cy - ay) * ny < 0:
306
+ nx, ny = -nx, -ny
307
+ # Keep where (P(t) - a)·n >= 0 ⇒ base + t·slope >= 0.
308
+ base = (px - ax) * nx + (py - ay) * ny
309
+ slope = dx * nx + dy * ny
310
+ if abs(slope) < 1e-12:
311
+ if base < -1e-9:
312
+ return None # line runs wholly outside this edge — no crossing
313
+ continue
314
+ t = -base / slope
315
+ if slope > 0:
316
+ t_lo = max(t_lo, t)
317
+ else:
318
+ t_hi = min(t_hi, t)
319
+ if t_lo > t_hi:
320
+ return None
321
+ if not math.isfinite(t_lo) or not math.isfinite(t_hi) or t_hi - t_lo < 1e-9:
322
+ return None
323
+ return ((px + t_lo * dx, py + t_lo * dy), (px + t_hi * dx, py + t_hi * dy))