Skip to content

Commit

Permalink
geosolutions-it#9978: Add 360 photo support with Mapillary (geosoluti…
Browse files Browse the repository at this point in the history
…ons-it#10027)

* geosolutions-it#9978: Add 360 photo support with Mapillary
Description:
- adding the mapillary viewer for 360 photo support beside Google amd cyclemedia
- handle view custom 360 photos into mapillary viewer using GeoJSONDataProvider
- handle view the custom images in 2d and 3d modes
- install mapillary-js npm package
- edit VectorLayer to enable add layer features via geojson url in 2d + 3d views
- adding unit tests for mapillary

* geosolutions-it#9978: Add 360 photo support with Mapillary
Description:
- edit the test img for mapillary

* geosolutions-it#9978: Add 360 photo support with Mapillary
Description:
- fix issues in unit tests
- edit in test files of mapillary

* geosolutions-it#9978: Add 360 photo support with Mapillary
Description:
- edit in mapillary unit tests

* geosolutions-it#9978: Resolve review comments on [360 photo support with Mapillary]
Description:
-  remove all the changes in VectorLayer and move zoomTo layer in streetView epics
- add a notification if the service is not available for mapillary custom data layer
- replace legacy way of style with geostyler for marker streetview
- edit the streetview in monitorState to be more specific
- edit unit cases based on changes

* review marker rotation and 3d support

* revert changes in cesium vector layer

* revert changes in ol vector layer

* revert changes in url utils

* add tests

* fix jsdoc

* remove zoom to action and added clamp to ground option

* fix geojson data provider

---------

Co-authored-by: allyoucanmap <[email protected]>
  • Loading branch information
mahmoudadel54 and allyoucanmap authored Apr 16, 2024
1 parent 8d4df57 commit 0ec0d92
Show file tree
Hide file tree
Showing 44 changed files with 1,905 additions and 274 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@
"leaflet.nontiledlayer": "1.0.7",
"lodash": "4.17.21",
"lrucache": "1.0.3",
"mapillary-js": "4.1.2",
"md5": "2.3.0",
"moment": "2.29.4",
"node-geo-distance": "1.2.0",
Expand Down
6 changes: 4 additions & 2 deletions web/client/components/map/cesium/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ class CesiumMap extends React.Component {
const groupIntersectedFeatures = features.reduce((acc, feature) => {
let msId;
let properties;
let geometry = null;
if (feature instanceof Cesium.Cesium3DTileFeature && feature?.tileset?.msId) {
msId = feature.tileset.msId;
// 3d tile feature does not contain a geometry in the Cesium3DTileFeature class
Expand All @@ -389,6 +390,7 @@ class CesiumMap extends React.Component {
const getFeatureById = feature?.id?._msGetFeatureById || feature?.primitive?._msGetFeatureById;
const value = getFeatureById(feature.id);
properties = value.feature.properties;
geometry = value.feature.geometry;
msId = value.msId;
}
if (!properties || !msId) {
Expand All @@ -397,8 +399,8 @@ class CesiumMap extends React.Component {
return {
...acc,
[msId]: acc[msId]
? [...acc[msId], { type: 'Feature', properties, geometry: null }]
: [{ type: 'Feature', properties, geometry: null }]
? [...acc[msId], { type: 'Feature', properties, geometry }]
: [{ type: 'Feature', properties, geometry }]
};
}, []);
return Object.keys(groupIntersectedFeatures).map(id => ({ id, features: groupIntersectedFeatures[id] }));
Expand Down
56 changes: 54 additions & 2 deletions web/client/components/map/cesium/__tests__/Map-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,63 @@ describe('CesiumMap', () => {
features: [
{
type: 'Feature', properties: { category: 'area' },
geometry: null
geometry: {
coordinates: [
[
[
1.0975911519593637,
48.583411572759644
],
[
1.0975911519593637,
38.03615349112002
],
[
19.43550678615742,
38.03615349112002
],
[
19.43550678615742,
48.583411572759644
],
[
1.0975911519593637,
48.583411572759644
]
]
],
type: 'Polygon'
}
},
{
type: 'Feature', properties: { category: 'boundary' },
geometry: null
geometry: {
coordinates: [
[
[
1.0975911519593637,
48.583411572759644
],
[
1.0975911519593637,
38.03615349112002
],
[
19.43550678615742,
38.03615349112002
],
[
19.43550678615742,
48.583411572759644
],
[
1.0975911519593637,
48.583411572759644
]
]
],
type: 'Polygon'
}
}
]
}
Expand Down
111 changes: 86 additions & 25 deletions web/client/components/map/cesium/plugins/WFSLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,50 @@
*/

import Layers from '../../../../utils/cesium/Layers';
import * as Cesium from 'cesium';
import isEqual from 'lodash/isEqual';
import axios from '../../../../libs/ajax';
import { getFeature } from '../../../../api/WFS';
import { needsReload } from '../../../../utils/WFSLayerUtils';
import { getFeature, getFeatureLayer } from '../../../../api/WFS';
import { needsReload, needsCredentials, getConfig } from '../../../../utils/WFSLayerUtils';
import { optionsToVendorParams } from '../../../../utils/VendorParamsUtils';
import {
getStyle,
layerToGeoStylerStyle
} from '../../../../utils/VectorStyleUtils';
import { applyDefaultStyleToVectorLayer } from '../../../../utils/StyleUtils';
import GeoJSONStyledFeatures from '../../../../utils/cesium/GeoJSONStyledFeatures';
import { ServerTypes } from '../../../../utils/LayersUtils';

const requestFeatures = (options, params, cancelToken) => {
const requestFeatures = (options, params, config) => {
return getFeature(options.url, options.name, {
// ...(!params?.CQL_FILTER && { bbox: [minx, miny, maxx, maxy, projection].join(',') }),
outputFormat: 'application/json',
srsname: 'EPSG:4326',
...params
}, {
cancelToken
});
}, config);
};

const createLoader = (options) => {
if (options.serverType === ServerTypes.NO_VENDOR) {
if (needsCredentials(options)) {
return () => null;
}

if (options?.strategy === 'bbox') {
return (extent) => getFeatureLayer(options, { filters: [{
spatialField: {
operation: 'BBOX',
geometry: {
projection: 'EPSG:4326',
extent: [extent] // use array because bbox is buggy
}
}
}], proj: 'EPSG:4326' }, getConfig(options));
}
return () => getFeatureLayer(options, { filters: [], proj: 'EPSG:4326' }, getConfig(options));
}
const params = optionsToVendorParams(options);
const config = getConfig(options);
return () => requestFeatures(options, params, config);
};

const createLayer = (options, map) => {
Expand All @@ -47,26 +70,61 @@ const createLayer = (options, map) => {
opacity: options.opacity,
queryable: options.queryable === undefined || options.queryable
});
const params = optionsToVendorParams(options);

const cancelToken = axios.CancelToken;
const source = cancelToken.source();
requestFeatures(options, params, source.token)
.then(({ data: collection }) => {
styledFeatures.setFeatures(collection.features);
layerToGeoStylerStyle(options)
.then((style) => {
getStyle(applyDefaultStyleToVectorLayer({
...options,
features: collection.features,
style
}), 'cesium')
.then((styleFunc) => {
styledFeatures.setStyleFunction(styleFunc);
const loader = createLoader(options);
let loadingBbox;
let bboxTimeout;
if (options?.strategy === 'bbox') {
loadingBbox = () => {
if (bboxTimeout) {
clearTimeout(bboxTimeout);
bboxTimeout = undefined;
}
bboxTimeout = setTimeout(() => {
const viewRectangle = map.camera.computeViewRectangle();
const cameraPitch = Math.abs(Cesium.Math.toDegrees(map.camera.pitch));
if (viewRectangle && cameraPitch > 60) {
loader([
Cesium.Math.toDegrees(viewRectangle.west),
Cesium.Math.toDegrees(viewRectangle.south),
Cesium.Math.toDegrees(viewRectangle.east),
Cesium.Math.toDegrees(viewRectangle.north)
])
.then(({ data: collection }) => {
styledFeatures.setFeatures(collection.features);
layerToGeoStylerStyle(options)
.then((style) => {
getStyle(applyDefaultStyleToVectorLayer({
...options,
features: collection.features,
style
}), 'cesium')
.then((styleFunc) => {
styledFeatures.setStyleFunction(styleFunc);
});
});
});
});
});

}
}, 300);
};
map.camera.moveEnd.addEventListener(loadingBbox);
} else {
loader()
.then(({ data: collection }) => {
styledFeatures.setFeatures(collection.features);
layerToGeoStylerStyle(options)
.then((style) => {
getStyle(applyDefaultStyleToVectorLayer({
...options,
features: collection.features,
style
}), 'cesium')
.then((styleFunc) => {
styledFeatures.setStyleFunction(styleFunc);
});
});
});
}
return {
detached: true,
styledFeatures,
Expand All @@ -75,6 +133,9 @@ const createLayer = (options, map) => {
styledFeatures.destroy();
styledFeatures = undefined;
}
if (loadingBbox) {
map.camera.moveEnd.removeEventListener(loadingBbox);
}
}
};
};
Expand Down
34 changes: 2 additions & 32 deletions web/client/components/map/openlayers/plugins/WFSLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,9 @@ import GeoJSON from 'ol/format/GeoJSON';

import { getFeature, getFeatureLayer } from '../../../../api/WFS';
import { optionsToVendorParams } from '../../../../utils/VendorParamsUtils';
import { getCredentials } from '../../../../utils/SecurityUtils';
import { needsReload } from '../../../../utils/WFSLayerUtils';
import { needsReload, needsCredentials, getConfig } from '../../../../utils/WFSLayerUtils';
import { applyDefaultStyleToVectorLayer } from '../../../../utils/StyleUtils';
const needsCredentials = (options) => {
const security = options?.security || {};
const {type, sourceId} = security;
const {username, password} = getCredentials(sourceId) ?? {};
return type?.toLowerCase?.() === "basic" && (!username || !password);
};
const getConfig = (options) => {
const security = options?.security || {};
const config = {};
const {type, sourceId} = security;
const credentials = getCredentials(sourceId);
if (credentials) {
const {username, password} = credentials;
switch (type?.toLowerCase?.()) {
case "basic":
config.headers = {
Authorization: `Basic ${btoa(`${username}:${password}`)}`
};
break;
case "bearer":
config.headers = {
Authorization: `Bearer ${credentials.token}`
};
break;
default:
break;
}
}
return config;
};

const createLoader = (source, options) => (extent, resolution, projection) => {
let proj = projection.getCode();
let req;
Expand Down
Loading

0 comments on commit 0ec0d92

Please sign in to comment.