Skip to content

Commit

Permalink
Merge pull request #5079 from mind84/circle_measurement
Browse files Browse the repository at this point in the history
[Feature] Circular geometry measurement on draw
  • Loading branch information
nboisteault authored Dec 9, 2024
2 parents eb7e9c6 + 9864a3d commit 42c0979
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 10 deletions.
69 changes: 59 additions & 10 deletions assets/src/modules/Digitizing.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Vector as VectorLayer } from 'ol/layer.js';
import { Feature } from 'ol';

import { Point, LineString, Polygon, Circle as CircleGeom, MultiPoint, GeometryCollection } from 'ol/geom.js';
import { circular } from 'ol/geom/Polygon.js';
import { circular, fromCircle } from 'ol/geom/Polygon.js';

import { getArea, getLength } from 'ol/sphere.js';
import Overlay from 'ol/Overlay.js';
Expand Down Expand Up @@ -480,11 +480,7 @@ export class Digitizing {
geom.set('totalOverlay', Array.from(this._measureTooltips).pop()[1], true);
geom.on('change', (e) => {
const geom = e.target;
if (geom instanceof Polygon) {
this._updateTotalMeasureTooltip(geom.getCoordinates()[0], geom, 'Polygon', geom.get('totalOverlay'));
} else if (geom instanceof LineString) {
this._updateTotalMeasureTooltip(geom.getCoordinates(), geom, 'Linestring', geom.get('totalOverlay'));
}
this._setTooltipContentByGeom(geom);
});

this._constraintLayer.setVisible(false);
Expand Down Expand Up @@ -809,7 +805,10 @@ export class Digitizing {

// Total length for LineStrings
// Perimeter and area for Polygons
if (coords.length > 2) {
// Radius and area for Circles
if(geomType == 'Circle') {
this._updateTotalMeasureTooltip(coords, geom, geomType, Array.from(this._measureTooltips).pop()[1]);
} else if (coords.length > 2) {
this._updateTotalMeasureTooltip(coords, geom, geomType, Array.from(this._measureTooltips).pop()[1]);

// Display angle ABC between three points. B is center
Expand All @@ -830,8 +829,8 @@ export class Digitizing {
segmentTooltipContent += '<br>' + angleInDegrees + '°';
}

// Display current segment measure only when drawing lines, polygons or circles
if (['line', 'polygon', 'circle'].includes(this.toolSelected)) {
// Display current segment measure only when drawing lines or polygons
if (['line', 'polygon'].includes(this.toolSelected)) {
this._segmentMeasureTooltipElement.innerHTML = segmentTooltipContent;
Array.from(this._measureTooltips).pop()[0].setPosition(geom.getLastCoordinate());
}
Expand All @@ -847,7 +846,16 @@ export class Digitizing {

overlay.getElement().innerHTML = totalTooltipContent;
overlay.setPosition(geom.getInteriorPoint().getCoordinates());
} else {
} else if(geomType == 'Circle') {
// get polygon from circular geometry by approximating the circle with a 128-sided polygon
let circularGeom = fromCircle(geom,128);
let totalTooltipContent = this.formatLength(new LineString([coords[0], coords[1]]));
totalTooltipContent += '<br>' + this.formatArea(circularGeom);

overlay.getElement().innerHTML = totalTooltipContent;
overlay.setPosition(circularGeom.getInteriorPoint().getCoordinates());
}
else {
overlay.getElement().innerHTML = this.formatLength(geom);
overlay.setPosition(geom.getCoordinateAt(0.5));
}
Expand Down Expand Up @@ -885,6 +893,43 @@ export class Digitizing {
return output;
}

/**
* Initializes measure tooltip and change event on a feature loaded from local storage.
* @param {Geometry} geom The geometry.
*/
_initMeasureTooltipOnLoadedFeatures(geom){
// create overlays
this.createMeasureTooltips();

geom.set('totalOverlay', Array.from(this._measureTooltips).pop()[1], true);
// calculate measures
this._setTooltipContentByGeom(geom);
geom.on('change', (e) => {
const geom = e.target;
this._setTooltipContentByGeom(geom);
});
// make measure tooltip static and hidden
this._totalMeasureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
this._totalMeasureTooltipElement.classList.toggle('hide', !this._hasMeasureVisible);

// reset measureTooltip element
this._totalMeasureTooltipElement = null;
}

/**
* Calculates measuements for a specific geometry.
* @param {Geometry} geom The geometry.
*/
_setTooltipContentByGeom(geom){
if (geom instanceof Polygon) {
this._updateTotalMeasureTooltip(geom.getCoordinates()[0], geom, 'Polygon', geom.get('totalOverlay'));
} else if (geom instanceof LineString) {
this._updateTotalMeasureTooltip(geom.getCoordinates(), geom, 'Linestring', geom.get('totalOverlay'));
} else if ( geom instanceof CircleGeom) {
this._updateTotalMeasureTooltip([geom.getFirstCoordinate(), geom.getLastCoordinate()], geom, 'Circle', geom.get('totalOverlay'));
}
}

/**
* Creates measure tooltips
*/
Expand Down Expand Up @@ -1100,6 +1145,8 @@ export class Digitizing {

if(loadedGeom){
const loadedFeature = new Feature(loadedGeom);
// init measure tooltip
this._initMeasureTooltipOnLoadedFeatures(loadedFeature.getGeometry());
loadedFeature.set('color', feature.color);
loadedFeatures.push(loadedFeature);
}
Expand All @@ -1114,6 +1161,8 @@ export class Digitizing {
console.log(loadedFeatures.length+' features read from WKT!');
// set color
for(const loadedFeature of loadedFeatures){
// init measure tooltip
this._initMeasureTooltipOnLoadedFeatures(loadedFeature.getGeometry());
loadedFeature.set('color', this._drawColor);
}
// No features read from localStorage so remove the data
Expand Down
27 changes: 27 additions & 0 deletions tests/end2end/playwright/draw.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,26 @@ test.describe('Draw', () => {
expect(await page.evaluate(() => lizMap.mainLizmap.digitizing.featureDrawn)).toBeNull();
});

test('Circular geometry measure', async ({ page }) => {
await page.locator('#draw button.dropdown-toggle:nth-child(2)').click();
await page.locator('.digitizing-circle > svg').click();
await page.locator('#newOlMap').click({
position: {
x: 450,
y: 75
}
});
await page.locator('#newOlMap').click({
position: {
x: 480,
y: 115
}
});
await page.locator('#draw button.digitizing-toggle-measure').click();
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toBeVisible();
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toHaveText('3.3 km34.27 km2');
})

test('From local storage', async ({ page }) => {
const the_json = '[{"type":"Polygon","color":"#000000","coords":[[[764321.0416656,6290805.935670358],[767628.3399468632,6290805.935670358],[767628.3399468632,6295105.423436],[764321.0416656,6295105.423436],[764321.0416656,6290805.935670358],[764321.0416656,6290805.935670358]]]}]';
await page.evaluate(token => localStorage.setItem('testsrepository_draw_draw_drawLayer', token), the_json);
Expand Down Expand Up @@ -313,6 +333,13 @@ test.describe('Draw', () => {
await expect(drawn[0][4]).toHaveLength(2);
await expect(drawn[0][5]).toHaveLength(2);

// check measure initialization
await page.locator('#draw button.digitizing-toggle-measure').click();
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toBeVisible();
await expect(page.locator('.ol-tooltip.ol-tooltip-static')).toHaveText('15.2 km14.19 km2');
// hide measure
await page.locator('#draw button.digitizing-toggle-measure').click();

// Hide all elements but #map, #newOlMap and their children
await page.$eval("*", el => el.style.visibility = 'hidden');
await page.$eval("#newOlMap, #newOlMap *", el => el.style.visibility = 'visible');
Expand Down

0 comments on commit 42c0979

Please sign in to comment.