const inherit = require('../inherit');
const registerAnnotation = require('../registry').registerAnnotation;
const markerFeature = require('../markerFeature');
const util = require('../util');
const annotationState = require('./annotation').state;
const rectangleAnnotation = require('./rectangleAnnotation');
/**
* Ellipse annotation class.
*
* Ellipses are always rendered as markers.
*
* @class
* @alias geo.ellipseAnnotation
* @extends geo.annotation
*
* @param {geo.ellipseAnnotation.spec?} [args] Options for the annotation.
* @param {string} [annotationName='ellipse'] Override the annotation name.
*/
var ellipseAnnotation = function (args, annotationName) {
'use strict';
if (!(this instanceof ellipseAnnotation)) {
return new ellipseAnnotation(args, annotationName);
}
args = util.deepMerge({}, this.constructor.defaults, args);
rectangleAnnotation.call(this, args, annotationName || 'ellipse');
var m_this = this;
/**
* Get a list of renderable features for this annotation.
*
* @returns {array} An array of features.
*/
this.features = function () {
var opt = m_this.options(),
state = m_this.state(),
features;
features = [];
if (opt.corners && opt.corners.length >= 4) {
const style = m_this.styleForState(state);
const w = ((opt.corners[0].x - opt.corners[1].x) ** 2 + (opt.corners[0].y - opt.corners[1].y) ** 2) ** 0.5;
const h = ((opt.corners[0].x - opt.corners[3].x) ** 2 + (opt.corners[0].y - opt.corners[3].y) ** 2) ** 0.5;
const radius = Math.max(w, h) / 2 / m_this.layer().map().unitsPerPixel(0);
const aspect = w ? h / w : 1e20;
const rotation = -Math.atan2(opt.corners[1].y - opt.corners[0].y, opt.corners[1].x - opt.corners[0].x);
features = [{
marker: {
x: (opt.corners[0].x + opt.corners[1].x + opt.corners[2].x + opt.corners[3].x) / 4,
y: (opt.corners[0].y + opt.corners[1].y + opt.corners[2].y + opt.corners[3].y) / 4,
style: Object.assign(
{}, style,
{
radius: radius,
symbolValue: aspect,
rotation: rotation,
strokeOffset: 0,
radiusIncludesStroke: false,
scaleWithZoom: markerFeature.scaleMode.fill,
rotateWithMap: true,
strokeOpacity: style.stroke === false ? 0 : style.strokeOpacity,
fillOpacity: style.fill === false ? 0 : style.fillOpacity
})
}
}];
}
if (state === annotationState.edit) {
m_this._addEditHandles(features, opt.corners);
}
return features;
};
/**
* Return this annotation as a polygon list.
*
* @param {geo.util.polyop.spec} [opts] The ``tolerance`` and
* ``pixelTolerance`` parameters are used if set. Otherwise, a polygon is
* approximated to 1/10th of a pixel at the map's current maximum zoom
* level.
* @returns {geo.polygonList} A list of polygons.
*/
this.toPolygonList = function (opts) {
const coord = m_this._coordinates();
if (coord.length < 3) {
return [];
}
let tolerance = (opts && opts.tolerance) || 0;
if (!tolerance) {
const map = m_this.layer().map();
if (opts && opts.pixelTolerance) {
tolerance = map.unitsPerPixel(map.zoom()) * opts.pixelTolerance;
} else {
tolerance = map.unitsPerPixel(map.zoomRange().max) * 0.1;
}
}
const w = ((coord[0].x - coord[1].x) ** 2 + (coord[0].y - coord[1].y) ** 2) ** 0.5;
const h = ((coord[0].x - coord[3].x) ** 2 + (coord[0].y - coord[3].y) ** 2) ** 0.5;
const cx = (coord[0].x + coord[2].x) / 2;
const cy = (coord[0].y + coord[2].y) / 2;
const radius = Math.max(w, h) / 2;
const rotation = -Math.atan2(coord[1].y - coord[0].y, coord[1].x - coord[0].x);
const sides = Math.max(12, Math.ceil(Math.PI / Math.acos((radius - tolerance) / (radius + tolerance))));
const a = w / 2 * (1 + (1 - Math.cos(Math.PI / sides)) / 2);
const b = h / 2 * (1 + (1 - Math.cos(Math.PI / sides)) / 2);
const poly = [];
const cosr = Math.cos(rotation), sinr = Math.sin(rotation);
for (let s = 0; s < sides; s += 1) {
const sa = Math.PI * 2 * s / sides;
const cosa = Math.cos(sa), sina = Math.sin(sa);
const x = cx + a * cosr * cosa - b * sinr * sina;
const y = cy + a * sinr * cosa + b * cosr * sina;
poly.push([x, y]);
}
return [[poly]];
};
};
inherit(ellipseAnnotation, rectangleAnnotation);
/**
* This object contains the default options to initialize the class.
*/
ellipseAnnotation.defaults = Object.assign({}, rectangleAnnotation.defaults, {
});
var ellipseRequiredFeatures = {};
ellipseRequiredFeatures[markerFeature.capabilities.feature] = true;
registerAnnotation('ellipse', ellipseAnnotation, ellipseRequiredFeatures);
module.exports = ellipseAnnotation;