Skip to content

Commit 9c78d46

Browse files
committed
perf: Allow cutting annotations by polygon or line
Before, we just supported line cuts. This adds alt-ctrl polygon to use a polygon for cutting.
1 parent b8400ed commit 9c78d46

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

src/annotationLayer.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ var annotationLayer = function (arg) {
224224
*/
225225
this._handleBooleanOperation = function () {
226226
const op = m_this.currentBooleanOperation();
227-
if (!op || !m_this.currentAnnotation || (op !== 'cut' && !m_this.currentAnnotation.toPolygonList) || (op === 'cut' && !(m_this.currentAnnotation instanceof lineAnnotation))) {
227+
if (!op || !m_this.currentAnnotation || (!m_this.currentAnnotation.toPolygonList && (op !== 'cut' || !(m_this.currentAnnotation instanceof lineAnnotation)))) {
228228
return;
229229
}
230230
const newAnnot = m_this.currentAnnotation;
@@ -245,6 +245,16 @@ var annotationLayer = function (arg) {
245245
}
246246
};
247247

248+
/**
249+
* Given a line defined by two points, extend the first point to intersect a
250+
* bounding box.
251+
*
252+
* @param {number[]} p1 A 2-coordinate point.
253+
* @param {number[]} p2 A 2-coordinate point.
254+
* @param {object} bbox A bounding box consisting on min and max, each of
255+
* which has x and y.
256+
* @returns {number[]} A 2-coordinate point.
257+
*/
248258
this._extendLine = function (p1, p2, bbox) {
249259
const dx = p2[0] - p1[0];
250260
const dy = p2[1] - p1[1];
@@ -270,12 +280,12 @@ var annotationLayer = function (arg) {
270280
};
271281

272282
/**
273-
* Given a cut line, cut existing polygons and lines.
283+
* Convert a line annotation to a polygonList.
274284
*
275-
* @param {geo.annotation} cutLine The line to use to cut the existing
276-
* annotations.
285+
* @param {geo.annotation} cutLine The line to convert.
286+
* @returns {geo.polygonList} A list of polygons.
277287
*/
278-
this.cutOperation = function (cutLine) {
288+
this._cutLineToPoly = function (cutLine) {
279289
const cutPts = cutLine.coordinates(null).map((p) => [p.x, p.y]);
280290
let range;
281291
for (let p = 0; p < cutPts.length; p += 1) {
@@ -316,7 +326,7 @@ var annotationLayer = function (arg) {
316326
}
317327
});
318328
if (range === undefined || range.min.x === range.max.x || range.min.y === range.max.y) {
319-
return;
329+
return [];
320330
}
321331
// expand the range so that all polygons and lines, including our cut line
322332
// are guaranteed to be inside the bounding box.
@@ -341,14 +351,30 @@ var annotationLayer = function (arg) {
341351
for (let idx = idx0; idx % 4 !== idx1; idx += 1) {
342352
cutPoly.push(corners[idx % 4]);
343353
}
354+
return [[cutPoly]];
355+
};
356+
357+
/**
358+
* Given a cut line or polygon, cut existing polygons and lines.
359+
*
360+
* @param {geo.annotation} cutLineOrPoly The line or polygon to use to cut
361+
* the existing annotations.
362+
*/
363+
this.cutOperation = function (cutLineOrPoly) {
364+
let cutPoly;
365+
if (cutLineOrPoly instanceof lineAnnotation) {
366+
cutPoly = this._cutLineToPoly(cutLineOrPoly);
367+
} else {
368+
cutPoly = cutLineOrPoly.toPolygonList();
369+
}
344370
// mimic some of what is done in fromPolygonList because we need both sides
345371
// of the cut.
346372
let diffPoly;
347373
const annot = m_this.annotations();
348-
const diff = {poly2: [[cutPoly]], correspond: {}, keepAnnotations: 'exact', style: {fromPolygonList: (poly, opts) => { diffPoly = poly; }}};
374+
const diff = {poly2: cutPoly, correspond: {}, keepAnnotations: 'exact', style: {fromPolygonList: (poly, opts) => { diffPoly = poly; }}};
349375
diff.poly1 = m_this.toPolygonList(diff);
350376
util.polyops.difference(diff);
351-
util.polyops.intersect(m_this, [[cutPoly]], {correspond: {}, keepAnnotations: 'exact', style: m_this});
377+
util.polyops.intersect(m_this, cutPoly, {correspond: {}, keepAnnotations: 'exact', style: m_this});
352378
const indices = (diff.annotationIndices || {})[m_this.id()];
353379
const correspond = diff.correspond.poly1;
354380
const exact = diff.correspond.exact1;
@@ -422,7 +448,7 @@ var annotationLayer = function (arg) {
422448
return;
423449
}
424450
const op = Object.keys(m_this._booleanClasses).find((op) =>
425-
m_this._booleanClasses[op] === mod && (ops === true || ops.includes(op)));
451+
m_this._booleanClasses[op].includes(mod) && (ops === true || ops.includes(op)));
426452
if (m_this._currentBooleanClass === op) {
427453
return;
428454
}
@@ -807,11 +833,11 @@ var annotationLayer = function (arg) {
807833
/* Keys are classes to apply to the map node. Values are short-hand for
808834
* preferred event modifiers. */
809835
this._booleanClasses = {
810-
'annotation-union': 's',
811-
'annotation-intersect': 'sc',
812-
'annotation-difference': 'c',
813-
'annotation-xor': 'sa',
814-
'annotation-cut': 'c'
836+
'annotation-union': ['s'],
837+
'annotation-intersect': ['sc'],
838+
'annotation-difference': ['c'],
839+
'annotation-xor': ['sa'],
840+
'annotation-cut': ['c', 'ca']
815841
};
816842

817843
/**

tests/cases/annotationLayer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ describe('geo.annotationLayer', function () {
148148
expect(layer.annotations().length).toBe(6);
149149
layer.cutOperation(line2);
150150
expect(layer.annotations().length).toBe(5);
151+
layer.cutOperation(rect2);
152+
expect(layer.annotations().length).toBe(5);
151153
});
152154
});
153155
describe('Public utility functions', function () {

0 commit comments

Comments
 (0)