Skip to content

Commit b0db7fe

Browse files
authored
ProjectionScheme: Add "none" projection, make naming consistent (#1417)
* Add support for "none" projection in ProjectionScheme * Move functions to ProjectionScheme * Normalize the naming schemes * Add tests * clampToNormalizedBounds -> clampToBounds * Adjust function name
1 parent b78c28c commit b0db7fe

8 files changed

Lines changed: 228 additions & 116 deletions

File tree

src/three/plugins/images/EllipsoidProjectionTilesPlugin.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ export class EllipsoidProjectionTilesPlugin extends ImageFormatPlugin {
7171
_uv.fromBufferAttribute( uv, i );
7272

7373
// convert the plane position to lat / lon
74-
const lon = projection.convertProjectionToLongitude( MathUtils.mapLinear( _uv.x, 0, 1, minU, maxU ) );
75-
let lat = projection.convertProjectionToLatitude( MathUtils.mapLinear( _uv.y, 0, 1, minV, maxV ) );
74+
const lon = projection.convertNormalizedToLongitude( MathUtils.mapLinear( _uv.x, 0, 1, minU, maxU ) );
75+
let lat = projection.convertNormalizedToLatitude( MathUtils.mapLinear( _uv.y, 0, 1, minV, maxV ) );
7676

7777
// snap the edges to the poles if using mercator projection and end caps are enabled
7878
if ( projection.isMercator && this.endCaps ) {
@@ -95,7 +95,7 @@ export class EllipsoidProjectionTilesPlugin extends ImageFormatPlugin {
9595
// as much as possible at low LoDs.
9696
if ( projection.isMercator && _uv.y !== 0 && _uv.y !== 1 ) {
9797

98-
const latLimit = projection.convertProjectionToLatitude( 1 );
98+
const latLimit = projection.convertNormalizedToLatitude( 1 );
9999
const vStep = 1 / yVerts;
100100

101101
const prevLat = MathUtils.mapLinear( _uv.y - vStep, 0, 1, south, north );
@@ -119,8 +119,8 @@ export class EllipsoidProjectionTilesPlugin extends ImageFormatPlugin {
119119
ellipsoid.getCartographicToNormal( lat, lon, _norm );
120120

121121
// map from the uvs for the tile into the uv range
122-
const u = MathUtils.mapLinear( projection.convertLongitudeToProjection( lon ), minU, maxU, uvRange[ 0 ], uvRange[ 2 ] );
123-
const v = MathUtils.mapLinear( projection.convertLatitudeToProjection( lat ), minV, maxV, uvRange[ 1 ], uvRange[ 3 ] );
122+
const u = MathUtils.mapLinear( projection.convertLongitudeToNormalized( lon ), minU, maxU, uvRange[ 0 ], uvRange[ 2 ] );
123+
const v = MathUtils.mapLinear( projection.convertLatitudeToNormalized( lat ), minV, maxV, uvRange[ 1 ], uvRange[ 3 ] );
124124

125125
// update the geometry
126126
uv.setXY( i, u, v );
@@ -210,9 +210,9 @@ export class EllipsoidProjectionTilesPlugin extends ImageFormatPlugin {
210210
// find the most bowed point of the latitude range since the amount that latitude changes is
211211
// dependent on the Y value of the image
212212
const midLat = ( south > 0 ) !== ( north > 0 ) ? 0 : Math.min( Math.abs( south ), Math.abs( north ) );
213-
const midV = projection.convertLatitudeToProjection( midLat );
214-
const lonFactor = projection.getLongitudeDerivativeAtProjection( minU );
215-
const latFactor = projection.getLatitudeDerivativeAtProjection( midV );
213+
const midV = projection.convertLatitudeToNormalized( midLat );
214+
const lonFactor = projection.getLongitudeDerivativeAtNormalized( minU );
215+
const latFactor = projection.getLatitudeDerivativeAtNormalized( midV );
216216

217217
// calculate the size of a pixel on the surface
218218
const [ xDeriv, yDeriv ] = getCartographicToMeterDerivative( this.tiles.ellipsoid, midLat, east );

src/three/plugins/images/overlays/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export function getMeshesCartographicRange( meshes, ellipsoid, meshToEllipsoidMa
145145
// ellipsoid projections (Web mercator, equirect) the projection ranges always span the entire
146146
// globe range.
147147
// const clampedRange = [ minLon, minLat, maxLon, maxLat ];
148-
clampedRange = tiling.clampToProjectionBounds( [ minLon, minLat, maxLon, maxLat ] );
148+
clampedRange = tiling.clampToBounds( [ minLon, minLat, maxLon, maxLat ] );
149149
const [ minU, minV, maxU, maxV ] = tiling.toNormalizedRange( clampedRange );
150150
uvs.forEach( uv => {
151151

src/three/plugins/images/utils/ProjectionScheme.js

Lines changed: 138 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,25 @@ export class ProjectionScheme {
3838
this.tileCountY = 1;
3939
break;
4040

41+
case 'none':
42+
this.tileCountX = 1;
43+
this.tileCountY = 1;
44+
break;
45+
4146
default:
4247
throw new Error( `ProjectionScheme: Unknown projection scheme "${ scheme }"` );
4348

4449
}
4550

4651
}
4752

48-
convertProjectionToLatitude( v ) {
53+
convertNormalizedToLatitude( v ) {
54+
55+
if ( this.scheme === 'none' ) {
4956

50-
if ( this.isMercator ) {
57+
return v;
58+
59+
} else if ( this.isMercator ) {
5160

5261
// https://gis.stackexchange.com/questions/447421/convert-a-point-on-a-flat-2d-web-mercator-map-image-to-a-coordinate
5362
const ratio = MathUtils.mapLinear( v, 0, 1, - 1, 1 );
@@ -61,15 +70,27 @@ export class ProjectionScheme {
6170

6271
}
6372

64-
convertProjectionToLongitude( v ) {
73+
convertNormalizedToLongitude( v ) {
74+
75+
if ( this.scheme === 'none' ) {
76+
77+
return v;
78+
79+
} else {
80+
81+
return MathUtils.mapLinear( v, 0, 1, - Math.PI, Math.PI );
6582

66-
return MathUtils.mapLinear( v, 0, 1, - Math.PI, Math.PI );
83+
}
6784

6885
}
6986

70-
convertLatitudeToProjection( lat ) {
87+
convertLatitudeToNormalized( lat ) {
88+
89+
if ( this.scheme === 'none' ) {
90+
91+
return lat;
7192

72-
if ( this.isMercator ) {
93+
} else if ( this.isMercator ) {
7394

7495
// https://stackoverflow.com/questions/14329691/convert-latitude-longitude-point-to-a-pixels-x-y-on-mercator-projection
7596
const mercatorN = Math.log( Math.tan( ( Math.PI / 4 ) + ( lat / 2 ) ) );
@@ -83,48 +104,143 @@ export class ProjectionScheme {
83104

84105
}
85106

86-
convertLongitudeToProjection( lon ) {
107+
convertLongitudeToNormalized( lon ) {
87108

88-
return ( lon + Math.PI ) / ( 2 * Math.PI );
109+
if ( this.scheme === 'none' ) {
89110

90-
}
111+
return lon;
112+
113+
} else {
91114

92-
getLongitudeDerivativeAtProjection( value ) {
115+
return ( lon + Math.PI ) / ( 2 * Math.PI );
93116

94-
return 2 * Math.PI;
117+
}
95118

96119
}
97120

98-
getLatitudeDerivativeAtProjection( value ) {
121+
getLongitudeDerivativeAtNormalized( value ) {
99122

100-
const EPS = 1e-5;
101-
let yp = value - EPS;
102-
if ( yp < 0 ) {
123+
if ( this.scheme === 'none' ) {
103124

104-
yp = value + EPS;
125+
return 1;
126+
127+
} else {
128+
129+
return 2 * Math.PI;
105130

106131
}
107132

108-
if ( this.isMercator ) {
133+
}
134+
135+
getLatitudeDerivativeAtNormalized( value ) {
109136

110-
// TODO: why is this 2 * Math.PI rather than Math.PI?
111-
return Math.abs( this.convertProjectionToLatitude( value ) - this.convertProjectionToLatitude( yp ) ) / EPS;
137+
if ( this.scheme === 'none' ) {
138+
139+
return 1;
112140

113141
} else {
114142

115-
return Math.PI;
143+
const EPS = 1e-5;
144+
let yp = value - EPS;
145+
if ( yp < 0 ) {
146+
147+
yp = value + EPS;
148+
149+
}
150+
151+
if ( this.isMercator ) {
152+
153+
// TODO: why is this 2 * Math.PI rather than Math.PI?
154+
return Math.abs( this.convertNormalizedToLatitude( value ) - this.convertNormalizedToLatitude( yp ) ) / EPS;
155+
156+
} else {
157+
158+
return Math.PI;
159+
160+
}
116161

117162
}
118163

119164
}
120165

121166
getBounds() {
122167

168+
if ( this.scheme === 'none' ) {
169+
170+
return [ 0, 0, 1, 1 ];
171+
172+
} else {
173+
174+
return [
175+
this.convertNormalizedToLongitude( 0 ), this.convertNormalizedToLatitude( 0 ),
176+
this.convertNormalizedToLongitude( 1 ), this.convertNormalizedToLatitude( 1 ),
177+
];
178+
179+
}
180+
181+
}
182+
183+
toNormalizedPoint( x, y ) {
184+
185+
const result = [ x, y ];
186+
result[ 0 ] = this.convertLongitudeToNormalized( result[ 0 ] );
187+
result[ 1 ] = this.convertLatitudeToNormalized( result[ 1 ] );
188+
189+
return result;
190+
191+
}
192+
193+
toNormalizedRange( range ) {
194+
123195
return [
124-
this.convertProjectionToLongitude( 0 ), this.convertProjectionToLatitude( 0 ),
125-
this.convertProjectionToLongitude( 1 ), this.convertProjectionToLatitude( 1 ),
196+
...this.toNormalizedPoint( range[ 0 ], range[ 1 ] ),
197+
...this.toNormalizedPoint( range[ 2 ], range[ 3 ] ),
126198
];
127199

128200
}
129201

202+
toCartographicPoint( x, y ) {
203+
204+
const result = [ x, y ];
205+
result[ 0 ] = this.convertNormalizedToLongitude( result[ 0 ] );
206+
result[ 1 ] = this.convertNormalizedToLatitude( result[ 1 ] );
207+
208+
return result;
209+
210+
}
211+
212+
toCartographicRange( range ) {
213+
214+
return [
215+
...this.toCartographicPoint( range[ 0 ], range[ 1 ] ),
216+
...this.toCartographicPoint( range[ 2 ], range[ 3 ] ),
217+
];
218+
219+
}
220+
221+
clampToBounds( range, normalized = false ) {
222+
223+
const result = [ ...range ];
224+
let clampBounds;
225+
226+
if ( normalized ) {
227+
228+
clampBounds = [ 0, 0, 1, 1 ];
229+
230+
} else {
231+
232+
clampBounds = this.getBounds();
233+
234+
}
235+
236+
const [ minX, minY, maxX, maxY ] = clampBounds;
237+
result[ 0 ] = MathUtils.clamp( result[ 0 ], minX, maxX );
238+
result[ 1 ] = MathUtils.clamp( result[ 1 ], minY, maxY );
239+
result[ 2 ] = MathUtils.clamp( result[ 2 ], minX, maxX );
240+
result[ 3 ] = MathUtils.clamp( result[ 3 ], minY, maxY );
241+
242+
return result;
243+
244+
}
245+
130246
}

0 commit comments

Comments
 (0)