1

I'm trying to create program where will be List of fishes drawn on the canvas. (Next step will be changing the place of fishes based on some calculation) Each fish is represented by bitmap (png file 7x12 px with picture of fish).

I created Form on which is PictureBox which is my drawing canvas. It has size 640x480 px.

In code below is simplified code I use (I cutted off all not necesary stuff). My problem is with tranformation matrix, at the moment only with rotation.

Problem is in class Fish in method Draw() where I'm trying to make a tranformation, at the moment I set the rotation 30 degrees for each fish but later each fish will have different start rotation angle. I want to make a transformation with the where will the fish will be rotated by the rotation angle around its centre. So in this case all fishes should be in one line and rotated each by its rotation angle (here 30 degrees).
But they are placed on diagonale, so the transformation is messed up somehow. How can I fix this? I'm probably using tansformation incorectly.

Namespaces using in classes

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

Fish

    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

Form

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

Main 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());
        }
    }
user1097772
  • 3,499
  • 15
  • 59
  • 95
  • @x... But how should i use the Paint event? Its overriding I thing OnPaint method, but where? I mean on what object?? How is that connected to my Grafic g which I use to create the canvas (PictureBox) on my Form? – user1097772 Jul 24 '16 at 00:49

1 Answers1

1

You should use RotateAt instead of Rotate. Rotate method rotates the fish around the upper left corner of the control (origin) while RotateAt rotates something around a point specified by you.

Just calculate the center of each fish (X=Left+FishWidth/2, Y=Top+FishHeight/2) and rotate around that point.

Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
  • This solve the rotation, but if i want to do more transformations? for example scalling? I use to learn something about it, there was something like moving to origin, do the tranformations and move back or something like that. – user1097772 Jul 24 '16 at 00:22
  • 1
    Moving to the origin (so that the image's middle point is at 0,0), rotating around it and moving back is an example that I've seen in a few places. It's another way to do the rotation that you're looking for but using RotateAt is much clearer. However, it's important to do the transformations in a correct order. [Here's a good article](https://msdn.microsoft.com/en-us/library/eews39w7(v=vs.110).aspx) about them. You can actually still find quite a lot of GDI+ related articles on MSDN. – Timo Salomäki Jul 24 '16 at 00:41
  • Do you know how is that e.Graphics used? I found that you have to override OnPaint method but on what object and how is that used?? Here I use Draw method for drawing, so it would be something like OnPaint method in Fish class and than fish.Invalidate() ?? – user1097772 Jul 24 '16 at 01:11
  • 1
    You should draw to an off-screen buffer instead of drawing every element one by one in the OnPaint method. Otherwise, you'll have flickering graphics and poor performance. The basic idea is that you create an instance of the Bitmap class, that has the same width and height as your PictureBox. Then you draw everything to that Bitmap and draw it into the PictureBox (or some other control) in the OnPaint event. It's been a long time since I last worked on this stuff, so remember to [double check the information](https://msdn.microsoft.com/en-us/library/yhez825d(v=vs.110).aspx). – Timo Salomäki Jul 24 '16 at 01:29
  • PictureBox is Doublebuffered out of the box, so it will not flicker. – TaW Jul 24 '16 at 07:25