Skip to content

Commit feb03ce

Browse files
committed
feat: limit max guides generated per feature via an option
1 parent c808a36 commit feb03ce

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"description": "OpenLayers Editor",
55
"version": "2.4.4",
66
"main": "build/index.js",
7-
"dependencies": {},
87
"peerDependencies": {
98
"jsts": ">=2",
109
"lodash.throttle": ">=4",

src/control/cad.js

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { times, sortedIndexBy } from 'lodash';
12
import { Style, Stroke } from 'ol/style';
23
import { Point, LineString, Polygon, MultiPoint, Circle } from 'ol/geom';
34
import Feature from 'ol/Feature';
45
import Vector from 'ol/layer/Vector';
56
import VectorSource from 'ol/source/Vector';
67
import { Pointer, Snap } from 'ol/interaction';
8+
import { distance as euclideanDistance } from 'ol/coordinate';
79
import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay';
810
import { getUid } from 'ol/util';
911
import Control from './control';
@@ -40,6 +42,8 @@ class CadControl extends Control {
4042
* @param {Function} [options.lineFilter] An optional filter for the generated snapping lines
4143
* array (takes the lines and cursor coordinate as arguments and returns the new line array)
4244
* @param {Number} [options.nbClosestFeatures] Number of features to use for snapping (closest first). Default is 5.
45+
* @param {Number} [options.limitGuidesPerFeature] A feature with complex geometry may generate
46+
* a large number of lines. This option can be used to limit the guides to the n closest segments. Deafult is 3.
4347
* @param {Number} [options.snapTolerance] Snap tolerance in pixel
4448
* for snap lines. Default is 10.
4549
* @param {Boolean} [options.showSnapLines] Whether to show
@@ -134,6 +138,18 @@ class CadControl extends Control {
134138
this.nbClosestFeatures =
135139
options.nbClosestFeatures === undefined ? 5 : options.nbClosestFeatures;
136140

141+
/**
142+
* Number of guide lines to limit cad to generate for a single feature.
143+
* this.nbClosestFeatures * this.limitGuidesPerFeature will be the maximum
144+
* number of guides shown at any time. Default is 3.
145+
* @type {Number}
146+
* @private
147+
*/
148+
this.limitGuidesPerFeature =
149+
options.limitGuidesPerFeature === undefined
150+
? 3
151+
: options.limitGuidesPerFeature;
152+
137153
/**
138154
* Snap tolerance in pixel.
139155
* @type {Number}
@@ -505,7 +521,6 @@ class CadControl extends Control {
505521
getSegmentLines(coordinate, snapCoords, snapCoordsBefore) {
506522
const mousePx = this.map.getPixelFromCoordinate(coordinate);
507523
const doubleTol = this.snapTolerance * 2;
508-
const [mouseX, mouseY] = mousePx;
509524
const lines = [];
510525

511526
for (let i = 0; i < snapCoords.length; i += 1) {
@@ -522,13 +537,12 @@ class CadControl extends Control {
522537

523538
// Calculate projected point
524539
const projMousePx = getProjectedPoint(mousePx, snapPxBefore, snapPx);
525-
const [projMouseX, projMouseY] = projMousePx;
526-
const distance = Math.sqrt(
527-
(projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2,
528-
);
540+
const distance = euclideanDistance(mousePx, projMousePx);
541+
529542
let newPt;
530543

531544
if (distance <= this.snapTolerance) {
545+
const [projMouseX, projMouseY] = projMousePx;
532546
// lineFunc is undefined when it's a vertical line
533547
const lineFunc = getEquationOfLine(snapPxBefore, snapPx);
534548
const newX = projMouseX + (projMouseX < snapX ? -doubleTol : doubleTol);
@@ -557,7 +571,6 @@ class CadControl extends Control {
557571
getOrthoLines(coordinate, snapCoords, snapCoordsBefore) {
558572
const mousePx = this.map.getPixelFromCoordinate(coordinate);
559573
const doubleTol = this.snapTolerance * 2;
560-
const [mouseX, mouseY] = mousePx;
561574
const lines = [];
562575

563576
for (let i = 0; i < snapCoords.length; i += 1) {
@@ -579,13 +592,11 @@ class CadControl extends Control {
579592
[orthoLine1, orthoLine2].forEach((line) => {
580593
const [anchorPx, last] = line.getCoordinates();
581594
const projMousePx = getProjectedPoint(mousePx, anchorPx, last);
582-
const [projMouseX, projMouseY] = projMousePx;
583-
const distance = Math.sqrt(
584-
(projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2,
585-
);
595+
const distance = euclideanDistance(mousePx, projMousePx);
586596

587597
let newPt;
588598
if (distance <= this.snapTolerance) {
599+
const [projMouseX, projMouseY] = projMousePx;
589600
// lineFunc is undefined when it's a vertical line
590601
const lineFunc = getEquationOfLine(anchorPx, projMousePx);
591602
const newX =
@@ -623,6 +634,38 @@ class CadControl extends Control {
623634
const snapCoords = [];
624635
const snapCoordsAfter = []; // store the direct next point in the coordinate array
625636

637+
// Parse the list of coords, we will add the ortho and segment lines which
638+
// are closest to the users cursor up until the limit of `this.limitGuidesPerFeature`
639+
const parseCoordList = (coords) => {
640+
let includedCoords;
641+
if (coords.length > this.limitGuidesPerFeature) {
642+
includedCoords = [];
643+
// Check the euclidean distance between coord at index and the
644+
// included vertices so far. Create an array of `this.limitGuidesPerFeature`
645+
// closest items.
646+
for (let index = 0; index < coords.length; index += 1) {
647+
const addIndex = sortedIndexBy(includedCoords, index, (i) =>
648+
euclideanDistance(coords[i], coordinate),
649+
);
650+
if (addIndex < this.limitGuidesPerFeature) {
651+
includedCoords.splice(
652+
addIndex,
653+
includedCoords.length === this.limitGuidesPerFeature ? 1 : 0,
654+
index,
655+
);
656+
}
657+
}
658+
} else {
659+
includedCoords = times(coords.length);
660+
}
661+
662+
includedCoords.forEach((index) => {
663+
snapCoordsBefore.push(coords[index - 1]);
664+
snapCoords.push(coords[index]);
665+
snapCoordsAfter.push(coords[index + 1]);
666+
});
667+
};
668+
626669
for (let i = 0; i < features.length; i += 1) {
627670
const geom = features[i].getGeometry();
628671
let featureCoord = geom.getCoordinates();
@@ -641,17 +684,9 @@ class CadControl extends Control {
641684
// Add feature vertices
642685
// eslint-disable-next-line no-lonely-if
643686
if (geom instanceof LineString) {
644-
for (let j = 0; j < featureCoord.length; j += 1) {
645-
snapCoordsBefore.push(featureCoord[j - 1]);
646-
snapCoords.push(featureCoord[j]);
647-
snapCoordsAfter.push(featureCoord[j + 1]);
648-
}
687+
parseCoordList(featureCoord);
649688
} else if (geom instanceof Polygon) {
650-
for (let j = 0; j < featureCoord[0].length; j += 1) {
651-
snapCoordsBefore.push(featureCoord[0][j - 1]);
652-
snapCoords.push(featureCoord[0][j]);
653-
snapCoordsAfter.push(featureCoord[0][j + 1]);
654-
}
689+
parseCoordList(featureCoord[0]);
655690
}
656691

657692
// Add extent vertices

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3904,7 +3904,7 @@ lodash.upperfirst@^4.3.1:
39043904

39053905
lodash@^4.0.1, lodash@^4.17.15, lodash@^4.17.21:
39063906
version "4.17.21"
3907-
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
3907+
resolved "https://npm.clearpathrobotics.com:443/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
39083908
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
39093909

39103910
log-symbols@^4.0.0:

0 commit comments

Comments
 (0)