From bcf8b9425639ae57e039c84fc8654919aed9bc8b Mon Sep 17 00:00:00 2001 From: Andrey Kuznecov Date: Wed, 7 Sep 2022 15:42:51 +0700 Subject: [PATCH] init --- demo/index.ts | 14 ++- src/mapglViewport.ts | 292 +++++++++++++++++++++++++++++++++++++++++++ src/utils.ts | 15 ++- 3 files changed, 311 insertions(+), 10 deletions(-) create mode 100644 src/mapglViewport.ts diff --git a/demo/index.ts b/demo/index.ts index 9ceba87..e2c7ffb 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -7,8 +7,10 @@ declare global { declare var window: any; const map = new mapgl.Map('container', { - center: [55.31878, 25.23584], - zoom: 16.2, + center: [55.30401193485671, 25.273124140912344], + zoom: 17.021087495312493, + pitch: 35.38661417565734, + rotation: -111.26507733271275, key: '4970330e-7f1c-4921-808c-0eb7c4e63001', }); initDeckGL(); @@ -16,7 +18,7 @@ initDeckGL(); async function initDeckGL() { console.log('Layer data - Loading...'); fetch( - 'https://urbi-geo-api-staging2.web-staging.2gis.ru/building/items/values?tag=floors_count,height&bounds=POLYGON+((55.13142+25.544679,+55.203999+25.567715,+55.279599+25.566579,+55.43176+25.759947,+55.55436+25.811148,+55.666094+25.897751,+55.76817+25.925981,+55.826597+26.007005,+55.888369+26.151722,+56.086425+26.050441,+56.15912+26.062127,+56.195513+25.979301,+56.163975+25.946893,+56.177561+25.892732,+56.139167+25.8325,+56.1725+25.769167,+56.140833+25.735,+56.143611+25.676111,+56.191111+25.648056,+56.201874+25.611984,+56.253291+25.60219,+56.266328+25.606335,+56.254586+25.613159,+56.264173+25.627665,+56.418384+25.682657,+56.549221+25.692716,+56.591385+25.549234,+56.602446+25.323577,+56.585359+25.087633,+56.594079+25.007481,+56.323288+24.972644,+56.348923+24.934376,+56.338442+24.914535,+56.259358+24.859817,+56.205659+24.850507,+56.201022+24.784219,+56.144333+24.741556,+56.060585+24.746639,+56.036157+24.810922,+55.978341+24.877363,+55.980164+24.894492,+56.062185+24.870801,+56.042048+24.886589,+56.058722+24.949126,+56.042075+24.947686,+56.045483+24.967887,+56.006871+24.994727,+55.960882+25.005958,+55.910907+24.965663,+55.851301+24.965812,+55.812409+24.910874,+55.836502+24.671031,+55.793833+24.637012,+55.816207+24.615223,+55.767784+24.572526,+55.764989+24.52949,+55.834202+24.409554,+55.833944+24.327733,+55.759405+24.261142,+55.752895+24.234821,+55.833523+24.200902,+55.954447+24.222568,+55.969652+24.182449,+55.960753+24.170318,+56.017506+24.066605,+55.902317+24.046941,+55.833035+24.01459,+55.801126+24.025482,+55.781754+24.055948,+55.731246+24.058066,+55.485274+23.944384,+55.533725+23.849352,+55.531869+23.757286,+55.569228+23.720734,+55.572308+23.629646,+55.452588+23.465217,+55.430691+23.399593,+55.416507+23.382151,+55.401537+23.392525,+55.232271+23.110348,+55.216283+23.02621,+55.227508+22.791619,+55.21284+22.705686,+55.137388+22.631591,+52.58104+22.939203,+51.590376+24.126971,+51.589825+24.26588,+51.529512+24.336352,+51.416071+24.393194,+51.466454+24.462489,+51.565206+24.553035,+51.589187+24.619704,+51.586122+24.664189,+52.02542+24.75828,+52.309194+24.842176,+52.378334+24.900336,+52.337088+24.949252,+52.345961+24.997718,+52.405921+25.018775,+52.450032+24.982958,+52.647202+25.143128,+52.894479+25.470458,+54.182354+25.450646,+55.13142+25.544679))', + 'https://urbi-geo-api-staging.web-staging.2gis.ru/building/items/values?tag=floors_count,height&bounds=POLYGON+((55.13142+25.544679,+55.203999+25.567715,+55.279599+25.566579,+55.43176+25.759947,+55.55436+25.811148,+55.666094+25.897751,+55.76817+25.925981,+55.826597+26.007005,+55.888369+26.151722,+56.086425+26.050441,+56.15912+26.062127,+56.195513+25.979301,+56.163975+25.946893,+56.177561+25.892732,+56.139167+25.8325,+56.1725+25.769167,+56.140833+25.735,+56.143611+25.676111,+56.191111+25.648056,+56.201874+25.611984,+56.253291+25.60219,+56.266328+25.606335,+56.254586+25.613159,+56.264173+25.627665,+56.418384+25.682657,+56.549221+25.692716,+56.591385+25.549234,+56.602446+25.323577,+56.585359+25.087633,+56.594079+25.007481,+56.323288+24.972644,+56.348923+24.934376,+56.338442+24.914535,+56.259358+24.859817,+56.205659+24.850507,+56.201022+24.784219,+56.144333+24.741556,+56.060585+24.746639,+56.036157+24.810922,+55.978341+24.877363,+55.980164+24.894492,+56.062185+24.870801,+56.042048+24.886589,+56.058722+24.949126,+56.042075+24.947686,+56.045483+24.967887,+56.006871+24.994727,+55.960882+25.005958,+55.910907+24.965663,+55.851301+24.965812,+55.812409+24.910874,+55.836502+24.671031,+55.793833+24.637012,+55.816207+24.615223,+55.767784+24.572526,+55.764989+24.52949,+55.834202+24.409554,+55.833944+24.327733,+55.759405+24.261142,+55.752895+24.234821,+55.833523+24.200902,+55.954447+24.222568,+55.969652+24.182449,+55.960753+24.170318,+56.017506+24.066605,+55.902317+24.046941,+55.833035+24.01459,+55.801126+24.025482,+55.781754+24.055948,+55.731246+24.058066,+55.485274+23.944384,+55.533725+23.849352,+55.531869+23.757286,+55.569228+23.720734,+55.572308+23.629646,+55.452588+23.465217,+55.430691+23.399593,+55.416507+23.382151,+55.401537+23.392525,+55.232271+23.110348,+55.216283+23.02621,+55.227508+22.791619,+55.21284+22.705686,+55.137388+22.631591,+52.58104+22.939203,+51.590376+24.126971,+51.589825+24.26588,+51.529512+24.336352,+51.416071+24.393194,+51.466454+24.462489,+51.565206+24.553035,+51.589187+24.619704,+51.586122+24.664189,+52.02542+24.75828,+52.309194+24.842176,+52.378334+24.900336,+52.337088+24.949252,+52.345961+24.997718,+52.405921+25.018775,+52.450032+24.982958,+52.647202+25.143128,+52.894479+25.470458,+54.182354+25.450646,+55.13142+25.544679))', ) .then((response) => { return response.json(); @@ -38,12 +40,12 @@ function createDeckLayer(data, map) { pickable: true, parameters: { - depthTest: false, + depthTest: true, }, radius: 100, - elevationScale: 4, + elevationScale: 1, getPosition: (d: any) => [d.point.lon, d.point.lat], - extruded: false, + extruded: true, } as any); // todo need add call in map.addLayer(layer) for customLayer poiLayer.onAdd(map, map.getWebGLContext()); diff --git a/src/mapglViewport.ts b/src/mapglViewport.ts new file mode 100644 index 0000000..4758b11 --- /dev/null +++ b/src/mapglViewport.ts @@ -0,0 +1,292 @@ +import { WebMercatorViewport } from '@deck.gl/core'; + +export default class MapglViewport { + static displayName = 'WebMercatorViewport'; + viewport: WebMercatorViewport; + + constructor(viewport: WebMercatorViewport) { + this.viewport = viewport; + } + + getDistanceScales(coordinateOrigin?: number[]) { + return this.viewport.getDistanceScales(coordinateOrigin) + } + + get longitude(): number { + return this.viewport.longitude + } + get latitude(): number { + return this.viewport.latitude + } + get pitch(): number { + return this.viewport.pitch + } + get bearing(): number { + return this.viewport.bearing + } + get altitude(): number { + return this.viewport.altitude + } + get fovy(): number { + return this.viewport.fovy + } + get orthographic(): number { + return this.viewport.orthographic + } + + get metersPerPixel(): number { + return this.viewport.metersPerPixel + } + + get projectionMode(): number { + return this.viewport.projectionMode + } + + get id(): string { + return this.viewport.id + } + get x(): number { + return this.viewport.x + } + get y(): number { + return this.viewport.y + } + get width(): number { + return this.viewport.width + } + get height(): number { + return this.viewport.height + } + get isGeospatial(): boolean { + return this.viewport.isGeospatial + } + get zoom(): number { + return this.viewport.zoom + } + get focalDistance(): number { + return this.viewport.focalDistance + } + get position(): number[] { + return this.viewport.position + } + get modelMatrix(): number[] | null { + return this.viewport.modelMatrix + } + + /** Derived parameters */ + + // `!` post-fix expression operator asserts that its operand is non-null and non-undefined in contexts + // where the type checker is unable to conclude that fact. + + get distanceScales(): any { + return this.viewport.distanceScales +} + get scale(): number { + return this.viewport.scale +} + get center(): number[] { + return this.viewport.center +} + get cameraPosition(): number[] { + return this.viewport.cameraPosition +} + get projectionMatrix(): number[] { + return this.viewport.projectionMatrix +} + get viewMatrix(): number[] { + return this.viewport.viewMatrix +} + get viewMatrixUncentered(): number[] { + return this.viewport.viewMatrixUncentered +} + get viewMatrixInverse(): number[] { + return this.viewport.viewMatrixInverse +} + get viewProjectionMatrix(): number[] { + return this.viewport.viewProjectionMatrix +} + get pixelProjectionMatrix(): number[] { + return this.viewport.pixelProjectionMatrix +} + get pixelUnprojectionMatrix(): number[] { + return this.viewport.pixelUnprojectionMatrix +} + get resolution(): number[] { + return this.viewport.resolution +} + + + + // Two viewports are equal if width and height are identical, and if + // their view and projection matrices are (approximately) equal. + equals(viewport: any): boolean { + return this.viewport.equals(viewport) + } + + /** + * Projects xyz (possibly latitude and longitude) to pixel coordinates in window + * using viewport projection parameters + * - [longitude, latitude] to [x, y] + * - [longitude, latitude, Z] => [x, y, z] + * Note: By default, returns top-left coordinates for canvas/SVG type render + * + * @param {Array} lngLatZ - [lng, lat] or [lng, lat, Z] + * @param {Object} opts - options + * @param {Object} opts.topLeft=true - Whether projected coords are top left + * @return {Array} - [x, y] or [x, y, z] in top left coords + */ + project(xyz: number[], { topLeft = true }: { topLeft?: boolean } = {}): number[] { + return this.viewport.project(xyz, { topLeft }) + } + + /** + * Unproject pixel coordinates on screen onto world coordinates, + * (possibly [lon, lat]) on map. + * - [x, y] => [lng, lat] + * - [x, y, z] => [lng, lat, Z] + * @param {Array} xyz - + * @param {Object} opts - options + * @param {Object} opts.topLeft=true - Whether origin is top left + * @return {Array|null} - [lng, lat, Z] or [X, Y, Z] + */ + unproject( + xyz: number[], + { topLeft = true, targetZ }: { topLeft?: boolean; targetZ?: number } = {} + ): number[] { + return this.viewport.unproject(xyz, { topLeft, targetZ }) + } + + // NON_LINEAR PROJECTION HOOKS + // Used for web meractor projection + + projectPosition(xyz: number[]): [number, number, number] { + console.log(xyz,this.viewport.projectPosition(xyz)); + return this.viewport.projectPosition(xyz) + } + + unprojectPosition(xyz: number[]): [number, number, number] { + return this.viewport.unprojectPosition(xyz) + } + + /** + * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile. + * Performs the nonlinear part of the web mercator projection. + * Remaining projection is done with 4x4 matrices which also handles + * perspective. + * @param {Array} lngLat - [lng, lat] coordinates + * Specifies a point on the sphere to project onto the map. + * @return {Array} [x,y] coordinates. + */ + projectFlat(xyz: number[]): [number, number] { + return this.viewport.projectFlat(xyz) + } + + /** + * Unproject world point [x,y] on map onto {lat, lon} on sphere + * @param {object|Vector} xy - object with {x,y} members + * representing point on projected map plane + * @return {GeoCoordinates} - object with {lat,lon} of point on sphere. + * Has toArray method if you need a GeoJSON Array. + * Per cartographic tradition, lat and lon are specified as degrees. + */ + unprojectFlat(xyz: number[]): [number, number] { + return this.viewport.unprojectFlat(xyz) + } + + /** + * Get bounds of the current viewport + * @return {Array} - [minX, minY, maxX, maxY] + */ + getBounds(options: { z?: number } = {}): [number, number, number, number] { + return this.viewport.getBounds(options) + } + + + containsPixel({ + x, + y, + width = 1, + height = 1 + }: { + x: number; + y: number; + width?: number; + height?: number; + }): boolean { + return this.viewport.containsPixel(x, y, width, height) + } + + // Extract frustum planes in common space + getFrustumPlanes(): { + left: any; + right: any; + bottom: any; + top: any; + near: any; + far: any; + } { + return this.viewport.getFrustumPlanes() + } + + // EXPERIMENTAL METHODS + + /** + * Needed by panning and linear transition + * Pan the viewport to place a given world coordinate at screen point [x, y] + * + * @param {Array} coords - world coordinates + * @param {Array} pixel - [x,y] coordinates on screen + * @return {Object} props of the new viewport + */ + panByPosition(coords: number[], pixel: number[]): any { + return this.viewport.panByPosition(coords, pixel); + } + + get subViewports(): WebMercatorViewport[] | null { + return this.viewport.subViewports + } + + + /** + * Add a meter delta to a base lnglat coordinate, returning a new lnglat array + * + * Note: Uses simple linear approximation around the viewport center + * Error increases with size of offset (roughly 1% per 100km) + * + * @param {[Number,Number]|[Number,Number,Number]) lngLatZ - base coordinate + * @param {[Number,Number]|[Number,Number,Number]) xyz - array of meter deltas + * @return {[Number,Number]|[Number,Number,Number]) array of [lng,lat,z] deltas + */ + addMetersToLngLat(lngLatZ: number[], xyz: number[]): number[] { + return this.viewport.addMetersToLngLat(lngLatZ, xyz) + } + + + + + /** + * Returns a new viewport that fit around the given rectangle. + * Only supports non-perspective mode. + */ + fitBounds( + /** [[lon, lat], [lon, lat]] */ + bounds: [[number, number], [number, number]], + options: { + /** If not supplied, will use the current width of the viewport (default `1`) */ + width?: number; + /** If not supplied, will use the current height of the viewport (default `1`) */ + height?: number; + /** In degrees, 0.01 would be about 1000 meters */ + minExtent?: number; + /** Max zoom level */ + maxZoom?: number; + /** Extra padding in pixels */ + padding?: number | Required; + /** Center shift in pixels */ + offset?: number[]; + } = {} + ) { + return this.viewport.fitBounds(bounds, options); + } + +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index e3a8157..243c385 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,10 +4,11 @@ import type { Map } from '@2gis/mapgl/types'; import { DeckCustomLayer } from './types'; import { Deck2gisLayer } from './deckgl2gisLayer'; +import MapglViewport from './mapglViewport'; type UserData = { isExternal: boolean; - currentViewport?: WebMercatorViewport | null; + currentViewport?: MapglViewport | null; customLayers: Set; }; @@ -98,13 +99,16 @@ export function updateLayer(deck: Deck, _layer: Deck2gisLayer): void { updateLayers(deck); } -export function drawLayer(deck: Deck, map: Map, layer: Deck2gisLayer): void { +export function drawLayer(deck: Deck, map: Map, layer: Deck2gisLayer, m?): void { let { currentViewport } = deck.userData as UserData; let clearStack = false; if (!currentViewport) { // This is the first layer drawn in this render cycle. // Generate viewport from the current map state. - currentViewport = getViewport(deck, map, true); + + // Обвертка над вьюпортом WebMercatorViewport + // попробовать тут применить наши матрицы проекций на карту и на экран + currentViewport = new MapglViewport(getViewport(deck, map, true, m)); (deck.userData as UserData).currentViewport = currentViewport; clearStack = true; } @@ -112,7 +116,10 @@ export function drawLayer(deck: Deck, map: Map, layer: Deck2gisLayer): void if (!deck.isInitialized) { return; } - + // отчистить буфер глубины что бы перекрыть 3д объекты карты + //const gl = map.getWebGLContext(); + //gl.clear(gl.DEPTH_BUFFER_BIT); + //gl.clearDepth(0); deck._drawLayers('2gis-repaint', { viewports: [currentViewport], layerFilter: ({ layer: deckLayer }) => layer.id === deckLayer.id,