Skip to content

Commit

Permalink
refactor(TileBuilder): convert to TypeScript
Browse files Browse the repository at this point in the history
Improve performance by using statically-sized ArrayBuffers.
Reorganize code to get rid of some of the params/builder mess.
Cleanup computeBuffers function.

Squashed commit history (oldest to youngest):
- fix: UV_1 generation
- refacto(wip): cleanup and optimize computeBuffers
- refacto(wip): improve index generation
- wip: correct offset, off-by-one still at large
- fix: change calls to allow camera debug
- fix: found the error, off by a power of 2 actually
- fix(uv): correct indices passed to UV buffering
- fix(index): only generate buffer when needed
- wip: enable cache
- fix(computeBuffers): group tile and skirt together
- fix(wip): squash rogue private field access
- refacto: convert TileGeometry to TypeScript
- style(builders): make method visibility explicit
- refactor(exports): remove default exports
- feat(TileGeometry): add OBB type
- refactor: rename BuilderEllipsoidTile, fix imports
- fix(tileGeometry): update tests to use public api
- fix(TileBuilder): remove dead code comments
  • Loading branch information
HoloTheDrunk committed Nov 12, 2024
1 parent c862ca7 commit 55a01e7
Show file tree
Hide file tree
Showing 17 changed files with 950 additions and 573 deletions.
7 changes: 4 additions & 3 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ module.exports = {
devDependencies: ['test/**', 'tests/**', 'examples/**'],
}], */
'import/no-extraneous-dependencies': 'off',
'import/prefer-default-export': 'off',

// TODO reactivate all the following rules

Expand Down Expand Up @@ -95,9 +96,9 @@ module.exports = {
'error',
'ignorePackages',
{
'js': 'never',
'ts': 'never',
'tsx': 'never',
js: 'never',
ts: 'never',
tsx: 'never',
},
],
camelcase: 'off',
Expand Down
6 changes: 3 additions & 3 deletions src/Converter/convertToTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as THREE from 'three';
import TileMesh from 'Core/TileMesh';
import LayeredMaterial from 'Renderer/LayeredMaterial';
import newTileGeometry from 'Core/Prefab/TileBuilder';
import { newTileGeometry } from 'Core/Prefab/TileBuilder';
import ReferLayerProperties from 'Layer/ReferencingLayerProperties';
import { geoidLayerIsVisible } from 'Layer/GeoidLayer';

Expand Down Expand Up @@ -52,7 +52,7 @@ export default {

return newTileGeometry(builder, paramsGeometry).then((result) => {
// build tile mesh
result.geometry._count++;
result.geometry.increaseRefCount();
const crsCount = layer.tileMatrixSets.length;
const material = new LayeredMaterial(layer.materialOptions, crsCount);
ReferLayerProperties(material, layer);
Expand All @@ -61,7 +61,7 @@ export default {

if (parent && parent.isTileMesh) {
// get parent extent transformation
const pTrans = builder.computeSharableExtent(parent.extent);
const pTrans = builder.computeShareableExtent(parent.extent);
// place relative to his parent
result.position.sub(pTrans.position).applyQuaternion(pTrans.quaternion.invert());
result.quaternion.premultiply(pTrans.quaternion);
Expand Down
126 changes: 0 additions & 126 deletions src/Core/Prefab/Globe/BuilderEllipsoidTile.js

This file was deleted.

4 changes: 2 additions & 2 deletions src/Core/Prefab/Globe/GlobeLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as THREE from 'three';
import TiledGeometryLayer from 'Layer/TiledGeometryLayer';
import { ellipsoidSizes } from 'Core/Math/Ellipsoid';
import { globalExtentTMS, schemeTiles } from 'Core/Tile/TileGrid';
import BuilderEllipsoidTile from 'Core/Prefab/Globe/BuilderEllipsoidTile';
import { GlobeTileBuilder } from 'Core/Prefab/Globe/GlobeTileBuilder';
import CRS from 'Core/Geographic/Crs';

// matrix to convert sphere to ellipsoid
Expand Down Expand Up @@ -57,7 +57,7 @@ class GlobeLayer extends TiledGeometryLayer {
CRS.tms_3857,
];
const uvCount = config.tileMatrixSets.length;
const builder = new BuilderEllipsoidTile({ crs: 'EPSG:4978', uvCount });
const builder = new GlobeTileBuilder({ crs: 'EPSG:4978', uvCount });

super(id, object3d || new THREE.Group(), schemeTile, builder, config);

Expand Down
170 changes: 170 additions & 0 deletions src/Core/Prefab/Globe/GlobeTileBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import * as THREE from 'three';
import Coordinates from 'Core/Geographic/Coordinates';
import Extent from 'Core/Geographic/Extent';
import {
Projected,
ShareableExtent,
TileBuilder,
TileBuilderParams,
} from '../TileBuilder';

const PI_OV_FOUR = Math.PI / 4;
const INV_TWO_PI = 1.0 / (Math.PI * 2);
const axisZ = new THREE.Vector3(0, 0, 1);
const axisY = new THREE.Vector3(0, 1, 0);
const quatToAlignLongitude = new THREE.Quaternion();
const quatToAlignLatitude = new THREE.Quaternion();
const quatNormalToZ = new THREE.Quaternion();

function WGS84ToOneSubY(latitude: number) {
return 1.0 - (0.5 - Math.log(Math.tan(
PI_OV_FOUR + THREE.MathUtils.degToRad(latitude) * 0.5,
)) * INV_TWO_PI);
}

export interface GlobeTileBuilderParams extends TileBuilderParams {
nbRow: number;
deltaUV1: number;
quatNormalToZ: THREE.Quaternion;
}

export class GlobeTileBuilder
implements TileBuilder<GlobeTileBuilderParams> {
private _crs: string;
private _transform: {
coords: Coordinates[];
position: THREE.Vector3;
dimension: THREE.Vector2;
};

public computeExtraOffset?: (params: GlobeTileBuilderParams) => number;

public get crs(): string {
return this._crs;
}

public constructor(options: {
crs: string,
uvCount: number,
}) {
this._transform = {
coords: [
new Coordinates('EPSG:4326', 0, 0),
new Coordinates('EPSG:4326', 0, 0),
],
position: new THREE.Vector3(),
dimension: new THREE.Vector2(),
};

this._crs = options.crs;
// Order crs projection on tiles

// UV: Normalized coordinates (from degree) on the entire tile
// EPSG:4326
// Offset: Float row coordinate from Pseudo mercator coordinates
// EPSG:3857
if (options.uvCount > 1) {
this.computeExtraOffset = GlobeTileBuilder._computeExtraOffset;
}
}

private static _computeExtraOffset(params: GlobeTileBuilderParams): number {
const t = WGS84ToOneSubY(params.projected.latitude) * params.nbRow;
return (!isFinite(t) ? 0 : t) - params.deltaUV1;
}

// prepare params
// init projected object -> params.projected
public prepare(params: TileBuilderParams): GlobeTileBuilderParams {
const nbRow = 2 ** (params.level + 1.0);
let st1 = WGS84ToOneSubY(params.extent.south);

if (!isFinite(st1)) { st1 = 0; }

const sizeTexture = 1.0 / nbRow;

const start = (st1 % (sizeTexture));

const newParams = {
nbRow,
deltaUV1: (st1 - start) * nbRow,
// transformation to align tile's normal to z axis
quatNormalToZ: quatNormalToZ.setFromAxisAngle(
axisY,
-(Math.PI * 0.5 - THREE.MathUtils.degToRad(
params.extent.center().latitude,
))),
// let's avoid building too much temp objects
projected: new Projected(),
};

params.extent.planarDimensions(this._transform.dimension);

return { ...params, ...newParams };
}

// get center tile in cartesian 3D
public center(extent: Extent) {
return extent.center(this._transform.coords[0])
.as(this.crs, this._transform.coords[1])
.toVector3();
}

// get position 3D cartesian
public vertexPosition(position: THREE.Vector2): THREE.Vector3 {
return this._transform.coords[0]
.setFromValues(position.x, position.y)
.as(this.crs, this._transform.coords[1])
.toVector3(this._transform.position);
}

// get normal for last vertex
public vertexNormal() {
return this._transform.coords[1].geodesicNormal;
}

// coord u tile to projected
public uProject(u: number, extent: Extent): number {
return extent.west + u * this._transform.dimension.x;
}

// coord v tile to projected
public vProject(v: number, extent: Extent): number {
return extent.south + v * this._transform.dimension.y;
}

public computeShareableExtent(extent: Extent): ShareableExtent {
// Compute shareable extent to pool the geometries
// the geometry in common extent is identical to the existing input
// with a transformation (translation, rotation)

// TODO: It should be possible to use equatorial plan symetrie,
// but we should be reverse UV on tile
// Common geometry is looking for only on longitude
const sizeLongitude = Math.abs(extent.west - extent.east) / 2;
const shareableExtent = new Extent(
extent.crs,
-sizeLongitude, sizeLongitude,
extent.south, extent.north,
);

// compute rotation to transform tile to position on ellipsoid
// this transformation takes into account the transformation of the
// parents
const rotLon = THREE.MathUtils.degToRad(
extent.west - shareableExtent.west,
);
const rotLat = THREE.MathUtils.degToRad(
90 - extent.center(this._transform.coords[0]).latitude,
);
quatToAlignLongitude.setFromAxisAngle(axisZ, rotLon);
quatToAlignLatitude.setFromAxisAngle(axisY, rotLat);
quatToAlignLongitude.multiply(quatToAlignLatitude);

return {
shareableExtent,
quaternion: quatToAlignLongitude.clone(),
position: this.center(extent),
};
}
}
2 changes: 1 addition & 1 deletion src/Core/Prefab/Planar/PlanarLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as THREE from 'three';
import TiledGeometryLayer from 'Layer/TiledGeometryLayer';
import { globalExtentTMS } from 'Core/Tile/TileGrid';
import CRS from 'Core/Geographic/Crs';
import PlanarTileBuilder from './PlanarTileBuilder';
import { PlanarTileBuilder } from './PlanarTileBuilder';

/**
* @property {boolean} isPlanarLayer - Used to checkout whether this layer is a
Expand Down
Loading

0 comments on commit 55a01e7

Please sign in to comment.