ThinkGeo.com    |     Documentation    |     Premium Support

RotationProjection

I'm trying to add map rotation to our custom .NET windows application.  Following the sample 'CenteringAndRotatingOnMovingFeature', I've added code to implement map rotation.  However, my data displays somewhere out in left field now when I set rotateProjection.Angle to 45, and when I find the data through panning and zooming out to left field the map/data is not being rotated.  I assume my code is not correct and could use help identifying the problem.  Without pasting to much code, here are some snippets pertaining to the map rotation.  I'd be much apprecitive if someone can help spot the problem or give me some hints for debugging.




private RotationProjection rotateProjection = new RotationProjection();

void LayoutMapGeoView_Loaded(object sender, RoutedEventArgs e)
 {

   rotateProjection.Angle = (float)LayoutMapGeoViewModel.MapAngle;    // value = 45,  I'm assuming units are degrees

    lineSegmentLayer = new LineSegmentFeatureLayer(LayoutMapGeoViewModel, this);
    lineSegmentLayer.FeatureSource.Projection = rotateProjection;
    pointsOverlay.Layers.Add(SEGMENTS_LAYER_NAME, lineSegmentLayer);

 

    pfLayer = new PointsFeatureLayer(LayoutMapGeoViewModel, this);
    pfLayer.FeatureSource.Projection = rotateProjection;
    pointsOverlay.Layers.Add(POINTS_LAYER_NAME, pfLayer);

 

    ResetExtents();

   ...

}

        private void ResetExtents()
        {
            log.DebugFormat("LayoutMapGeoView.ResetExtents");
            pfLayer.Open();
            rotateProjection.Angle = (float)LayoutMapGeoViewModel.MapAngle;
            wpfMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(pfLayer.FeatureSource.GetBoundingBox());
            wpfMap1.CenterAt(pfLayer.GetBoundingBox().GetCenterPoint());
           
            pfLayer.Close();
        }

 

        class LineSegmentFeatureLayer : InMemoryFeatureLayer
        {
            private static ILog log = LogManager.GetLogger(typeof(LineSegmentFeatureLayer));

            private Feature DEFAULT_FEATURE = new Feature(-1, -1);
            SpreadManagerMapViewModel viewModel = null;
            LayoutMapGeoView view = null;
            LineSegmentLineStyle lineStyle = null;

            public LineSegmentFeatureLayer(SpreadManagerMapViewModel viewModel, LayoutMapGeoView view)
            {
                this.viewModel = viewModel;
                this.view = view;
                ((INotifyCollectionChanged)viewModel.LineSegments).CollectionChanged += new NotifyCollectionChangedEventHandler(LineSegments_CollectionChanged);

                ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

                DrawingQuality = DrawingQuality.HighSpeed;

                lineStyle = new LineSegmentLineStyle();
                ZoomLevelSet.ZoomLevel01.CustomStyles.Add(lineStyle);

                AddFeatures(viewModel.LineSegments);
            }


I looked at the code and unfortunatly there seems to be a lot of different parameters we don’t have access to. 
 If you don’t mind, can you create a little self contained sample app that recreates the problem? I am afraid that with only the code snippet, we are going to spend a lot of time trying to recreate your condition and make it run. Thank you.

Yes, I understand and will work on a sample.  That will help me too understand how to use the RotationProjection.  Our application has way too much code and dependencies to show and isolate just this issue - and I was afraid that posting only a few snippets would make it difficult to see exactly what the problem is.

Thank you for taking the effort to work on a sample app for that. This is going to save us a lot of time and I think we will be in a better position to help you.



Attached is a self contained application that demonstrates the problem I'm having using RotationProjection.   When you first load and run the application, it will display a field of point features (non-rotated).  To reproduce the issue, uncomment the two lines I've marked with  // <------ un-comment and remove or comment out the line marked with // <----- comment out.   When you run the application there is a text box at the top where you can enter the rotation angle, and a button [Rotate Map] to apply the map rotation angle.  The desired behavior is for the map to redraw, centered at the same center point, and same scale, but with the north direction rotated the amout specified.    Thank you for helping me to understand how to correclty apply RotationProjection!


 


        private void buttonSetMapAngle_Click(object sender, RoutedEventArgs e)

        {

            rotateProjection.Angle = MapAngle; 

            PerformRefresh();

        }  



Rod,


Thanks for your post and sample code.
 
Unfortunately I am afraid I do not quite understand very well on your point. While I just want to mention something from my point view to keep us in the same line before going any further.
 
1, when I run the application you attached without those two lines uncommented, that is to say we do not set the RotationProjection to the PointsFeatureLayer. It will show a whole bunch of points. While, when I set the RotationProjection to the PointsFeatureLayer, run again, nothing will be shown on the Map Control, Right?
 
If Yes, then problem is hidden in the f.Tag(f is a feature) used in the DrawCore of LayoutPointStyle. This can be considered as a bug when we add the Tag property; the Tag will be lost when we do projection against Feature. This problem has been fixed and it should be available in next version or later version (4.0.59.0 or higher version).
 
2, I tried the following code to rotate Points in the ShapeFileFeatureLayer by setting the RotationProjection to it, it works fine. Take a look by just replace the following code in the HowDoI\Projection\ Use RotationProjection for a feature layer sample.

  

private void UseRotationProjectionForAFeatureLayer_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.Meter;
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);
 
            ShapeFileFeatureLayer majorCitiesShapeLayer = new ShapeFileFeatureLayer(@"..\..\SampleData\Data\MajorCities.shp");
            majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
            majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.City1("AREANAME");
           majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.BestPlacement = true;
            majorCitiesShapeLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            rotateProjection = new RotationProjection();
            majorCitiesShapeLayer.FeatureSource.Projection = rotateProjection;
 
            LayerOverlay worldOverlay = new LayerOverlay();
            worldOverlay.Layers.Add("WorldLayer", majorCitiesShapeLayer);
            winformsMap1.Overlays.Add("WorldOverlay", worldOverlay);
 
            winformsMap1.ZoomLevelSnapping = ZoomLevelSnappingMode.None;
            winformsMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(new RectangleShape(-180.0, 83.0, 180.0, -90.0));
 
            winformsMap1.Refresh();
        }
 
        private void btnRotateCounterclockwise_Click(object sender, EventArgs e)
        {
            rotateProjection.Angle += 20;
            winformsMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(winformsMap1.CurrentExtent);
 
            winformsMap1.Refresh(winformsMap1.Overlays["WorldOverlay"]);
        }
 
        private void btnRotateClockwise_Click(object sender, EventArgs e)
        {
            rotateProjection.Angle -= 20;
            winformsMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(winformsMap1.CurrentExtent);
 
            winformsMap1.Refresh(winformsMap1.Overlays["WorldOverlay"]);
        }

 
Any more questions just feel free to let us know.
 
Thanks.
 
Yale

Yale, 
  
 Thank you for investigating my sample.  Yes - your statement is correct.  When I add the RotationProjection, the result is that no data displays in the sample.  I had just assumed it may have been displaying way off someplace, as in my actual application I examined the new extents and new center point and the geographic coordinates were magnitudes different.  In the sample, the behavior is as you stated - nothing displays when the rotation projection is used. Thank you for the fix that retains the tag through the projection process.  I’ll obtain the next version and study the code you posted to make sure I’m using RotationProjection correctly.   When using the revised version, did my sample app also perform and display the rotation? 
  
 Thank you very much! 
  
 Rod

Rod, 
  
 Thanks for your post and feedback. 
  
 Did you have a try on the latest version with the tag problem fixed? With the new revised version, the map should display after we set the RotationProjection as we want. While unfortunately, it seems that the sample you provided seems cannot works as well as the sample I provided above, I have not fully investigated the reason for it quite complicated.  Just take a try with the latest DLLs, and let me know if any more questions. 
  
 Any more questions just feel free to let me know. 
  
 Thanks. 
  
 Yale 


Yale, 
  
 I updated my DLL’s this morning to the latest version (4.0.63.0).  My sample app with the Feature Layer containing points still does not display data when using the RotationProjection and a MapAngle of 30.  Using breakpoints to examine extents under each scenario (not using RotationProjection and using RotationProjection). 
  
 Current Extent (not using RotationProjection) 
 {-99.6901544433323,35.8697216699985,-99.3242077766677,35.59526167} 
  
 ? pfLayer.GetBoundingBox().GetCenterPoint() 
 {-99.50718111,35.7324916699992,0} 
     base {ThinkGeo.MapSuite.Core.PointBaseShape}: {-99.50718111,35.7324916699992,0} 
     CanRotate: true 
     X: -99.507181109999976 
     Y: 35.732491669999234 
     Z: 0.0 
  
  
  
  
 Current Extent (using RotationProjection) 
  
 {-104.235425423453,-18.6632703621041,-103.848559647024,-18.9534196944255} 
  
 ? pfLayer.GetBoundingBox().GetCenterPoint() 
 {-127.385148988742,30.6928108087098,0} 
     base {ThinkGeo.MapSuite.Core.PointBaseShape}: {-127.385148988742,30.6928108087098,0} 
     CanRotate: true 
     X: -127.38514898874203 
     Y: 30.692810808709766 
  
  
 It’s strange that the extents are all negative coordinates when using RotationProjection, however the CenterPoint reports a positive value for the Y coordinate. Either the extents are wrong or the new CenterPoint is wrong.  In either case, the RotationProjection is not functioning correctly.  The point data is definately being transformed when using RotationProjection, but I have not been able to view it, zoom to it etc.  Shouldn’t the center point remain the same?  Is there a way to set the coordinate value of the point of rotation, or is that always the center coordinate?    
  
 I really need to get the RotationProjection working with my sample app as that is how our application will use it.  ie, we are not displaying shapefiles, and we are not using winForms. 
  
 Studying the code above that you provided for rotating the shapefile data, as far as I can tell, the same code is being used in my sample: 
  
 1)  instantiate a RotationProjection 
 
private RotationProjection rotateProjection = new RotationProjection(); 
 
 
  
 2) set a map angle 
 
rotateProjection.Angle = 30;
 
  
 3) apply the RotationProjection to the Feature Layer 
 
pfLayer.FeatureSource.Projection = rotateProjection;
 
 
  
 4) Set the map extent 
 
this.wpfMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(pfLayer.FeatureSource.GetBoundingBox());
 
  
 5) Center the map 
 
this.wpfMap1.CenterAt(pfLayer.GetBoundingBox().GetCenterPoint());
 
  
 6) Redraw the map 
 
this.wpfMap1.Refresh();
 
  
 The result being a blank map.   
  
 
        private void wpfmap_Loaded(object sender, RoutedEventArgs e)
        {
            InitializeData();

            MapAngle = 30.0;  // <-----
            rotateProjection.Angle = MapAngle;  // <-----

            this.wpfMap1.ZoomLevelSnapping = ZoomLevelSnappingMode.None;
            pointsOverlay = new LayerOverlay();

            pfLayer = new PointsFeatureLayer(this);
            pfLayer.FeatureSource.Projection = rotateProjection;

            pointsOverlay.Layers.Add(POINTS_LAYER_NAME, pfLayer);
            this.wpfMap1.Overlays.Add(POINTS_OVERLAY_NAME, pointsOverlay);
            pointsOverlay.IsBase = false;
            this.wpfMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.SimpleColors.Black);
            this.wpfMap1.MapUnit = GeographyUnit.DecimalDegree;
            this.wpfMap1.ThreadingMode = MapThreadingMode.SingleThreaded;

            pfLayer.FeatureSource.Open();
            this.wpfMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(pfLayer.FeatureSource.GetBoundingBox());  // <------
            this.wpfMap1.CenterAt(pfLayer.GetBoundingBox().GetCenterPoint());   // <------

            this.wpfMap1.Refresh();
        }
 
  
  
 I’m in need of additional help or ideas to get the rotation working in this code.  Thank you! 
  
 Rod

my latest attempt using hard coded coordinates for new Extent and CenterAt values.   result: blank map / no data displayed. 
  
 
            try
            {
                MapAngle = 30.0;
                rotateProjection.Angle = MapAngle;

                this.wpfMap1.ZoomLevelSnapping = ZoomLevelSnappingMode.None;
                pointsOverlay = new LayerOverlay();

                pfLayer = new PointsFeatureLayer(this);
                pfLayer.FeatureSource.Projection = rotateProjection;

                pointsOverlay.Layers.Add(POINTS_LAYER_NAME, pfLayer);
                this.wpfMap1.Overlays.Add(POINTS_OVERLAY_NAME, pointsOverlay);
                pointsOverlay.IsBase = false;
                this.wpfMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.SimpleColors.Black);
                this.wpfMap1.MapUnit = GeographyUnit.DecimalDegree;
                this.wpfMap1.ThreadingMode = MapThreadingMode.SingleThreaded;

                pfLayer.FeatureSource.Open();
                this.wpfMap1.CurrentExtent = rotateProjection.GetUpdatedExtent(new RectangleShape(-127.8, 30.9, -127.0, 30.8));
                this.wpfMap1.CenterAt(new PointShape(-127.38514898874203, 30.692810808709766, 0.0));

                this.wpfMap1.Refresh();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.InnerException.ToString());
            }


Rod,


Thanks for your post and code samples.
 
Finally I got the other problems hidden in the customized style; also I made some minor modification on the code to get it optimized and easy to read.
 
I attached the updated sample and as well as a screenshot for it.
 

 
Any more questions just feel free to let me know.
 
Thanks.
 
Yale

Post7755UpdateSample.zip (14.6 KB)

Thank you for figuring this out Yale!  I’ll download your update and let you know if I have any more questions.

Rod, 
  
 Just go ahead having a try and let us know if any more questions. 
  
 Thanks. 
  
 Yale