I'm trying to draw some polygons and lines usinng e.Graphics.DrawPolygon (or DrawLine). But I have a little problem specifying the coordinates where to draw. I am drawing onto a PictureBox using its Paint event. The elements draw correctly relatively to each other (creating the required final picture), but seem always to draw in the upper-left corner of the PictureBox. When creating the points to draw, when I just try to multiply the coordinates, it draws it at the same place but bigger (size is multiplied, instead of location coordinates).
Here is my code:
//some for loop
{
//getting the coordinates
Point toAdd = new Point((int)xCoord, (int)yCoord); // creating the point from originaly a double, here i tried to multiply..
tmpPoints.Add(toAdd); // tmpPoints is a List<Point>
}
points.Add(tmpPoints.ToArray()); //List<Point[]>
drawBuffer = points; //saving to a public List<Point[]>
points.Clear();
this.Invalidate();
here part of the pictureBox1_Paint method:
for (int i = 0; i < drawBuffer.Count; i++)
{
//some other stuff like deciding which color to use, not very important
Brush br = new SolidBrush(polyColor);
e.Graphics.FillPolygon(br, drawBuffer[i]);
brush.Dispose();
}
I have checked using breakpoint, the coordiinates are the same ratio (what was 100 pixels wide is still 100 pixels wide), they are at coordinates like x 3000 and y 1500, but it just draws itself in the upper-left corner. When i multiply the coordinates 3 times (see the code for the place where i multiplied), it draws at the same place but 3 times bigger (doesn't make sense after checking the coords...)
So, my question is - how do I set the location correctly, or is there any other way to do this?
Like this (I know, this is nonsense, just an example)
foreach(Polygon poly in e.Graphics)
{
poly.Location = new Point(poly.Location.X * 2, poly.Location.Y * 2);
}
When you multiply the coordinates of the points, they're scaled around the point (0, 0), the top-left corner of the canvas:
In order to scale it around its center (and I suppose you expected it to work this way), you need to calculate some kind of center of the polygon. For simplicity, it can be even an arithmetic mean of the coordinates, on X and Y axes respectively. If you already have the coordinates of the center, translate the coordinates of every point by a reversed vector made from the center coordinates (this is how it would look like if you drew it after this operation - the polygon's center is in the center of the coordinate system):
Now, do your scaling:
and move it back by the vector of polygon's center coordinates:
when you multiply
poly.Location = new Point(poly.Location.X * 2, poly.Location.Y * 2);
you are doing a stretch operation when you add
poly.Location = new Point(poly.Location.X + 50, poly.Location.Y +50); you are doing a translation operation.
If you want to shift everything without modifying the stored coords then just translate the graphics before drawing:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(100, 100); // shift the origin somehow
// ... draw the polygons as before ...
}
Related
I am trying to draw set of squares but the origin(0,0) of squares was in top left corner initially and I wanted squares to render from bottom right corner,
and I found this code to flip the co ordinates, but nothing is rendering on winform.
I know that I have gone wrong in Height attribute of TranslateTransform. I dont get as to why Height is required as i am trying to draw a set of 2d squares.
I tried hardcoding the height attribute still of no use.
public void ScaleTransformFloat(PaintEventArgs e,List<Square> lstSquare)
{
int Height = 10;
// Begin graphics container
GraphicsContainer containerState = e.Graphics.BeginContainer();
// Flip the Y-Axis
e.Graphics.ScaleTransform(1.0F, -1.0F);
// Translate the drawing area accordingly
//
e.Graphics.TranslateTransform(0.0F, -(float)Height);
// Whatever you draw now (using this graphics context) will appear as
// though (0,0) were at the bottom left corner
//User-defined function to draw a square
DrawSquare(e,lstSquare);
// End graphics container
e.Graphics.EndContainer(containerState);
}
Method to draw set of squares
public void DrawSquare(PaintEventArgs e,List<Square> lstSquare)
{
foreach(Square s in lstSquare){
e.Graphics.DrawRectangle(Pens.Black, 0,0 ,s.m_Side, s.m_Side);
}
}
When doing matrix operation like transformations usually the order does matter.
In your case you need to either translate first, then scale/flip or reverse the direction of the translation. Your code seems to get it right.
The Height is not a 3d height. It is the total Height of the target control you want to draw on.
Imagine laying a sheet of paper on your control; the control is your viewport. Now imagine flipping the paper topwise by the top left edge. It has left the viewport. Now you need to move it down. But by what distance? Answer: The paper's height..
Your code has a Height = 10 pixels. This is certainly not the size of your control, right? Maybe it comes from code you copied; there it probably meant the Form's Height. If you want to draw on the Form also (usually not a good idea), simply delete the line int Height = 10;!
Let's do a simple example: We draw a few rectangles onto a Panel:
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (checkBox1.Checked)
{
e.Graphics.ScaleTransform(1, -1);
e.Graphics.TranslateTransform(0, -panel1.Height);
}
e.Graphics.DrawRectangle(Pens.Violet, 1, 1, 33, 33);
e.Graphics.DrawRectangle(Pens.OrangeRed, 11, 11, 133, 55);
e.Graphics.DrawRectangle(Pens.Magenta, 44, 11, 233, 77);
e.Graphics.DrawRectangle(Pens.Olive, 55, 44, 33, 99);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
panel1.Invalidate();
}
After checking the CheckBox the result is flipped:
Also note that your DrawSquare draws all squares at the same location (0,0). Not sure if that is what you want..
Final note: DrawRectangle has a nasty habit of overdrawing the botton and right sides by one pixel. After changing the first loaction from (1,1) to (0,0) the (then) bottom side will be cut off. You might consider translating the graphics coodinates by 1 pixel less..
I have to do application for tilling in C#. The tiles will have some shape and my app should be able to modify the shape. I will have a some shape - polygon, made from vertices. I will have for example field of 16 vertices, then I draw the polygon.
What I need to know how can I move with the the vertice using drag and drop. I will also have to recount other vertices in order to fit one tile to next tile, but it's just some math.
To conclude:
I have polygon defined 16 vertices in field of Vertices, I move (with mouse) with one vertice, recount the coordinates of ohter vertices and draw new polygon. My problem is moving (probably using drag & drop) with one vertice from filed of vertices.
This is what part of my previous code without drag & drop - just for idea what tools I'm using for drawing one tile:
private Bitmap canvasBitmap; //canvas for drawing
private Graphics g; // enter to graphics tool
Bitmap b = (Bitmap)Bitmap.FromFile("obr.bmp");
TextureBrush brush = new TextureBrush(b);
Pen pen = new Pen(Color.Black, 1);
hexaVertices[0] = new PointF(-40 + 40, 0 + 30);
hexaVertices[1] = new PointF(-20 + 40, 30 + 30);
hexaVertices[2] = new PointF(20 + 40, 30 + 30);
hexaVertices[3] = new PointF(40 + 40, 0 + 30);
hexaVertices[4] = new PointF(20 + 40, -30 + 30);
hexaVertices[5] = new PointF(-20 + 40, -30 + 30);
g.FillPolygon(brush, hexaVertices);
g.DrawPolygon(pen, hexaVertices);
Thx for advices.
I can only give you a rough outline for Windows Forms here. In WPF you could use Adorners and there are tutorials out there for how to do it. Here we go for a manual process in Windows Forms:
First, the array of vertices should be a member variable of the class and should be initialized only once at the start of the program.
Then, draw the polygon with the current set of vertices as you're doing right now. Also, draw some "handles" if you want, so you know that the vertices can be grabbed (this could be rectangles around the actual PointF).
Now for the magic :-) Assign the MouseDown, MouseMove and MouseUp events to the control you're using for displaying the image. Also, create a new member variable bool m_draggingVertex and another that contains the index to the vertex array of the vertex you're currently dragging.
In MouseDown:
Check whether the current mouse position is within the range of a vertext (I would assume a 5x5 rectangle around a vertex, so that is is easier to hit with the cursor). If you pressed the button on a vertex, set m_draggingVertex to true and store the index of the vertex in the other variable.
In MouseMove:
If m_draggingVertex is true, change the vertext at the index stored above to the new coordinates, recalc your positions and repaint so that the current position of the vertex is shown.
In MouseUp:
If m_draggingVertex is true, set it to false and do final work.
This is how I'd do it ...
using Cairo;
I have drawn a rectangle inside a bigger rectangle witch is inside a drawing area.
I have managed to attach a event to the Drawing area witch is a object I have extended from it
this.AddEvents ((int) EventMask.ButtonPressMask);
this.ButtonPressEvent += delegate(object o, ButtonPressEventArgs args) {
hasInterface(args.Event.X, args.Event.Y);
Console.WriteLine("Button Pressed " + args.Event.X + ", " + args.Event.Y);
};
I'm dynamically drawing the squares using:
cr.Translate(width/2, height/2);
cr.Rectangle((pX + (i * tmp)) , pY, boxsize, boxsize);
private void recordPosition(double x, double y)
{
x = x*2;
y = y*2;
boxCoordinates.Add( new double[,]
{
{x, y}
}
); // store coords
}
List<double,double> boxCoordinates
So for the inside of the drawing area the square is drawn at x=0, y=0 from the "outside" point of view it's in x=90, y=45; the width = 180 , height = 100
I was using translate (since half of this is copied ) of the size/2 so this means that the drawing area was doing a resize of the square, to solve this issue I was saving the position's multiplying it by 2, but this is not working has I'm getting "hits" outside of the rectangle drawn.
What is the best way to do this? I mean to translate the X Y positions from the window to the drawing area, I saw this was possible in other languages but not sure how to do it in C# and the drawing area from mono.
Thanks for any help.
I've done this a few times in C w SDL and C# with Cairo, basically, you want to be able to convert the bounding box of each of your rectangles to and from the coordinates you are using for rendering on the cairo canvas.
For each of your rectangles, you'll have the location you of your rectangles in thier own world. I like to call these the "world coordinates" and their "screen coordinates" (which map to where your mouse will be).
You can store the world coordinates of each box and then translate them to screen ones for each frame you render.
public class Shape {
public Point WorldLoc { get; set; }
}
You would do all your physics (if you have any) on the WorldLoc values. When you come to render, You want to be able to convert your WorldLoc to ScreenLoc.
public class Scene {
public double Zoom;
public Point Offset;
public Point WorldToScreen( Point world ){
var p = new Point();
p.x = (world.x - Offset.x) * Zoom;
p.y = (world.y - Offset.y) * Zoom;
return p;
}
}
Each time you render somthing in this Scene, you'll use WorldToScreen() to get the screen coordinates. You can then use the same thing to work out if your mouse is in the screen box of a world box.
I'm not sure why this code isn't simply drawing a triangle to screen (orthographically). I'm using OpenTK 1.1 which is the same thing as OpenGL 1.1.
List<Vector3> simpleVertices = new List<Vector3>();
simpleVertices.Add(new Vector3(0,0,0));
simpleVertices.Add(new Vector3(100,0,0));
simpleVertices.Add(new Vector3(100,100,0));
GL.MatrixMode(All.Projection);
GL.LoadIdentity();
GL.MatrixMode(All.Projection);
GL.Ortho(0, 480, 320, 0,0,1000);
GL.MatrixMode(All.Modelview);
GL.LoadIdentity();
GL.Translate(0,0,10);
unsafe
{
Vector3* data = (Vector3*)Marshal.AllocHGlobal(
Marshal.SizeOf(typeof(Vector3)) * simpleVertices.Count);
for(int i = 0; i < simpleVertices.Count; i++)
{
((Vector3*)data)[i] = simpleVertices[i];
}
GL.VertexPointer(3, All.Float, sizeof(Vector3), new IntPtr(data));
GL.DrawArrays(All.Triangles, 0, simpleVertices.Count);
}
The code executes once every update cycle in a draw function. What I think I'm doing (but evidentially am not) is creating a set of position vertices to form a triangle and drawing it 10 units in front of the camera.
Why is this code not drawing a triangle?
In OpenGL, the Z axis points out of the screen, so when you write
GL.Translate(0,0,10);
it actually translates it "in front" of the screen.
Now your two last parameters to GL.Ortho are 0,1000. This means that everything between 0 and 1000 in the MINUS Z direction ( = in front of the camera ) will be displayed.
In other words, GL.Translate(0,0,-10); will put your object in front of the camera, while GL.Translate(0,0,10); will put it behind.
i draw the circle in c# using directx.i like to draw the circle with same dimensions in c# using GDI.It means i like to convert that circle from directx to GDI. Is any body help for me.plz provide the answer for me.how can i do it.Is any algorithm available for that........
And also i give the input for center of the circle is (x,y)in this point format.but in gdi it is pixel format .so how can i convert the directx points to gdi+ pixels
Here is a link from MSDN that introduces Graphics and Drawing in Windows Forms. And it's likely that you will need something similar to:
public Form1()
{
InitializeComponent();
this.Paint += new PaintEventHandler(Form1_Paint);
// This works too
//this.Paint += (_, args) => DrawCircle(args.Graphics);
}
void Form1_Paint(object sender, PaintEventArgs e)
{
DrawCircle(e.Graphics);
}
private void DrawCircle(Graphics g)
{
int x = 0;
int y = 0;
int radius = 50;
// The x,y coordinates here represent the upper left corner
// so if you have the center coordinates (cenX, cenY), you will have to
// substract radius from both cenX and cenY in order to represent the
// upper left corner.
// The width and height represents that of the bounding rectangle of the circle
g.DrawEllipse(Pens.Black, x, y, radius * 2, radius * 2);
// Use this instead if you need a filled circle
//g.FillEllipse(Brushes.Black, x, y, radius * 2, radius * 2);
}
After that you might want to look into double-buffering techniques, a few links :
[SO] How to double buffer .NET controls on a form?
[MSDN] Double Buffered Graphics
[MSDN] Using Double Buffering