how to rotate a marker 0-360 degrees

Topics: Windows Forms
Feb 24, 2013 at 3:06 PM
Hi,

I un-commented out some code that appeared to use the Bearing.
It sort of worked, but rotated the canvas and markers in a way I can't understand.
So I have hope that it could work, but don't have the brains to get it working.

Q: Has anyone been able to rotate markers?

This is my last attempt at reaching out to see if anyone has done this.
Otherwise I will be creating:
Resource/yellow_360.png
Resource/yellow_90.png
etc

Thanks for any leads.
-cellurl
Feb 25, 2013 at 9:16 PM
You have to create a matrix for the Graphix on the OnRender method
Then RotateAt the matrix

Something like this
public override void OnRender(Graphics g)
{
  Point p0 = LocalPosition;

  Matrix mx = new Matrix();
  mx.RotateAt(45, new PointF(p0.X, p0.Y), MatrixOrder.Append);
  g.Transform = mx;

  g.DrawYourStuff();
  g.ResetTransform();
}
Feb 26, 2013 at 5:01 AM
Thanks for the reply.
It rotates the markers but puts them up at the top always.
Image
I am running the demo source.
Thanks for helping!
cellurl

GMarkerGoogle.cs
      public override void OnRender(Graphics g)
      {
#if !PocketPC
         //if(!Bearing.HasValue)
         {
            if(BitmapShadow != null)
            {
               g.DrawImage(BitmapShadow, LocalPosition.X, LocalPosition.Y, BitmapShadow.Width, BitmapShadow.Height);
            }
         }

          //jim uncommented this whole entire if/body thing...
         //if (Bearing.HasValue)
         //{
         //    g.RotateTransform(Bearing.Value - Overlay.Control.Bearing);
         //    g.FillPolygon(Brushes.Red, Arrow);
         //}

          //jim uncommented this one if line only
         //if (!Bearing.HasValue)
         {
             Matrix mx = new Matrix();
            mx.RotateAt(45, new PointF(LocalPosition.X, LocalPosition.Y), MatrixOrder.Append);
            g.Transform = mx;
            g.DrawImage(Bitmap, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
            g.ResetTransform();
         }
#else
         if(BitmapShadow != null)
         {
            DrawImageUnscaled(g, BitmapShadow, LocalPosition.X, LocalPosition.Y);
         }
         DrawImageUnscaled(g, Bitmap, LocalPosition.X, LocalPosition.Y);
#endif
      }
Feb 26, 2013 at 5:58 AM
Hello

In my example I've set the rotation angle to 45 degree, you have to change it to the needed value (in degree)

mx.RotateAt(45, new PointF(LocalPosition.X, LocalPosition.Y),
Feb 26, 2013 at 6:42 AM
Yep, I realize you hardwired 45 in there for test.
I still get the same thing, the markers are in the wrong place, everything is rotated...

Q: Is LocalPosition.X a latitude? (hope not). I stepped in and it was 6,12, small numbers.
I am out of ideas...
Thanks for looking
-cellurl



GMarkerGoogle.cs

      public override void OnRender(Graphics g)
      {
#if !PocketPC
          {
              Matrix mx = new Matrix();
              mx.RotateAt(45, new PointF(LocalPosition.X, LocalPosition.Y), MatrixOrder.Append);
              g.Transform = mx;
              g.DrawImage(Bitmap, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
              g.ResetTransform();
          }
#else
         if(BitmapShadow != null)
         {
            DrawImageUnscaled(g, BitmapShadow, LocalPosition.X, LocalPosition.Y);
         }
         DrawImageUnscaled(g, Bitmap, LocalPosition.X, LocalPosition.Y);
#endif
      }
Feb 26, 2013 at 10:08 AM
i recommend to rotate image itself, at least until i or someone else will manage to get the code right...
Feb 26, 2013 at 10:31 AM
Using RotateAt you set the center of rotation to LocalPosition

But LocalPosition is probably not the center of your image but the top left corner of your marker (according to offset)
Feb 26, 2013 at 10:37 AM
yes, LocalPosition is topLeft of markers image, but the origin isn't topLeft of the view, it's marked as blue cross in debug mode and is dynamic...
Feb 26, 2013 at 2:35 PM
If I hear you right radioman, its solvable, but on the back burner and not super simple...

Anyway, lets table this for now and I will go to plan B (bunch of separate png files).

I will monitor the forum for future solutions.

Thanks everyone!

-cellurl
Feb 26, 2013 at 2:45 PM
just use one image, and make rotated image using the first as reference
Feb 26, 2013 at 5:05 PM
However I'm quite sure that my proposition will work
In the constructor Set size the size of image

public override void OnRender(Graphics g)
{
Point p0 = LocalPosition;
p0.X+=Size.With /2;
p0.Y+=Size.Height /2;

Matrix mx = new Matrix();
mx.RotateAt(Angle, new PointF(p0.X, p0.Y), MatrixOrder.Append);
g.Transform = mx;

g.DrawYourStuff();
g.ResetTransform();
}

N.B. Maybe you have to save g.Transform before and restore after
Feb 26, 2013 at 9:33 PM
Edited Feb 26, 2013 at 9:36 PM
This work fine
class C_GmapDirectionMarker : GMapMarker
{
    Color Co;
    double Angle = 0;
    Image Img;
 
    public C_GmapDirectionMarker(PointLatLng p0,double Angle, Image _Img)
      : base(p0)
    {

      this.Img = _Img;
      this.Size = new Size(Img.Width, Img.Height);
      this.Offset = new Point(-Size.Width / 2, -Size.Height / 2);
      this.Angle = Angle;
    }

    public override void OnRender(Graphics g)
    {
      Point p0 = LocalPosition;
      p0.X -= Offset.X;
      p0.Y -= Offset.Y;

      Matrix mx = new Matrix();
      mx.RotateAt((float)Angle, new PointF(p0.X, p0.Y), MatrixOrder.Append);
      g.Transform = mx;

      g.DrawImageUnscaled(Img, LocalPosition.X, LocalPosition.Y);
      g.ResetTransform();
    }
}
Feb 27, 2013 at 5:06 AM
Thanks for that.
I just tried it.
It almost worked.
It rotates the markers wonderfully,
but
it places them in the upper left corner.

You guys are the best.
Don't spend any more time on this.
I appreciate it! I really do.


-cellurl
Feb 27, 2013 at 5:50 AM
Here is how it works on my road

Image

And the icon used

Image
Feb 27, 2013 at 2:22 PM
can you fork it somewhere and I grab it all??
It looks wonderful, just what I need ( just the markers... )
Feb 27, 2013 at 3:12 PM
Hello CellUrl

I'm just using the code already given : I make an extension of GMapMarker
It should work for you too !

One tricky thing can be to compute the angle...

What problem do you encounter ?
Feb 28, 2013 at 5:28 AM
I just downloaded new source (greatmaps_5794a8864f7c)
I modified the Flight Radar Demo to show all points at 45 degree angle.
The points are at an angle. There are two things that don't seem correct.
1) In the left top, I see DEBUG BUILD cross.
2) When I rightclick mouse and move map a small amount, the markers do not move.
The map moves, but the markers don't. (two screenshots below)

If you want to recreate this, here are the only two files I changed
TEXT
TEXT

Before moving screen
After moving screen (notice marker didnt move. I waited and it never moved)
TEXT
TEXT
Mar 1, 2013 at 9:22 AM
Edited Mar 1, 2013 at 9:24 AM
Here's the correct method, i think olibara uses an older version of GMap without "LocalAreaInControlSpace":
        /// <summary>
        /// Override Render function
        /// </summary>
        /// <param name="g"></param>
        public override void OnRender(Graphics g)
        {
            if (RotationAngle != 0f)
            {
                GraphicsState savedState = g.Save();
                g.ResetTransform();
                g.Transform.RotateAt(RotationAngle, new PointF(LocalAreaInControlSpace.Location.X - Offset.X, LocalAreaInControlSpace.Location.Y - Offset.Y));
                g.DrawImage(img, LocalAreaInControlSpace.Location.X, LocalAreaInControlSpace.Location.Y, Size.Width, Size.Height);
                g.Restore(savedState);
            }
            else
                g.DrawImage(img, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
        }
Mar 2, 2013 at 7:59 PM
Edited Mar 2, 2013 at 8:02 PM
I put this in at the top of file: GMapMarker.cs
It doesn't rotate, but it doesn't hurt anything, so I call that progress..

Q: How do I modify the constructor to rotate the icon in there.
(I don't know how to rotate a bitmap).
Thanks for helping
-cellurl
    using GMap.NET.WindowsForms.Markers;
    using System.Windows.Forms.Properties;
    using System.Drawing.Drawing2D;

    public class C_GmapDirectionMarker : GMapMarker
    {
        float RotationAngle = 0;
        public Image Img;

        public C_GmapDirectionMarker(PointLatLng p0, float Angle, GMarkerGoogleType _type)
            : base(p0)
        {
              switch (_type)
              {
                  case GMarkerGoogleType.yellow_small:
                      Img = Resources.yellow_small;
                      break;
                  default:
                      Img = Resources.yellow_small;
                      break;
              }

            this.Size = new Size(Img.Width, Img.Height);
            this.Offset = new Point(-Size.Width / 2, -Size.Height / 2);
            this.RotationAngle = Angle;
        }

        /// <summary>
        /// Override Render function
        /// </summary>
        /// <param name="g"></param>
        public override void OnRender(Graphics g)
        {
            if (RotationAngle != 0f)
            {
                GraphicsState savedState = g.Save();
                g.ResetTransform();
             
                g.Transform.RotateAt(RotationAngle, new PointF(LocalAreaInControlSpace.Location.X - Offset.X, LocalAreaInControlSpace.Location.Y - Offset.Y));

                g.DrawImage(Img, LocalAreaInControlSpace.Location.X, LocalAreaInControlSpace.Location.Y, Size.Width, Size.Height);
                g.Restore(savedState);
            }
            else
                g.DrawImage(Img, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
        }
    }
Mar 3, 2013 at 8:38 AM
Oops, sorry, I changed something in the code without testing, the problem was, that it's not possible to directly set the transformation matrix for the Graphics object, because it returns a COPY of the matrix..... Here's the working code. By the way, in your class, you are not Disposing the Image!! That can cause trouble (memory leak).
        /// <summary>
        /// Override Render function
        /// </summary>
        /// <param name="g"></param>
        public override void OnRender(Graphics g)
        {
            if (rotAngle != 0f)
            {
                GraphicsState savedState = g.Save();
                g.ResetTransform();

                Matrix rot = new Matrix();
                rot.RotateAt(rotAngle, new PointF(LocalAreaInControlSpace.Location.X - Offset.X, LocalAreaInControlSpace.Location.Y - Offset.Y));
                g.Transform = rot;

                g.DrawImage(MarkerImage, LocalAreaInControlSpace.Location.X, LocalAreaInControlSpace.Location.Y, Size.Width, Size.Height);
                g.Restore(savedState);
            }
            else
                g.DrawImage(MarkerImage, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
        }
Image
Mar 3, 2013 at 9:02 AM
Here's the complete code for an ImageMarker. You can also set the size of the image.
 public class GMapMarkerImage : GMapMarker
    {
        private Size imgSize = Size.Empty;
        /// <summary>
        /// Gets or sets the Image size
        /// </summary>
        public Size ImageSize
        {
            get
            {
                return imgSize;
            }
            set
            {
                imgSize = value;
                this.Size = new System.Drawing.Size(imgSize.Width, imgSize.Height);
                this.Offset = new System.Drawing.Point(-Size.Width / 2, -Size.Height / 2);
            }
        }

        private float rot;
        /// <summary>
        /// Gets or sets the Rotation Angle in degrees
        /// </summary>
        public float RotationAngle
        {
            get { return rot; }
            set 
            { 
                rot = value;
                if (Overlay != null && Overlay.Control != null && !Overlay.Control.HoldInvalidation)
                {
                    Overlay.Control.Refresh();
                }
            }
        }


        private Image img;
        /// <summary>
        /// The image to display as a marker.
        /// </summary>
        public Image MarkerImage
        {
            get
            {
                return img;
            }
            set
            {
                img = value;
                if (img != null)
                {
                    ImageSize = img.Size;
                    if (Overlay != null && Overlay.Control != null)
                    {
                        Overlay.Control.UpdateMarkerLocalPosition(this);
                    }
                }
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="p">The position of the marker</param>
        public GMapMarkerImage(PointLatLng p, Image image, MarkerType typ)
            : base(p)
        {
            img = image;
            ImageSize = img.Size;
            this.TypeOfMarker = typ;
            rot = 0f;
        }

        /// <summary>
        /// Overload with Angle
        /// </summary>
        /// <param name="p"></param>
        /// <param name="image"></param>
        /// <param name="typ"></param>
        /// <param name="angle"></param>
        public GMapMarkerImage(PointLatLng p, Image image, MarkerType typ, float angle)
            : this(p, image, typ)
        {
            rot = angle;
        }

        /// <summary>
        /// Override Render function
        /// </summary>
        /// <param name="g"></param>
        public override void OnRender(Graphics g)
        {
            var tmp = g.InterpolationMode;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            if (rot != 0f)
            {
                GraphicsState savedState = g.Save();
                g.ResetTransform();
                Matrix transformationMatrix = new Matrix();
                transformationMatrix.RotateAt(rot, new PointF(LocalAreaInControlSpace.Location.X - Offset.X, LocalAreaInControlSpace.Location.Y - Offset.Y));
                g.Transform = transformationMatrix;
                g.DrawImage(img, LocalAreaInControlSpace.Location.X, LocalAreaInControlSpace.Location.Y, imgSize.Width, imgSize.Height);
                g.Restore(savedState);
            }
            else
                g.DrawImage(img, LocalPosition.X, LocalPosition.Y, imgSize.Width, imgSize.Height);

            g.InterpolationMode = tmp;
        }

        bool disposed = false;
        /// <summary>
        /// Dispose all resources
        /// </summary>
        public override void Dispose()
        {
            if (!disposed)
            {
                disposed = true;
                if (MarkerImage != null)
                {
                    MarkerImage.Dispose();
                    MarkerImage = null;
                }
                base.Dispose();
            }
        }
    }
Mar 4, 2013 at 5:03 AM
Edited Mar 4, 2013 at 5:04 AM
I put in the onRender() and it worked!
Thanks.
I had some trouble with the GMapMarkerImage, so I just went with the onRender fix above.

If anyone wants it, here is the entire file:
GMapMarker.cs

Thanks Xandolph, olibara and radioman.
I will put kukos on our site.
Thanks again.
-cellurl
Mar 14, 2013 at 7:02 PM
@cellurl

How you managed to build the code? I'm getting error on LocalAreaInControlSpace. Seems it's marked as internal. How can this be solved?
Mar 15, 2013 at 4:47 AM
step 1: compile the lastest windows forms using visual studio 10.net
step 2: Substitute this file for the one in ./WindowsForms/Forms or ./WIndowsForms/src
GmapMarker.cs

I don't have a clue what your error is sorry.
Jan 15, 2015 at 4:14 PM
rotation fixed

p.s. marker rotation demo [left menu, Live->FlightRadar] and GMarkerArrow.cs
Marked as answer by radioman on 1/15/2015 at 8:15 AM