Skip to content

Commit

Permalink
Merge pull request #339 from chrismayer/angle-tool
Browse files Browse the repository at this point in the history
Extend MeasureTool by angle tool
  • Loading branch information
chrismayer committed Jul 24, 2023
2 parents 1cf2cfa + 18bf5ef commit e4275a8
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 25 deletions.
1 change: 1 addition & 0 deletions docs/module-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Module identifier: `wgu-measuretool`
| sketchFillColor | Fill color of the measurement sketch geometry (while measuring). Takes a CSS3 compliant color value. | `"sketchFillColor": "rgba(198,40,40,0.1)"`. |
| sketchVertexStrokeColor | Stroke color of the vertex of the sketch geometry (while measuring). Takes a CSS3 compliant color value. | `"sketchVertexStrokeColor": "#c62828"`. |
| sketchVertexFillColor | Fill color of the vertex of the sketch geometry (while measuring). Takes a CSS3 compliant color value | `"sketchVertexFillColor": "rgba(198,40,40,0.2)"`. |
| showAngleTool | Flag to show / hide the angle tool to calculate the azimuth of a drawn 2-point line. | `"showAngleTool": true` |

## ZoomToMaxExtent

Expand Down
57 changes: 47 additions & 10 deletions src/components/measuretool/MeasureResult.vue
Original file line number Diff line number Diff line change
@@ -1,51 +1,61 @@
<template>

<div class="">
<div class="measure-result">
<div class="measure-result" v-if="measureType === 'distance' || measureType === 'area'">
{{ $t("wgu-measuretool.length") }}: {{distance}}
</div>
<div class="measure-result">
<div class="measure-result" v-if="measureType === 'area'">
{{ $t("wgu-measuretool.area") }}: {{area}}
</div>
<div class="measure-result" v-if="measureType === 'angle'">
{{ $t("wgu-measuretool.angle") }}: {{angle}}
</div>
</div>

</template>

<script>
import AngleUtil from '../../../src/util/Angle';
import LineStringGeom from 'ol/geom/LineString';
import PolygonGeom from 'ol/geom/Polygon';
import { getArea, getLength } from 'ol/sphere.js';
const EMPTY_RESULT_TEXT = ' -- ';
export default {
name: 'wgu-measure-result',
props: {
measureGeom: { type: Object }
measureGeom: { type: Object },
measureType: { type: String }
},
data () {
return {
area: ' -- ',
distance: ' -- '
area: EMPTY_RESULT_TEXT,
distance: EMPTY_RESULT_TEXT,
angle: EMPTY_RESULT_TEXT
}
},
watch: {
measureGeom () {
const me = this;
const geom = me.measureGeom.geom;
let output;
if (geom instanceof PolygonGeom) {
if (geom && this.measureType === 'area') {
output = me.formatArea(geom);
me.area = output;
// perimeter of outer LinearRing of measure polygon
me.distance = me.formatLength(new LineStringGeom(
geom.getLinearRing(0).getCoordinates()
));
} else if (geom instanceof LineStringGeom) {
} else if (geom && this.measureType === 'distance') {
output = me.formatLength(geom);
me.distance = output;
} else if (geom && this.measureType === 'angle') {
me.angle = me.formatAngle(geom);
} else {
me.area = ' -- ';
me.distance = ' -- ';
me.area = EMPTY_RESULT_TEXT;
me.distance = EMPTY_RESULT_TEXT;
me.angle = EMPTY_RESULT_TEXT;
}
}
},
Expand Down Expand Up @@ -83,6 +93,33 @@ export default {
[Math.round(area * 100) / 100]);
}
return output;
},
/**
* Calculates and formats the angle of the given 2 point line.
*/
formatAngle (line) {
const coords = line.getCoordinates();
const numCoords = coords.length;
if (numCoords < 2) {
return EMPTY_RESULT_TEXT;
}
const firstPoint = coords[0];
const lastPoint = coords[1];
// when clicked only once the geom is a line with 2 identical points
const isSamePoint = firstPoint.toString() === lastPoint.toString();
if (isSamePoint) {
return EMPTY_RESULT_TEXT;
}
let angle = AngleUtil.angle360(firstPoint, lastPoint);
angle = AngleUtil.makeZeroDegreesAtNorth(angle);
angle = AngleUtil.makeClockwise(angle);
angle = angle.toFixed(2);
return angle + '°';
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/measuretool/MeasureTypeChooser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<v-btn large value="area">
{{ $t("wgu-measuretool.area") }}
</v-btn>
<v-btn large value="angle" v-if="showAngleTool">
{{ $t("wgu-measuretool.angle") }}
</v-btn>
</v-btn-toggle>

</template>
Expand All @@ -15,7 +18,8 @@
export default {
name: 'wgu-measure-type-chooser',
props: {
measureType: { type: String, default: 'distance' }
measureType: { type: String, default: 'distance' },
showAngleTool: { type: Boolean, default: false }
},
data () {
return {
Expand Down
6 changes: 4 additions & 2 deletions src/components/measuretool/MeasureWin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
<!-- toggle button to choose measure type -->
<wgu-measure-type-chooser
:measureType="measureType"
:showAngleTool="showAngleTool"
@wgu-measuretype-change="applyMeasureType"
/>
</v-card-title>

<v-card-actions>
<!-- result display -->
<wgu-measure-result :measureGeom="measureGeom" />
<wgu-measure-result :measureGeom="measureGeom" :measureType="measureType" />
</v-card-actions>
</wgu-module-card>
</template>
Expand All @@ -38,7 +39,8 @@ export default {
},
mixins: [Mapable],
props: {
icon: { type: String, required: false, default: 'photo_size_select_small' }
icon: { type: String, required: false, default: 'photo_size_select_small' },
showAngleTool: { type: Boolean, required: false, default: false }
},
data () {
return {
Expand Down
10 changes: 10 additions & 0 deletions src/components/measuretool/OlMeasureController.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export default class OlMeasureController {
const draw = new DrawInteraction({
source: me.source,
type: type,
maxPoints: measureType === 'angle' ? 2 : undefined,
style: new Style({
fill: new Fill({
color: measureConf.sketchFillColor || 'rgba(255, 255, 255, 0.2)'
Expand All @@ -98,6 +99,8 @@ export default class OlMeasureController {
})
})
});
// preserve measure type to re-use in draw events
draw.set('measureType', measureType);
me.map.addInteraction(draw);

let listener;
Expand All @@ -116,8 +119,15 @@ export default class OlMeasureController {
}, me);

draw.on('drawend', () => {
if (draw.get('measureType') === 'angle') {
// execute given callback to update angle
const geom = sketch.getGeometry();
mapClickCb(geom);
}

// unset sketch
sketch = null;

unByKey(listener);
}, me);

Expand Down
5 changes: 3 additions & 2 deletions src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"wgu-toolbar-menu": {
"title": "Menüleiste ausklappen"
},

"wgu-attributetable": {
"title": "Attribut Tabelle",
"selectorLabel": "Layer auswählen",
Expand Down Expand Up @@ -62,7 +62,7 @@
},

"wgu-layerlist": {
"title": "Layer"
"title": "Layer"
},

"wgu-maprecorder": {
Expand All @@ -86,6 +86,7 @@
"distance": "Entfernung",
"length": "Länge",
"area": "Fläche",
"angle": "Winkel",
"lengthKm": "{0} km",
"lengthMeter": "{0} m",
"areaSquareKm": "{0} km²",
Expand Down
9 changes: 5 additions & 4 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"name": "Drag/Drop Data"
}
},

"wgu-toolbar-menu": {
"title": "Open toolbar menu"
},
Expand Down Expand Up @@ -56,13 +56,13 @@

"wgu-infoclick": {
"title": "Map Click Info",
"mapClick": "Click on the map to get information for the clicked map position.",
"mapClick": "Click on the map to get information for the clicked map position.",
"mediaClick": "Click on a feature on the map to show connected media information.",
"mediaInfoLinkText": null
},

"wgu-layerlist": {
"title": "Layers"
"title": "Layers"
},

"wgu-maprecorder": {
Expand All @@ -76,7 +76,7 @@
"stop": "Stop",
"error": "Failed to start recording."
},

"wgu-zoomtomaxextent": {
"title": "Reset Map Extent"
},
Expand All @@ -86,6 +86,7 @@
"distance": "Distance",
"length": "Length",
"area": "Area",
"angle": "Angle",
"lengthKm": "{0} km",
"lengthMeter": "{0} m",
"areaSquareKm": "{0} km²",
Expand Down
80 changes: 80 additions & 0 deletions src/util/Angle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Util class for angle related calculations.
*/
const AngleUtil = {
/**
* Determine the angle between two coordinates. The angle will be between
* -180° and 180°, with 0° being in the east. The angle will increase
* counter-clockwise.
*
* Inspired by http://stackoverflow.com/a/31136507
*
* @param {ol/coordinate} start The start coordinates of the line with the
* x-coordinate being at index `0` and y-coordinate being at index `1`.
* @param {ol/coordinate} end The end coordinates of the line with the
* x-coordinate being at index `0` and y-coordinate being at index `1`.
* @returns {Number} the angle in degrees, ranging from -180° to 180°.
*/
calcAngle (start, end) {
const dx = start[0] - end[0];
const dy = start[1] - end[1];
// range (-PI, PI]
let theta = Math.atan2(dy, dx);
// rads to degs, range (-180, 180]
theta *= 180 / Math.PI;
return theta;
},

/**
* Determine the angle between two coordinates. The angle will be between
* 0° and 360°, with 0° being in the east. The angle will increase
* counter-clockwise.
*
* Inspired by http://stackoverflow.com/a/31136507
*
* @param {ol/coordinate} start The start coordinates of the line with the
* x-coordinate being at index `0` and y-coordinate being at index `1`.
* @param {ol/coordinate} end The end coordinates of the line with the
* x-coordinate being at index `0` and y-coordinate being at index `1`.
* @returns {Number} the angle in degreees, ranging from 0° and 360°.
*/
angle360 (start, end) {
// range (-180, 180]
let theta = this.calcAngle(start, end);
if (theta < 0) {
// range [0, 360)
theta = 360 + theta;
}
return theta;
},

/**
* This methods adds an offset of 90° to an counter-clockwise increasing
* angle of a line so that the origin (0°) lies at the top (in the north).
*
* @param {Number} angle360 The input angle obtained counter-clockwise, with
* 0° degrees being in the east
* @returns {Number} The adjusted angle, with 0° being in the north
*/
makeZeroDegreesAtNorth (angle360) {
let corrected = angle360 + 90;
if (corrected > 360) {
corrected = corrected - 360;
}
return corrected;
},

/**
* Given an angle between 0° and 360° this angle returns the exact opposite
* of the angle, e.g. for 90° you'll get back 270°. This effectively turns
* the direction of the angle from counter-clockwise to clockwise.
*
* @param {Number} angle360 The input angle obtained counter-clockwise
* @returns {Number} The clockwise angle
*/
makeClockwise (angle360) {
return 360 - angle360;
}
}

export default AngleUtil;
Loading

0 comments on commit e4275a8

Please sign in to comment.