Flip coordinates when drawing set of rectangles - c#

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..

Related

Moving a transparent image in a picturebox

For a project, I'm making a game and in it I have a scrolling map. The map moves left and right and is redrawn in a picturebox so that I can have a large map in a small picturebox. The top portion of the map is transparent so that I can change the sky colour later on. However when I move the map, the transparent part glitches out.
Original map before moving
After moving the map a bit
As you can see, everything above the tree line gets stretched, that is because that is where the transparency starts. The picturebox's parent is the form and the form is light blue, which is why the background is light blue.
Here is my code for moving the picture/redrawing it onto the picturebox:
private void timerTick_Tick(object sender, EventArgs e)
{
move();
//Draws new portion of the map
g.DrawImage(image, new Rectangle(0, 0, pbMap.Width, pbMap.Height), new Rectangle(imageX, imageY, pbMap.Width, pbMap.Height), GraphicsUnit.Pixel);
//Refreshes
pbMap.Image = bmp;
}
private void move()
{
//Right arrow events
if (right)
{
imageX += mapSpeed;
//Makes sure the picture stays within borders
if (imageX >= (imageWidth - pbMap.Width))
{
imageX = imageWidth - pbMap.Width;
}
}
//Left arrow events
if (left)
{
imageX -= mapSpeed;
//Makes sure the picture stays within borders
if (imageX <= 0)
{
imageX = 0;
}
}
}
Can anyone help explain the glitching?
Try calling g.Clear() with your sky color before the g.DrawImage() call. I think it's just drawing on top of itself and that's causing the smearing.
To me it seems like you are redrawing over and over without clearing the display from the previous draw! What type of framework are you using to develop that? Does it have a custom drawing class? As tesserex suggested more specifically call g.Clear() and u will be fine.
You shouldn't need g.Clear in this case because you're Re-Drawing a new image every time.
My bet is that imageX is greater then (imageWidth - pbMap.Width) so it will not enter the IF, therefore it will redraw the same as before.
Note: I don't know how you create g but if you use .CreateGraphics() don't forget to Dispose()
Cheers

How to convert my Graphics.Drawline drawing on panel, to saved image?

I have a panel called "canvas". It is transparent. So the background is from the form image, which is dark blue. This shows in the panel or canvas.
When I save the canvas to image, it saves the background, but not what I have drawn thereon, my drawline pen is yellow. And I can see it drawing on the panel. But when I save it... there are not yellow lines in the image.
What am I missing? Where are my yellow lines?
I am running this with my timer tick... to get the view to update.
This tracks the position of a CNC type machine. Gives a visual of where
the machine is in relation to Zero.
My ultimate goal, is to have a "viewport" that is zoomable, thus getting it
into a image, for easy resizing, and displaying in a pictureBox, which will
handle the stretched image and center it automatically?
I have read some complex solutions, but I am after the simple ones.
Any help would be appreciated. Sincerely,
private void VMoveNow()//Draw on panel called "canvas".
{
double a = GV.MYa * -1; //Change Direction of Y Drawing.
xc = Convert.ToInt32(GV.MXa) + (canvas.Width / 2);
yc = Convert.ToInt32(a) + (canvas.Height / 2);
g = canvas.CreateGraphics();
g.DrawLine(p, x, y, xc, yc);
x = xc;
y = yc;
g.Dispose();
}
private void SaveBMP()
{
try
{
Bitmap mybmp = new Bitmap(canvas.Width, canvas.Height);
canvas.DrawToBitmap(mybmp, canvas.Bounds);
mybmp.Save("C:\\myimage.bmp");
}
catch
{
return;
}
}
Thanks for looking.
I answered my own problem, after several attempts... I have figured out that I can scale my var's used for this drawings... and the size of the Drawline will be scale as a result.
So I now have scaling of the Drawline drawing, in a panel, with no picture or picture box needed. Does what I wished.
Setting the Pen width to -1 takes care of it resizing.

Positioning Graphics draw

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 ...
}

Drag & Drop modyfiing polygon shape by moving vertices in C#

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 ...

Border in DrawRectangle

Well, I'm coding the OnPaint event for my own control and it is very nescessary for me to make it pixel-accurate.
I've got a little problem with borders of rectangles.
See picture:
removed dead ImageShack link
These two rectangles were drawn with the same location and size parameters, but using different size of the pen. See what happend? When border became larger it has eaten the free space before the rectangle (on the left).
I wonder if there is some kind of property which makes border be drawn inside of the rectangle, so that the distance to rectangle will always be the same. Thanks.
You can do this by specifying PenAlignment
Pen pen = new Pen(Color.Black, 2);
pen.Alignment = PenAlignment.Inset; //<-- this
g.DrawRectangle(pen, rect);
If you want the outer bounds of the rectangle to be constrained in all directions you will need to recalculate it in relation to the pen width:
private void DrawRectangle(Graphics g, Rectangle rect, float penWidth)
{
using (Pen pen = new Pen(SystemColors.ControlDark, penWidth))
{
float shrinkAmount = pen.Width / 2;
g.DrawRectangle(
pen,
rect.X + shrinkAmount, // move half a pen-width to the right
rect.Y + shrinkAmount, // move half a pen-width to the down
rect.Width - penWidth, // shrink width with one pen-width
rect.Height - penWidth); // shrink height with one pen-width
}
}
This isn't a direct answer to the question, but you might want to consider using the ControlPaint.DrawBorder method. You can specify the border style, colour, and various other properties. I also believe it handles adjusting the margins for you.
I guess not... but you may move the drawing position half the pen size to the bottom right

Categories