Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Fixed size annotations. #1205

Merged
merged 1 commit into from
May 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# GeoJS Change Log

## Version 1.8.6

### Improvements

- Allow constraining rectangle and ellipse annotations to a list of fixed sizes ([#1205](../../pull/1205))

## Version 1.8.5

### Improvements

-Optimize reordering fetch queue ([#1203](../../pull/1203))
- Optimize reordering fetch queue ([#1203](../../pull/1203))

## Version 1.8.4

Expand Down
38 changes: 27 additions & 11 deletions src/annotation/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1266,10 +1266,12 @@ function continuousVerticesProcessAction(m_this, evt, name) {
* that the aspect ratio of a rectangle-like selection is a specific value or
* range of values.
*
* @param {number|number[]} ratio Either a single aspect ratio or a list of
* allowed aspect ratios. For instance, 1 will require that the selection
* square, 2 would require that it is twice as wide as tall, [2, 1/2] would
* allow it to be twice as wide or half as wide as it is tall.
* @param {number|number[]|geo.geoSize|geo.geoSize[]} ratio Either a single
* aspect ratio, a single size, or a list of allowed aspect ratios and sizes.
* For instance, 1 will require that the selection square, 2 would require
* that it is twice as wide as tall, [2, 1/2] would allow it to be twice as
* wide or half as wide as it is tall. Sizes (e.g., {width: 400, height:
* 500}) snap to that size.
* @returns {function} A function that can be passed to the mapIterator
* selectionConstraint or to an annotation constraint function.
*/
Expand Down Expand Up @@ -1315,16 +1317,23 @@ function constrainAspectRatio(ratio) {
const area = Math.abs(dist1 * dist3);
let shape, edge;
ratios.forEach((ratio) => {
if (ratio !== 1 && !(index % 2)) {
ratio = 1.0 / ratio;
let width, height;
if (ratio.width) {
width = ratio.width;
height = ratio.height;
} else {
width = (area * ratio) ** 0.5;
height = width / ratio;
}
const width = (area * ratio) ** 0.5;
const score = (width - dist3) ** 2 + (width / ratio - dist1) ** 2;
if (width !== height && !(index % 2)) {
[width, height] = [height, width];
}
const score = (width - dist3) ** 2 + (height - dist1) ** 2;
if (best === undefined || score < best) {
best = score;
shape = {
w: width,
h: width / ratio
h: height
};
}
});
Expand Down Expand Up @@ -1366,10 +1375,17 @@ function constrainAspectRatio(ratio) {
/* Not in edit vertex or edge mode */
const area = Math.abs((pos.x - origin.x) * (pos.y - origin.y));
ratios.forEach((ratio) => {
const width = (area * ratio) ** 0.5;
let width, height;
if (ratio.width) {
width = ratio.width;
height = ratio.height;
} else {
width = (area * ratio) ** 0.5;
height = width / ratio;
}
const adjusted = {
x: origin.x + Math.sign(pos.x - origin.x) * width,
y: origin.y + Math.sign(pos.y - origin.y) * width / ratio
y: origin.y + Math.sign(pos.y - origin.y) * height
};
const score = (adjusted.x - pos.x) ** 2 + (adjusted.y - pos.y) ** 2;
if (best === undefined || score < best) {
Expand Down
9 changes: 9 additions & 0 deletions src/typedef.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@
* @property {number} [z=0] Altitude coordinate, often zero.
*/

/**
* Represention of a size in gcs coordinates.
*
* @typedef geo.geoSize
* @type {object}
* @property {number} width Width in gcs coordinates.
* @property {number} height Height in gcs coordinates.
*/

/**
* Represention of a size in pixels.
*
Expand Down
65 changes: 65 additions & 0 deletions tests/cases/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,71 @@ describe('geo.annotation', function () {
});
});

describe('contrainAspectRatio', function () {
it('ratio', function () {
const func = geo.annotation.constrainAspectRatio([2, 0.5]);

let result;
result = func(
{x: 40, y: 5},
{x: 0, y: 0});
expect(result.pos).toEqual({x: 20, y: 10});
result = func(
{x: 40, y: 5},
{x: 0, y: 0},
[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}]);
expect(result.pos).toEqual({x: 20, y: 10});
result = func(
{x: 5, y: 40},
{x: 0, y: 0},
[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}]);
expect(result.pos).toEqual({x: 10, y: 20});
result = func(
{x: 0, y: 0},
{x: 0, y: 0},
[{x: -10, y: 5}, {x: 30, y: 5}, {x: 30, y: 10}, {x: -10, y: 10}],
'edge', [0, -Math.PI / 2, Math.PI, Math.PI / 2], 0);
expect(result.corners).toEqual([{x: 20, y: 20}, {x: 0, y: 20}, {x: 0, y: 10}, {x: 20, y: 10}]);
result = func(
{x: 0, y: 0},
{x: 0, y: 0},
[{x: -10, y: 5}, {x: 30, y: 5}, {x: 30, y: 10}, {x: -10, y: 10}],
'vertex', [0, -Math.PI / 2, Math.PI, Math.PI / 2], 0);
expect(result.corners).toEqual([{x: 10, y: 20}, {x: 30, y: 20}, {x: 30, y: 10}, {x: 10, y: 10}]);
});
it('fixed size', function () {
const func = geo.annotation.constrainAspectRatio({width: 20, height: 10});

let result;
result = func(
{x: 40, y: 5},
{x: 0, y: 0});
expect(result.pos).toEqual({x: 20, y: 10});
result = func(
{x: 40, y: 5},
{x: 0, y: 0},
[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}]);
expect(result.pos).toEqual({x: 20, y: 10});
result = func(
{x: 5, y: 40},
{x: 0, y: 0},
[{x: 0, y: 0}, {x: 10, y: 0}, {x: 10, y: 10}, {x: 0, y: 10}]);
expect(result.pos).toEqual({x: 20, y: 10});
result = func(
{x: 0, y: 0},
{x: 0, y: 0},
[{x: -10, y: 5}, {x: 30, y: 5}, {x: 30, y: 10}, {x: -10, y: 10}],
'edge', [0, -Math.PI / 2, Math.PI, Math.PI / 2], 0);
expect(result.corners).toEqual([{x: 20, y: 20}, {x: 0, y: 20}, {x: 0, y: 10}, {x: 20, y: 10}]);
result = func(
{x: 0, y: 0},
{x: 0, y: 0},
[{x: -10, y: 5}, {x: 30, y: 5}, {x: 30, y: 10}, {x: -10, y: 10}],
'vertex', [0, -Math.PI / 2, Math.PI, Math.PI / 2], 0);
expect(result.corners).toEqual([{x: 10, y: 20}, {x: 30, y: 20}, {x: 30, y: 10}, {x: 10, y: 10}]);
});
});

describe('annotation registry', function () {
var newshapeCount = 0;
it('listAnnotations', function () {
Expand Down