Changeset 672

Show
Ignore:
Timestamp:
09/07/08 17:14:04 (2 months ago)
Author:
tom
Message:

updating PolylinesClip? to work the same way as MarkerClip? and PolygonClip?

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/as3/lib/com/modestmaps/extras/PolyLinesClip.as

    r647 r672  
    88 
    99        import com.modestmaps.Map; 
     10        import com.modestmaps.core.Coordinate; 
    1011        import com.modestmaps.events.MapEvent; 
    11         import com.modestmaps.events.MarkerEvent; 
    1212        import com.modestmaps.geo.Location; 
    1313         
     
    2020        public class PolyLinesClip extends Sprite 
    2121        { 
    22                  
    23             protected var map:Map; 
    24             private var starting:Point; 
    25              
    26             protected var polyLines:Array = []; // all markers 
    27             private var polylinesByName:Object = {}; 
    28  
    29         // enable this if you want intermediate zooming steps to 
    30         // stretch your graphics instead of reprojecting the points 
    31         // it looks worse and probably isn't faster, but there it is :) 
    32         public var scaleZoom:Boolean = false; 
    33          
    34             public function PolyLinesClip(map:Map) 
    35             { 
    36                 this.map = map; 
    37                 this.x = map.getWidth() / 2; 
    38                 this.y = map.getHeight() / 2; 
    39                 
    40                 map.addEventListener(MapEvent.START_ZOOMING, onMapStartZooming); 
    41                 map.addEventListener(MapEvent.STOP_ZOOMING, onMapStopZooming); 
    42                 map.addEventListener(MapEvent.ZOOMED_BY, onMapZoomedBy); 
    43                 map.addEventListener(MapEvent.START_PANNING, onMapStartPanning); 
    44                 map.addEventListener(MapEvent.STOP_PANNING, onMapStopPanning); 
    45                 map.addEventListener(MapEvent.PANNED, onMapPanned); 
    46                 map.addEventListener(MapEvent.RESIZED, onMapResized); 
    47                 map.addEventListener(MapEvent.EXTENT_CHANGED, updatePolyLines); 
    48             } 
    49              
    50             public function addPolyLine(polyLine:PolyLine):void 
    51             { 
    52                  
    53                 polylinesByName[polyLine.id] = polyLine;                
    54                 polyLines.push(polyLine);              
    55             } 
    56              
    57             public function getPolyLine(id:String):PolyLine 
    58             { 
    59                  
    60                 return polylinesByName[id] as PolyLine; 
    61             } 
    62              
    63             public function removePolyLine(id:String):void 
    64             {            
    65                 var polyLine:PolyLine = getPolyLine(id); 
    66                 if (polyLine) { 
    67                          
    68                  
    69                 var index:int = polyLines.indexOf(polyLine); 
    70                 if (index >= 0) { 
    71                         polyLines.splice(index,1); 
    72                 } 
    73                  
    74                 delete polylinesByName[polyLine.id]; 
    75             }              
    76             } 
    77                  
    78             /** 
    79             * Redraw each active polyLine 
    80             */  
    81             public function updatePolyLines(event:Event=null):void 
    82             {            
    83                 this.graphics.clear();                          
    84                 for each (var polyLine:PolyLine in polyLines) {             
    85                     updatePolyLine(polyLine);                   
    86                 }                
    87             } 
    88             /** 
    89             * Update an individual polyLine - determine its visibility and draw if so 
    90             */ 
    91             public function updatePolyLine(polyLine:PolyLine):void 
    92             { 
    93                 var w:Number = map.getWidth() * 2; 
    94                 var h:Number = map.getHeight() * 2; 
    95                                          
    96                 var localPointsArray:Array=new Array();      
    97                 var i:uint=0; 
    98                  
    99                 this.graphics.lineStyle(polyLine.lineThickness,polyLine.lineColor,polyLine.lineAlpha,polyLine.pixelHinting,polyLine.scaleMode,polyLine.caps,polyLine.joints,polyLine.miterLimit); 
    100                                  
    101                 var boundaryWindow:Rectangle=new Rectangle(-w/2,-h/2,w,h); 
    102                  
    103                 // Calculate local coordinates for each point 
    104                 for (i=0;i<polyLine.locationsArray.length;i++) 
    105                 {                        
    106                         var tLocation:Location=polyLine.locationsArray[i]; 
    107                         var point:Point = map.locationPoint(tLocation, this); 
    108                         localPointsArray.push(point);    
    109                 } 
    110                  
    111                 for (i=1;i<polyLine.locationsArray.length;i++) 
    112                 { 
    113                         // Create duplicates of each point for clipping 
    114                         var tPoint1:Point=new Point(localPointsArray[i-1].x,localPointsArray[i-1].y); 
    115                         var tPoint2:Point=new Point(localPointsArray[i].x,localPointsArray[i].y); 
    116                          
    117                         // Clip each point and draw if visible 
    118                         if (clipLineToRect(tPoint1,tPoint2,boundaryWindow)) 
    119                         { 
    120                                 this.graphics.moveTo(tPoint1.x,tPoint1.y); 
    121                                 this.graphics.lineTo(tPoint2.x,tPoint2.y); 
    122                         } 
    123                 } 
    124             } 
    125              
    126             /** 
    127             * Test for a line intersection. TODO - tidy up as no need to calc line equation twice 
    128             */ 
    129                 private function lineIntersectLine( v1:Point, v2:Point, v3:Point, v4:Point ):Boolean 
    130                 { 
    131                     var denom:Number = ((v4.y - v3.y) * (v2.x - v1.x)) - ((v4.x - v3.x) * (v2.y - v1.y)); 
    132                     var numerator:Number = ((v4.x - v3.x) * (v1.y - v3.y)) - ((v4.y - v3.y) * (v1.x - v3.x));            
    133                     var numerator2:Number = ((v2.x - v1.x) * (v1.y - v3.y)) - ((v2.y - v1.y) * (v1.x - v3.x));           
    134                     if ( denom == 0.0 ) 
    135                     { 
    136                         if ( numerator == 0.0 && numerator2 == 0.0 ) return false;//COINCIDENT;               
    137                         return false;// PARALLEL; 
    138                     } 
    139                     var ua:Number = numerator / denom; 
    140                     var ub:Number = numerator2/ denom;           
    141                     return (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0); 
     22                protected var map:Map; 
     23                 
     24                protected var drawCoord:Coordinate; 
     25                 
     26                protected var polyLines:Array = []; // all markers 
     27                protected var polylinesByName:Object = {}; 
     28 
     29                // enable this if you want intermediate zooming steps to 
     30                // stretch your graphics instead of reprojecting the points 
     31                // you'll probably want to set scaleMode to "none" in your polyline  
     32                // if you enable this 
     33                public var scaleZoom:Boolean = true; 
     34                 
     35                protected var _dirty:Boolean = true; 
     36                 
     37                public function PolyLinesClip(map:Map) 
     38                { 
     39                        this.map = map; 
     40                        this.x = map.getWidth() / 2; 
     41                        this.y = map.getHeight() / 2; 
     42                    
     43                        drawCoord = map.grid.centerCoordinate.copy(); 
     44                    
     45                        map.addEventListener(MapEvent.START_ZOOMING, onMapStartZooming); 
     46                        map.addEventListener(MapEvent.STOP_ZOOMING, onMapStopZooming); 
     47                        map.addEventListener(MapEvent.ZOOMED_BY, onMapZoomedBy); 
     48                        map.addEventListener(MapEvent.START_PANNING, onMapStartPanning); 
     49                        map.addEventListener(MapEvent.STOP_PANNING, onMapStopPanning); 
     50                        map.addEventListener(MapEvent.PANNED, onMapPanned); 
     51                        map.addEventListener(MapEvent.RESIZED, onMapResized); 
     52                        map.addEventListener(MapEvent.EXTENT_CHANGED, onMapExtentChanged); 
     53                        map.addEventListener(MapEvent.RENDERED, updatePolyLines); 
     54                } 
     55                 
     56                public function addPolyLine(polyLine:PolyLine):void 
     57                { 
     58                        polylinesByName[polyLine.id] = polyLine;                    
     59                        polyLines.push(polyLine); 
     60                        dirty = true;              
     61                } 
     62                 
     63                public function getPolyLine(id:String):PolyLine 
     64                { 
     65                        return polylinesByName[id] as PolyLine; 
     66                } 
     67                 
     68                public function removePolyLine(id:String):void 
     69                {                        
     70                        var polyLine:PolyLine = getPolyLine(id); 
     71                        if (polyLine) { 
     72                                var index:int = polyLines.indexOf(polyLine); 
     73                                if (index >= 0) { 
     74                                        polyLines.splice(index,1); 
     75                                } 
     76                                delete polylinesByName[polyLine.id]; 
     77                        }                  
     78                } 
     79                         
     80                /** 
     81                * Redraw each active polyLine 
     82                */  
     83                public function updatePolyLines(event:Event=null):void 
     84                {                        
     85                        if (!dirty) return; 
     86                         
     87                        trace('updating polylines'); 
     88                         
     89                        drawCoord = map.grid.centerCoordinate.copy(); 
     90                         
     91                        scaleX = scaleY = 1; 
     92                         
     93                        x = map.getWidth()/2; 
     94                        y = map.getHeight()/2; 
     95                         
     96                        this.graphics.clear();                                      
     97                        for each (var polyLine:PolyLine in polyLines) {                     
     98                                updatePolyLine(polyLine);                                   
     99                        } 
     100                         
     101                        dirty = false; 
     102                } 
     103                 
     104                /** 
     105                * Update an individual polyLine - determine its visibility and draw if so 
     106                */ 
     107                public function updatePolyLine(polyLine:PolyLine):void 
     108                { 
     109                        var w:Number = map.getWidth() * 2; 
     110                        var h:Number = map.getHeight() * 2; 
     111                                                                 
     112                        var localPointsArray:Array=new Array();          
     113                        var i:uint=0; 
     114                         
     115                        this.graphics.lineStyle(polyLine.lineThickness,polyLine.lineColor,polyLine.lineAlpha,polyLine.pixelHinting,polyLine.scaleMode,polyLine.caps,polyLine.joints,polyLine.miterLimit); 
     116                                                 
     117                        var boundaryWindow:Rectangle=new Rectangle(-w/2,-h/2,w,h); 
     118                         
     119                        // Calculate local coordinates for each point 
     120                        for (i=0;i<polyLine.locationsArray.length;i++) 
     121                        {                                
     122                                var tLocation:Location=polyLine.locationsArray[i]; 
     123                                var point:Point = map.locationPoint(tLocation, this); 
     124                                localPointsArray.push(point);    
     125                        } 
     126                         
     127                        for (i=1;i<polyLine.locationsArray.length;i++) 
     128                        { 
     129                                // Create duplicates of each point for clipping 
     130                                var tPoint1:Point=new Point(localPointsArray[i-1].x,localPointsArray[i-1].y); 
     131                                var tPoint2:Point=new Point(localPointsArray[i].x,localPointsArray[i].y); 
     132                                 
     133                                // Clip each point and draw if visible 
     134                                if (clipLineToRect(tPoint1,tPoint2,boundaryWindow)) 
     135                                { 
     136                                        this.graphics.moveTo(tPoint1.x,tPoint1.y); 
     137                                        this.graphics.lineTo(tPoint2.x,tPoint2.y); 
     138                                } 
     139                        } 
     140                } 
     141                 
     142                /** 
     143                * Test for a line intersection. TODO - tidy up as no need to calc line equation twice 
     144                */ 
     145                protected function lineIntersectLine( v1:Point, v2:Point, v3:Point, v4:Point ):Boolean 
     146                {        
     147                        var denom:Number = ((v4.y - v3.y) * (v2.x - v1.x)) - ((v4.x - v3.x) * (v2.y - v1.y)); 
     148                        var numerator:Number = ((v4.x - v3.x) * (v1.y - v3.y)) - ((v4.y - v3.y) * (v1.x - v3.x));                
     149                        var numerator2:Number = ((v2.x - v1.x) * (v1.y - v3.y)) - ((v2.y - v1.y) * (v1.x - v3.x));               
     150                        if ( denom == 0.0 ) 
     151                        { 
     152                                if ( numerator == 0.0 && numerator2 == 0.0 ) return false;//COINCIDENT;                   
     153                                return false;// PARALLEL; 
     154                        } 
     155                        var ua:Number = numerator / denom; 
     156                        var ub:Number = numerator2/ denom;               
     157                        return (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0); 
    142158                } 
    143159                 
     
    146162                 * Clips a line (passed as 2 points) to a rectangle. Returns true if the line is at all visible, false if not 
    147163                 */ 
    148                 private function clipLineToRect( v1:Point, v2:Point, r:Rectangle ):Boolean 
    149                 { 
    150                         var lowerLeft:Point=new Point( r.x, r.y+r.height ); 
    151                         var upperRight:Point=new Point( r.x+r.width, r.y ); 
    152                         var upperLeft:Point=new Point( r.x, r.y ); 
    153                         var lowerRight:Point=new Point( r.x+r.width, r.y+r.height); 
    154                          
    155                         // Check completely out the box 
    156                         if (v1.x>upperRight.x && v2.x>upperRight.x) return false; 
    157                         if (v1.x<upperLeft.x && v2.x<upperLeft.x) return false; 
    158                         if (v1.y<upperRight.y && v2.y<upperRight.y) return false; 
    159                         if (v1.y>lowerRight.y && v2.y>lowerRight.y) return false; 
    160                          
    161                       
    162                         // check if it is inside 
    163                         if (v1.x > lowerLeft.x && v1.x < upperRight.x && v1.y < lowerLeft.y && v1.y > upperRight.y && 
    164                             v2.x > lowerLeft.x && v2.x < upperRight.x && v2.y < lowerLeft.y && v2.y > upperRight.y ) 
    165                         {    
    166                             return true; 
    167                         } 
    168                          
    169                         // Calc gradient 
    170                         var gradient:Number=(v2.y-v1.y)/(v2.x-v1.x); 
    171                         // Calc constant 
    172                         var lineConstant:Number=v1.y-gradient*v1.x; 
    173                                                                         
    174                         // Check intersection with left of viewbox and clip 
    175                         if (lineIntersectLine(v1,v2, upperLeft, lowerLeft ) )  
    176                         { 
    177                                 if (v1.x<v2.x) {v1.x=lowerLeft.x;v1.y=v1.x*gradient+lineConstant;} 
    178                                 else {v2.x=lowerLeft.x;v2.y=v2.x*gradient+lineConstant;}                                 
    179                         } 
    180                         // Check intersection with bottom of viewbox and clip                                    
    181                         if (lineIntersectLine(v1,v2, lowerLeft, lowerRight)) 
    182                         { 
    183                                 if (v1.y>v2.y) {v1.y=lowerRight.y;v1.x=(v1.y-lineConstant)/gradient;} 
    184                                 else {v2.y=lowerRight.y;v2.x=(v2.y-lineConstant)/gradient;} 
    185                         } 
    186                         // Check intersection with top of viewbox and clip 
    187                         if (lineIntersectLine(v1,v2, upperLeft, upperRight)) 
    188                         { 
    189                                 if (v1.y<v2.y) {v1.y=upperLeft.y;v1.x=(v1.y-lineConstant)/gradient;} 
    190                                 else {v2.y=upperLeft.y;v2.x=(v2.y-lineConstant)/gradient;}                               
    191                         } 
    192                         // Check intersection with right of viewbox and clip 
    193                         if (lineIntersectLine(v1,v2, upperRight, lowerRight) )  
    194                         { 
    195                                 if (v1.x>v2.x) {v1.x=lowerRight.x;v1.y=v1.x*gradient+lineConstant;} 
    196                                 else {v2.x=lowerRight.x;v2.y=v2.x*gradient+lineConstant;}                                
    197                         } 
    198                         return true; 
    199                 } 
    200              
    201               
    202             private function onMapStartPanning(event:MapEvent):void 
    203             { 
    204                 starting = new Point(x, y); 
    205             } 
    206              
    207             private function onMapPanned(event:MapEvent):void 
    208             { 
    209                 if (starting) { 
    210                     x = starting.x + event.panDelta.x; 
    211                     y = starting.y + event.panDelta.y; 
    212                 } 
    213                 else { 
    214                     x = event.panDelta.x; 
    215                     y = event.panDelta.y;                    
    216                 } 
    217             } 
    218              
    219             private function onMapStopPanning(event:MapEvent):void 
    220             { 
    221                 if (starting) { 
    222                         x = starting.x; 
    223                         y = starting.y; 
    224                     } 
    225                 updatePolyLines(); 
    226             } 
    227              
    228             private function onMapResized(event:MapEvent):void 
    229             { 
    230                 x = event.newSize[0]/2; 
    231                 y = event.newSize[1]/2; 
    232                 updatePolyLines(); 
    233             } 
    234              
    235             private function onMapStartZooming(event:MapEvent):void 
    236             { 
    237                 updatePolyLines();  
    238             } 
    239              
    240             private function onMapStopZooming(event:MapEvent):void 
    241             { 
    242                 if (scaleZoom) { 
    243                     scaleX = scaleY = 1.0; 
    244                 } 
    245             updatePolyLines(); 
    246             } 
    247              
    248             private function onMapZoomedBy(event:MapEvent):void 
    249             { 
    250                 if (scaleZoom) { 
    251                 scaleX = scaleY = Math.pow(2, event.zoomDelta); 
    252                 } 
    253                 else { 
    254                 updatePolyLines(); 
    255                 } 
    256             } 
    257              
     164                protected function clipLineToRect( v1:Point, v2:Point, r:Rectangle ):Boolean 
     165                { 
     166                        var lowerLeft:Point=new Point( r.x, r.y+r.height ); 
     167                        var upperRight:Point=new Point( r.x+r.width, r.y ); 
     168                        var upperLeft:Point=new Point( r.x, r.y ); 
     169                        var lowerRight:Point=new Point( r.x+r.width, r.y+r.height); 
     170                         
     171                        // Check completely out the box 
     172                        if (v1.x>upperRight.x && v2.x>upperRight.x) return false; 
     173                        if (v1.x<upperLeft.x && v2.x<upperLeft.x) return false; 
     174                        if (v1.y<upperRight.y && v2.y<upperRight.y) return false; 
     175                        if (v1.y>lowerRight.y && v2.y>lowerRight.y) return false; 
     176                         
     177                        // check if it is inside 
     178                        if (v1.x > lowerLeft.x && v1.x < upperRight.x && v1.y < lowerLeft.y && v1.y > upperRight.y && 
     179                                v2.x > lowerLeft.x && v2.x < upperRight.x && v2.y < lowerLeft.y && v2.y > upperRight.y ) 
     180                        {    
     181                                return true; 
     182                        } 
     183                         
     184                        // Calc gradient 
     185                        var gradient:Number=(v2.y-v1.y)/(v2.x-v1.x); 
     186                        // Calc constant 
     187                        var lineConstant:Number=v1.y-gradient*v1.x; 
     188                                                                                    
     189                        // Check intersection with left of viewbox and clip 
     190                        if (lineIntersectLine(v1,v2, upperLeft, lowerLeft ) )  
     191                        { 
     192                                if (v1.x<v2.x) {v1.x=lowerLeft.x;v1.y=v1.x*gradient+lineConstant;} 
     193                                else {v2.x=lowerLeft.x;v2.y=v2.x*gradient+lineConstant;}                                         
     194                        } 
     195                        // Check intersection with bottom of viewbox and clip                                                    
     196                        if (lineIntersectLine(v1,v2, lowerLeft, lowerRight)) 
     197                        { 
     198                                if (v1.y>v2.y) {v1.y=lowerRight.y;v1.x=(v1.y-lineConstant)/gradient;} 
     199                                else {v2.y=lowerRight.y;v2.x=(v2.y-lineConstant)/gradient;} 
     200                        } 
     201                        // Check intersection with top of viewbox and clip 
     202                        if (lineIntersectLine(v1,v2, upperLeft, upperRight)) 
     203                        { 
     204                                if (v1.y<v2.y) {v1.y=upperLeft.y;v1.x=(v1.y-lineConstant)/gradient;} 
     205                                else {v2.y=upperLeft.y;v2.x=(v2.y-lineConstant)/gradient;}                                       
     206                        } 
     207                        // Check intersection with right of viewbox and clip 
     208                        if (lineIntersectLine(v1,v2, upperRight, lowerRight) )  
     209                        { 
     210                                if (v1.x>v2.x) {v1.x=lowerRight.x;v1.y=v1.x*gradient+lineConstant;} 
     211                                else {v2.x=lowerRight.x;v2.y=v2.x*gradient+lineConstant;}                                        
     212                        } 
     213                        return true; 
     214                } 
     215                 
     216                protected function onMapStartPanning(event:MapEvent):void 
     217                { 
     218                        cacheAsBitmap = true; 
     219                }  
     220                 
     221                protected function onMapExtentChanged(event:MapEvent):void 
     222                { 
     223                        onMapPanned(event); 
     224                        onMapZoomedBy(event); 
     225                } 
     226                 
     227                protected function onMapPanned(event:MapEvent):void 
     228                { 
     229                        var pt:Point = map.grid.coordinatePoint(drawCoord); 
     230                        x = pt.x; 
     231                        y = pt.y; 
     232                } 
     233                 
     234                protected function onMapStopPanning(event:MapEvent):void 
     235                { 
     236                        cacheAsBitmap = false; 
     237                        dirty = true; 
     238                } 
     239                 
     240                protected function onMapResized(event:MapEvent):void 
     241                { 
     242                        dirty = true; 
     243                        // Flash doesn't always dispatch a rendered event during resize 
     244                        // so... 
     245                        updatePolyLines(); 
     246                } 
     247                 
     248                protected function onMapStartZooming(event:MapEvent):void 
     249                { 
     250                        cacheAsBitmap = false;  
     251                } 
     252                 
     253                protected function onMapStopZooming(event:MapEvent):void 
     254                { 
     255                        dirty = true; 
     256                } 
     257                 
     258                protected function onMapZoomedBy(event:MapEvent):void 
     259                { 
     260                        cacheAsBitmap = false; 
     261                        if (scaleZoom) { 
     262                                scaleX = scaleY = Math.pow(2, map.grid.zoomLevel-drawCoord.zoom); 
     263                        } 
     264                        else { 
     265                                dirty = true; 
     266                        } 
     267                } 
     268                 
     269                protected function set dirty(d:Boolean):void 
     270                { 
     271                        _dirty = d; 
     272                        if (d) { 
     273                                // this requests an Event.RENDER which Map will 
     274                                // respond to and dispatch MapEvent.RENDERED  
     275                                // when it's done shuffling tiles 
     276                                if (stage) stage.invalidate(); 
     277                        } 
     278                } 
     279                 
     280                protected function get dirty():Boolean 
     281                { 
     282                        return _dirty; 
     283                } 
     284 
    258285        } 
    259          
    260286}