C# Forms - Rotation smoothness? Thank you very much M$!

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • dzenanz
    New Member
    • Feb 2008
    • 45

    C# Forms - Rotation smoothness? Thank you very much M$!

    I am trying to make a spinning (rotating) label. I have inherited from control. Code (which is given below) works, but animation is not smooth. Text is not stable around the center, but it "shakes". Copy the code there is also a timer with 10ms interval) and see what I'm talking about.
    Is it too soon to blame Microsoft for this?
    If someone wants me to send him entire zipped project, send e-mail to dzenanz at gmail
    Code (optimized for viewing):
    Code:
    public partial class RotateLabel : Control
    {
        public RotateLabel()
        {
            InitializeComponent();
            DoubleBuffered = true;//Flickers a lot without this
            aTimer.Start();
        }
    
        private sbyte _MinRotate=-90;
        private sbyte _MaxRotate=+90;
        private sbyte _RotateStep = 1;
        private sbyte _CurrentRotate;//rotation in degrees
    
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.TranslateTransform(Size.Width / 2, Size.Height / 2);
            e.Graphics.RotateTransform(_CurrentRotate);
            SizeF tsize = e.Graphics.MeasureString(Text, Font);
            e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), -tsize.Width / 2, -tsize.Height / 2);
            e.Graphics.DrawEllipse(Pens.Red, -1, -1, 2, 2);//red dot in center - debugging
        }
    
        private void aTimer_Tick(object sender, EventArgs e)//animation timer tick
        {
            if (_CurrentRotate == _MaxRotate)
                _RotateStep = (sbyte)-1;
            if (_CurrentRotate == _MinRotate)
                _RotateStep = (sbyte)+1;
            _CurrentRotate = (sbyte)(_CurrentRotate + _RotateStep);
            Refresh();
        }
    }
    Code (optimized for copy&paste):
    public partial class RotateLabel : Control
    {
    public RotateLabel()
    {
    InitializeCompo nent();
    DoubleBuffered = true;//Flickers a lot without this
    aTimer.Start();
    }

    private sbyte _MinRotate=-90;
    private sbyte _MaxRotate=+90;
    private sbyte _RotateStep = 1;
    private sbyte _CurrentRotate;//rotation in degrees

    protected override void OnPaint(PaintEv entArgs e)
    {
    base.OnPaint(e) ;
    e.Graphics.Tran slateTransform( Size.Width / 2, Size.Height / 2);
    e.Graphics.Rota teTransform(_Cu rrentRotate);
    SizeF tsize = e.Graphics.Meas ureString(Text, Font);
    e.Graphics.Draw String(Text, Font, new SolidBrush(Fore Color), -tsize.Width / 2, -tsize.Height / 2);
    e.Graphics.Draw Ellipse(Pens.Re d, -1, -1, 2, 2);//red dot in center - debugging
    }

    private void aTimer_Tick(obj ect sender, EventArgs e)//animation timer tick
    {
    if (_CurrentRotate == _MaxRotate)
    _RotateStep = (sbyte)-1;
    if (_CurrentRotate == _MinRotate)
    _RotateStep = (sbyte)+1;
    _CurrentRotate = (sbyte)(_Curren tRotate + _RotateStep);
    Refresh();
    }
    }
  • dzenanz
    New Member
    • Feb 2008
    • 45

    #2
    Any ideas? Anyone? Who is to blame, me or Microsoft?

    Comment

    • Plater
      Recognized Expert Expert
      • Apr 2007
      • 7872

      #3
      Well MS is possibly to blame, but there could be a flicker do to rounding?

      Also, you refresh the entire control on every drawing increment and not just the "dirty" sections. With that being said however, I've never figured out how to get the "only draw the changed section of the control" stuff to work correctly either.

      I was planning on trying it out, but wonder what else I need to trigger those things to happen?

      Comment

      • dzenanz
        New Member
        • Feb 2008
        • 45

        #4
        well, in this text rotation control, it is always needed to repaint whole control. For example, if rotation changes from 1° to 2° text has changed, and control only contains text.

        Comment

        • Plater
          Recognized Expert Expert
          • Apr 2007
          • 7872

          #5
          You may find you need to use DirectX to get the better graphics controll to do the angled drawing of text

          Comment

          • dzenanz
            New Member
            • Feb 2008
            • 45

            #6
            Hehe, I know I can get smooth animation with DirectX, but that is hardly standard drawing (requiring more investigation by me, as I am not familiar with DX). I was wandering if I can get more out of this approach. Or more specifically, I wanted confirmation that such jerkiness is Microsoft's fault, not mine :)

            Comment

            • Plater
              Recognized Expert Expert
              • Apr 2007
              • 7872

              #7
              Hmm, well often are you calling the refresh, how long does it take to draw, how big of a "leap" are you making(i.e. difference in between each 'frame')

              If you really wanted a test, create a bitmap object for every single 'frame' of a test animation and then play them through, then see if it still looks "jerky"

              I think it takes 32 frames per second to fool the eye, although I am sure there are techiniques that can be employed to fool the eye with slower frame rates.

              Comment

              • dzenanz
                New Member
                • Feb 2008
                • 45

                #8
                The timer is set to either 10 or 20 ms (it does not make any difference). Animation seems smooth, but the text changes size and position a bit at certain angles (around 15° and around 75°) - that is the problem.
                However, idea to render all drawn frames to bitmaps is a good one, so I will give it a try.

                Comment

                • dzenanz
                  New Member
                  • Feb 2008
                  • 45

                  #9
                  I did export it to images.

                  This ugly changeover is in this gif. Any idea why this is happening?

                  Comment

                  • dzenanz
                    New Member
                    • Feb 2008
                    • 45

                    #10
                    This changeover takes place when _CurrentRotate goes from 24,83° to 24,84°

                    Comment

                    • dzenanz
                      New Member
                      • Feb 2008
                      • 45

                      #11
                      Similar thing also happens between 81.4° and 81.5°

                      Comment

                      • Plater
                        Recognized Expert Expert
                        • Apr 2007
                        • 7872

                        #12
                        It looks like it goes from a bold version of the font to a non-bold version of the font.
                        Are you using a truetype or other vectorized font? Have you played around with various fonts/font-styles to see if they all do it?

                        Comment

                        • dzenanz
                          New Member
                          • Feb 2008
                          • 45

                          #13
                          It is font and font-size dependent!
                          !!!
                          Bigger fonts tend to make this problem. For example, Microsoft Sans Serif, bold, at size 32pt does not exhibit this behavior, but at 36pt it does!

                          Conclusion: I cannot solve this problem, and it seem to be deep. Recommend users to try out different fonts :D

                          Comment

                          • Plater
                            Recognized Expert Expert
                            • Apr 2007
                            • 7872

                            #14
                            Yeah, I would guess that there is really nothing you can do about it

                            Comment

                            • dzenanz
                              New Member
                              • Feb 2008
                              • 45

                              #15
                              Just for those who come by this thread through search engines, solution is this
                              Code:
                              protected override void OnPaint(PaintEventArgs e)
                                  {
                                      base.OnPaint(e);
                              
                                      e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;//line which solves the problem
                              
                                      e.Graphics.TranslateTransform(Size.Width / 2, Size.Height / 2);
                                      e.Graphics.RotateTransform(_CurrentRotate);
                                      SizeF tsize = e.Graphics.MeasureString(Text, Font);
                                      e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), -tsize.Width / 2, -tsize.Height / 2);
                                      e.Graphics.DrawEllipse(Pens.Red, -1, -1, 2, 2);//red dot in center - debugging
                                  }

                              Comment

                              Working...