/**
* Handler to draw an N sided regular ploygon on the map. A point is drawn on mouse down,
* a line is drawn on mouse move (representing the radius), and the polygon is drawn on mouse up.
* Use the "sides" option to set the number of polygon sides.
*
* @class
* @requires OpenLayers/Handler/Point.js
* @requires OpenLayers/Geometry/Polygon.js
*/
OpenLayers.Handler.RegularPolygon = OpenLayers.Class.create();
OpenLayers.Handler.RegularPolygon.prototype =
OpenLayers.Class.inherit(OpenLayers.Handler.Point, {
/**
* @type OpenLayers.Feature.Vector
* @private
*/
line: null,
/**
* @type OpenLayers.Feature.Vector
* @private
*/
regularPolygon: null,
/**
* The number of sides the polygon will have
* @type int
*/
sides: 50,
/**
* @constructor
*
* @param {OpenLayers.Control} control
* @param {Array} callbacks An object with a 'done' property whos value is
* a function to be called when the path drawing is
* finished. The callback should expect to recieve a
* single argument, the polygon geometry.
* If the callbacks object contains a 'point'
* property, this function will be sent each point
* as they are added. If the callbacks object contains
* a 'cancel' property, this function will be called when
* the handler is deactivated while drawing. The cancel
* should expect to receive a geometry.
* @param {Object} options
*/
initialize: function(control, callbacks, options) {
OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
},
/**
* Add temporary geometries
*/
createFeature: function() {
this.line = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString());
this.point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point());
this.regularPolygon = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon());
},
/**
* Destroy temporary geometries
*/
destroyFeature: function() {
this.line.destroy();
this.point.destroy();
this.regularPolygon.destroy();
this.line = null;
this.regularPolygon = null;
},
/**
* Modify the existing geometry given the new point
*
*/
modifyFeature: function() {
var index = this.line.geometry.components.length - 1;
this.line.geometry.components[index].x = this.point.geometry.x;
this.line.geometry.components[index].y = this.point.geometry.y;
},
/**
* Render geometries on the temporary layer.
*/
drawFeature: function() {
this.layer.drawFeature(this.line, this.style);
this.layer.drawFeature(this.point, this.style);
},
/**
* Add point to geometry. Send the point index to override
* the behavior of LinearRing that disregards adding duplicate points.
*/
addPoint: function() {
this.line.geometry.addComponent(this.point.geometry.clone(),
this.line.geometry.components.length);
this.callback("point", [this.point.geometry]);
},
/**
* Return a clone of the relevant geometry.
*
* @type OpenLayers.Geometry.LineString
*/
geometryClone: function() {
return this.regularPolygon.geometry.clone();
},
createRegularPolygon: function() {
        var pointList = [];
// the radius is the length of the line segment
var radius = this.line.geometry.getLength();
// draw the polygon, the center is the first point drawn at mousedown
if (radius > 0) {
var cenx = this.line.geometry.components[0].x;
var ceny = this.line.geometry.components[0].y;
var piNum = Math.PI * 2;
var segments = piNum / this.sides;
for (var a = 0; a < piNum; a += segments) {
                var x = cenx + radius * Math.sin(a);
                var y = ceny + radius * Math.cos(a);         
var newPoint = new OpenLayers.Geometry.Point(x,y);
pointList.push(newPoint);
}
pointList.push(pointList[0]);
var linearRing = new OpenLayers.Geometry.LinearRing(pointList);
this.regularPolygon.geometry.addComponent(linearRing);
}
},
/**
* Return the radius of the polygon
*
* @type int
*/
getRadius: function() {
this.line.geometry.getLength();
},
/**
* Handle mouse down. Add the starting (center) point of the polygon and render it
* Return determines whether to propagate the event on the map.
*
* @param {Event} evt
* @type Boolean
*/
mousedown: function(evt) {
if(this.line == null) {
this.createFeature();
}
this.mouseDown = true;
var lonlat = this.control.map.getLonLatFromPixel(evt.xy);
this.point.geometry.x = lonlat.lon;
this.point.geometry.y = lonlat.lat;
this.addPoint();
this.drawFeature();
return false;
},
/**
* Handle mouse move. Adjust the geometry and redraw the line.
* Return determines whether to propagate the event on the map.
*
* @param {Event} evt
* @type Boolean
*/
mousemove: function (evt) {
if ((this.line == null) || (this.line.geometry == null))
return true;
if(this.line.geometry.components.length > 0) {
var lonlat = this.map.getLonLatFromPixel(evt.xy);
if (this.line.geometry.components.length == 1) {
this.point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point());
this.addPoint();
}
this.point.geometry.x = lonlat.lon;
this.point.geometry.y = lonlat.lat;
this.modifyFeature();
this.drawFeature();
}
return false;
},
/**
* Handle mouse up. Send the last point in the geometry to the control. If we
* have a valid line segment (radius), then draw the polygon.
* Return determines whether to propagate the event on the map.
*
* @param {Event} evt
* @type Boolean
*/
mouseup: function (evt) {
this.mouseDown = false;
if (this.line.geometry.components.length == 2) {
this.createRegularPolygon();
}
this.point.destroy();
this.line.destroy();
this.finalize();
return false;
},
/** @final @type String */
CLASS_NAME: "OpenLayers.Handler.RegularPolygon"
});