Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(TileBuilder): migrate to TypeScript #2440

Merged
merged 2 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

5 changes: 3 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';

// matrix to convert sphere to ellipsoid
const worldToScaledEllipsoid = new THREE.Matrix4();
Expand Down Expand Up @@ -61,8 +61,9 @@ class GlobeLayer extends TiledGeometryLayer {
'EPSG:4326',
'EPSG:3857',
];

const uvCount = tileMatrixSets.length;
const builder = new BuilderEllipsoidTile({ crs: 'EPSG:4978', uvCount });
const builder = new GlobeTileBuilder({ uvCount });

super(id, object3d || new THREE.Group(), schemeTile, builder, {
tileMatrixSets,
Expand Down
172 changes: 172 additions & 0 deletions src/Core/Prefab/Globe/GlobeTileBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import * as THREE from 'three';
import Coordinates from 'Core/Geographic/Coordinates';
import Extent from 'Core/Geographic/Extent';
import {
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();

/** Transforms a WGS84 latitude into a usable texture offset. */
function WGS84ToOneSubY(latitude: number): number {
return 1.0 - (0.5 - Math.log(Math.tan(
PI_OV_FOUR + THREE.MathUtils.degToRad(latitude) * 0.5,
)) * INV_TWO_PI);
}

type Transform = {
/** Buffers for 2-part coordinate mapping operations. */
coords: [Coordinates, Coordinates];
position: THREE.Vector3;
dimension: THREE.Vector2;
};

/** Specialized parameters for the [GlobeTileBuilder]. */
export interface GlobeTileBuilderParams extends TileBuilderParams {
/** Number of rows of tiles, essentially the resolution of the globe. */
nbRow: number;
/** Offset of the second texture set. */
deltaUV1: number;
HoloTheDrunk marked this conversation as resolved.
Show resolved Hide resolved
/** Transformation to align a tile's normal to the Z axis. */
quatNormalToZ: THREE.Quaternion;
}

/**
* TileBuilder implementation for the purpose of generating globe (or more
* precisely ellipsoidal) tile arrangements.
*/
export class GlobeTileBuilder
jailln marked this conversation as resolved.
Show resolved Hide resolved
implements TileBuilder<GlobeTileBuilderParams> {
private static _crs: string = 'EPSG:4978';
private static _computeExtraOffset(params: GlobeTileBuilderParams): number {
const t = WGS84ToOneSubY(params.coordinates.latitude) * params.nbRow;
return (!isFinite(t) ? 0 : t) - params.deltaUV1;
}

/**
* Buffer holding information about the tile/vertex currently being
* processed.
*/
private _transform: Transform;

public computeExtraOffset?: (params: GlobeTileBuilderParams) => number;
HoloTheDrunk marked this conversation as resolved.
Show resolved Hide resolved

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

public constructor(options: {
/** Number of unaligned texture sets. */
uvCount: number,
HoloTheDrunk marked this conversation as resolved.
Show resolved Hide resolved
}) {
this._transform = {
coords: [
new Coordinates('EPSG:4326', 0, 0),
new Coordinates('EPSG:4326', 0, 0),
],
position: new THREE.Vector3(),
dimension: new THREE.Vector2(),
};
jailln marked this conversation as resolved.
Show resolved Hide resolved

// 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;
}
}

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
coordinates: new Coordinates(this.crs),
};

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

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

public center(extent: Extent) {
return extent.center(this._transform.coords[0])
.as(this.crs, this._transform.coords[1])
.toVector3();
}

public vertexPosition(coordinates: Coordinates): THREE.Vector3 {
return this._transform.coords[0]
.setFromValues(coordinates.x, coordinates.y)
.as(this.crs, this._transform.coords[1])
.toVector3(this._transform.position);
}

public vertexNormal() {
return this._transform.coords[1].geodesicNormal;
}

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

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

public computeShareableExtent(extent: Extent): ShareableExtent {
// NOTE: It should be possible to take advantage of equatorial plane
// symmetry, for which we'd have to reverse the tile's UVs.
// This would halve the memory requirement when viewing a full globe,
// but that case is not that relevant for iTowns' usual use cases and
// the globe mesh memory usage is already inconsequential.
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 the tile to position on the ellispoid.
// This transformation takes the parents' transformation into account.
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 @@ -2,7 +2,7 @@ import * as THREE from 'three';

import TiledGeometryLayer from 'Layer/TiledGeometryLayer';
import { globalExtentTMS } from 'Core/Tile/TileGrid';
import PlanarTileBuilder from './PlanarTileBuilder';
import { PlanarTileBuilder } from './PlanarTileBuilder';

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