title: XNA - Bounding Box Rotation Nightmare
body: <p>I'm currently going throught kind of a nightmare right now by trying to find the right formula to obtain a bounding box that correspond to my sprite orientation.</p>
  
  <p>I KNOW ! There is a bunch of examples, solution, explanations on the internet, including here, on this site. But trust me, I've tried them all. I tried to just apply solutions, I tried to understand explanations, but every post gives a different solution and none of them work.</p>
  
  <p>I'm obviously missing something important here...</p>
  
  <p>So, basically, I have a sprite which texture is natively (20 width * 40 height) and located at (200,200) when starting the app. The sprite origin is a classic </p>
  
  <pre><code>_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
  </code></pre>
  
  <p>So origin would return a (5.5;8) vector 2</p>
  
  <p>By keyboard input, I can rotate this sprite. Default rotation is 0 or Key.Up. Then rotation 90 corresponds to Key.Right, 180 to Key.Down, and so on...</p>
  
  <p>For the moment, there is no move involved, just rotation.</p>
  
  <p>So here is my code to calculate the bounding rectangle:</p>
  
  <pre><code>public partial class Character : ICollide
  {
      private const int InternalRunSpeedBonus = 80;
      private const int InternalSpeed = 80;
      private Vector2 _origin;
      private Texture2D _texture;
      private Texture2D _axisBase;
      private Texture2D _axisOrig;
  
      public Character()
      {
          MoveData = new MoveWrapper { Rotation = 0f, Position = new Vector2(200, 200), Speed = new Vector2(InternalSpeed) };
      }
  
      public MoveWrapper MoveData { get; set; }
  
      #region ICollide Members
  
      public Rectangle Bounds
      {
          get { return MoveData.Bounds; }
      }
  
      public Texture2D Texture
      {
          get { return _texture; }
      }
      #endregion ICollide Members
  
      public void Draw(SpriteBatch theSpriteBatch)
      {
          theSpriteBatch.Draw(_texture, MoveData.Position, null, Color.White, MoveData.Rotation, _origin, 1f, SpriteEffects.None, 0);//main sprite
          theSpriteBatch.Draw(_axisOrig, MoveData.Position, null, Color.White, 0f, _origin, 1f, SpriteEffects.None, 0);//green
          theSpriteBatch.Draw(_axisBase, MoveData.Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0);//red
  
      }
  
      public void Load(ContentManager theContentManager)
      {
          _texture = theContentManager.Load&lt;Texture2D&gt;("man");
          _axisBase = theContentManager.Load&lt;Texture2D&gt;("axis");
          _axisOrig = theContentManager.Load&lt;Texture2D&gt;("axisOrig");
          _origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
  
      }
  
      public void MoveForward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
      {
          InternalMove(theGameTime, aCurrentKeyboardState);
      }
  
      private void InternalMove(GameTime theGameTime, KeyboardState aCurrentKeyboardState, bool forward = true)
      {
          //stuff to get the move wrapper data valorized (new position, speed, rotation, etc.)
          MoveWrapper pm = MovementsHelper.Move(MoveData.Position, MoveData.Rotation, aCurrentKeyboardState, InternalSpeed,
                                                InternalRunSpeedBonus, theGameTime, forward);
          pm.Bounds = GetBounds(pm);
          MoveData = pm;
      }
  
      public void MoveBackward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
      {
          InternalMove(theGameTime, aCurrentKeyboardState, false);
  
      }
  
      private Rectangle GetBounds(MoveWrapper pm)
      {
          return GetBoundingBox(pm, _texture.Width, _texture.Height);
      }
  
      public  Rectangle GetBoundingBox(MoveWrapper w, int tWidth, int tHeight)
      {
          //1) get original bounding vectors
  
          //upper left =&gt; same as position
          Vector2 p1 = w.Position;
  
          //upper right x = x0+width, y = same as position
          Vector2 p2 = new Vector2(w.Position.X + tWidth, w.Position.Y);
  
          //lower right x = x0+width, y = y0+height
          Vector2 p3 = new Vector2(w.Position.X + tWidth, w.Position.Y + tHeight);
  
          //lower left x = same as position,y = y0+height
          Vector2 p4 = new Vector2(w.Position.X, w.Position.Y + tHeight);
  
  
          //2) rotate all points given rotation and origin
          Vector2 p1r = RotatePoint(p1, w);
          Vector2 p2r = RotatePoint(p2, w);
          Vector2 p3r = RotatePoint(p3, w);
          Vector2 p4r = RotatePoint(p4, w);
  
          //3) get vector2 bouding rectancle location
          var minX = Math.Min(p1r.X, Math.Min(p2r.X, Math.Min(p3r.X, p4r.X)));
          var maxX = Math.Max(p1r.X, Math.Max(p2r.X, Math.Max(p3r.X, p4r.X)));
  
          //4) get bounding rectangle width and height
          var minY = Math.Min(p1r.Y, Math.Min(p2r.Y, Math.Min(p3r.Y, p4r.Y)));
          var maxY = Math.Max(p1r.Y, Math.Max(p2r.Y, Math.Max(p3r.Y, p4r.Y)));
  
          var width = maxX - minX;
          var height = maxY - minY;
  
          // --&gt; begin hack to get it work for 0,90,180,270 degrees
          var origMod = new Vector2((float)tWidth / 2, (float)tHeight / 2);
  
          var degree = (int)MathHelper.ToDegrees(w.Rotation);
  
          if (degree == 0)
          {
              minX -= origMod.X;
              minY -= origMod.Y;
          }
          else if (degree == 90)
          {
              minX += origMod.Y;
              minY -= origMod.X;
          }
          else if (degree == 180)
          {
              minX += origMod.X;
              minY += origMod.Y;
          }
          else if (degree == 270)
          {
              minX -= origMod.Y;
              minY += origMod.X;
          }
          // end hack &lt;--
  
          return new Rectangle((int)minX, (int)minY, (int)width, (int)height);
      }
  
      public  Vector2 RotatePoint(Vector2 p, MoveWrapper a)
      {
          var m = Matrix.CreateRotationZ(a.Rotation);
  
          var refToWorldOrig = p - a.Position;
          Vector2 rotatedVector = Vector2.Transform(refToWorldOrig, m);
          var backToSpriteOrig = rotatedVector + a.Position;
          return backToSpriteOrig;
  
          //does not work
          //var Origin = new Vector3(_origin, 0);
          //var Position = new Vector3(p, 0);
  
          //var m = Matrix.CreateTranslation(-Origin)
          //        * Matrix.CreateRotationZ(a.Rotation)
          //        * Matrix.CreateTranslation(Position);
  
          //return Vector2.Transform(p, m);
      }
  }
  </code></pre>
  
  <p>The rotation paramter is MathHelper degree to radians result.</p>
  
  <p>I have a function to draw a rectangle corresponding to the bounding box and I expect that bounding box to overlap exactly with my sprite, at least for 0,90,180 and 270 degrees angle rotations. </p>
  
  <p>Instead I have strange coordinates after rotation calculation:
   - when rotation to 90°, bounding box X is negative (so the box is not visible)
   - when rotation to 180°, bounding box X and Y are negative (so the box is not visible)
   - when rotation to 270°, bounding box Y is negative (so the box is not visible)</p>
  
  <p>Can someone explain to me what I'm doing wrong, and do it like is was explaining to 3 year old child, because regarding Maths, this is what I am !!!</p>
  
  <p>:)</p>
  
  <p><em><strong>EDIT</strong></em> : I have found a hack to make it work for 0, 90, 180, 270 degrees but now i'm stuck for intermediate positions (45,135,215, 325 degrees) which make me thinks that THERE MUST BE a way to compute all that stuff in one single formula that would work for any angle...</p>
  
  <p><img src="https://i.stack.imgur.com/1YgPA.jpg" alt="correct behavior for 90° rotation"></p>