Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exploring 3D CesiumJS tools in MapStore Open So...

Exploring 3D CesiumJS tools in MapStore Open Source WebGIS

MapStore is an open-source WebGIS application designed for cross-platform compatibility, functioning seamlessly across various web browsers and mobile devices. Its user-friendly interface empowers users to effortlessly create, customize, and share a wide range of interactive geospatial content, including dynamic maps, insightful dashboards, informative charts, and compelling geostories. Users can integrate and visualize diverse geospatial data and design engaging presentations that effectively communicate spatial information and insights on top of OGC community standards. MapStore’s nature fosters collaboration and community-driven development, allowing users to contribute to the project, extend its functionality, and tailor it to their specific needs. This presentation outlines the open-source tools that the author and his team implemented in MapStore to enrich its 3D capabilities. The presenter will showcase the most relevant 3D tools implemented on top of CesiumJS as a result of many contributions coming from Italian Public Administrations such as the municipalities of Florence and Genoa as well as the Austrocontrol Austrian Aerospace and many others organizations worldwide. The presentation also focuses on specific code implementation of such tools, to highlight the potential of the framework's capabilities in managing functionalities like: 3D measurements, 3D annotations, styling, 3D Tiles and 3D models support, Map Views and Terrain layers.

Avatar for Simone Giannecchini

Simone Giannecchini

June 29, 2025
Tweet

More Decks by Simone Giannecchini

Other Decks in Technology

Transcript

  1. • Our Services GeoSolutions • Offices in Italy & US,

    Global Clients/Team • 40+ collaborators • Our products GeoServer MapStore GeoNode GeoNetwork Enterprise Support Subscription Professional Training Custom Solutions
  2. What’s MapStore? MapStore is an highly modular Open Source WebGIS

    framework to create, manage and share various types of contents, like maps, dashboards and geostories.
  3. What’s MapStore? MapStore is written in ReactJS MapStore is map

    library agnostic and ensures the greatest flexibility: its abstraction tier allows to work with different web mapping libraries The mapping engines currently supported are OpenLayers, LeafletJS and CesiumJS 1. Municipality of Turin - MapStore using CesiumJS to render 3D Tiles of the urban area 2. MapStorle using CesiumJS with the full globe view
  4. MapStore and CesiumJS integration • CesiumJS was included in MapStore

    on Jan 26, 2016 for the first time • Now is integrated inside a ReactJS component with the support of multiple layer types: ◦ 3D Tiles ◦ Terrain (Cesium Quantized Mesh) ◦ Vector (GeoJSON, Shapefile) ◦ Web Map Service (WMS) ◦ Web Map Tile Service (WMTS) ◦ Web Feature Service (WFS) ◦ Tiles Map Service (TMS) ◦ ArcGIS Map and Image services ◦ IFC Model ◦ … class CesiumMap extends React.Component { static propTypes = { id: PropTypes.string, // ... } // ... componentDidMount() { // ... this.map = new Cesium.Viewer(this.props.id, /* */); // ... } // ... render() { // ... return ( <div id={this.props.id} style={this.props.style}> {children} {/* ... */} </div> ); } https://github.com/geosolutions-it/MapStore2/blob/2025.01.xx/web/client/components/map/cesium/Map.jsx
  5. MapStore and CesiumJS integration Relevant 3D tools implemented on top

    of CesiumJS are the result of many contributions coming from Italian Public Administrations and others organizations worldwide such as: • Municipality of Genoa • Municipality of Florence • Austrocontrol Austrian Aerospace • Total Energies • Vlaanderen • …
  6. MapStore and CesiumJS integration Multiple implementations has been contributed to

    MapStore to enhance the user experience and user interface inside the 3D map viewer, next a selection of few of them: • Map views and clipping 3D Tiles at runtime • 3D drawing system, annotations and measurement • Style editor and interactive legend • Special 3D layers
  7. Map views and clipping 3D Tiles at runtime Represent the

    same map as a sequence of multiple differently configured views: • add description for view • store camera position • allow clipping 3D Tiles or terrain • allow changing layer visibility and opacity • allow changing globe opacity 1. Municipality of Genoa - A map view where the underground building structure are displayed using 3D Tiles 2. Municipality of Genoa - A map view where the master plan area of a new project is displayed using clipping functionality
  8. Map views and clipping 3D Tiles at runtime 3D Clipping

    using Cesium.ClippingPlane const outerRingCoordinates = uniqBy(union ? coordinates : coordinates.reverse(), (coords) => `${coords[0]}${coords[1]}`); const points = outerRingCoordinates.map(([lng, lat, height = 0]) => { const point = Cesium.Cartesian3.fromDegrees(lng, lat, height); return point; }); const pointsLength = points.length; // Create center points for each clipping plane const clippingPlanes = []; for (let i = 0; i < pointsLength; ++i) { const nextIndex = (i + 1) % pointsLength; let midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3()); midpoint = Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint); const up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3()); let right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3()); right = Cesium.Cartesian3.normalize(right, right); let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3()); normal = Cesium.Cartesian3.normalize(normal, normal); // Compute distance by pretending the plane is at the origin const originCenteredPlane = new Cesium.Plane(normal, 0.0); const distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint); clippingPlanes.push(new Cesium.ClippingPlane(normal, distance)); } 1. Municipality of Genoa - Mapstore showing a clipped 3D Tiles to highlight a subway station inside the CesiumJS viewer 2. https://github.com/geosolutions-it/MapStore2/blob/2025.01.xx/web/client/utils/cesium/PrimitivesUtils.js
  9. Map views and clipping 3D Tiles at runtime Current clipping

    plane approach limitations: • One clipping area allowed per 3D Tiles • Only convex shape supported Possible improvement: • ClippingPolygons instead of ClippingPlanes const clippingPolygons = new ClippingPolygonCollection({ polygons: geoJSONPolygonFeatures.map(feature => { return new ClippingPolygon({ positions: Cesium.Cartesian3.fromRadiansArray( feature.geometry.coordinates[0] ) }); }), inverse: false }); tileset.clippingPolygons = clippingPolygons;
  10. Map views and clipping 3D Tiles at runtime Historical data

    reconstruction to highlight evolution of the urban environment 1. Municipality of Genoa - 3D Tiles of the historical coastline (white) showing in red the lighthouse location 2. Municipality of Genoa - Clipped 3D Tiles showing now and then combined together
  11. Map views and clipping 3D Tiles at runtime Municipality of

    Genoa - Usage of addiational tools such as the measurement tool inside a map view
  12. 3D drawing system, annotations and measurement Drawing system implementation focused

    on: • Support of different types of geometry: Point, LineString, Polygon and Circle • React component re-usable and extendable for new plugins 1. Municipality of Genoa - MapStore showing the measurement tool 2. Municipality of Florence - MapStore showing the annotations tool
  13. 3D drawing system, annotations and measurement Management of drawing interaction:

    • Usage of ScreenSpaceEventHandler for mouse inputs • Usage of Cesium.PrimitiveCollection and Cesium.BillboardCollection class CesiumDrawGeometryInteraction { constructor(options) { // ... this._handler = new Cesium.ScreenSpaceEventHandler( this._map.canvas ); this._handler.setInputAction((movement) => { this._handleDrawEnd(movement, true); }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // ... this._dynamicPrimitivesCollection = new Cesium.PrimitiveCollection({ destroyPrimitives: true }); // ... this._dynamicBillboardCollection = new Cesium.BillboardCollection({ scene: this._map.scene }); // ... } https://github.com/geosolutions-it/MapStore2/blob/2025.01.xx/web/client/utils/cesium/DrawGeometryInteraction.js
  14. 3D drawing system, annotations and measurement Compute position information priorities:

    1. scene.pickPosition 2. scene.drillPickFromRay 3. globe.pick export function computePositionInfo(map, movement, { pickObjectsLimit = Number.MAX_VALUE } = {}) { const scene = map.scene; const camera = map.camera; const position = movement.position || movement.endPosition; const feature = scene.pick(position); const depthCartesian = scene.pickPosition(position); if (!(feature?.primitive instanceof Cesium.GroundPrimitive) && !(feature?.primitive instanceof Cesium.GroundPolylinePrimitive) && !!(feature && depthCartesian)) { return {/* ... cartesian, cartographic, feature */}; } const ray = camera.getPickRay(position); const drillPickFeature = scene.drillPickFromRay(ray, pickObjectsLimit) .find(({ exclude, object, position: rayIntersectionPosition }) => !exclude && rayIntersectionPosition && object) || null; if (drillPickFeature) { return {/* ... cartesian, cartographic, feature */}; } const globeCartesian = scene.globe.pick(ray, scene); if (globeCartesian) { const cartographic = Cesium.Cartographic.fromCartesian(globeCartesian); return {/* ... cartesian, cartographic, feature */}; } return {}; } https://github.com/geosolutions-it/MapStore2/blob/2025.01.xx/web/client/utils/cesium/ClickUtils.js
  15. 3D drawing system, annotations and measurement The React component exposes

    props interface to control the activation, geometry type and all the drawing phases function MyDrawingSupport({ cesiumViewer, active, mapType, feature, geometryType = 'Point', geodesic = false, onChange = () => {} }) { return ( <DrawGeometrySupport map={cesiumViewer} active={active && feature.geometry === null} depthTestAgainstTerrain={false} geometryType={geometryType} geodesic={geodesic} getObjectsToExcludeOnPick={() => []} onDrawEnd={({ feature: newFeature }) => onChange(newFeature) } /> ); } - https://github.com/geosolutions- it/MapStore2/blob/2025.01.xx/web/client/plugins/Annotations/containers/AnnotationsMapInteractionsSuppo rt.jsx - https://github.com/geosolutions- it/MapStore2/blob/2025.01.xx/web/client/components/map/cesium/MeasurementSupport.jsx
  16. 3D drawing system, annotations and measurement Municipality of Florence -

    MapStore showing the measurement tool in action drawing distance polylines inside the CesiumJS viewer
  17. 3D drawing system, annotations and measurement Municipality of Genoa -

    MapStore showing annotation tool with the coordinates editor and in the CesiumJS viewer rendered annotation features using extrusions, labels and GLTF 3D models
  18. Style editor and interactive legend Style editor implementation focused on:

    • Interoperability with internal json style structure • Style support for different layer types: 3D Tiles, GeoJSON and WFS 1. Municipality of Tertenia - MapStore in GeoNode showing 3D Tiles of the urban area 2. Municipality of Florence - MapStore showing 3D Tiles buildings with classified point cloud filtered and styled for rooftop and vegetation rendered inside CesiumJS viewer
  19. Style editor and interactive legend Definition of style as a

    JSON list of rules and symbolizers with possibility of editing with User Interface { "rules": [ { "name": ">= 159.055 and < 77987.823", "filter": ["&&", [ ">=", "LAND_KM", 159.055 ], [ "<", "LAND_KM", 77987.823 ]], "symbolizers": [ { "kind": "Fill", "color": "#ffffcc", "fillOpacity": 1, "outlineColor": "#777777", "outlineWidth": 0, "msClassificationType": "both", "msClampToGround": false, "msExtrudedHeight": { "name": "property", "args": [ "LAND_KM" ] } } ] }, // ... ] } 1. MapStore showing classified style using property value to define the CesiumJS polygon entity extrusion 2. https://docs.mapstore.geosolutionsgroup.com/en/latest/developer-guide/vector-style/
  20. Style editor and interactive legend A custom class GeoJSONStyledFeatures manages

    entities and primitives updates with filtering support class GeoJSONStyledFeatures { constructor(options = {}) { this._msId = options.id; this._dataSource = new Cesium.CustomDataSource( options.id); this._primitives = new Cesium.PrimitiveCollection({ destroyPrimitives: true }); // ... this.setFeatures(options.features); } // ... setStyleFunction(styleFunction) { this._styleFunction = styleFunction; this._update(); } 1. MapStore viewer showing interactivity between legend and Cesium viewer by filtering selected style rules 2. https://github.com/geosolutions- it/MapStore2/blob/2025.01.xx/web/client/utils/cesium/GeoJSONStyledFeatures.js
  21. Style editor and interactive legend Municipality of Florence - Stylized

    WFS layer combined with 3D Tiles Buildings inside MapStore using CesiumJS to highlight degradation of building facades
  22. Style editor and interactive legend Abitat Treviso - Rendering of

    multiple 3D Tiles layers with style applied via style editor inside MapStore using CesiumJS. Building have been stylized using filter rules based on building height property
  23. Special 3D layers Additional layers supported by the 3D viewer:

    • IFC 3D model layer • Terrain layer 1. Austrocontrol Austrian Aerospace - terrain rendered with GeoServer WMS layer 2. Municipality of Genoa - IFC model showing underground portion of a building rendered inside MapStore with CesiumJS engine
  24. IFC 3D model layer • Implemented using web-ifc parser •

    Usage of 2 Cesium.Primitive for opaque and translucent geometries • Usage of Cesium.ColorGeometryInstan ceAttribute to assign different color to all geometries let primitives = new Cesium.PrimitiveCollection({ destroyPrimitives: true }); getIFCModel(options.url) .then(({ifcModule, data}) => { const { meshes } = ifcDataToJSON({ ifcModule, data }); const translucent = createPrimitiveFromMeshes( meshes, options, 'translucentPrimitive' ); const opaque = createPrimitiveFromMeshes( meshes, options, 'opaquePrimitive' ); primitives.add(translucent); primitives.add(opaque); updatePrimitivesMatrix(primitives, options?.features?.[0]); }); map.scene.primitives.add(primitives); https://github.com/geosolutions- it/MapStore2/blob/2025.01.xx/web/client/components/map/cesium/plugins/ModelLayer.js
  25. IFC 3D model layer Municipality of Florence - Rendering of

    an IFC model inside MapStore using the CesiumJS engine
  26. Terrain layers • Terrain layer with support of multiple providers:

    cesium, cesium-ion and wms • List component to manage terrain layer from map viewer let terrainProvider; switch (config.provider) { case 'wms': { terrainProvider = new GeoServerBILTerrainProvider( WMSUtils.wmsToCesiumOptionsBIL(config)); break; } case 'cesium': { terrainProvider = new Cesium.CesiumTerrainProvider( cesiumOptionsMapping(config)); break; } case 'ellipsoid': { terrainProvider = new Cesium.EllipsoidTerrainProvider(); break; } case 'cesium-ion': { terrainProvider = new Cesium.CesiumTerrainProvider( cesiumIonOptionsMapping(config)); break; } default: terrainProvider = new Cesium.EllipsoidTerrainProvider(); break; } map.terrainProvider = terrainProvider; https://github.com/geosolutions- it/MapStore2/blob/2025.01.xx/web/client/components/map/cesium/plugins/TerrainLayer.js
  27. How to try MapStore • MapStore documentation: https://docs.mapstore.geosolutionsgroup.com/en/latest/ • MapStore

    repository: https://github.com/geosolutions-it/MapStore2 • MapStore latest release 2025.01.00: https://github.com/geosolutions-it/MapStore2/releases/tag/v2025.01.00 • MapStore demo: https://mapstore.geosolutionsgroup.com/mapstore/#/