Проблема ротации (преобразования) С#

Я пытаюсь создать программу, в которой будет список рыб, нарисованных на холсте. (Следующим шагом будет изменение места рыб на основе некоторых вычислений) Каждая рыба представлена ​​растровым изображением (файл png 7x12 px с изображением рыбы).

Я создал форму, на которой находится PictureBox, который является моим холстом для рисования. Размер 640x480 пикселей.

В коде ниже приведен упрощенный код, который я использую (я отрезал все ненужное). У меня проблема с матрицей трансформации, пока только с вращением.

Проблема в классе Fish в методе Draw(), где я пытаюсь сделать трансформацию, на данный момент я установил поворот на 30 градусов для каждой рыбы, но позже у каждой рыбы будет разный начальный угол поворота. Я хочу сделать преобразование с тем, где рыба будет вращаться на угол поворота вокруг своего центра. Так что в этом случае все рыбы должны стоять в одну линию и поворачиваться каждая на свой угол поворота (здесь 30 градусов).
Но они расположены по диагонали, так что преобразование как-то запутано. Как я могу это исправить? Возможно, я неправильно использую преобразование.

Пространства имен, используемые в классах

using System.Drawing;//Graphics, Point
using System.Drawing.Drawing2D;//Matrix

Рыбы

    class Fish {
      public Point position;
      public int rotation;
      public Graphics g;
      public Image fishImage;
      private Rectangle rect;
      private Matrix matrix;

      public Fish(ref Graphics g, int x, int y, int rotation,Image img){
        this.g =  g;
        position = new Point(x,y);
        this.rotation = rotation;
        this.fishImage = img;
        this.rect = new Rectangle(position.X,position.Y, fishImage.Width, fishImage.Height);

      }

   public void Draw() {
    matrix = new Matrix();
    matrix.Rotate((float)rotation, Matrix.Append); //if i comment this it
    //will be drawn in one line
    //according to the initial values for position
    //if i let the rotation here it will be on diagonale
    //i want it on one line but rotated
    g.Transform = matrix;

    rect = new Rectangle(position.X, position.Y, fishImage.Width, fishImage.Height);
    g.DrawImage(fishImage, rect);
   }
}//end Fish class

Форма

public partial class Form1 : Form
{
 private Bitmap canvasBitmap; //bitmap for drawing
 private Graphics g;          
 Image fishImage;

 private List<Fish> fishes = new List<Fish>();
  public Form1() {
    InitializeComponent();
   //png image 7x12 pixels 
   fishImage = FishGenetic.Properties.Resources.fishImage; 
   //on Form there is placed PictureBox called canvas
   //so canvas is PictureBox 640x480 px
   canvasBitmap = new Bitmap(canvas.Width, canvas.Height);
   canvas.Image = canvasBitmap;

   //prepare graphics
   g = Graphics.FromImage(canvasBitmap);
   g.SmoothingMode = SmoothingMode.AntiAlias;

   InitFishes();
   DrawFishes();
   canvas.Invalidate(); //invalidate the canvas 

  }//end Form1 constructor     


 private void InitFishes() {

   Fish fish1 = new Fish(ref g, 10, 10, 30, fishImage);
   Fish fish2 = new Fish(ref g, 20, 10, 30, fishImage);
   Fish fish3 = new Fish(ref g, 30, 10, 30, fishImage);
   Fish fish4 = new Fish(ref g, 40, 10, 30, fishImage);
   Fish fish5 = new Fish(ref g, 50, 10, 30, fishImage);
   fishes.Add(fish1);
   fishes.Add(fish2);
   fishes.Add(fish3);
   fishes.Add(fish4);
   fishes.Add(fish5);
 }

private void DrawFishes() {
   foreach(Fish fish in fishes) {
       fish.Draw();
   }
}

}//end Form1 class

Основной класс

static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

person user1097772    schedule 23.07.2016    source источник
comment
@x... Но как мне использовать событие Paint? Я считаю, что это переопределяет метод OnPaint, но где? в смысле на каком объекте?? Как это связано с моим Grafic g, который я использую для создания холста (PictureBox) в моей форме?   -  person user1097772    schedule 24.07.2016


Ответы (1)


Вы должны использовать RotateAt вместо Rotate. Метод Rotate поворачивает рыбу вокруг верхнего левого угла элемента управления (исходной точки), в то время как RotateAt вращает что-то вокруг указанной вами точки.

Просто вычислите центр каждой рыбы (X=Left+FishWidth/2, Y=Top+FishHeight/2) и поверните вокруг этой точки.

person Timo Salomäki    schedule 24.07.2016
comment
Это решает вращение, но если я хочу сделать больше преобразований? например шелушение? Я использую, чтобы кое-что узнать об этом, было что-то вроде перехода к происхождению, выполнения преобразований и возврата или что-то в этом роде. - person user1097772; 24.07.2016
comment
Перемещение к исходной точке (так, чтобы средняя точка изображения находилась в точке 0,0), вращение вокруг нее и перемещение назад — пример, который я видел в нескольких местах. Это еще один способ сделать вращение, которое вы ищете, но использование RotateAt намного понятнее. Однако важно выполнять преобразования в правильном порядке. Вот хорошая статья о них. На самом деле вы все еще можете найти довольно много статей, связанных с GDI+, в MSDN. - person Timo Salomäki; 24.07.2016
comment
Вы знаете, как используется e.Graphics? Я обнаружил, что вам нужно переопределить метод OnPaint, но на каком объекте и как он используется?? Здесь я использую метод Draw для рисования, так что это будет что-то вроде метода OnPaint в классе Fish, а не fish.Invalidate() ?? - person user1097772; 24.07.2016
comment
Вы должны рисовать в буфер за пределами экрана, а не рисовать каждый элемент один за другим в методе OnPaint. В противном случае у вас будет мерцающая графика и низкая производительность. Основная идея заключается в том, что вы создаете экземпляр класса Bitmap, который имеет ту же ширину и высоту, что и ваш PictureBox. Затем вы рисуете все в этом растровом изображении и рисуете его в PictureBox (или другом элементе управления) в событии OnPaint. Прошло много времени с тех пор, как я в последний раз работал над этим материалом, поэтому не забудьте перепроверьте информацию. - person Timo Salomäki; 24.07.2016
comment
PictureBox имеет двойную буферизацию из коробки, поэтому он не будет мерцать. - person TaW; 24.07.2016