1+ import { times , sortedIndexBy } from 'lodash' ;
12import { Style , Stroke } from 'ol/style' ;
23import { Point , LineString , Polygon , MultiPoint , Circle } from 'ol/geom' ;
34import Feature from 'ol/Feature' ;
45import Vector from 'ol/layer/Vector' ;
56import VectorSource from 'ol/source/Vector' ;
67import { Pointer , Snap } from 'ol/interaction' ;
8+ import { distance as euclideanDistance } from 'ol/coordinate' ;
79import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay' ;
810import { getUid } from 'ol/util' ;
911import 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
0 commit comments