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

Refactors the Projection classed only #5163

Merged
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
3 changes: 2 additions & 1 deletion src/geo/projection/covering_tiles.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {beforeEach, describe, expect, test} from 'vitest';
import {GlobeTransform} from './globe_transform';
import {globeConstants, type GlobeProjection} from './globe';
import {type GlobeProjection} from './globe_projection';
import {getGlobeProjectionMock} from '../../util/test/util';
import {LngLat} from '../lng_lat';
import {coveringTiles, coveringZoomLevel, type CoveringZoomOptions} from './covering_tiles';
import {OverscaledTileID} from '../../source/tile_id';
import {MercatorTransform} from './mercator_transform';
import {globeConstants} from './vertical_perspective_projection';

describe('coveringTiles', () => {
describe('globe', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/geo/projection/globe_camera_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {normalizeCenter} from '../transform_helper';
import {interpolates} from '@maplibre/maplibre-gl-style-spec';

import type {IReadonlyTransform, ITransform} from '../transform_interface';
import type {GlobeProjection} from './globe';
import type {GlobeProjection} from './globe_projection';
import type {CameraForBoundsOptions} from '../../ui/camera';
import type {LngLatBounds} from '../lng_lat_bounds';
import type {PaddingOptions} from '../edge_insets';
Expand Down
143 changes: 143 additions & 0 deletions src/geo/projection/globe_projection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {type ProjectionDefinition, type ProjectionDefinitionSpecification, type ProjectionSpecification, type StylePropertySpecification, latest as styleSpec} from '@maplibre/maplibre-gl-style-spec';
import {DataConstantProperty, type PossiblyEvaluated, Properties, Transitionable, type Transitioning, type TransitionParameters} from '../../style/properties';
import {Evented} from '../../util/evented';
import {EvaluationParameters} from '../../style/evaluation_parameters';
import {MercatorProjection} from './mercator_projection';
import {VerticalPerspectiveProjection} from './vertical_perspective_projection';
import {type Projection, type ProjectionGPUContext, type TileMeshUsage} from './projection';
import {type PreparedShader} from '../../shaders/shaders';
import {type SubdivisionGranularitySetting} from '../../render/subdivision_granularity_settings';
import {type Context} from '../../gl/context';
import {type CanonicalTileID} from '../../source/tile_id';
import {type Mesh} from '../../render/mesh';

type ProjectionProps = {
type: DataConstantProperty<ProjectionDefinition>;
}

type ProjectionPossiblyEvaluated = {
type: ProjectionDefinitionSpecification;
}

const properties: Properties<ProjectionProps> = new Properties({
'type': new DataConstantProperty(styleSpec.projection.type as StylePropertySpecification)
});

export class GlobeProjection extends Evented implements Projection {
properties: PossiblyEvaluated<ProjectionProps, ProjectionPossiblyEvaluated>;

_transitionable: Transitionable<ProjectionProps>;
_transitioning: Transitioning<ProjectionProps>;
_mercatorProjection: MercatorProjection;
_verticalPerspectiveProjection: VerticalPerspectiveProjection;

// HM TODO: remove this in the future
_useGlobeRendering: boolean = false;

constructor(projection?: ProjectionSpecification) {
super();
this._transitionable = new Transitionable(properties);
this.setProjection(projection);
this._transitioning = this._transitionable.untransitioned();
this.recalculate(new EvaluationParameters(0));
this._mercatorProjection = new MercatorProjection();
this._verticalPerspectiveProjection = new VerticalPerspectiveProjection();
}

public get transitionState(): number {
const currentProjectionSpecValue = this.properties.get('type');
if (typeof currentProjectionSpecValue === 'string' && currentProjectionSpecValue === 'mercator') {
return 0;
}
if (typeof currentProjectionSpecValue === 'string' && currentProjectionSpecValue === 'vertical-perspective') {
return 1;
}

Check warning on line 54 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L48-L54

Added lines #L48 - L54 were not covered by tests
// HM TODO: check this!
if ('transition' in (currentProjectionSpecValue as any)) {
return (currentProjectionSpecValue as any).transition;
};
return 1;

Check warning on line 59 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L56-L59

Added lines #L56 - L59 were not covered by tests
}

get useGlobeRendering(): boolean {
return this._useGlobeRendering;
}

set useGlobeRendering(value: boolean) {
this._useGlobeRendering = value;
}

get errorQueryLatitudeDegrees(): number { return this._verticalPerspectiveProjection.errorQueryLatitudeDegrees; }
set errorQueryLatitudeDegrees(value: number) { this._verticalPerspectiveProjection.errorQueryLatitudeDegrees = value; }
get latitudeErrorCorrectionRadians(): number { return this._verticalPerspectiveProjection.latitudeErrorCorrectionRadians; }

private get currentProjection(): Projection {
return this.useGlobeRendering ? this._verticalPerspectiveProjection : this._mercatorProjection;
}

setProjection(projection?: ProjectionSpecification) {
this._transitionable.setValue('type', projection?.type || 'mercator');
}

updateTransitions(parameters: TransitionParameters) {
this._transitioning = this._transitionable.transitioned(parameters, this._transitioning);

Check warning on line 83 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L83

Added line #L83 was not covered by tests
}

hasTransition() {
return this._transitioning.hasTransition();

Check warning on line 87 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L87

Added line #L87 was not covered by tests
}

recalculate(parameters: EvaluationParameters) {
this.properties = this._transitioning.possiblyEvaluate(parameters);
}

get name(): ProjectionSpecification['type'] {
return 'globe';
}

get useSubdivision(): boolean {
return this.currentProjection.useSubdivision;
}

get shaderVariantName(): string {
return this.currentProjection.shaderVariantName;
}

get shaderDefine(): string {
return this.currentProjection.shaderDefine;
}

get shaderPreludeCode(): PreparedShader {
return this.currentProjection.shaderPreludeCode;
}

get vertexShaderPreludeCode(): string {
return this.currentProjection.vertexShaderPreludeCode;

Check warning on line 115 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L115

Added line #L115 was not covered by tests
}

get subdivisionGranularity(): SubdivisionGranularitySetting {
return this.currentProjection.subdivisionGranularity;
}

get useGlobeControls(): boolean {
return this.transitionState > 0;

Check warning on line 123 in src/geo/projection/globe_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/globe_projection.ts#L123

Added line #L123 was not covered by tests
}

public destroy(): void {
this._mercatorProjection.destroy();
this._verticalPerspectiveProjection.destroy();
}

public isRenderingDirty(): boolean {
return this.currentProjection.isRenderingDirty(); // HM: TODO: should use hasTransition also
}

public updateGPUdependent(context: ProjectionGPUContext): void {
this._mercatorProjection.updateGPUdependent(context);
this._verticalPerspectiveProjection.updateGPUdependent(context);
}

public getMeshFromTileID(context: Context, _tileID: CanonicalTileID, _hasBorder: boolean, _allowPoles: boolean, _usage: TileMeshUsage): Mesh {
return this.currentProjection.getMeshFromTileID(context, _tileID, _hasBorder, _allowPoles, _usage);
}
}
3 changes: 2 additions & 1 deletion src/geo/projection/globe_transform.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {describe, expect, test} from 'vitest';
import {globeConstants, type GlobeProjection} from './globe';
import {type GlobeProjection} from './globe_projection';
import {EXTENT} from '../../data/extent';
import Point from '@mapbox/point-geometry';
import {LngLat} from '../lng_lat';
Expand All @@ -10,6 +10,7 @@ import {expectToBeCloseToArray, getGlobeProjectionMock, sleep} from '../../util/
import {MercatorCoordinate} from '../mercator_coordinate';
import {tileCoordinatesToLocation} from './mercator_utils';
import {MercatorTransform} from './mercator_transform';
import {globeConstants} from './vertical_perspective_projection';

function testPlaneAgainstLngLat(lngDegrees: number, latDegrees: number, plane: Array<number>) {
const lat = latDegrees / 180.0 * Math.PI;
Expand Down
3 changes: 2 additions & 1 deletion src/geo/projection/globe_transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {LngLat, type LngLatLike,} from '../lng_lat';
import {createMat4f32, createMat4f64, differenceOfAnglesDegrees, easeCubicInOut, lerp, warnOnce} from '../../util/util';
import {OverscaledTileID, type UnwrappedTileID, type CanonicalTileID} from '../../source/tile_id';
import {browser} from '../../util/browser';
import {globeConstants, type GlobeProjection} from './globe';
import {type GlobeProjection} from './globe_projection';
import {EXTENT} from '../../data/extent';

import type Point from '@mapbox/point-geometry';
Expand All @@ -19,6 +19,7 @@ import type {IReadonlyTransform, ITransform, TransformUpdateResult} from '../tra
import type {PaddingOptions} from '../edge_insets';
import type {ProjectionData, ProjectionDataParams} from './projection_data';
import type {CoveringTilesDetailsProvider} from './covering_tiles_details_provider';
import {globeConstants} from './vertical_perspective_projection';

/**
* Globe transform is a transform that moves between vertical perspective and mercator projections.
Expand Down
4 changes: 2 additions & 2 deletions src/geo/projection/projection_factory.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {type ProjectionSpecification} from '@maplibre/maplibre-gl-style-spec';
import {warnOnce} from '../../util/util';
import {MercatorProjection} from './mercator';
import {MercatorProjection} from './mercator_projection';
import {MercatorTransform} from './mercator_transform';
import {MercatorCameraHelper} from './mercator_camera_helper';
import {GlobeProjection} from './globe';
import {GlobeProjection} from './globe_projection';
import {GlobeTransform} from './globe_transform';
import {GlobeCameraHelper} from './globe_camera_helper';
import {VerticalPerspectiveTransform} from './vertical_perspective_transform';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
import {SubdivisionGranularityExpression, SubdivisionGranularitySetting} from '../../render/subdivision_granularity_settings';
import type {Projection, ProjectionGPUContext, TileMeshUsage} from './projection';
import {type PreparedShader, shaders} from '../../shaders/shaders';
import {MercatorProjection} from './mercator';
import {ProjectionErrorMeasurement} from './globe_projection_error_measurement';
import {createTileMeshWithBuffers, type CreateTileMeshOptions} from '../../util/create_tile_mesh';
import {type EvaluationParameters} from '../../style/evaluation_parameters';

export const VerticalPerspectiveShaderDefine = '#define GLOBE';
export const VerticalPerspectiveShaderVariantKey = 'globe';

export const globeConstants = {
globeTransitionTimeSeconds: 0.5,
Expand All @@ -32,17 +35,9 @@
circle: 3
});

export class GlobeProjection implements Projection {
private _mercator: MercatorProjection;

export class VerticalPerspectiveProjection implements Projection {
private _tileMeshCache: {[_: string]: Mesh} = {};

/**
* Stores whether globe rendering should be used.
* The value is injected from GlobeTransform.
*/
private _useGlobeRendering: boolean = true;

// GPU atan() error correction
private _errorMeasurement: ProjectionErrorMeasurement;
private _errorQueryLatitudeDegrees: number;
Expand All @@ -51,40 +46,28 @@
private _errorCorrectionPreviousValue: number = 0.0;
private _errorMeasurementLastChangeTime: number = -1000.0;

get name(): 'globe' {
return 'globe';
get name(): 'vertical-perspective' {
return 'vertical-perspective';

Check warning on line 50 in src/geo/projection/vertical_perspective_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/vertical_perspective_projection.ts#L50

Added line #L50 was not covered by tests
}

/**
* This property is true when globe rendering and globe shader variants should be in use.
* This is false when globe is disabled, or when globe is enabled, but mercator rendering is used due to zoom level (and no transition is happening).
*/
get useGlobeRendering(): boolean {
return this._useGlobeRendering;
}

/**
* @internal
* Intended for internal use, only called from GlobeTransform.
*/
set useGlobeRendering(value: boolean) {
this._useGlobeRendering = value;
get transitionState(): number {
return 1;

Check warning on line 54 in src/geo/projection/vertical_perspective_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/vertical_perspective_projection.ts#L54

Added line #L54 was not covered by tests
}

get useSubdivision(): boolean {
return this.useGlobeRendering;
return true;
}

get shaderVariantName(): string {
return this.useGlobeRendering ? 'globe' : this._mercator.shaderVariantName;
return VerticalPerspectiveShaderVariantKey;
}

get shaderDefine(): string {
return this.useGlobeRendering ? '#define GLOBE' : this._mercator.shaderDefine;
return VerticalPerspectiveShaderDefine;
}

get shaderPreludeCode(): PreparedShader {
return this.useGlobeRendering ? shaders.projectionGlobe : this._mercator.shaderPreludeCode;
return shaders.projectionGlobe;
}

get vertexShaderPreludeCode(): string {
Expand All @@ -96,7 +79,7 @@
}

get useGlobeControls(): boolean {
return this._useGlobeRendering;
return true;

Check warning on line 82 in src/geo/projection/vertical_perspective_projection.ts

View check run for this annotation

Codecov / codecov/patch

src/geo/projection/vertical_perspective_projection.ts#L82

Added line #L82 was not covered by tests
}

get errorQueryLatitudeDegrees(): number { return this._errorQueryLatitudeDegrees; }
Expand All @@ -118,10 +101,6 @@
*/
get latitudeErrorCorrectionRadians(): number { return this._errorCorrectionUsable; }

constructor() {
this._mercator = new MercatorProjection();
}

public destroy() {
if (this._errorMeasurement) {
this._errorMeasurement.destroy();
Expand All @@ -139,7 +118,6 @@
}

public updateGPUdependent(renderContext: ProjectionGPUContext): void {
this._mercator.updateGPUdependent(renderContext);
if (!this._errorMeasurement) {
this._errorMeasurement = new ProjectionErrorMeasurement(renderContext);
}
Expand Down Expand Up @@ -190,4 +168,8 @@
this._tileMeshCache[key] = mesh;
return mesh;
}
}

recalculate(_params: EvaluationParameters): void {
// Do nothing.
}
}
2 changes: 1 addition & 1 deletion src/render/draw_custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {Map} from '../ui/map';
import {drawCustom} from './draw_custom';
import {CustomStyleLayer} from '../style/style_layer/custom_style_layer';
import {MercatorTransform} from '../geo/projection/mercator_transform';
import {MercatorProjection} from '../geo/projection/mercator';
import {MercatorProjection} from '../geo/projection/mercator_projection';

vi.mock('./painter');
vi.mock('./program');
Expand Down
2 changes: 1 addition & 1 deletion src/render/draw_symbol.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {type IReadonlyTransform} from '../geo/transform_interface';
import type {EvaluationParameters} from '../style/evaluation_parameters';
import type {SymbolLayerSpecification} from '@maplibre/maplibre-gl-style-spec';
import {type Style} from '../style/style';
import {MercatorProjection} from '../geo/projection/mercator';
import {MercatorProjection} from '../geo/projection/mercator_projection';
import type {ProjectionData} from '../geo/projection/projection_data';

vi.mock('./painter');
Expand Down
2 changes: 1 addition & 1 deletion src/render/painter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {drawDepth, drawCoords} from './draw_terrain';
import {type OverscaledTileID} from '../source/tile_id';
import {drawSky, drawAtmosphere} from './draw_sky';
import {Mesh} from './mesh';
import {MercatorShaderDefine, MercatorShaderVariantKey} from '../geo/projection/mercator';
import {MercatorShaderDefine, MercatorShaderVariantKey} from '../geo/projection/mercator_projection';

import type {IReadonlyTransform} from '../geo/transform_interface';
import type {Style} from '../style/style';
Expand Down
2 changes: 1 addition & 1 deletion src/ui/camera.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {getZoomAdjustment} from '../geo/projection/globe_utils';
import {GlobeCameraHelper} from '../geo/projection/globe_camera_helper';
import {MercatorCameraHelper} from '../geo/projection/mercator_camera_helper';

import type {GlobeProjection} from '../geo/projection/globe';
import type {GlobeProjection} from '../geo/projection/globe_projection';
import type {Terrain} from '../render/terrain';

beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/ui/map_tests/map_events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {type MapGeoJSONFeature} from '../../util/vectortile_to_geojson';
import {type MapLayerEventType, type MapLibreEvent} from '../events';
import {Map, type MapOptions} from '../map';
import {Event as EventedEvent, ErrorEvent} from '../../util/evented';
import {GlobeProjection} from '../../geo/projection/globe';
import {GlobeProjection} from '../../geo/projection/globe_projection';

type IsAny<T> = 0 extends T & 1 ? T : never;
type NotAny<T> = T extends IsAny<T> ? never : T;
Expand Down
2 changes: 1 addition & 1 deletion src/ui/map_tests/map_resize.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {describe, beforeEach, test, expect, vi} from 'vitest';
import {MercatorProjection} from '../../geo/projection/mercator';
import {MercatorProjection} from '../../geo/projection/mercator_projection';
import {createMap, beforeMapTest, sleep} from '../../util/test/util';

beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/util/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {MercatorTransform} from '../../geo/projection/mercator_transform';
import {RequestManager} from '../request_manager';
import {type IReadonlyTransform, type ITransform} from '../../geo/transform_interface';
import {type Style} from '../../style/style';
import type {GlobeProjection} from '../../geo/projection/globe';
import type {GlobeProjection} from '../../geo/projection/globe_projection';

export class StubMap extends Evented {
style: Style;
Expand Down
Loading
Loading