circularise
authorRichard Fairhurst <richard@systemed.net>
Fri, 26 Mar 2010 18:32:03 +0000 (18:32 +0000)
committerRichard Fairhurst <richard@systemed.net>
Fri, 26 Mar 2010 18:32:03 +0000 (18:32 +0000)
net/systemeD/halcyon/connection/Way.as
net/systemeD/potlatch2/Toolbox.as
net/systemeD/potlatch2/tools/Circularise.as [new file with mode: 0644]
potlatch2.mxml

index 832d09b..a838fb8 100644 (file)
@@ -181,6 +181,29 @@ package net.systemeD.halcyon.connection {
                        return (nodes[0].id==nodes[nodes.length-1].id && nodes.length>2);
                }
                
+               public function get clockwise():Boolean {
+                       var lowest:uint=0;
+                       var xmin:Number=-999999; var ymin:Number=-999999;
+                       for (var i:uint=0; i<nodes.length; i++) {
+                               if      (nodes[i].latp> ymin) { lowest=i; xmin=nodes[i].lon; ymin=nodes[i].latp; }
+                               else if (nodes[i].latp==ymin
+                                         && nodes[i].lon > xmin) { lowest=i; xmin=nodes[i].lon; ymin=nodes[i].latp; }
+                       }
+                       return (this.onLeft(lowest)>0);
+               }
+               
+               private function onLeft(j:uint):Number {
+                       var left:Number=0;
+                       var i:int, k:int;
+                       if (nodes.length>=3) {
+                               i=j-1; if (i==-1) { i=nodes.length-2; }
+                               k=j+1; if (k==nodes.length) { k=1; }
+                               left=((nodes[j].lon-nodes[i].lon) * (nodes[k].latp-nodes[i].latp) -
+                                         (nodes[k].lon-nodes[i].lon) * (nodes[j].latp-nodes[i].latp));
+                       }
+                       return left;
+               }
+
                public override function remove():void {
                        var node:Node;
                        suspend();
index 4d93a8c..f684dab 100644 (file)
@@ -77,5 +77,11 @@ package net.systemeD.potlatch2 {
                        }
                }
 
+               public function doCircularise():void {
+                       if (entity is Way) {
+                               Circularise.circularise(Way(entity),controller.map);
+                       }
+               }
+
        }
 }
\ No newline at end of file
diff --git a/net/systemeD/potlatch2/tools/Circularise.as b/net/systemeD/potlatch2/tools/Circularise.as
new file mode 100644 (file)
index 0000000..4283d5a
--- /dev/null
@@ -0,0 +1,86 @@
+package net.systemeD.potlatch2.tools {
+       import net.systemeD.halcyon.Map;
+       import net.systemeD.halcyon.connection.Way;
+       import net.systemeD.halcyon.connection.Node;
+
+       public class Circularise {
+
+               public static function circularise(way:Way,map:Map):void {
+                       if (way.length<4) { return; }
+
+                       var a:Node=way.getNode(0);
+                       var b:Node=way.getNode(way.length-1);
+                       if (a!=b) { return; }
+
+                       // Find centre-point
+                       // ** should be refactored to be within Way.as, so we can share with WayUI.as
+                       var patharea:Number=0;
+                       var cx:Number=0; var lx:Number=b.lon;
+                       var cy:Number=0; var ly:Number=b.latp;
+                       var i:uint,j:uint,n:Node;
+                       for (i=0; i<way.length; i++) {
+                               n=way.getNode(i);
+                               var sc:Number = (lx*n.latp-n.lon*ly);
+                               cx += (lx+n.lon )*sc;
+                               cy += (ly+n.latp)*sc;
+                               patharea += sc;
+                               lx=n.lon; ly=n.latp;
+                       }
+                       patharea/=2;
+                       cx/=patharea*6;
+                       cy/=patharea*6;
+
+                       // Average distance to centre
+                       var d:Number=0; var angles:Array=[];
+                       for (i=0; i<way.length; i++) {
+                               d+=Math.sqrt(Math.pow(way.getNode(i).lon -cx,2)+
+                                                        Math.pow(way.getNode(i).latp-cy,2));
+                       }
+                       d=d/way.length;
+                       
+                       // Move each node
+                       for (i=0; i<way.length-1; i++) {
+                               n=way.getNode(i);
+                               var c:Number=Math.sqrt(Math.pow(n.lon-cx,2)+Math.pow(n.latp-cy,2));
+                               n.setLonLatp(cx+(n.lon -cx)/c*d,
+                                            cy+(n.latp-cy)/c*d);
+                       }
+
+                       // Insert extra nodes to make circle
+                       // clockwise: angles decrease, wrapping round from -170 to 170
+                       i=0;
+                       var clockwise:Boolean=way.clockwise;
+                       var diff:Number, ang:Number;
+                       while (i<way.length-1) {
+                               j=(i+1) % way.length;
+                               var a1:Number=Math.atan2(way.getNode(i).lon-cx,way.getNode(i).latp-cy)*(180/Math.PI);
+                               var a2:Number=Math.atan2(way.getNode(j).lon-cx,way.getNode(j).latp-cy)*(180/Math.PI);
+
+                               if (clockwise) {
+                                       if (a2>a1) { a2=a2-360; }
+                                       diff=a1-a2;
+                                       if (diff>20) {
+                                               for (ang=a1-20; ang>a2+10; ang-=20) {
+                                                       way.insertNode(j,map.connection.createNode({},
+                                                               map.latp2lat(cy+Math.cos(ang*Math.PI/180)*d),
+                                                               cx+Math.sin(ang*Math.PI/180)*d));
+                                                       j++; i++;
+                                               }
+                                       }
+                               } else {
+                                       if (a1>a2) { a1=a1-360; }
+                                       diff=a2-a1;
+                                       if (diff>20) {
+                                               for (ang=a1+20; ang<a2-10; ang+=20) {
+                                                       way.insertNode(j,map.connection.createNode({},
+                                                               map.latp2lat(cy+Math.cos(ang*Math.PI/180)*d),
+                                                               cx+Math.sin(ang*Math.PI/180)*d));
+                                                       j++; i++;
+                                               }
+                                       }
+                               }
+                               i++;
+                       }
+               }
+       }
+}
\ No newline at end of file
index 13050cc..ea1eef3 100755 (executable)
@@ -66,6 +66,7 @@
                                click='toolbox.doStraighten();' 
                                width="28" height="28" textAlign="left" paddingLeft="5" paddingRight="0" />
                <mx:Button icon="@Embed('embedded/circle.svg')" 
+                               click='toolbox.doCircularise();' 
                                width="28" height="28" textAlign="left" paddingLeft="4" paddingRight="0" />
                <mx:Button icon="@Embed('embedded/quadrilateralise.svg')" 
                                click='toolbox.doQuadrilateralise();'