Transforming envelopes in the display


Summary
This topic explains how to get a rectangle from the transform and specify a rectangle to the transform. IGeometry, IDisplayTransformation, and tagRect are implemented in this topic.


About transforming envelopes in the display

Understanding how rotation is implemented within display objects is important since it affects all displayed entities. Rotation happens below the transformation level so clients of DisplayTransformation always deal with un-rotated shapes. For example, when you get a shape from one of the transform routines, it is in un-rotated space. When you specify an extent to the transform, the extent is also in un-rotated space. There are no issues with rotation when working with polygons. However, it is more complicated when working with envelopes, because rotated rectangles cannot be represented. The following sections demonstrate these complications.

Getting a rectangle from the transform

For example, you want a rectangle representing the client area of the window. Since the user is seeing rotated space on the display, it is not possible to represent the requested area as an envelope. The four corners of the rectangle have unique x,y values in map space. The internal representation of the Envelope class assumes shared x,y values for the sides. As a result, the envelope returned by DisplayTransformation.FittedBounds is not what you want because a rectangular polygon is needed to accurately represent the client area in un-rotated map space. Most clients avoid using an envelope when there is rotation and implement code to find the rectangular polygon that matches a rectangle on the user's display. See the following code example:
[VB.NET]
Private Sub ToUnrotatedMap(ByVal r As tagRECT, ByVal geomBounds As IGeometry, ByVal dispTransform As IDisplayTransformation)
    Dim mapPoints() As WKSPoint = New WKSPoint(5)
    Dim rectCorners() As tagPOINT = New tagPOINT(4)
    rectCorners(0).x = r.Left
    rectCorners(0).y = r.bottom
    rectCorners(1).x = r.Left
    rectCorners(1).y = r.top
    rectCorners(2).x = r.Right
    rectCorners(2).y = r.top
    rectCorners(3).x = r.Right
    rectCorners(3).y = r.bottom
    
    'Transform all four points.
    dispTransform.TransformCoords(mapPoints(0), rectCorners(0), 4, 4 | 1)
    dispTransform.TransformCoords(mapPoints(1), rectCorners(1), 4, 4 | 1)
    dispTransform.TransformCoords(mapPoints(2), rectCorners(2), 4, 4 | 1)
    dispTransform.TransformCoords(mapPoints(3), rectCorners(3), 4, 4 | 1)
    
    ' Build polygon from mapPoints.
    mapPoints(4) = mapPoints(0)
    Dim boundsPointCollection As IPointCollection
    Dim boundsTopologicalOperator2 As ITopologicalOperator2
    
    boundsPointCollection = CType(geomBounds, IPointCollection)
    boundsTopologicalOperator2 = CType(geomBounds, ITopologicalOperator2)
    
    boundsPointCollection.SetWKSPoints(1, ref mapPoints(0))
    boundsPointCollection.SetWKSPoints(1, ref mapPoints(1))
    boundsPointCollection.SetWKSPoints(1, ref mapPoints(2))
    boundsPointCollection.SetWKSPoints(1, ref mapPoints(3))
    boundsPointCollection.SetWKSPoints(1, ref mapPoints(4))
    boundsTopologicalOperator2.IsKnownSimple_2 = True
    
End Sub
[C#]
private void ToUnrotatedMap(tagRECT r, IGeometry geomBounds, IDisplayTransformation
    dispTransform)
{
    WKSPoint[] mapPoints = new WKSPoint[5];
    tagPOINT[] rectCorners = new tagPOINT[4];
    rectCorners[0].x = r.left;
    rectCorners[0].y = r.bottom;
    rectCorners[1].x = r.left;
    rectCorners[1].y = r.top;
    rectCorners[2].x = r.right;
    rectCorners[2].y = r.top;
    rectCorners[3].x = r.right;
    rectCorners[3].y = r.bottom;
    //Transform all four points.
    dispTransform.TransformCoords(ref mapPoints[0], ref rectCorners[0], 4, 4 | 1);
    dispTransform.TransformCoords(ref mapPoints[1], ref rectCorners[1], 4, 4 | 1);
    dispTransform.TransformCoords(ref mapPoints[2], ref rectCorners[2], 4, 4 | 1);
    dispTransform.TransformCoords(ref mapPoints[3], ref rectCorners[3], 4, 4 | 1);
    // Build polygon from mapPoints.
    mapPoints[4] = mapPoints[0];
    IPointCollection boundsPointCollection;
    ITopologicalOperator2 boundsTopologicalOperator2;
    boundsPointCollection = (IPointCollection)geomBounds;
    boundsTopologicalOperator2 = (ITopologicalOperator2)geomBounds;
    boundsPointCollection.SetWKSPoints(1, ref mapPoints[0]);
    boundsPointCollection.SetWKSPoints(1, ref mapPoints[1]);
    boundsPointCollection.SetWKSPoints(1, ref mapPoints[2]);
    boundsPointCollection.SetWKSPoints(1, ref mapPoints[3]);
    boundsPointCollection.SetWKSPoints(1, ref mapPoints[4]);
    boundsTopologicalOperator2.IsKnownSimple_2 = true;
}

Specifying a rectangle to the transform

The client needs to work in un-rotated space and let the transform handle the rotation before displaying. In the case of dragging a zoom rectangle, this means the user sees rotation space. The dragged rectangle is in rotation space. The tool needs to convert the rectangle to un-rotated space before specifying it to the transform. The following code example shows how to do this (rotatedExtent is a rectangular polygon that exactly matches the dragged rectangle):
[VB.NET]
Dim area As IArea = rotatedExtent
Dim center As IPoint = area.Centroid
Dim trans As ITransform2D = rotatedExtent
trans.Rotate(pCenter, (90 * (3.1416 / 180)))
[C#]
IArea area = rotatedExtent;
IPoint center = pArea.Centroid;
ITransform2D trans = rotatedExtent;
trans.Rotate(pCenter, (90 * (3.1416 / 180)));


See Also:

Working with the map display




To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Development licensing Deployment licensing
ArcGIS for Desktop Basic ArcGIS for Desktop Basic
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced
Engine Developer Kit Engine