[OpenLayers-Commits] r4205 - in trunk/openlayers: examples lib lib/OpenLayers/Geometry lib/OpenLayers/Handler tests tests/Geometry tests/Handler

commits at openlayers.org commits at openlayers.org
Mon Sep 10 16:24:28 EDT 2007


Author: tschaub
Date: 2007-09-10 16:24:27 -0400 (Mon, 10 Sep 2007)
New Revision: 4205

Added:
   trunk/openlayers/examples/regular-polygons.html
   trunk/openlayers/lib/OpenLayers/Handler/RegularPolygon.js
   trunk/openlayers/tests/Handler/test_RegularPolygon.html
Modified:
   trunk/openlayers/lib/OpenLayers.js
   trunk/openlayers/lib/OpenLayers/Geometry/Polygon.js
   trunk/openlayers/tests/Geometry/test_Polygon.html
   trunk/openlayers/tests/list-tests.html
Log:
Adding a RegularPolygon handler for drawing squares, triangles, circles, etc.  Demo in the regular-polygon.html example.  Also adding a createRegularPolygon class method to the Polygon geometry class.  Thanks to crschmidt for all the tests and help getting this in (closes #828).

Added: trunk/openlayers/examples/regular-polygons.html
===================================================================
--- trunk/openlayers/examples/regular-polygons.html	                        (rev 0)
+++ trunk/openlayers/examples/regular-polygons.html	2007-09-10 20:24:27 UTC (rev 4205)
@@ -0,0 +1,162 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>OpenLayers Regular Polygon Example</title>
+    <style type="text/css">
+        html, body {
+            margin: 0;
+            padding: 1em;
+            font: 0.9em Verdana, Arial, sans serif;
+        }
+        input, select, textarea {
+            font: 1em Verdana, Arial, sans serif;
+        }
+        #map {
+            width: 512px;
+            height: 350px;
+            border: 1px solid gray;
+        }
+        p {
+            width: 512px;
+        }
+        #config {
+            margin-top: 1em;
+            width: 512px;
+            position: relative;
+            height: 8em;
+        }
+        #controls {
+            padding-left: 2em;
+            margin-left: 0;
+            width: 12em;
+        }
+        #controls li {
+            padding-top: 0.5em;
+            list-style: none;
+        }
+        #options {
+            font-size: 1em;
+            top: 0;
+            margin-left: 15em;
+            position: absolute;
+        }
+    </style>
+    <script src="../lib/OpenLayers.js"></script>
+    <script type="text/javascript">
+        <!--
+        var map, polygonControl;
+        OpenLayers.Util.onImageLoadErrorColor = "transparent";
+        function init(){
+            map = new OpenLayers.Map('map');
+            
+            var wmsLayer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
+                "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); 
+
+            var polygonLayer = new OpenLayers.Layer.Vector("Polygon Layer");
+
+            map.addLayers([wmsLayer, polygonLayer]);
+            map.addControl(new OpenLayers.Control.LayerSwitcher());
+            map.addControl(new OpenLayers.Control.MousePosition());
+
+            polyOptions = {sides: 4};
+            polygonControl = new OpenLayers.Control.DrawFeature(polygonLayer,
+                                            OpenLayers.Handler.RegularPolygon,
+                                            {handlerOptions: polyOptions});
+            
+            map.addControl(polygonControl);
+            
+            map.setCenter(new OpenLayers.LonLat(0, 0), 3);
+            
+            document.getElementById('noneToggle').checked = true;
+        }
+        function setOptions(options) {
+            polygonControl.handler.setOptions(options);
+        }
+        function setSize(fraction) {
+            var radius = fraction * map.getExtent().getHeight();
+            polygonControl.handler.setOptions({radius: radius,
+                                               angle: 0});
+        }
+        // -->
+    </script>
+  </head>
+  <body onload="init()">
+    <h2>OpenLayers Regular Polygon Example</h2>
+    <div id="map"></div>
+    <div id="config">
+        
+        <ul id="controls"><b>Map Controls</b>
+            <li>
+                <input type="radio" name="type"
+                       value="none" id="noneToggle"
+                       onclick="polygonControl.deactivate()"
+                       checked="checked" />
+                <label for="noneToggle">navigate</label>
+            </li>
+            <li>
+                <input type="radio" name="type"
+                       value="polygon" id="polygonToggle"
+                       onclick="polygonControl.activate()" />
+                <label for="polygonToggle">draw polygon</label>
+            </li>
+        </ul>
+        <table id="options">
+            <tbody>
+                <tr>
+                    <th>Draw Option</th>
+                    <th>Value</th>
+                </tr>
+                <tr>
+                    <td>
+                        shape
+                    </td>
+                    <td>
+                        <select name="sides"
+                                onchange="setOptions({sides: parseInt(this.value)})">
+                            <option value="3">triangle</option>
+                            <option value="4" selected="selected">square</option>
+                            <option value="5">pentagon</option>
+                            <option value="6">hexagon</option>
+                            <option value="40">circle</option>
+                        </select>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        snap angle
+                    </td>
+                    <td>
+                        <select name="angle"
+                                onchange="setOptions({snapAngle: parseFloat(this.value)})">
+                            <option value="" selected="selected">no snap</option>
+                            <option value="15">15&deg;</option>
+                            <option value="45">45&deg;</option>
+                            <option value="90">90&deg;</option>
+                        </select>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        size
+                    </td>
+                    <td>
+                        <select name="size"
+                                onchange="setSize(parseFloat(this.value))">
+                            <option value="" selected="selected">variable</option>
+                            <option value="0.1">small</option>
+                            <option value="0.2">medium</option>
+                            <option value="0.4">large</option>
+                        </select>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    <p>
+        Regular polygons can be drawn by pointing a DrawFeature control to the
+        RegularPolygon handler class.  The options above demonstrate how the
+        handler can be configured.  Note if you are in angle snapping mode (if
+        the snap angle is non-null) and you hold down the <b>Shift</b> key, you
+        will toggle to non-snapping mode.
+    </p>
+  </body>
+</html>

Modified: trunk/openlayers/lib/OpenLayers/Geometry/Polygon.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Geometry/Polygon.js	2007-09-10 20:10:55 UTC (rev 4204)
+++ trunk/openlayers/lib/OpenLayers/Geometry/Polygon.js	2007-09-10 20:24:27 UTC (rev 4205)
@@ -59,3 +59,31 @@
 
     CLASS_NAME: "OpenLayers.Geometry.Polygon"
 });
+
+/**
+ * APIMethod: createRegularPolygon
+ * Create a regular polygon around a radius. Useful for creating circles 
+ * and the like.
+ *
+ * Parameters:
+ * origin - {<OpenLayers.Geometry.Point>} center of polygon.
+ * radius - {Float} distance to vertex, in map units.
+ * sides - {Integer} Number of sides. 20 approximates a circle.
+ * rotation - {Float} original angle of rotation, in degrees.
+ */
+OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {  
+    var angle = Math.PI * ((1/sides) - (1/2));
+    if(rotation) {
+        angle += (rotation / 180) * Math.PI;
+    }
+    var rotateAngle, x, y;
+    var points = [];
+    for(var i=0; i<sides; ++i) {
+        rotatedAngle = angle + (i * 2 * Math.PI / sides);
+        x = origin.x + (radius * Math.cos(rotatedAngle));
+        y = origin.y + (radius * Math.sin(rotatedAngle));
+        points.push(new OpenLayers.Geometry.Point(x, y));
+    }
+    var ring = new OpenLayers.Geometry.LinearRing(points);
+    return new OpenLayers.Geometry.Polygon([ring]);
+}

Added: trunk/openlayers/lib/OpenLayers/Handler/RegularPolygon.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Handler/RegularPolygon.js	                        (rev 0)
+++ trunk/openlayers/lib/OpenLayers/Handler/RegularPolygon.js	2007-09-10 20:24:27 UTC (rev 4205)
@@ -0,0 +1,356 @@
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt 
+ * for the full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Drag.js
+ * 
+ * Class: OpenLayers.Handler.RegularPolygon
+ * Handler to draw a regular polygon on the map.  Polygon is displayed on mouse
+ *     down, moves or is modified on mouse move, and is finished on mouse up.
+ *     The handler triggers callbacks for 'done' and 'cancel'.  Create a new
+ *     instance with the <OpenLayers.Handler.RegularPolygon> constructor.
+ * 
+ * Inherits from:
+ *  - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, {
+    
+    /**
+     * APIProperty: sides
+     * {Integer} Number of sides for the regular polygon.  Needs to be greater
+     *     than 2.  Defaults to 4.
+     */
+    sides: 4,
+
+    /**
+     * APIProperty: radius
+     * {Float} Optional radius in map units of the regular polygon.  If this is
+     *     set to some non-zero value, a polygon with a fixed radius will be
+     *     drawn and dragged with mose movements.  If this property is not
+     *     set, dragging changes the radius of the polygon.  Set to null by
+     *     default.
+     */
+    radius: null,
+    
+    /**
+     * APIProperty: snapAngle
+     * {Float} If set to a non-zero value, the handler will snap the polygon
+     *     rotation to multiples of the snapAngle.  Value is an angle measured
+     *     in degrees counterclockwise from the positive x-axis.  
+     */
+    snapAngle: null,
+    
+    /**
+     * APIProperty: snapToggle
+     * {String} If set, snapToggle is checked on mouse events and will set
+     *     the snap mode to the opposite of what it currently is.  To disallow
+     *     toggling between snap and non-snap mode, set freehandToggle to
+     *     null.  Acceptable toggle values are 'shiftKey', 'ctrlKey', and
+     *     'altKey'. Snap mode is only possible if this.snapAngle is set to a
+     *     non-zero value.
+     */
+    snapToggle: 'shiftKey',
+    
+    /**
+     * APIProperty: persist
+     * {Boolean} Leave the feature rendered until clear is called.  Default
+     *     is false.  If set to true, the feature remains rendered until
+     *     clear is called, typically by deactivating the handler or starting
+     *     another drawing.
+     */
+    persist: false,
+
+    /**
+     * Property: angle
+     * {Float} The angle from the origin (mouse down) to the current mouse
+     *     position, in radians.  This is measured counterclockwise from the
+     *     positive x-axis.
+     */
+    angle: null,
+
+    /**
+     * Property: fixedRadius
+     * {Boolean} The polygon has a fixed radius.  True if a radius is set before
+     *     drawing begins.  False otherwise.
+     */
+    fixedRadius: false,
+
+    /**
+     * Property: feature
+     * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature
+     */
+    feature: null,
+
+    /**
+     * Property: layer
+     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
+     */
+    layer: null,
+
+    /**
+     * Property: origin
+     * {<OpenLayers.Geometry.Point>} Location of the first mouse down
+     */
+    origin: null,
+
+    /**
+     * Constructor: OpenLayers.Handler.RegularPolygon
+     * Create a new regular polygon handler.
+     *
+     * Parameters:
+     * control - {<OpenLayers.Control>} The control that owns this handler
+     * callbacks - {Array} An object with a 'done' property whos value is a
+     *     function to be called when the polygon drawing is finished.
+     *     The callback should expect to recieve a single argument,
+     *     the polygon geometry.  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.
+     * options - {Object} An object with properties to be set on the handler.
+     *     If the options.sides property is not specified, the number of sides
+     *     will default to 4.
+     */
+    initialize: function(control, callbacks, options) {
+        this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+
+        OpenLayers.Handler.prototype.initialize.apply(this,
+                                                [control, callbacks, options]);
+        this.options = (options) ? options : new Object();
+    },
+    
+    /**
+     * APIMethod: setOptions
+     * 
+     * Parameters:
+     * newOptions - {Object} 
+     */
+    setOptions: function (newOptions) {
+        OpenLayers.Util.extend(this.options, newOptions);
+        OpenLayers.Util.extend(this, newOptions);
+    },
+    
+    /**
+     * APIMethod: activate
+     * Turn on the handler.
+     *
+     * Return:
+     * {Boolean} The handler was successfully activated
+     */
+    activate: function() {
+        var activated = false;
+        if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+            // create temporary vector layer for rendering geometry sketch
+            var options = {displayInLayerSwitcher: false};
+            this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
+            this.map.addLayer(this.layer);
+            activated = true;
+        }
+        return activated;
+    },
+
+    /**
+     * APIMethod: deactivate
+     * Turn off the handler.
+     *
+     * Return:
+     * {Boolean} The handler was successfully deactivated
+     */
+    deactivate: function() {
+        var deactivated = false;
+        if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) {
+            // call the cancel callback if mid-drawing
+            if(this.dragging) {
+                this.cancel();
+            }
+            this.map.removeLayer(this.layer, false);
+            this.layer.destroy();
+            if (this.feature) {
+                this.feature.destroy();
+            }    
+            deactivated = true;
+        }
+        return deactivated;
+    },
+    
+    /**
+     * Method: downFeature
+     * Start drawing a new feature
+     *
+     * Parameters:
+     * evt - {Event} The drag start event
+     */
+    down: function(evt) {
+        this.fixedRadius = !!(this.radius);
+        var maploc = this.map.getLonLatFromPixel(evt.xy);
+        this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
+        // create the new polygon
+        if(!this.fixedRadius) {
+            // smallest radius should not be less one pixel in map units
+            // VML doesn't behave well with smaller
+            this.radius = this.map.getResolution();
+        }
+        if(this.persist) {
+            this.clear();
+        }
+        this.feature = new OpenLayers.Feature.Vector();
+        this.createGeometry();
+        this.layer.addFeatures([this.feature]);
+        this.layer.drawFeature(this.feature, this.style);
+    },
+    
+    /**
+     * Method: move
+     * Respond to drag move events
+     *
+     * Parameters:
+     * evt - {Evt} The move event
+     */
+    move: function(evt) {
+        var maploc = this.map.getLonLatFromPixel(evt.xy);
+        var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
+        if(this.fixedRadius) {
+            this.origin = point;
+        } else {
+            this.calculateAngle(point, evt);
+            this.radius = Math.max(this.map.getResolution() / 2,
+                                   point.distanceTo(this.origin));
+        }
+        this.modifyGeometry();
+        this.layer.drawFeature(this.feature, this.style);
+    },
+
+    /**
+     * Method: up
+     * Finish drawing the feature
+     *
+     * Parameters:
+     * evt - {Event} The mouse up event
+     */
+    up: function(evt) {
+        this.finalize();
+    },
+
+    /**
+     * Method: out
+     * Finish drawing the feature.
+     *
+     * Parameters:
+     * evt - {Event} The mouse out event
+     */
+    out: function(evt) {
+        this.finalize();
+    },
+
+    /**
+     * Method: createGeometry
+     * Create the new polygon geometry.  This is called at the start of the
+     *     drag and at any point during the drag if the number of sides
+     *     changes.
+     */
+    createGeometry: function() {
+        this.angle = Math.PI * ((1/this.sides) - (1/2));
+        if(this.snapAngle) {
+            this.angle += this.snapAngle * (Math.PI / 180);
+        }
+        this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(
+            this.origin, this.radius, this.sides, this.snapAngle
+        );
+    },
+    
+    /**
+     * Method: modifyGeometry
+     * Modify the polygon geometry in place.
+     */
+    modifyGeometry: function() {
+        var angle, dx, dy, point;
+        var ring = this.feature.geometry.components[0];
+        // if the number of sides ever changes, create a new geometry
+        if(ring.components.length != (this.sides + 1)) {
+            this.createGeometry();
+        }
+        for(var i=0; i<this.sides; ++i) {
+            point = ring.components[i];
+            angle = this.angle + (i * 2 * Math.PI / this.sides);
+            point.x = this.origin.x + (this.radius * Math.cos(angle));
+            point.y = this.origin.y + (this.radius * Math.sin(angle));
+            point.clearBounds();
+        }
+    },
+    
+    /**
+     * Method: calculateAngle
+     * Calculate the angle based on settings.
+     *
+     * Parameters:
+     * point - {OpenLayers.Geometry.Point}
+     * evt - {Event}
+     */
+    calculateAngle: function(point, evt) {
+        var alpha = Math.atan2(point.y - this.origin.y,
+                               point.x - this.origin.x);
+        if(this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) {
+            var snapAngleRad = (Math.PI / 180) * this.snapAngle;
+            this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad;
+        } else {
+            this.angle = alpha;
+        }
+    },
+
+    /**
+     * APIMethod: cancel
+     * Finish the geometry and call the "cancel" callback.
+     */
+    cancel: function() {
+        // the polygon geometry gets cloned in the callback method
+        this.callback("cancel", null);
+        this.finalize();
+    },
+
+    /**
+     * Method: finalize
+     * Finish the geometry and call the "done" callback.
+     */
+    finalize: function() {
+        this.origin = null;
+        this.radius = this.options.radius;
+    },
+
+    /**
+     * APIMethod: clear
+     * Clear any rendered features on the temporary layer.  This is called
+     *     when the handler is deactivated, canceled, or done (unless persist
+     *     is true).
+     */
+    clear: function() {
+        this.layer.renderer.clear();
+        this.layer.destroyFeatures();
+    },
+    
+    /**
+     * Method: callback
+     * Trigger the control's named callback with the given arguments
+     *
+     * Parameters:
+     * name - {String} The key for the callback that is one of the properties
+     *     of the handler's callbacks object.
+     * args - {Array} An array of arguments with which to call the callback
+     *     (defined by the control).
+     */
+    callback: function (name, args) {
+        // override the callback method to always send the polygon geometry
+        if (this.callbacks[name]) {
+            this.callbacks[name].apply(this.control,
+                                       [this.feature.geometry.clone()]);
+        }
+        // since sketch features are added to the temporary layer
+        // they must be cleared here if done or cancel
+        if(!this.persist && (name == "done" || name == "cancel")) {
+            this.clear();
+        }
+    },
+
+    /** @final @type String */
+    CLASS_NAME: "OpenLayers.Handler.RegularPolygon"
+});

Modified: trunk/openlayers/lib/OpenLayers.js
===================================================================
--- trunk/openlayers/lib/OpenLayers.js	2007-09-10 20:10:55 UTC (rev 4204)
+++ trunk/openlayers/lib/OpenLayers.js	2007-09-10 20:24:27 UTC (rev 4205)
@@ -119,6 +119,7 @@
             "OpenLayers/Handler/Polygon.js",
             "OpenLayers/Handler/Feature.js",
             "OpenLayers/Handler/Drag.js",
+            "OpenLayers/Handler/RegularPolygon.js",
             "OpenLayers/Handler/Box.js",
             "OpenLayers/Handler/MouseWheel.js",
             "OpenLayers/Handler/Keyboard.js",

Modified: trunk/openlayers/tests/Geometry/test_Polygon.html
===================================================================
--- trunk/openlayers/tests/Geometry/test_Polygon.html	2007-09-10 20:10:55 UTC (rev 4204)
+++ trunk/openlayers/tests/Geometry/test_Polygon.html	2007-09-10 20:24:27 UTC (rev 4205)
@@ -173,6 +173,47 @@
         
     }
 
+    function test_Polygon_createRegular(t) {
+        t.plan(22);
+        var sides = 40;
+        var poly = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(5,0), 6, sides);
+        var polyBounds = poly.getBounds();
+        t.eq(polyBounds.toBBOX(), "-0.981504,-5.981504,10.981504,5.981504", sides + " sided figure generates correct bbox.");
+        t.eq(poly.components.length, 1, "Poly has one linear ring");
+        t.eq(poly.components[0].components.length, sides + 1, "ring has 41 components");
+        t.eq(poly.components[0].components[0].id, poly.components[0].components[sides].id, "ring starts and ends with same geom");
+        t.eq(Math.round(poly.getArea()), Math.round(Math.PI * 36), "area of "+sides+" sided poly rounds to same area as a circle.");
+        
+        var sides = 3;
+        var poly = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(5,0), 6, sides);
+        var polyBounds = poly.getBounds();
+        t.eq(polyBounds.toBBOX(), "-0.196152,-3,10.196152,6", sides + " sided figure generates correct bbox.");
+        t.eq(poly.components.length, 1, "Poly has one linear ring");
+        t.eq(poly.components[0].components.length, sides + 1, "ring has  correct count of  components");
+        t.eq(poly.components[0].components[0].id, poly.components[0].components[sides].id, "ring starts and ends with same geom");
+        t.eq(Math.round(poly.getArea()), 47, "area of 3 sided poly is correct");
+        
+        var sides = 3;
+        var poly3 = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(10,0), 15, sides);
+        var polyBounds = poly3.getBounds();
+        t.eq(polyBounds.toBBOX(), "-2.990381,-7.5,22.990381,15", sides + " sided figure generates correct bbox.");
+        t.eq(Math.round(polyBounds.getCenterLonLat().lon), 10, "longitude of center of bounds is same as origin");
+        t.eq(poly3.components.length, 1, "Poly has one linear ring");
+        t.eq(poly3.components[0].components.length, sides + 1, "ring has  correct count of  components");
+        t.eq(poly3.components[0].components[0].id, poly3.components[0].components[sides].id, "ring starts and ends with same geom");
+        t.ok(poly3.getArea() > poly.getArea(), "area with radius 15 > poly with radius 6"); 
+        
+        var sides = 4;
+        var poly4 = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(10,0), 15, sides);
+        var polyBounds = poly4.getBounds();
+        t.eq(polyBounds.toBBOX(), "-0.606602,-10.606602,20.606602,10.606602", sides + " sided figure generates correct bbox.");
+        t.eq(Math.round(polyBounds.getCenterLonLat().lon), 10, "longitude of center of bounds is same as origin");
+        t.eq(poly4.components.length, 1, "Poly has one linear ring");
+        t.eq(poly4.components[0].components.length, sides + 1, "ring has  correct count of  components");
+        t.eq(poly4.components[0].components[0].id, poly4.components[0].components[sides].id, "ring starts and ends with same geom");
+        t.ok(poly4.getArea() > poly3.getArea(), "square with radius 15 > triangle with radius 15"); 
+    }
+
     function test_Polygon_equals(t) {
         t.plan(3);
         

Added: trunk/openlayers/tests/Handler/test_RegularPolygon.html
===================================================================
--- trunk/openlayers/tests/Handler/test_RegularPolygon.html	                        (rev 0)
+++ trunk/openlayers/tests/Handler/test_RegularPolygon.html	2007-09-10 20:24:27 UTC (rev 4205)
@@ -0,0 +1,135 @@
+<html>
+<head>
+  <script src="../../lib/OpenLayers.js"></script>
+  <script type="text/javascript">
+    function test_Handler_RegularPolygon_constructor(t) {
+        t.plan(3);
+        var control = new OpenLayers.Control();
+        control.id = Math.random();
+        var callbacks = {foo: "bar"};
+        var options = {bar: "foo"};
+        
+        var oldInit = OpenLayers.Handler.prototype.initialize;
+        
+        OpenLayers.Handler.prototype.initialize = function(con, call, opt) {
+            t.eq(con.id, control.id,
+                 "constructor calls parent with the correct control");
+            t.eq(call, callbacks,
+                 "constructor calls parent with the correct callbacks");
+            t.eq(opt, options,
+                 "regular polygon constructor calls parent with the correct options");
+        }
+        var handler = new OpenLayers.Handler.RegularPolygon(control, callbacks, options);
+
+        OpenLayers.Handler.prototype.initialize = oldInit;
+    }
+
+    function test_Handler_RegularPolygon_activation(t) {
+        t.plan(3);
+        var map = new OpenLayers.Map('map');
+        var control = new OpenLayers.Control();
+        map.addControl(control);
+        var handler = new OpenLayers.Handler.RegularPolygon(control);
+        handler.active = true;
+        var activated = handler.activate();
+        t.ok(!activated,
+             "activate returns false if the handler was already active");
+        handler.active = false;
+        activated = handler.activate();
+        t.ok(activated,
+             "activate returns true if the handler was not already active");
+        activated = handler.deactivate();
+        t.ok(activated,
+             "deactivate returns true if the handler was active already");
+    }
+
+    function test_Handler_RegularPolygon_four_corners(t) {
+        t.plan(7);
+        var map = new OpenLayers.Map('map');
+        map.addLayer(new OpenLayers.Layer.WMS("", "", {}));
+        map.zoomToMaxExtent();
+        var control = new OpenLayers.Control();
+        map.addControl(control);
+        var handler = new OpenLayers.Handler.RegularPolygon(control, {});
+        var activated = handler.activate();
+        var evt = {xy: new OpenLayers.Pixel(150, 75), which: 1};
+        handler.down(evt);
+        var evt = {xy: new OpenLayers.Pixel(175, 75), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-35.15625,-35.15625,35.15625,35.15625",
+             "correct bounds after move");
+        t.eq(handler.feature.geometry.components[0].components.length, 5,
+             "geometry has 5 components");
+        t.eq(handler.feature.geometry.CLASS_NAME,
+             "OpenLayers.Geometry.Polygon",
+             "geometry is a polygon");
+        t.eq(handler.radius, 25*1.40625, "feature radius as set on handler");
+        var evt = {xy: new OpenLayers.Pixel(175, 80), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-35.15625,-35.15625,35.15625,35.15625",
+             "correct bounds after move with a fixed radius");
+        handler.cancel();
+        handler.setOptions({radius:2 / Math.sqrt(2)});
+        var evt = {xy: new OpenLayers.Pixel(150, 75), which: 1};
+        handler.down(evt);
+        
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-1,-1,1,1",
+             "bounds with manual radius setting");
+        var evt = {xy: new OpenLayers.Pixel(175, 90), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "34.15625,-22.09375,36.15625,-20.09375",
+             "bounds with manual radius setting and mousemove");
+    }
+
+    function test_Handler_RegularPolygon_circle(t) {
+        t.plan(7);
+        var map = new OpenLayers.Map('map');
+        map.addLayer(new OpenLayers.Layer.WMS("", "", {}));
+        map.zoomToMaxExtent();
+        var control = new OpenLayers.Control();
+        map.addControl(control);
+        var handler = new OpenLayers.Handler.RegularPolygon(control, {}, {'sides':40});
+        var activated = handler.activate();
+        var evt = {xy: new OpenLayers.Pixel(150, 75), which: 1};
+        handler.down(evt);
+        var evt = {xy: new OpenLayers.Pixel(175, 75), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-35.15625,-35.15625,35.15625,35.15625",
+             "correct bounds after move");
+        t.eq(handler.feature.geometry.components[0].components.length, 41,
+             "geometry has correct numbre of components");
+        t.eq(handler.feature.geometry.CLASS_NAME,
+             "OpenLayers.Geometry.Polygon",
+             "geometry is a polygon");
+        t.eq(handler.radius, 25*1.40625, "feature radius as set on handler");
+        var evt = {xy: new OpenLayers.Pixel(175, 80), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-35.823348,-35.823348,35.823348,35.823348",
+             "correct bounds after move with fixed radius");
+        handler.cancel();
+        handler.setOptions({radius:1});
+        var evt = {xy: new OpenLayers.Pixel(150, 75), which: 1};
+        handler.down(evt);
+        
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "-0.996917,-0.996917,0.996917,0.996917",
+             "bounds with manual radius setting");
+        var evt = {xy: new OpenLayers.Pixel(175, 80), which: 1};
+        handler.move(evt);
+        t.eq(handler.feature.geometry.getBounds().toBBOX(),
+             "34.159333,-8.028167,36.153167,-6.034333",
+             "bounds with manual radius setting and mousemove");
+    }     
+
+  </script>
+</head>
+<body>
+    <div id="map" style="width: 300px; height: 150px;"/>
+</body>
+</html>

Modified: trunk/openlayers/tests/list-tests.html
===================================================================
--- trunk/openlayers/tests/list-tests.html	2007-09-10 20:10:55 UTC (rev 4204)
+++ trunk/openlayers/tests/list-tests.html	2007-09-10 20:24:27 UTC (rev 4205)
@@ -80,5 +80,6 @@
     <li>Handler/test_Point.html</li>
     <li>Handler/test_Path.html</li>
     <li>Handler/test_Polygon.html</li>
+    <li>Handler/test_RegularPolygon.html</li>
     <li>test_Map.html</li>
 </ul>



More information about the Commits mailing list