Skip to content

Commit

Permalink
Merge pull request #976 from OpenGeoscience/polygon-annotation-drag
Browse files Browse the repository at this point in the history
Allow continuous drawing of polygon annotations.
  • Loading branch information
manthey authored Feb 19, 2019
2 parents 89facb1 + e24be5f commit 46df92a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 55 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### Features
- Polygon annotations can be drawn in the same continuous smooth manner as line annotations.

### Changes
- Rename the d3 renderer to svg. d3 still works as an alias (#965)
- Rename the vgl renderer to webgl. vgl still works as an alias (#965)
Expand Down
166 changes: 112 additions & 54 deletions src/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,89 @@ var annotation = function (type, args) {
};
};

/* Functions used by multiple annotations */

/**
* Return actions needed for the specified state of this annotation.
*
* @param {object} m_this The current annotation instance.
* @param {function} s_actions The parent actions method.
* @param {string} [state] The state to return actions for. Defaults to
* the current state.
* @param {string} name The name of this annotation.
* @param {Array} originalArgs arguments to original call
* @returns {geo.actionRecord[]} A list of actions.
*/
function continuousVerticesActions(m_this, s_actions, state, name, originalArgs) {
if (!state) {
state = m_this.state();
}
switch (state) {
case annotationState.create:
return [{
action: geo_action['annotation_' + name],
name: name + ' create',
owner: annotationActionOwner,
input: 'left',
modifiers: {shift: false, ctrl: false}
}, {
action: geo_action['annotation_' + name],
name: name + ' create',
owner: annotationActionOwner,
input: 'pan'
}];
default:
return s_actions.apply(m_this, originalArgs);
}
}

/**
* Process actions to allow drawing continuous vertices for an annotation.
*
* @param {object} m_this The current annotation instance.
* @param {geo.event} evt The action event.
* @param {string} name The name of this annotation.
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
* annotation was completed (changed from create to done state),
* `'remove'` if the annotation should be removed, falsy to not update
* anything.
*/
function continuousVerticesProcessAction(m_this, evt, name) {
var layer = m_this.layer();
if (m_this.state() !== annotationState.create || !layer ||
evt.state.action !== geo_action['annotation_' + name]) {
return;
}
var cpp = layer.options('continuousPointProximity');
var cpc = layer.options('continuousPointColinearity');
if (cpp || cpp === 0) {
var vertices = m_this.options('vertices');
if (!vertices.length) {
vertices.push(evt.mouse.mapgcs);
vertices.push(evt.mouse.mapgcs);
return true;
}
var dist = layer.displayDistance(vertices[vertices.length - 2], null, evt.mouse.map, 'display');
if (dist && dist > cpp) {
// combine nearly colinear points
if (vertices.length >= (m_this._lastClickVertexCount || 1) + 3) {
var d01 = layer.displayDistance(vertices[vertices.length - 3], null, vertices[vertices.length - 2], null),
d12 = dist,
d02 = layer.displayDistance(vertices[vertices.length - 3], null, evt.mouse.map, 'display');
if (d01 && d02) {
var costheta = (d02 * d02 - d01 * d01 - d12 * d12) / (2 * d01 * d12);
if (costheta > Math.cos(cpc)) {
vertices.pop();
}
}
}
vertices[vertices.length - 1] = evt.mouse.mapgcs;
vertices.push(evt.mouse.mapgcs);
return true;
}
}
}

/**
* Rectangle annotation specification. Extends {@link geo.annotation.spec}.
*
Expand Down Expand Up @@ -1530,7 +1613,8 @@ var polygonAnnotation = function (args) {
delete args.coordinates;
annotation.call(this, 'polygon', args);

var m_this = this;
var m_this = this,
s_actions = this.actions;

/**
* Get a list of renderable features for this annotation. When the polygon
Expand Down Expand Up @@ -1660,6 +1744,7 @@ var polygonAnnotation = function (args) {
vertices.push(evt.mapgcs);
}
m_this._lastClick = evt.time;
m_this._lastClickVertexCount = vertices.length;
}
if (end) {
if (vertices.length < 4) {
Expand All @@ -1672,6 +1757,30 @@ var polygonAnnotation = function (args) {
return !skip;
};

/**
* Return actions needed for the specified state of this annotation.
*
* @param {string} [state] The state to return actions for. Defaults to
* the current state.
* @returns {geo.actionRecord[]} A list of actions.
*/
this.actions = function (state) {
return continuousVerticesActions(m_this, s_actions, state, 'polygon', arguments);
};

/**
* Process any actions for this annotation.
*
* @param {geo.event} evt The action event.
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
* annotation was completed (changed from create to done state),
* `'remove'` if the annotation should be removed, falsy to not update
* anything.
*/
this.processAction = function (evt) {
return continuousVerticesProcessAction(m_this, evt, 'polygon');
};

/**
* Return the coordinates to be stored in a geojson geometry object.
*
Expand Down Expand Up @@ -1934,26 +2043,7 @@ var lineAnnotation = function (args) {
* @returns {geo.actionRecord[]} A list of actions.
*/
this.actions = function (state) {
if (!state) {
state = m_this.state();
}
switch (state) {
case annotationState.create:
return [{
action: geo_action.annotation_line,
name: 'line create',
owner: annotationActionOwner,
input: 'left',
modifiers: {shift: false, ctrl: false}
}, {
action: geo_action.annotation_line,
name: 'line create',
owner: annotationActionOwner,
input: 'pan'
}];
default:
return s_actions.apply(m_this, arguments);
}
return continuousVerticesActions(m_this, s_actions, state, 'line', arguments);
};

/**
Expand All @@ -1966,39 +2056,7 @@ var lineAnnotation = function (args) {
* anything.
*/
this.processAction = function (evt) {
var layer = m_this.layer();
if (m_this.state() !== annotationState.create || !layer ||
evt.state.action !== geo_action.annotation_line) {
return;
}
var cpp = layer.options('continuousPointProximity');
var cpc = layer.options('continuousPointColinearity');
if (cpp || cpp === 0) {
var vertices = m_this.options('vertices');
if (!vertices.length) {
vertices.push(evt.mouse.mapgcs);
vertices.push(evt.mouse.mapgcs);
return true;
}
var dist = layer.displayDistance(vertices[vertices.length - 2], null, evt.mouse.map, 'display');
if (dist && dist > cpp) {
// combine nearly colinear points
if (vertices.length >= (m_this._lastClickVertexCount || 1) + 3) {
var d01 = layer.displayDistance(vertices[vertices.length - 3], null, vertices[vertices.length - 2], null),
d12 = dist,
d02 = layer.displayDistance(vertices[vertices.length - 3], null, evt.mouse.map, 'display');
if (d01 && d02) {
var costheta = (d02 * d02 - d01 * d01 - d12 * d12) / (2 * d01 * d12);
if (costheta > Math.cos(cpc)) {
vertices.pop();
}
}
}
vertices[vertices.length - 1] = evt.mouse.mapgcs;
vertices.push(evt.mouse.mapgcs);
return true;
}
}
return continuousVerticesProcessAction(m_this, evt, 'line');
};

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/annotationLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('geo.annotationLayer', function () {
expect(layer.mode()).toBe('polygon');
expect(layer.annotations().length).toBe(1);
expect(layer.annotations()[0].id()).not.toBe(id);
expect(map.interactor().hasAction(undefined, undefined, geo.annotation.actionOwner)).toBeNull();
expect(map.interactor().hasAction(undefined, undefined, geo.annotation.actionOwner)).not.toBeNull();
expect(layer.mode('rectangle')).toBe(layer);
expect(layer.mode()).toBe('rectangle');
expect(map.interactor().hasAction(undefined, undefined, geo.annotation.actionOwner)).not.toBeNull();
Expand Down

0 comments on commit 46df92a

Please sign in to comment.