Monday, March 21, 2011

Determine the Midpoint for a Polyline for ArcGIS API for Flex

/*
This method determines the midpoint of the specified polyline using the ArcGIS API for Flex geometry types. It is required that the coordinate system used by the geometry is Cartesian.

Remarks: This method does not support multipart objects. If multipart is necessary, it is required                some adjustments to the core functionality.
Author: José Sousa
Date: 22-03-2011
*/
private function GetPolylineMidpoint(polyline:Polyline):MapPoint
{  
   if(polyline == null || polyline.paths == null || polyline.paths.length < 1)
      return null;
                       
   // Does not support multiparts (in this case the center could be outside of the polylines itself)
   var totalDistance:Number = getPolylinePathLength(polyline.paths[0]); // Just get's the first path
   if(totalDistance <= 0)
      return null;
                     
   // Get the midpoint
   return getMidPoint(polyline.paths[0], totalDistance);
}
                 
private function getPolylinePathLength(points:Array):Number
{  
   var distance:Number = 0.0;                     
   for(var i:Number = 0; i < points.length - 1; i++)  
   {      
      distance += getDistance(points[i], points[i + 1]);  
   }                      
   return distance;
}
              
private function getMidPoint(points:Array, totalDistance:Number):MapPoint
{  
   var halfDistance:Number = totalDistance / 2;
   var sumDistance:Number = 0.0;  
   var distance:Number = 0.0;  
   var i:Number;
                     
   for(i = 0; i < points.length - 1; i++)  
   {      
      distance = getDistance(points[i], points[i + 1]);
      if((sumDistance + distance) < halfDistance)
      {
         sumDistance += distance;      
      }
      else
      {
         break
      }
   }
                      
   distance = halfDistance - sumDistance;                    
   return getCoordinate(points[i], points[i + 1], distance);
}
              
private function getCoordinate(fromPoint:MapPoint, toPoint:MapPoint, queryDistance:Number):MapPoint
{    
   var angle:Number;
   var distance:Number = getDistance(fromPoint, toPoint);
   var coordX:Number;
   var coordY:Number;                       
                       
   if((toPoint.x - fromPoint.x >= 0) && (toPoint.y - fromPoint.y >= 0))
   {
      angle = Math.asin((toPoint.y - fromPoint.y) / distance);                           
      coordX = queryDistance * Math.cos(angle) + fromPoint.x;
      coordY = queryDistance * Math.sin(angle) + fromPoint.y;
   }  
   else if((toPoint.x - fromPoint.x < 0) && (toPoint.y - fromPoint.y >= 0))
   {
      angle = Math.asin((fromPoint.x - toPoint.x) / distance);                                                               
      coordX = fromPoint.x - queryDistance * Math.sin(angle);
      coordY = queryDistance * Math.cos(angle) + fromPoint.y;
   }  
   else if((toPoint.x - fromPoint.x <= 0) && (toPoint.y - fromPoint.y < 0))
   {
      angle = Math.asin((fromPoint.y - toPoint.y) / distance);                                 
      coordX = fromPoint.x - queryDistance * Math.cos(angle);
      coordY = fromPoint.y - queryDistance * Math.sin(angle);
   } 
   else if((toPoint.x - fromPoint.x > 0) && (toPoint.y - fromPoint.y < 0))
   {
      angle = Math.asin((toPoint.x - fromPoint.x) / distance);                                                               
      coordX = queryDistance * Math.sin(angle) + fromPoint.x;
      coordY = fromPoint.y - queryDistance * Math.cos(angle);
   }
                                                                   
   if(fromPoint.spatialReference)
      return new MapPoint(coordX, 
                          coordY,
                          new SpatialReference(
                              fromPoint.spatialReference.wkid,   
                              fromPoint.spatialReference.wkt));
   return new MapPoint(coordX, coordY, null);
}

private function getDistance(point1:MapPoint, point2:MapPoint):Number
{
   return Math.sqrt((point2.x - point1.x) * (point2.x - point1.x) + 
                    (point2.y - point1.y) * (point2.y - point1.y));                  
}