Commit 297334ab authored by Matthias Betz's avatar Matthias Betz
Browse files

Add design spec for OpenGL 3D view



Replaces the JavaFX SubScene/MeshView rendering with an OpenGL viewport
(openglfx-jogl, GL 3.3 core), single global VBO, GPU color-picking, and
baked fake shading. Windows/Linux targets; JavaFX 3D path removed.

Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parents 5c2847ef bd40b396
package de.hft.stuttgart.citydoctor2.webservice.endpoints;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import javax.ws.rs.core.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.junit.Test;
public class ValidationEndpointTest {
@Test
public void testRetrieveXmlReport() throws ClientProtocolException, IOException {
HttpClient client = HttpClients.createMinimal();
LoginValues login = TestUtils.login(client);
HttpGet get = new HttpGet("http://localhost:8080/CityDoctorWebService/rest/models/validations/5/xml");
get.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + login.getToken());
HttpResponse response = client.execute(get);
File file = new File("C:/WebService/test.xml");
Files.copy(response.getEntity().getContent(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
assertTrue(file.exists());
}
@Test
public void testRetrievePdfReport() throws ClientProtocolException, IOException {
HttpClient client = HttpClients.createMinimal();
LoginValues login = TestUtils.login(client);
HttpGet get = new HttpGet("http://localhost:8080/CityDoctorWebService/rest/models/validations/5/pdf");
get.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + login.getToken());
HttpResponse response = client.execute(get);
File file = new File("C:/WebService/test.pdf");
Files.copy(response.getEntity().getContent(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
assertTrue(file.exists());
}
}
......@@ -112,24 +112,6 @@ Contact a Maintainer of this project for further information in this regard.
---
## CityDoctorWebService
Contains a web service implementation for CityDoctor2.
### Usage
> ⚠ This module has been abandoned. As of writing the module is still functional, but it may break at any time.
>Issues, bug reports and suggestions for this module will not be processed.
> ⚠ CityDoctorWebservice requires connection to a PostgreSQL Server. Connection parameters need to be set in the
pgpass.conf file found in the /DBScripts directory.
>
The PostgreSQL Server needs to contain a database called "CityDoctorDB" with a schema called "citydoctordb".
The required tables will be automatically created by the web service if they're missing.
To run the web service, build the module and [deploy CityDoctorWebService.war](https://tomcat.apache.org/tomcat-9.0-doc/deployer-howto.html)
to a Tomcat server (version 8 or 9).
---
## License
......
......@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId>
<version>3.16.0</version>
<version>3.18.3</version>
<packaging>pom</packaging>
<name>CityDoctorParent</name>
<properties>
......@@ -15,15 +15,11 @@
<log4j.version>2.18.0</log4j.version>
<revision>${project.version}</revision>
<nonMavenLibsPath>${project.baseUri}../non-maven-libs</nonMavenLibsPath>
<jre-version-short>17.0.10</jre-version-short>
<jre-version>${jre-version-short}+13</jre-version>
<jre-version-short>17.0.14</jre-version-short>
<jre-version>${jre-version-short}+10</jre-version>
<jfx-version>17.0.12</jfx-version>
</properties>
<repositories>
<repository>
<id>jogl</id>
<url>https://jogamp.org/deployment/maven/</url>
</repository>
<repository>
<id>non-maven-libs</id>
<url>${nonMavenLibsPath}</url>
......@@ -43,56 +39,31 @@
<configuration>
<testFailureIgnore>false</testFailureIgnore>
<excludes>
<exclude>
**/SolidSelfIntCheckFalsePositiveBigMeshTest.java</exclude>
<exclude>**/SolidSelfIntCheckFalsePositiveBigMeshTest.java</exclude>
</excludes>
<excludedGroups>
de.hft.stuttgart.citydoctor2.connect.edge.CppTest
</excludedGroups>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- Source JAR generation -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
<annotationProcessorPaths>
<path>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
<version>4.7.6</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-api</artifactId>
<version>2.15.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-manager</artifactId>
<version>2.15.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-eclipse</artifactId>
<version>2.15.0</version>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
</plugin>
</plugins>
</build>
<dependencyManagement>
......@@ -147,6 +118,12 @@
<artifactId>CityDoctorHealer</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
......@@ -175,7 +152,7 @@
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.7</version>
<version>2.10</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
......@@ -191,7 +168,7 @@
<dependency>
<groupId>org.jogamp.gluegen</groupId>
<artifactId>gluegen-rt-main</artifactId>
<version>2.5.0</version>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>gov.nist.math</groupId>
......@@ -201,7 +178,7 @@
<dependency>
<groupId>org.jogamp.jogl</groupId>
<artifactId>jogl-all-main</artifactId>
<version>2.5.0</version>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
......@@ -231,7 +208,12 @@
<dependency>
<groupId>org.locationtech.proj4j</groupId>
<artifactId>proj4j</artifactId>
<version>1.1.5</version>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.locationtech.proj4j</groupId>
<artifactId>proj4j-epsg</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
......@@ -253,11 +235,31 @@
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.6</version>
</dependency>
<dependency>
<groupId>io.github.earcut4j</groupId>
<artifactId>earcut4j</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.orbisgis</groupId>
<artifactId>h2gis</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>7.0.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
......@@ -267,6 +269,32 @@
<version>4.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<modules>
<!--CityDoctor2 Core Modules-->
......@@ -277,12 +305,10 @@
<!--CityDoctor2 Extension Modules-->
<module>Extensions/CityDoctorGUI</module>
<!--
<module>Extensions/CityDoctorAutoPro</module>
<!-- <module>Extensions/CityDoctorAutoPro</module>-->
<module>Extensions/CityDoctorHealer</module>
<module>Extensions/CityDoctorHealerGenetic</module>
<!-- <module>Extensions/CityDoctorHealerGenetic</module>-->
<module>Extensions/CityDoctorHealerGUI</module>
<module>Extensions/CityDoctorWebService</module>
-->
</modules>
</project>
\ No newline at end of file
! Embedded database configuration
! Remove # at the beginning of a parameter line to override the value.
! Directory for the database file. DEFAULT: \\database\\
# database.directory=\\database\\
! Name of the database file. DEFAULT: cd_db
# database.name=cd_db
! Sets a limit for the number of pooled connections to the embedded database. DEFAULT: 10
! If not overridden CityDoctor will use the number of available CPU cores as limit.
# database.connectionPoolSize=10
! If temp mode is enabled the database-file will be created in the System's TEMP directory. DEFAULT: false
# database.tempMode=false
! If in-memory mode is enabled the database will be created in the Systems RAM. DEFAULT: false
! WARNING: Enabling in-memory mode can lead to out-of-memory errors when loading bigger CityGML files.
# database.inMemoryMode=false
! If fallback is enabled CityDoctor will attempt to use the in-memory mode if database-file creation fails DEFAULT: true
# database.attemptFallback=true
! If debug mode is enabled the embedded database will start in automatic mixed mode DEFAULT: false
! NOTE: Activating this mode will start a local server with random ports. This may trigger a Firewall request, which can be safely denied.
! NOTE: This server is only accessible locally and automatically rejects any remote connections.
# database.debugMode=false
......@@ -4,19 +4,38 @@
CityDoctor2 is a Java program for validating CityGML files. It checks whether certain criteria for e.g. geometries are met and outputs a report on the results.
CityDoctor2 supports version 3.0 of CityGML, with backwards compatibility for versions 2.0 and 1.0.
CityDoctor2 requires Java version 17 or higher.
## Homepage
[Here](https://transfer.hft-stuttgart.de/pages/citydoctor/citydoctorhomepage/de/) is a homepage with more detailed installation instruction and more information about the quality management process itself.
The [CityDoctor homepage](https://transfer.hft-stuttgart.de/pages/citydoctor/citydoctorhomepage/de/) contains detailed
installation instruction, as well as more information about the quality management process itself.
## Releases
The newest releases can be found in this [gitlab repository](https://transfer.hft-stuttgart.de/gitlab/citydoctor/citydoctorreleases).
The latest release of CityDoctor2 can be found under
the [Releases](https://transfer.hft-stuttgart.de/gitlab/citydoctor/citydoctor2/-/releases) tab.
Prebuilt binaries of the latest releases of the validation library (CityDoctorValidation-x.x.x) and the graphical user
interface (CityDoctorGUI-x.x.x) can be found in
this [gitlab repository](https://transfer.hft-stuttgart.de/gitlab/citydoctor/citydoctorreleases).
CityDoctor2 uses [Semantic Versioning](https://semver.org/).
You can download older releases from the BHT page [here](https://projekt.bht-berlin.de/citydoctor2/downloads/) or from a git repository [here](https://gitlab.com/volkercoors/CiD4Sim/-/tree/master/CityDoctorExtension).
### Older releases
Since version 3.12.0 CityDoctor2 requires java version 17, older version are based on version 1.8. The GUI version requires Javafx which is included in Java 1.8 but not in Java 17. You can download a Java version with Javafx included from [here](https://bell-sw.com/pages/downloads/#/java-17-lts). Choose your platform and then choose to download the full JRE or JDK which includes Javafx.
Older versions of CityDoctor2, back to version 3.14.0, can also be found under Releases.
The releases include builds for the validation library (CityDoctorValidation-x.x.x) and the grahpic user interface (CityDoctorGUI-x.x.x). While the GUI is not open source it is free to use.
Versions older than 3.14.0 can be downloaded from the BHT
page [here](https://projekt.bht-berlin.de/citydoctor2/downloads/) or from a git
repository [here](https://gitlab.com/volkercoors/CiD4Sim/-/tree/master/CityDoctorExtension).
Versions older than 3.15.0 require a JDK/JRE with the JavaFx library.
You can download a Java version with Javafx included from [here](https://bell-sw.com/pages/downloads/#/java-17-lts).
Versions older than 3.12.0 require Java version 8 or higher.
## Build
......@@ -24,7 +43,7 @@ Use [Maven](https://maven.apache.org/) to build CityDoctor2.
```bash
cd CityDoctorParent
mvn install
mvn clean install -P create-binaries
```
CityDoctor2 uses the [quality ade plugin](https://transfer.hft-stuttgart.de/gitlab/betzms/qualityade). A jar is provided in a local repository for ease of use.
......@@ -36,13 +55,18 @@ Once built there is a CityDoctorValidation-\<version\>.zip file in the target fo
There is a start script included in the binary releases of citydoctor. An example start command looks like this:
```bash
java -classpath libs/*;plugins/*;CityDoctorValidation-<version>.jar de.hft.stuttgart.citydoctor2.CityDoctorValidation -in <path-to-gml-file>.gml -config <path-to-validation-config>.yml -xmlReport <path-to-xml-output>.xml -pdfReport <path-to-pdf-output>.pdf -out <path-to-output-gml>.gml
java -classpath libs/*;plugins/*;CityDoctorValidation-<version>.jar de.hft.stuttgart.citydoctor2.CityDoctorValidation -in <path-to-gml-file>.gml -config <path-to-validation-config>.yml -xmlReport <path-to-xml-output>.xml -pdfReport <path-to-pdf-output>.pdf -out <path-to-output-gml>.gml -db_location <path-for-database-file> -db_settings <path-to-database-settings-file>.properties
```
Note:
-xmlReport, -pdfReport and -out are optional
Notes:
- -xmlReport, -pdfReport, -out, -db_location and -db_settings are optional
- Paths will be resolved from CityDoctor's working directory
- See [DBSettings.properties](DBSettings.properties) for the formatting of the database-settings file
- The -db_location parameter takes precedence over the location set in the database-settings file
- The start scripts included in the binary releases have -db_location set to the system's temp directory
## Extension
## Extension modules
Example extensions for CityDoctor are included in this repository, and can be found in the [Extensions subdirectory](./CityDoctorParent/Extensions)
alongside a short description for each respective extension.
......
# OpenGL 3D View — Design Spec
**Date:** 2026-06-18
**Branch:** 107-opengl-view
**Component:** `CityDoctorParent/Extensions/CityDoctorGUI`
## 1. Problem & Goal
The GUI renders 3D CityGML geometry with JavaFX, tesselating **each polygon into its own
`TriangleMesh` + `MeshView` + `PhongMaterial`** (see `TriangulatedGeometry`). At city scale this
produces thousands of scene-graph nodes, each with its own material — the JavaFX node overhead, not
just the lack of shader access, makes orbit/zoom stutter or freeze.
**Goal:** Replace the JavaFX `SubScene` 3D view with an OpenGL-rendered viewport that orbits, zooms,
and pans smoothly on whole-city models (millions of triangles), while preserving every existing view
feature (picking, highlights, filters, wireframe, culling, north arrow, screenshot).
## 2. Decisions (settled during brainstorming)
| Topic | Decision |
|-------|----------|
| Scale target | Whole cities, millions of triangles; smooth (30–60 fps) interaction. |
| Integration | Embed an OpenGL canvas via the already-present `openglfx-jogl` (huskerdev) dependency, in the `meshView` `Pane` where the `SubScene` lives today. |
| GL version | OpenGL **3.3 core profile**, GLSL shaders, VAO/VBO. |
| Platforms | **Windows + Linux** are hard targets. macOS bundle still builds but the GL view may degrade — accepted. |
| JavaFX 3D path | **Fully removed** (no fallback). |
| Buffer strategy | **Single global static VBO**; one `glDrawElements` per frame; filter/LOD changes rebuild the draw **index set** (EBO), not the VBO. |
| Picking | **GPU color-picking**: off-screen FBO encodes `polygonId` per fragment; `glReadPixels` on click. |
| Shading | **Keep existing fake shading** (`normal·AXIS` → brightness), **baked into per-vertex color on the CPU** at build time. No lighting in the shader. Normal attribute dropped from the VBO. |
| Selection | Shader `selectedId` uniform tints matching fragments — no buffer mutation. |
| Vertex/edge highlights | Separate small **dynamic** GL overlay buffer (replaces JavaFX `Sphere`/`Cylinder`). |
## 3. Architecture & Components
New/changed classes in `de.hft.stuttgart.citydoctor2.gui` (or a new `gui.gl` sub-package):
- **`GLViewport`** *(new)* — wraps the openglfx canvas, owns the GL context, the render callback, the
`Camera`, and GL resources (shaders, VAO/VBO/EBO, picking FBO, overlay buffer). Replaces the JavaFX
`SubScene`/`world`/`meshGroup`/`PerspectiveCamera`/`AmbientLight` built in `MainWindow.setup3dView`.
- **`SceneBuilder`** *(replaces `TriangulatedGeometry`)* — flattens the model into interleaved vertex
data and the `id → Polygon/Vertex/Edge` maps. Runs on a worker thread (as `Renderer.render` already
does). Reuses existing `Polygon.tesselate()` → `TesselatedPolygon`/`Triangle3d`, the
`findCenter`/`movedBy` recentering, and the `calculateMaterial` shade math.
- **`SceneBuffers`** *(new)* — owns the global VBO + static vertex data and rebuilds/uploads the draw
index set on filter/LOD changes. GL-thread owned; uploads queued from the worker thread.
- **`Camera`** *(new)* — view/projection matrices replicating today's interaction: orbit (Z + X
rotation, today on the `world` group), right-drag pan, scroll zoom, `zoomOutForBoundingBox`,
`resetCamera`. Reuses the existing angle/translate state in `MainWindow`.
- **`PickingPass`** *(new)* — off-screen FBO sized to the canvas; renders the `polygonId` pass and
reads back the cursor pixel on click.
- **`HighlightOverlay`** *(replaces the `Sphere`/`Cylinder` rendering in `HighlightController`)* —
small dynamic buffer for vertex/edge markers, rescaled on zoom like `changeScaling` does now.
- **`Renderer`** *(kept)* — **public API unchanged** (`render(model)`, `render(Geometry)`,
`render(CityObject)`, `highlight(...)`, `showWireFrame`, `enableCulling`, `enableLodN`/`disableLodN`,
`hideRoofs`/`showRoofs`, `clearCurrentRender`, etc.) so `CityDoctorController`, `MainWindow`, and the
error visitors (`ListErrorVisitor`, `GlobalErrorVisitor`) are largely untouched. Internally it drives
`SceneBuilder`/`SceneBuffers`/`GLViewport` instead of the JavaFX `meshGroup`.
## 4. Geometry Pipeline (single global VBO)
At load, off the FX thread:
1. Iterate city objects → polygons → `tesselate()` → triangles, recentered by `movedBy`
(`SceneBuilder.findCenter`, same as today).
2. Build **one interleaved static VBO** with per-vertex attributes:
- `position` — `vec3 float`
- `color` — `vec3 float`, the **baked shaded color** (see §6)
- `polygonId` — `uint` (or packed into a `vec4` for the picking pass)
(No normal attribute — shading is baked, picking/selection use the id.)
3. Build CPU-side maps **`polygonId → Polygon`** (and ids for vertices/edges) — these replace the
per-`MeshView` `userData` dispatchers (`PolygonClickDispatcher`, `VertexClickDispatcher`).
4. Build an **index buffer (EBO)** listing the triangles to draw. The existing `Renderer` filter set
(`lodFilters`, `roofFilter`) determines membership; toggling a filter rebuilds the index array on
the CPU and re-uploads it. The VBO is never touched. One `glDrawElements` per frame.
`polygonId` is a 32-bit value (RGBA8 in the picking FBO → ~4.2B ids), more than enough.
## 5. Render Loop & Threading
- openglfx calls a render callback on its GL render thread with a live context. The callback only
**draws** from prepared buffers (main pass; picking pass on demand; overlay pass).
- GL resource **creation/upload** also happens on the GL thread: `SceneBuilder` runs on a worker
thread and **queues** the prepared arrays; the render callback drains the queue and uploads.
- FX-thread code (filter toggles, tree selection, camera input) sets dirty flags / state the render
callback consumes. No GL calls off the GL thread.
## 6. Shading (baked, fake)
Keep the current surface-differentiation shading. At build time, for each polygon compute exactly as
`TriangulatedGeometry.calculateMaterial` does today:
```
normal = p.calculateNormalNormalized()
base = p.getRenderColor() (if set and not WHITE) else feature base color
acos = Math.acos(normal·AXIS) / Math.PI // AXIS = normalize(19, 0.8, 1.5)
shade = acos * 0.6 + 0.3 // range [0.3, 0.9]
vertexColor = base.deriveColor(0, 1.0, shade, 1.0)
```
Store `vertexColor` as the per-vertex `color` attribute. The fragment shader outputs the interpolated
vertex color directly — no lighting computation in the shader.
## 7. Picking (GPU color-picking)
- A picking shader writes `polygonId` (as RGBA8) into an off-screen FBO sized to the canvas.
- On click, reuse `MainWindow`'s existing press/release "did the mouse move >3px?" gate. Render (or
reuse) the id pass, `glReadPixels` the cursor pixel → `polygonId` → `Polygon`/`Vertex`/`Edge` via the
CPU map → same downstream handling that `PolygonClickDispatcher`/`VertexClickDispatcher` perform now.
- Readback only on click (never per frame) to avoid GPU stalls.
## 8. Selection & Highlights
- **Selection tint:** the main shader takes a `selectedId` uniform (or a small id set); fragments whose
id matches are tinted. Highlighting a clicked polygon needs no buffer mutation.
- **Vertex/edge markers** (today's `HighlightController` spheres/cylinders): drawn from a separate
**dynamic** buffer after the main pass — points/instanced quads for vertices, line segments (or thin
instanced cylinders) for edges — rescaled on zoom as `changeScaling` does today. `HighlightController`
keeps its public API (`highlight(Polygon/LinearRing/Edge/Vertex/...)`, `clearHighlights`,
`changeScaling`, `highlightEdges`, `highlightPolygons`) so callers are unaffected.
## 9. Feature Parity Checklist
All preserved:
- LOD1–LOD4 filters, hide-roofs toggle (index-set rebuild).
- Wireframe (`DrawMode.LINE` → `glPolygonMode(GL_LINE)` with the black grid color).
- Back-face culling toggle (`glEnable/Disable(GL_CULL_FACE)`).
- Per-feature base colors and per-polygon error coloring (`Polygon.getRenderColor()`).
- Vertex/edge/polygon highlighting.
- North-arrow overlay — stays a JavaFX `ImageView` layered on top of the GL canvas in the `meshView`
`Pane`; `alignNorthArrow` logic unchanged.
- Screenshot (`MainWindow.takeViewScreenshot`) — `glReadPixels` of the framebuffer → `BufferedImage` →
PNG, replacing `SubScene.snapshot`.
- Camera orbit/pan/zoom, `resetCamera`, `zoomOutForBoundingBox`.
## 10. Removals
- `TriangulatedGeometry` (replaced by `SceneBuilder`/`SceneBuffers`).
- The JavaFX 3D scene in `MainWindow.setup3dView`: `SubScene geomScene`, `world`/`meshGroup` groups,
`PerspectiveCamera`, `AmbientLight`, `cameraXRotation`/`cameraZRotation` transforms, and
`getMeshGroup()`.
- `Sphere`/`Cylinder` rendering inside `HighlightController` (logic moves to `HighlightOverlay`).
- Mesh-level JavaFX picking (`pickResult.getIntersectedNode()` → replaced by color-picking).
## 11. Risks & Mitigations
- **Native lib packaging:** openglfx + JOGL natives must ship in the win/lin assembly descriptors
(`src/assembly/{win,lin}/assembly.xml`). Verify the assembled bundles launch and render.
- **GL context lifecycle vs JavaFX resize:** handle canvas resize (recreate picking FBO, update
viewport/projection).
- **Picking readback stalls:** mitigated by reading only on click.
- **macOS degradation:** accepted; not a hard target.
## 12. Testing
- **Unit (headless):** `SceneBuilder` flattening — vertex/triangle counts, `id → Polygon` mapping
correctness, recentering by `movedBy`, baked-color math matches `calculateMaterial`.
- **Manual/visual:** rendering correctness, picking accuracy (click → correct polygon/vertex/edge),
filter/LOD/roof toggles, wireframe, culling, highlights, north arrow, screenshot, camera controls —
on a large city model, confirming smooth interaction.
## 13. Out of Scope
- LOD-of-detail mesh simplification / frustum culling / occlusion culling (single global VBO + one draw
call is expected to suffice; revisit only if profiling shows a need).
- macOS-specific GL/threading work.
- Any change to validation, parsing, or non-GUI modules.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment