Rotating a Point Around a Base Point

A while back, I was working on a project that required us to rotate a polygon around a base point and do a spatial query to analyze some underlying demographic data. I was working in ArcObjects and could find no intrinsic way to do what I needed to do so I wrote the following routine. As you can imagine, I had to break the polygon up into individual points and rotate each one. Despite the fact that I was using ArcObjects point objects and all of the attendant COM interop calls, it worked pretty well (a polygon consisting of ~5000 point was rotated in less than a second on a less-than-robust workstation).

The math is pretty simple: Assuming that the base point and target point form the two ends of the hypotenuse of a right triangle with one leg of the triangle being a segment of the X axis, you simply:

  1. Calculate the length of the hypotenuse
  2. Calculate the current angle of the hypotenuse
  3. Add the rotation angle to the current angle
  4. Calculate the coordinates of the new end point of the hypotenuse

The code below shows how to do it but there are a couple of notes about it:

  • The coordinates must be in decimal degrees so you’ll need to unproject any projected coordinates and then re-project the result. This may introduce some distortion. I didn’t notice any in my application but I’d suggest some more rigorous testing if you’ve got tight precision requirements.
  • Rotation follows engineering standards (zero East, counter-clockwise)
  • This code is only mildly based on ArcObjects. It uses the AO IPoint interface and Point but that’s it. It is trival to implement it with another point object (such as SharpMap) or just use numeric values.
  • The base point is shifted to 0,0 and the same offset is applied to all other points in order to keep the math straightforward.
  • It’s in C#

So there it is. It’s fairly simple but it’s been useful for me on a couple of occasions since I wrote it.
[sourcecode language=”csharp”]
private IPoint rotatePoint(IPoint basePoint, IPoint sourcePoint, double rotationAngle)
{
double r;
double theta;
double offsetX;
double offsetY;
double offsetTheta;
double rotateX;
double rotateY;
double rotationRadians;
IPoint retPoint;
try
{
//shift x and y relative to 0,0 origin
offsetX = (sourcePoint.X + (basePoint.X * -1));
offsetY = (sourcePoint.Y + (basePoint.Y * -1));
//convert to radians. take absolute value (necessary for x coord only).
offsetX = Math.Abs(offsetX * (Math.PI / 180));
offsetY = offsetY * (Math.PI / 180);
rotationRadians = rotationAngle * (Math.PI / 180);
//get distance from origin to source point
r = Math.Sqrt(Math.Pow(offsetX, 2) + Math.Pow(offsetY, 2));
//get current angle of orientation
theta = Math.Atan(offsetY / offsetX);
// add rotation value to theta to get new angle of orientation
offsetTheta = theta + rotationRadians;
//calculate new x coord
rotateX = r * Math.Cos(offsetTheta);
//calculate new y coord
rotateY = r * Math.Sin(offsetTheta);
//convert new x and y back to decimal degrees
rotateX = rotateX * (180 / Math.PI);
rotateY = rotateY * (180 / Math.PI);
//shift new x and y relative to base point
rotateX = (rotateX + basePoint.X);
rotateY = (rotateY + basePoint.Y);
//return new point
retPoint = new PointClass();
retPoint.X = rotateX;
retPoint.Y = rotateY;
return retPoint;
}
catch
{
return sourcePoint;
}
}[/sourcecode]

  • Eric

    Thanks for this. It’s proven useful for me.

    I don’t think you need to bother converting the x and y points to radians from degrees and back. The ratios (which is what matters) will remain the same and it will save you about 9 unnecessary operations plus the assignments.

  • You may be right. I seem to recall that I ran into an issue when I didn’t use radians (may have been calculating theta) but I need to go back and check. It’s been a while.

  • Ron

    Bill, why didn’t you just use ITransform2D. This interface will do what you want using Rotate:

    http://edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeometry/ITransform2D_Rotate.htm

  • Ron,

    Although I was using ArcObjects in this case, I wanted the rotation logic to be independent of ArcObjects so I could using it in other settings.

    Bill