-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Append Coding Standard with more Directory related information, and a…
…dd the Architectural Decision for symbology
- Loading branch information
Showing
3 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
docs/docs/developers/decisions/20241009-styling-of-layers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
# 2024-10-09 - Laagstijlen / Symbologie | ||
|
||
| | | | ||
|------------|--------------| | ||
| **Datum** | 09-10-2024 | | ||
| **Status** | Geaccepteerd | | ||
|
||
## Context | ||
|
||
Als uitkomst van dit voorstel willen we dat Netherlands3D gebruik maakt van visualisaties waarbij lagen worden | ||
gestileerd met behulp van symbologie, gebaseerd op de **OGC Cartographic Symbology - Part 1: Core Model & Encodings** | ||
(https://docs.ogc.org/DRAFTS/18-067r4.html). De implementatie is een **systeem vergelijkbaar met CSS**, waarbij een | ||
**Symbolizer** styling-eigenschappen bevat, en **Selectors** (beschreven als **Expressions**) bepalen wanneer en hoe | ||
deze eigenschappen worden toegepast. | ||
|
||
Hoewel de term "symbologie" gebruikelijk is in GIS, noemen we dit systeem "styling" om het toegankelijker te maken voor | ||
een breder publiek en de parallel met CSS te benadrukken. | ||
|
||
!!! warning "Scheiding tussen Styling en Visualisatie" | ||
|
||
Het styling-systeem zelf doet **niets** met de daadwerkelijke visualisatie. Het systeem beschrijft alleen hoe de | ||
styling moet zijn, maar het is aan de visualisatiecode die hoort bij een laag om te bepalen of en hoe de | ||
styling-eigenschappen worden toegepast. Dit betekent dat het mogelijk is dat bepaalde styling-eigenschappen **niet** | ||
worden toegepast als de visualisatiecode daarvoor geen ondersteuning biedt. | ||
|
||
## Besluit | ||
|
||
We implementeren een flexibel styling-systeem waarin **Symbolizers** styling-eigenschappen bevatten, en **Selectors** en | ||
**Expressions** bepalen wanneer deze eigenschappen van toepassing zijn. Dit systeem wordt toegepast op lagen, en de | ||
mogelijke waarden binnen een Symbolizer worden bepaald door de aanwezige **Symbolizer-extensies**. | ||
|
||
Externe partijen kunnen hun eigen extensies en **styling-eigenschap prefixes** toevoegen, volgens het patroon uit | ||
hoofdstuk 8.1.7 van de OGC-specificatie: `vendor.<vendor naam>.<eigenschap naam>`. Voor Netherlands3D betekent dit dat | ||
we de prefix `vendor.netherlands3d.<eigenschap naam>` zullen hanteren. | ||
|
||
## Rationale | ||
|
||
Het gebruik van een systeem, vergelijkbaar met CSS, biedt de flexibiliteit en uitbreidbaarheid die nodig is voor het | ||
werken met dynamische geodata. Door selectors en expressies te gebruiken, kunnen we styling-eigenschappen toepassen op | ||
basis van attribuutwaarden of andere condities. Symbolizer-extensies zorgen ervoor dat nieuwe styling-eigenschappen | ||
kunnen worden toegevoegd zonder de kernstructuur te verstoren. Door gebruik te maken van extension methods met | ||
default-waarden, waarborgen we een voorspelbare werking van het systeem, zelfs wanneer geen expliciete waarde aanwezig | ||
is. | ||
|
||
## Codeorganisatie | ||
|
||
De implementatie van het systeem wordt ondergebracht in een aparte **OpenUPM-package**. De code voor de verschillende | ||
**Symbolizer-extensies** wordt georganiseerd in mappen, waarbij iedere extensie een **Requirement Class** uit de | ||
OGC-specificatie volgt. Dit maakt het beheer van verschillende extensies overzichtelijk en zorgt voor een heldere | ||
scheiding tussen kernfunctionaliteit en uitbreidingen. | ||
|
||
Wij passen zelf de **styling-eigenschap prefix** `vendor.netherlands3d.<eigenschap naam>` toe voor onze eigen | ||
uitbreidingen. Derde partijen kunnen hun eigen extensies via hun eigen packages toevoegen en daarbij hun eigen | ||
**styling-eigenschap prefixes** introduceren volgens hetzelfde patroon uit hoofdstuk 8.1.7 van de OGC-specificatie. | ||
|
||
## Implementatiestrategie | ||
|
||
We voeren de implementatie **stapsgewijs** uit. Dit houdt in dat we niet alle eigenschappen van de Symbolizer in één | ||
keer toevoegen, maar in kleine iteraties werken. Elke iteratie implementeert één of meer specifieke **eigenschappen** | ||
van de Symbolizer, afhankelijk van de eisen van een user story. Bijvoorbeeld: wanneer een user story vraagt om een laag | ||
een enkele vulkleur te geven, wordt alleen de **fill**-eigenschap van de Symbolizer-extensie voor vectorfeatures | ||
geïmplementeerd. | ||
|
||
Hoewel hoofdstuk 17 van de OGC-specificatie extra opties beschrijft zoals het gebruik van het "alter" veld, variabelen | ||
en het includen van stylesheets, zullen we deze opties expliciet **niet** implementeren. Ons doel is niet om de | ||
volledige specificatie te implementeren, maar om de organisatiestructuur van symbolizers, expressies en styling te | ||
adopteren. Dit voorkomt dat we het wiel opnieuw uitvinden, maar zorgt ervoor dat we ons beperken tot een basisstructuur | ||
die ons flexibiliteit biedt zonder de complexiteit van volledige implementatie. | ||
|
||
## Implementatie | ||
|
||
```mermaid | ||
classDiagram | ||
namespace Netherlands3D { | ||
class Layers | ||
} | ||
namespace Layers { | ||
class LayerData { | ||
+LayerStyle styles | ||
} | ||
class Styles | ||
} | ||
namespace Styles { | ||
class LayerStyle { | ||
+StylingRule stylingRules | ||
+Metadata metadata | ||
} | ||
class Metadata { | ||
+ string name | ||
} | ||
class StylingRule { | ||
+string name | ||
+Symbolizer symbolizer | ||
+Expression selector | ||
} | ||
class Expression { | ||
} | ||
class Symbolizer { | ||
- Dictionary properties | ||
~ void GetProperty(string name) | ||
~ object SetProperty(string name, object value) | ||
} | ||
class CoreSymbolizerExtension { | ||
+GetVisibility() bool | ||
+SetVisibility(bool visible) | ||
+GetOpacity() float | ||
+SetOpacity(float opacity) | ||
} | ||
class VectorSymbolizerExtension { | ||
+GetFill() Color | ||
+SetFill(Color fillColor) | ||
} | ||
} | ||
LayerData --> "0..*" LayerStyle | ||
LayerStyle --> "0..*" StylingRule | ||
LayerStyle --> "0..1" Metadata | ||
StylingRule --> "0..1" Symbolizer | ||
StylingRule --> "0..1" Expression | ||
CoreSymbolizerExtension .. Symbolizer : extension of | ||
VectorSymbolizerExtension .. Symbolizer : extension of | ||
``` | ||
|
||
!!! note "Let op" | ||
|
||
We wijken in de naamgeving af van de beschrijving in de OGC standaard bij de LayerStyle klasse, in de OGC standaard | ||
heeft deze enkel `Style`, maar om consistent te zijn in de applicatie en ter verduidelijking voegen wij het | ||
voorzetsel `Layer` toe om te benadrukken dat dit een style is behorende bij layers; vergelijkbaar | ||
met `LayerPropertyData` | ||
|
||
### Opslag van Stijlen in het Projectbestand | ||
|
||
Elke **layer** in het projectbestand krijgt een nieuw veld genaamd **"styles"** waarin de stylinginformatie wordt | ||
opgeslagen. Dit veld verwijst naar een JSON-structuur die hetzelfde formaat is zoals gedefinieerd in hoofdstuk 17 van de | ||
**OGC Cartographic Symbology - Part 1: Core Model & Encodings** OGC-standaard. Hierdoor kunnen we stijlen opnieuw laden | ||
en heen en weer converteren tussen het interne representatiemodel en het JSON-bestand. Dit zorgt ervoor dat stijlen | ||
behouden blijven wanneer ze eenmaal gedefinieerd zijn. | ||
|
||
!!!warning "Technische Vereisten voor Serialization" | ||
|
||
Omdat het hele projectbestand wordt geserialized met **Newtonsoft's JSON.net**, moet de klassestructuur van de | ||
symbolizers ook in dit format worden geserialized. Dit waarborgt strict typing en maakt het consistent met de rest | ||
van het project. | ||
|
||
Voor de Symbolizer zal een aparte JsonConverter geschreven moeten worden die ervoor zorgt dat de waarden in | ||
de `properties` dictionary als losse velden direct in de JSON voor het symbolizer object verschijnen en niet dat een | ||
extra veld `properties` in de JSON terecht komt. | ||
|
||
### Expressions, en Selectors | ||
|
||
Bij het implementeren van **expressions** en **selectors** volgen we de structuur zoals beschreven in hoofdstuk 8.1.5 | ||
van de **OGC Cartographic Symbology - Part 1: Core Model & Encodings**. Net als bij de styling-eigenschappen, zullen we | ||
de expressie-taal niet in één keer volledig implementeren, maar stap voor stap, afhankelijk van de vereisten van user | ||
stories. | ||
|
||
!!!example "Voorbeeld" | ||
|
||
Een voorbeeld hiervan is een user story waarin we een groep features kleuren op basis van een attribuutwaarde. Voor deze | ||
implementatie hebben we alleen de volgende onderdelen nodig: | ||
|
||
- Een **vergelijkingsoperator** (alleen gelijkheid), | ||
- Een **attribuut-identiteits-expressie** (om het attribuut aan te duiden), | ||
- Een **TextLiteral-expressie** (om de letterlijke waarde te beschrijven). | ||
|
||
Dit iteratieve proces maakt het mogelijk om gericht de functionaliteiten toe te voegen die direct noodzakelijk zijn voor | ||
de behoeften van de gebruikers. | ||
|
||
## Risico's | ||
|
||
De OGC Cartographic Symbology-standaard bevindt zich in een draft-stadium, wat betekent dat de specificaties nog kunnen | ||
veranderen. We accepteren dat onze implementatie niet volledig overeenkomt met de definitieve specificatie, en houden | ||
hier rekening mee in toekomstige aanpassingen. | ||
|
||
## Appendix A: Woordenlijst | ||
|
||
- **OGC Cartographic Symbology-standaard**: De standaard waarop het styling-systeem is gebaseerd. | ||
- **Layer**: Een verzameling van geografische objecten die in een bepaalde stijl worden weergegeven. | ||
- **Styling**: Het toekennen van visuele eigenschappen aan geografische objecten. | ||
- **Style**: Een verzameling van stylingregels die wordt toegepast op een layer. | ||
- **Styling-eigenschap**: Een specifieke visuele eigenschap, zoals kleur of lijnstijl, die wordt toegepast op een | ||
object. | ||
- **Symbolizer**: Een object dat styling-eigenschappen bevat voor lagen. | ||
- **Symbologie**: Een GIS-term voor het beschrijven van hoe geografische objecten visueel worden weergegeven. | ||
- **Selector**: Een conditie die bepaalt wanneer een symbolizer moet worden toegepast. | ||
- **Expression**: Een voorwaarde of waarde die bepaalt hoe en wanneer een bepaalde styling-eigenschap wordt toegepast. | ||
- **Symbolizer-extensie**: Uitbreidingen die nieuwe styling-eigenschappen toevoegen aan de Symbolizer. | ||
- **Styling-eigenschap prefix**: Een voorvoegsel toegevoegd aan eigen styling-eigenschappen om conflicten met | ||
OGC-gedefinieerde eigenschappen te voorkomen, zoals beschreven in hoofdstuk 8.1.7 van de OGC-specificatie. | ||
|
||
## Appendix B: Voorbeeld flow voor het wijzigen van kleur | ||
|
||
Wanneer een gebruiker de kleur van een laag aanpast in de UI, doorloopt de applicatie de volgende stappen: | ||
|
||
```mermaid | ||
graph TD | ||
A[Gebruiker past kleur aan in UI] --> B[UI haalt huidige laag op] | ||
B --> C[UI zoekt standaard stylingregel op en haalt Symbology object op] | ||
C --> D[UI roept SetFillColor aan op Symbology-object] | ||
D --> E[Symbology slaat nieuwe kleur op in private dictionary] | ||
subgraph Update van visualisatie | ||
E --> F[Laag triggert update naar visualisatieklasse] | ||
F --> G[Visualisatieklasse haalt Symbology op] | ||
G --> H[Visualisatieklasse leest FillColor uit] | ||
H --> I[Visualisatieklasse past nieuwe kleur toe] | ||
end | ||
I --> J[Visualisatie wordt bijgewerkt] | ||
``` | ||
|
||
1. **Gebruiker past kleur aan in UI**: De gebruiker kiest een nieuwe kleur voor een laag. | ||
2. **UI haalt huidige laag en standaard stylingregel op**: De UI haalt de geselecteerde laag en de standaard | ||
stylingregel op, inclusief het bijbehorende Symbology-object. | ||
3. **Symbology-object bijwerken**: De UI roept de `SetFillColor` method aan op het Symbology-object, dat de nieuwe kleur | ||
opslaat in een private dictionary. | ||
4. **Update van visualisatie**: De laag triggert een update naar de visualisatieklasse, die vervolgens het | ||
Symbology-object ophaalt, de nieuwe kleur uitleest, en deze toepast op de visualisatie. | ||
5. **Visualisatie wordt bijgewerkt**: De visualisatie wordt automatisch bijgewerkt om de nieuwe stijl van de laag te | ||
reflecteren. | ||
|
||
Het updaten van de visualisatie is een herbruikbaar blok dat niet alleen in deze flow kan worden ingezet, maar ook bij | ||
het openen van een project. Door de scheiding tussen de symbologie data en de visualisatie kan, vergelijkbaar met de | ||
scheiding tussen LayerData en visualisatie, styling in het project uniform worden opgeslagen. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Architectural Decisions | ||
|
||
In the Netherlands3D project, we recognize the importance of documenting key architectural decisions to ensure that the | ||
rationale behind our choices is clear, traceable, and accessible to all contributors and stakeholders. This section | ||
serves as a living document where we track these decisions, both accepted and rejected, to provide a transparent record | ||
of our technical direction. | ||
|
||
## Why Track Architectural Decisions? | ||
|
||
Architectural decisions often shape the foundation of a project and influence how future features are built. By | ||
documenting these decisions: | ||
|
||
* **We ensure clarity and alignment**: Everyone working on the project understands why certain paths were chosen over | ||
others. | ||
* **We maintain consistency**: Having a record of decisions helps to maintain a coherent and stable architectural vision | ||
as the project evolves. | ||
* **We enable future-proofing**: Teams and future developers can reference past decisions to avoid re-evaluating or | ||
re-implementing resolved issues. | ||
* **We encourage informed collaboration**: It creates an open dialogue for discussing technical options and ensures | ||
everyone has access to the decision-making process. | ||
|
||
## What to Expect | ||
|
||
In this section, you will find a record of: | ||
|
||
* **Accepted proposals**: Decisions that have been approved and are guiding the current development. | ||
* **Rejected proposals**: Ideas that were considered but ultimately not adopted, along with the reasons why. | ||
* **Ongoing discussions**: Some entries may reflect decisions that are still under consideration, providing insight into | ||
our ongoing thought process. | ||
|
||
Each architectural decision is written in a lightweight, actionable format that includes a summary of the problem, the | ||
considered options, the decision taken, and the rationale behind it. We strive to keep these entries concise while | ||
capturing the essential technical and business context. | ||
|
||
## Language Considerations | ||
|
||
Since the core Netherlands3D team operates primarily in Dutch, many architectural proposals and discussions will | ||
initially be documented in Dutch. This allows us to facilitate faster and more in-depth discussions within the team. | ||
However, we strive to provide English translations for most of these decisions to ensure that non-Dutch speakers can | ||
follow and contribute to the project. Whenever possible, both Dutch and English versions of each decision will be | ||
available. |