From 30bde9da2e83da2f217f16f333a910a2bc04516c Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Wed, 13 May 2026 01:13:23 +0200 Subject: [PATCH] feat: Add tests for spline road mesh generation --- tests/geometry/spline-road-mesh.test.ts | 108 ++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 tests/geometry/spline-road-mesh.test.ts diff --git a/tests/geometry/spline-road-mesh.test.ts b/tests/geometry/spline-road-mesh.test.ts new file mode 100644 index 00000000..fb97ef3e --- /dev/null +++ b/tests/geometry/spline-road-mesh.test.ts @@ -0,0 +1,108 @@ +import { describe, expect, it } from "vitest"; + +import { createScenePath } from "../../src/document/paths"; +import { createTerrain } from "../../src/document/terrains"; +import { buildSplineRoadMeshData } from "../../src/geometry/spline-road-mesh"; + +describe("spline road mesh generation", () => { + it("builds a continuous road strip with arc-length UVs", () => { + const path = createScenePath({ + id: "path-road-mesh-straight", + road: { + enabled: true, + width: 2, + shoulderWidth: 1, + falloff: 0.5, + heightOffset: 0.1, + terrainConform: false, + materialId: null + }, + points: [ + { + id: "point-a", + position: { x: 0, y: 0, z: 0 } + }, + { + id: "point-b", + position: { x: 4, y: 0, z: 0 } + } + ] + }); + + const meshData = buildSplineRoadMeshData({ path }); + + expect(meshData).not.toBeNull(); + expect(meshData?.stationCount).toBe(2); + expect(meshData?.totalLength).toBe(4); + expect(Array.from(meshData!.positions)).toEqual([ + 0, + 0.1, + 1, + 0, + 0.1, + -1, + 4, + 0.1, + 1, + 4, + 0.1, + -1 + ]); + expect(Array.from(meshData!.uvs)).toEqual([0, 0, 1, 0, 0, 4, 1, 4]); + expect(Array.from(meshData!.indices)).toEqual([0, 1, 2, 2, 1, 3]); + }); + + it("conforms road edge vertices to terrain when enabled", () => { + const terrain = createTerrain({ + id: "terrain-road-mesh-conform", + position: { x: 0, y: 1, z: 0 }, + sampleCountX: 3, + sampleCountZ: 3, + cellSize: 1, + heights: [ + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 2 + ] + }); + const path = createScenePath({ + id: "path-road-mesh-conform", + road: { + enabled: true, + width: 2, + shoulderWidth: 0, + falloff: 0, + heightOffset: 0.25, + terrainConform: true, + materialId: null + }, + points: [ + { + id: "point-a", + position: { x: 0, y: 10, z: 1 } + }, + { + id: "point-b", + position: { x: 2, y: 10, z: 1 } + } + ] + }); + + const meshData = buildSplineRoadMeshData({ + path, + terrains: [terrain] + }); + + expect(meshData).not.toBeNull(); + expect(meshData!.positions[1]).toBe(3.25); + expect(meshData!.positions[4]).toBe(1.25); + expect(meshData!.positions[7]).toBe(3.25); + expect(meshData!.positions[10]).toBe(1.25); + }); +});