mirror of
https://github.com/n30nex/CartoLite-Server.git
synced 2026-10-22 12:22:26 +00:00
Merge pull request #25 from n30nex/codex/netgraph-camera-orientation-20261011
Fix inverted 3D Netgraph perspective (0.7.1)
This commit is contained in:
9 files changed
+38
-12
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Copy this file to .env and configure your MQTT feed. No map key or build is needed.
|
||||
# Keep .env and any optional .secrets files private.
|
||||
CARTOLITE_IMAGE=ghcr.io/n30nex/cartolite-server:0.7.0
|
||||
CARTOLITE_IMAGE=ghcr.io/n30nex/cartolite-server:0.7.1
|
||||
CARTOLITE_BIND_ADDR=127.0.0.1
|
||||
CARTOLITE_PORT=8080
|
||||
# Optional CARTO override: see compose.carto.yml and docs/deployment.md.
|
||||
|
||||
@@ -15,8 +15,8 @@ concurrency:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: ghcr.io/n30nex/cartolite-server
|
||||
# Exact published 0.6.4, in addition to the legacy 0.4.1 source migration below.
|
||||
UPGRADE_FROM_IMAGE: ghcr.io/n30nex/cartolite-server@sha256:aac2452b05f6de3a79404e3d2ea807d99543ef38ee67e63a478eb6914d7e8a97
|
||||
# Exact published 0.7.0, in addition to the legacy 0.4.1 source migration below.
|
||||
UPGRADE_FROM_IMAGE: ghcr.io/n30nex/cartolite-server@sha256:33d8a85d5052f7fd220845b0f46d5873b627c6507bd8721bc83713872328b41d
|
||||
|
||||
jobs:
|
||||
backend:
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.7.1 - Correct 3D Netgraph camera orientation
|
||||
|
||||
- Correct the reversed perspective depth so 3D looks down onto the scene: nearby groups appear larger and raised connections sit above the ground.
|
||||
- Keep panning, pointer anchoring, route picking and packet effects aligned with the corrected camera; top-down mode is unchanged.
|
||||
- Add physical camera-orientation regressions alongside the existing projection, gesture, mobile and scale checks.
|
||||
|
||||
## 0.7.0 - 3D Netgraph and connection inspection
|
||||
|
||||
- Start top-down, with a 3D button for raised geographic groups, arched links and depth-aware live packet effects.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ name: cartolite-server
|
||||
|
||||
services:
|
||||
cartolite:
|
||||
image: ${CARTOLITE_IMAGE:-ghcr.io/n30nex/cartolite-server:0.7.0}
|
||||
image: ${CARTOLITE_IMAGE:-ghcr.io/n30nex/cartolite-server:0.7.1}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${CARTOLITE_BIND_ADDR:-127.0.0.1}:${CARTOLITE_PORT:-8080}:8080"
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cartolite-server-web",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cartolite-server-web",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"dependencies": {
|
||||
"maplibre-gl": "6.4.1"
|
||||
},
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cartolite-server-web",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -13,6 +13,24 @@ describe('Netgraph shared 3D geometry', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('views the ground from above: foreground is larger and raised links rise toward the camera', () => {
|
||||
for (const tilt of [Math.PI / 6, GRAPH_TILT, 1.1]) for (const yaw of [-2.8, 0, 1.4]) {
|
||||
const p = new GraphProjection({ ...camera, x: 0, y: 0, zoom: 1, tilt, yaw }, 1200, 800);
|
||||
const point = (y: number, z = 0) => ({ x: y * Math.sin(yaw), y: y * Math.cos(yaw), z });
|
||||
const front = p.project(point(600)), back = p.project(point(-600));
|
||||
expect(front.scale).toBeGreaterThan(1); expect(back.scale).toBeLessThan(1);
|
||||
expect(front.y).toBeGreaterThan(400); expect(back.y).toBeLessThan(400);
|
||||
for (const y of [-600, 0, 600]) {
|
||||
expect(p.project(point(y, 100)).y).toBeLessThan(p.project(point(y)).y);
|
||||
}
|
||||
// A point lifted along the viewing ray stays centered and gets nearer.
|
||||
const alongRay = p.project(point(300 * Math.sin(tilt), 300 * Math.cos(tilt)));
|
||||
expect(alongRay.x).toBeCloseTo(600); expect(alongRay.y).toBeCloseTo(400);
|
||||
expect(alongRay.depth).toBeCloseTo(-300);
|
||||
expect(alongRay.scale).toBeCloseTo(camera.distance / (camera.distance - 300));
|
||||
}
|
||||
});
|
||||
|
||||
it('fits neighbours and arc crests into the space left by desktop and mobile inspectors', () => {
|
||||
const a = { x: -450, y: -100, z: 18 }, b = { x: 900, y: 450, z: 28 };
|
||||
const points = [a, b, graphArcPoint(a, b, 0.5, true)];
|
||||
@@ -47,7 +65,7 @@ describe('Netgraph shared 3D geometry', () => {
|
||||
|
||||
it('clips behind-camera points without drawing or picking a line across the gap', () => {
|
||||
const projection = new GraphProjection({ ...camera, tilt: 1, distance: 1000 }, 1200, 800);
|
||||
expect(projection.project({ x: 0, y: -5000 }).visible).toBe(false);
|
||||
expect(projection.project({ x: 0, y: 5000 }).visible).toBe(false);
|
||||
const broken = [{ x: 0, y: 0, progress: 0 }, { x: 100, y: 100, progress: 0.5, breakBefore: true }, { x: 110, y: 110, progress: 1 }];
|
||||
expect(distanceToGraphPath(broken, 50, 50)).toBeGreaterThan(50);
|
||||
expect(graphPathPoint(broken, 0.25).x).toBeLessThan(0);
|
||||
|
||||
@@ -25,7 +25,9 @@ export class GraphProjection {
|
||||
const dx = point.x - camera.x, dy = point.y - camera.y;
|
||||
const x = dx * this.cy - dy * this.sy, y = dx * this.sy + dy * this.cy;
|
||||
const z = camera.tilt === 0 ? 0 : (point.z ?? 0);
|
||||
const depth = y * this.st - z * this.ct;
|
||||
// The camera sits above the foreground (+y, +z). Screen-down and
|
||||
// depth must be orthogonal; foreground objects are nearer, not farther.
|
||||
const depth = -y * this.st - z * this.ct;
|
||||
const denominator = camera.distance + depth;
|
||||
if (!Number.isFinite(denominator) || denominator < camera.distance * 0.08) return hidden();
|
||||
const scale = camera.tilt === 0 ? 1 : camera.distance / denominator;
|
||||
@@ -38,9 +40,9 @@ export class GraphProjection {
|
||||
ground(x: number, y: number): GraphPoint {
|
||||
const u = (x - this.width / 2) / this.camera.zoom;
|
||||
const v = (y - this.height / 2) / this.camera.zoom;
|
||||
const denominator = Math.max(0.08, this.ct - v * this.st / this.camera.distance);
|
||||
const denominator = Math.max(0.08, this.ct + v * this.st / this.camera.distance);
|
||||
const ry = v / denominator;
|
||||
const rx = u * (1 + ry * this.st / this.camera.distance);
|
||||
const rx = u * (1 - ry * this.st / this.camera.distance);
|
||||
return { x: this.camera.x + rx * this.cy + ry * this.sy,
|
||||
y: this.camera.y - rx * this.sy + ry * this.cy };
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user