From 632688dceb2bbcbb49cf370a460d4a537327da5f Mon Sep 17 00:00:00 2001 From: Matteo V Date: Fri, 22 Mar 2024 12:46:40 +0100 Subject: [PATCH] Backport 2024.01.xx - Fix #10000 adding geodesic lines to 3d measures (#10110) * Fix #10000 adding geodesic lines to 3d measures (#10048) * Fix #10000 adding geodesic lines to 3d measures * fix test * fix test * fix test * fixing geodesic label and measured * updated geodesic length with correct line representation * also clean up call to computeArea, remvoed uncessary third param * Update web/client/components/map/cesium/DrawMeasureSupport.jsx Co-authored-by: stefano bovio --------- Co-authored-by: stefano bovio * Fix #10000 position of total length for geodesic distance (#10104) --------- Co-authored-by: stefano bovio --- .../map/cesium/DrawMeasureSupport.jsx | 88 ++++++++++++++++--- .../map/cesium/MeasurementSupport.jsx | 6 ++ .../__tests__/MeasurementSupport-test.jsx | 5 +- web/client/translations/data.de-DE.json | 1 + web/client/translations/data.en-US.json | 1 + web/client/translations/data.es-ES.json | 1 + web/client/translations/data.fr-FR.json | 1 + web/client/translations/data.it-IT.json | 1 + .../utils/cesium/DrawGeometryInteraction.js | 17 ++-- 9 files changed, 103 insertions(+), 18 deletions(-) diff --git a/web/client/components/map/cesium/DrawMeasureSupport.jsx b/web/client/components/map/cesium/DrawMeasureSupport.jsx index ca907e59c9..14690c893c 100644 --- a/web/client/components/map/cesium/DrawMeasureSupport.jsx +++ b/web/client/components/map/cesium/DrawMeasureSupport.jsx @@ -16,6 +16,9 @@ import { convertUom, mapUomAreaToLength } from '../../../utils/MeasureUtils'; +import { + calculateDistance +} from '../../../utils/CoordinatesUtils'; import { getCesiumColor, createPolylinePrimitive, @@ -75,6 +78,7 @@ function measureFeatureToCartesianCoordinates(feature) { return [Cesium.Cartographic.toCartesian(Cesium.Cartographic.fromDegrees(...coordinates))]; case MeasureTypes.ANGLE_3D: case MeasureTypes.POLYLINE_DISTANCE_3D: + case MeasureTypes.LENGTH: return coordinates.map((coords) => Cesium.Cartographic.toCartesian(Cesium.Cartographic.fromDegrees(...coords))); case MeasureTypes.SLOPE: case MeasureTypes.AREA_3D: @@ -302,7 +306,7 @@ function DrawMeasureSupport({ : `${value.toFixed(2)} ${unitOfMeasure.label}`; } - function addSegmentsLabels(pCollection, coordinates, measureType) { + function addSegmentsLabels(pCollection, coordinates, measureType, isGeodesicDistance = false) { const unitOfMeasure = measureType === MeasureTypes.AREA_3D ? mapUomAreaToLength[unitsOfMeasureRef.current[measureType]?.value] : unitsOfMeasureRef.current[measureType]; @@ -311,14 +315,26 @@ function DrawMeasureSupport({ const nextCartesian = coordinates[idx + 1]; if (nextCartesian) { const middlePoint = computeMiddlePoint(currentCartesian, nextCartesian); - const length = Cesium.Cartesian3.distance(currentCartesian, nextCartesian); + let length = Cesium.Cartesian3.distance(currentCartesian, nextCartesian); + if (isGeodesicDistance) { + const currentPoint = Cesium.Cartographic.fromCartesian(currentCartesian); + const nextPoint = Cesium.Cartographic.fromCartesian(nextCartesian); + length = calculateDistance([[ + Cesium.Math.toDegrees(currentPoint.longitude), + Cesium.Math.toDegrees(currentPoint.latitude) + ], + [ + Cesium.Math.toDegrees(nextPoint.longitude), + Cesium.Math.toDegrees(nextPoint.latitude) + ]]); + } + const { longitude, latitude, height } = Cesium.Cartographic.fromCartesian(middlePoint); const label = convertMeasure(unitOfMeasure, length, 'm'); pCollection.add({ position: middlePoint, text: label, ...getSecondaryLabelStyle() }); - const { longitude, latitude, height } = Cesium.Cartographic.fromCartesian(middlePoint); return [Cesium.Math.toDegrees(longitude), Cesium.Math.toDegrees(latitude), height, length, label]; } return null; @@ -387,8 +403,9 @@ function DrawMeasureSupport({ } }, [clearId]); - function featureToToPrimitives({ + function featureToPrimitives({ coordinates, + geodesicCoordinates, feature, measureType }) { @@ -456,6 +473,20 @@ function DrawMeasureSupport({ infoLabelText = infoLabelFormat(convertMeasure(unitOfMeasure, feature.properties.length, 'm')); } break; + case MeasureTypes.LENGTH: + if (geodesicCoordinates.length > 1) { + const coords4326 = geodesicCoordinates.map((cartesianPoint) => { + const {longitude, latitude} = Cesium.Cartographic.fromCartesian(cartesianPoint); + return [Cesium.Math.toDegrees(longitude), Cesium.Math.toDegrees(latitude)]; + }); + const geodesicDistance = calculateDistance(coords4326); + infoLabelTextPosition = geodesicCoordinates[geodesicCoordinates.length - 1]; + infoLabelText = infoLabelFormat(convertMeasure(unitOfMeasure, geodesicDistance, 'm')); + staticPrimitivesCollection.current.add(createPolylinePrimitive({ ...style?.line, coordinates: [...geodesicCoordinates], geodesic: true })); + segments = addSegmentsLabels(staticLabelsCollection.current, geodesicCoordinates, MeasureTypes.LENGTH, true); + } + break; + case MeasureTypes.AREA_3D: if (coordinates.length > 2) { staticPrimitivesCollection.current.add(createPolygonPrimitive({ ...style?.area, coordinates: [...coordinates] })); @@ -515,7 +546,7 @@ function DrawMeasureSupport({ const newFeatures = features.map((feature) => { const coordinates = measureFeatureToCartesianCoordinates(feature); - return featureToToPrimitives({ + return featureToPrimitives({ coordinates, feature, measureType: feature?.properties?.measureType @@ -528,10 +559,15 @@ function DrawMeasureSupport({ map.scene.requestRender(); } - function updateStaticCoordinates(coordinates, { feature }) { + function updateStaticCoordinates({ + coordinates, + geodesicCoordinates, + feature + }) { - const updatedFeature = featureToToPrimitives({ + const updatedFeature = featureToPrimitives({ coordinates, + geodesicCoordinates, feature, measureType: type }); @@ -549,7 +585,9 @@ function DrawMeasureSupport({ } }, [unitsOfMeasure[type]?.value]); - function updateDynamicCoordinates(coordinates, { + function updateDynamicCoordinates({ + coordinates, + geodesicCoordinates, area, distance } = {}) { @@ -624,6 +662,28 @@ function DrawMeasureSupport({ }); } break; + case MeasureTypes.LENGTH: + tooltipLabelText = tooltips.start; + if (geodesicCoordinates.length > 1) { + tooltipLabelText = tooltips.end; + const coords4326 = geodesicCoordinates.map((cartesianPoint) => { + const {longitude, latitude} = Cesium.Cartographic.fromCartesian(cartesianPoint); + return [Cesium.Math.toDegrees(longitude), Cesium.Math.toDegrees(latitude)]; + }); + const geodesicDistance = calculateDistance(coords4326); + infoLabelText = infoLabelFormat(convertMeasure(unitOfMeasure, geodesicDistance, 'm')); + addSegmentsLabels(dynamicLabelsCollection.current, geodesicCoordinates, MeasureTypes.LENGTH, true); + geodesicCoordinates.forEach((cartesian, idx) => { + if (idx !== (geodesicCoordinates.length - 1)) { + dynamicBillboardCollection.current.add({ + position: cartesian, + image: coordinateNodeImage.current, + ...getCoordinatesNodeStyle() + }); + } + }); + } + break; case MeasureTypes.AREA_3D: tooltipLabelText = tooltips.start; if (coordinates.length > 1) { @@ -670,10 +730,13 @@ function DrawMeasureSupport({ function handleDrawUpdate({ coordinates, + geodesicCoordinates, area, distance }) { - updateDynamicCoordinates(coordinates, { + updateDynamicCoordinates({ + coordinates, + geodesicCoordinates, area, distance }); @@ -681,10 +744,13 @@ function DrawMeasureSupport({ function handleDrawEnd({ coordinates, + geodesicCoordinates, feature }) { if (coordinates && feature) { - updateStaticCoordinates(coordinates, { + updateStaticCoordinates({ + coordinates, + geodesicCoordinates, feature }); } @@ -696,6 +762,7 @@ function DrawMeasureSupport({ case MeasureTypes.POINT_COORDINATES: return 'Point'; case MeasureTypes.ANGLE_3D: + case MeasureTypes.LENGTH: case MeasureTypes.POLYLINE_DISTANCE_3D: return 'LineString'; case MeasureTypes.SLOPE: @@ -727,6 +794,7 @@ function DrawMeasureSupport({ map={map} active={active} geometryType={getGeometryType()} + geodesic={type === MeasureTypes.LENGTH } onDrawStart={handleDrawUpdate} onMouseMove={handleDrawUpdate} onDrawing={handleDrawUpdate} diff --git a/web/client/components/map/cesium/MeasurementSupport.jsx b/web/client/components/map/cesium/MeasurementSupport.jsx index 54a6f615fa..77f0193b25 100644 --- a/web/client/components/map/cesium/MeasurementSupport.jsx +++ b/web/client/components/map/cesium/MeasurementSupport.jsx @@ -51,6 +51,7 @@ function MeasurementSupport({ onUpdateFeatures, onChangeUnitOfMeasure, tools = [ + MeasureTypes.LENGTH, MeasureTypes.POLYLINE_DISTANCE_3D, MeasureTypes.AREA_3D, MeasureTypes.POINT_COORDINATES, @@ -101,6 +102,10 @@ function MeasurementSupport({ unitsOfMeasure={unitsOfMeasure} onUpdateCollection={(collection) => onUpdateFeatures(collection?.features || [])} tooltipLabels={{ + [MeasureTypes.LENGTH]: { + start: getMessageById(messages, 'measureComponent.tooltipPolylineDistance3DStart'), + end: getMessageById(messages, 'measureComponent.tooltipPolylineDistance3DEnd') + }, [MeasureTypes.POLYLINE_DISTANCE_3D]: { start: getMessageById(messages, 'measureComponent.tooltipPolylineDistance3DStart'), end: getMessageById(messages, 'measureComponent.tooltipPolylineDistance3DEnd') @@ -124,6 +129,7 @@ function MeasurementSupport({ } }} infoLabelsFormat={{ + [MeasureTypes.LENGTH]: value => value, [MeasureTypes.POLYLINE_DISTANCE_3D]: value => value, [MeasureTypes.AREA_3D]: value => value, [MeasureTypes.POINT_COORDINATES]: (value, { latitude, longitude } = {}) => diff --git a/web/client/components/map/cesium/__tests__/MeasurementSupport-test.jsx b/web/client/components/map/cesium/__tests__/MeasurementSupport-test.jsx index 28d38656e5..9f7f77e314 100644 --- a/web/client/components/map/cesium/__tests__/MeasurementSupport-test.jsx +++ b/web/client/components/map/cesium/__tests__/MeasurementSupport-test.jsx @@ -79,8 +79,9 @@ describe('Cesium MeasurementSupport', () => { expect(viewer).toBeTruthy(); expect(ref.map.canvas).toBeTruthy(); const buttons = document.querySelectorAll('button'); - expect(buttons.length).toBe(8); + expect(buttons.length).toBe(9); expect([...buttons].map(button => button.querySelector('.glyphicon').getAttribute('class'))).toEqual([ + 'glyphicon glyphicon-1-measure-length', 'glyphicon glyphicon-polyline-3d', 'glyphicon glyphicon-polygon-3d', 'glyphicon glyphicon-point-coordinates', @@ -90,6 +91,6 @@ describe('Cesium MeasurementSupport', () => { 'glyphicon glyphicon-trash', 'glyphicon glyphicon-ext-json' ]); - Simulate.click(buttons[4]); + Simulate.click(buttons[5]); }); }); diff --git a/web/client/translations/data.de-DE.json b/web/client/translations/data.de-DE.json index dba0f6a0d1..66b2278059 100644 --- a/web/client/translations/data.de-DE.json +++ b/web/client/translations/data.de-DE.json @@ -858,6 +858,7 @@ "saveMeasure": "Speichern Sie die Messungen in Notizen / Zeichnungen", "resetTooltip": "Messung entfernen", "addAsLayer": "Als Ebene hinzufügen", + "lengthMeasure": "Messen Sie die geodätische Entfernung im 3D-Raum", "polylineDistance3DMeasure": "Entfernung im 3D-Raum messen", "area3DMeasure": "Fläche im 3D-Raum messen", "pointCoordinatesMeasure": "Punktkoordinaten messen", diff --git a/web/client/translations/data.en-US.json b/web/client/translations/data.en-US.json index 27c0c7417d..bf254b16c4 100644 --- a/web/client/translations/data.en-US.json +++ b/web/client/translations/data.en-US.json @@ -819,6 +819,7 @@ "exportToGeoJSON": "Export to GeoJSON", "resetTooltip": "Clear measures", "addAsLayer": "Add as layer", + "lengthMeasure": "Measure geodesic distance in 3D space", "polylineDistance3DMeasure": "Measure distance in 3D space", "area3DMeasure": "Measure area in 3D space", "pointCoordinatesMeasure": "Measure point coordinates", diff --git a/web/client/translations/data.es-ES.json b/web/client/translations/data.es-ES.json index 35f35818d4..1d786130dd 100644 --- a/web/client/translations/data.es-ES.json +++ b/web/client/translations/data.es-ES.json @@ -819,6 +819,7 @@ "saveMeasure": "Guarde las medidas en la anotación", "resetTooltip": "Medidas claras", "addAsLayer": "Agregar como capa", + "lengthMeasure": "Medir la distancia geodésica en el espacio 3D", "polylineDistance3DMeasure": "Medir distancia en el espacio 3D", "area3DMeasure": "Medir área en espacio 3D", "pointCoordinatesMeasure": "Medir las coordenadas del punto", diff --git a/web/client/translations/data.fr-FR.json b/web/client/translations/data.fr-FR.json index 1d0183e2e5..91cf22a9d5 100644 --- a/web/client/translations/data.fr-FR.json +++ b/web/client/translations/data.fr-FR.json @@ -819,6 +819,7 @@ "saveMeasure": "Enregistrer les mesures dans l'annotation", "resetTooltip": "Effacer les mesures", "addAsLayer": "Ajouter comme couche", + "lengthMeasure": "Mesurer la distance géodésique dans l'espace 3D", "polylineDistance3DMeasure": "Mesurer la distance dans l'espace 3D", "area3DMeasure": "Mesurer la zone dans l'espace 3D", "pointCoordinatesMeasure": "Mesurer les coordonnées du point", diff --git a/web/client/translations/data.it-IT.json b/web/client/translations/data.it-IT.json index f53190faf9..5d52be3354 100644 --- a/web/client/translations/data.it-IT.json +++ b/web/client/translations/data.it-IT.json @@ -819,6 +819,7 @@ "saveMeasure": "Salva le misure nell'annotazione", "resetTooltip": "Rimuovi Misurazioni", "addAsLayer": "Aggiungi come livello", + "lengthMeasure": "Misurare la distanza geodesica nello spazio 3D", "polylineDistance3DMeasure": "Misurare la distanza nello spazio 3D", "area3DMeasure": "Misurare l'area nello spazio 3D", "pointCoordinatesMeasure": "Misurare le coordinate di un punto", diff --git a/web/client/utils/cesium/DrawGeometryInteraction.js b/web/client/utils/cesium/DrawGeometryInteraction.js index 3a42a5bd79..c267403c56 100644 --- a/web/client/utils/cesium/DrawGeometryInteraction.js +++ b/web/client/utils/cesium/DrawGeometryInteraction.js @@ -307,7 +307,7 @@ class CesiumDrawGeometryInteraction { } else { const previousCartesian = this._coordinates[this._coordinates.length - 1]; const currentCoordinates = [...this._coordinates, cartesian]; - const area = computeArea(currentCoordinates, undefined, this._geodesic); + const area = computeArea(currentCoordinates, undefined); const distance = computeDistance(currentCoordinates, this._geodesic); this._onMouseMove(this._drawPrimitives({ area, @@ -352,10 +352,12 @@ class CesiumDrawGeometryInteraction { .then((currentCoordinates) => { this._onDrawStart(this._drawPrimitives({ cartesian: currentCoordinates[currentCoordinates.length - 1], - coordinates: currentCoordinates + coordinates: currentCoordinates, + geodesicCoordinates: computeGeodesicCoordinates(currentCoordinates) })); this._onDrawEnd(this._clearPrimitive({ coordinates: currentCoordinates, + geodesicCoordinates: computeGeodesicCoordinates(currentCoordinates), feature: this._sampleTerrain && currentCoordinates.length === 2 ? cesiumCoordinatesToGeoJSONFeature(this._type, currentCoordinates, { height: computeHeightSign(currentCoordinates) * computeDistance(currentCoordinates), @@ -370,7 +372,8 @@ class CesiumDrawGeometryInteraction { } else { this._onDrawStart(this._drawPrimitives({ cartesian, - coordinates: [...this._coordinates] + coordinates: [...this._coordinates], + geodesicCoordinates: computeGeodesicCoordinates(this._coordinates) })); this._drawing = true; } @@ -394,14 +397,15 @@ class CesiumDrawGeometryInteraction { const previousCartesian = this._coordinates[this._coordinates.length - 1]; this._coordinates.push(cartesian); const currentCoordinates = [...this._coordinates]; - const area = computeArea(currentCoordinates, undefined, this._geodesic); + const area = computeArea(currentCoordinates, undefined); const distance = computeDistance(currentCoordinates, this._geodesic); this._onDrawing(this._drawPrimitives({ area, distance, previousCartesian, cartesian, - coordinates: [...this._coordinates] + coordinates: [...this._coordinates], + geodesicCoordinates: computeGeodesicCoordinates(this._coordinates) })); } } @@ -431,13 +435,14 @@ class CesiumDrawGeometryInteraction { const currentCoordinates = this._type === 'Polygon' ? [...this._coordinates, this._coordinates[0]] : [...this._coordinates]; - const area = computeArea(currentCoordinates, undefined, this._geodesic); + const area = computeArea(currentCoordinates, undefined); const distance = computeDistance(currentCoordinates, this._geodesic); this._onDrawEnd(this._clearPrimitive({ area, distance, coordinates: currentCoordinates, + geodesicCoordinates: computeGeodesicCoordinates(currentCoordinates), feature: cesiumCoordinatesToGeoJSONFeature(this._type, currentCoordinates, { area, areaUom: 'sqm',