Drag & Drop modyfiing polygon shape by moving vertices in C# - 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 ...

Related

Creating a box in UI image using line renderer not working

I'm planning to create a square inside UI image using line renderer but size is too small that you need to zoom In. but if its outside the UI image its working. Please see attached imaged below
the line renderer component is attached to redkey1spawn object.
Tried derHugo code it works but somehow it overshoots in the screen
Your problem is that the LineRenderer works with coordinates in Unity Units.
A Screenspace Overlay canvas has pixel size scaling so the width and height (in Unity units) match up with the width and height (in Pixels) of the Window.
→ since you add 4 points
0, 0, 0
2, 0, 0
2, -2, 0
0, -2, 0
in worldspace it means they actually on the canvas will use e.g. 2px, -2px, 0px → very small.
You could e.g. multiply the sizes by the height or width of the image/canvas.
private void Start()
{
var lineRenderer = GetComponent<LineRenderer>();
var image = GetComponentInParent<RectTransform>();
// get the Unity worldspace coordinates of the images corners
// note: to get the scales like that ofcourse only works
// if the image is never rotated!
var worlsCorners = new Vector3[4];
image.GetWorldCorners(worlsCorners);
var imageWorldSize = new Vector2(Mathf.Abs(worlsCorners[0].x - worlsCorners[2].x), Mathf.Abs(worlsCorners[1].y - worlsCorners[3].y));
var positions = new Vector3[lineRenderer.positionCount];
var pointnum = lineRenderer.GetPositions(positions);
for (var i = 0; i < pointnum; i++)
{
positions[i] = positions[i] * imageWorldSize.x;
}
lineRenderer.SetPositions(positions);
}
Note, however, I'm actually not even sure you will see this LineRenderer since it is not a UI component I'm pretty sure the ScreenSpace Overlay will make every Image etc always render on top of it.

Flip coordinates when drawing set of rectangles

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

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

ZedGraph vertical lines with LineObj issue

I have a ZedGraphControl with a few curves in it and I want to add vertical lines at some fixed x-positions. The lines should of course only be inside the actual graph area.
I tried following
LineObj line = new LineObj(Color.Black, xPos, myPane.YAxis.Scale.Min, xPos, myPane.YAxis.Scale.Max);
line.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;
line.Line.Width = 1f;
myPane.GraphObjList.Add(line);
and this works fine until the user zooms the graph, the vertical lines will then stretch out of the actual graph area (see pic link below, also notice that it is not dashed inside the graph, odd).
http://imageshack.us/photo/my-images/196/zedgraphzoom.png/
Is there a way to solve this (if only there was a a way to get myPane.Xaxis.Scale.Min and Max of the current zoom and then update the graph in the ZoomEvent?) or are there any better classes/methods to use other than LineObj for this purpose?
Instead of defining a LineObj, define a LineItem and add it to the GraphPane.CurveList:
LineItem line = new LineItem(String.Empty, new[] { xPos, xPos },
new[] { myPane.YAxis.Scale.Min, myPane.YAxis.Scale.Max },
Color.Black, SymbolType.None);
line.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;
line.Line.Width = 1f;
myPane.CurveList.Add(line);
This binds line to the coordinate system in the graph pane, so that when you zoom or pan the line position will still be confined in the graph. Of course, if you zoom out without updating the y values of line, the line ends will be inside the graph.
I know from personal experience that dashing can be a problem in Zedgraph; however it seems like dashing is properly displayed when adding a LineItem, though.
You were on the good way using a LineObj rather than a CurveItem,.
Have a look on the Location struct and the CoordinateFrame property. It allows to use a different coordinate system for X and/or Y.
Setting the CoordinateFrame to XScaleYChartFraction allows to use 0d and 1d as Y, which means "the bottom" and "the top" of the graph pane (instead of YAxis.Scale.Min and YAxis.Scale.Max), as X continues to use the X Axis scale coordinate system.
That means you can use .AxisChange(), zoom, pan, and the LineObj will not interfer with the scale changes of the Y axis !
var line = new LineObj(Color.Black, xPos, 0, xPos, 1);
line.Location.CoordinateFrame = XScaleYChartFraction; // This do the trick !
line.IsClippedToChartRect = true;
line.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;
line.Line.Width = 1f;
myPane.GraphObjList.Add(line);

How do I draw a triangle using OpenTK?

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.

Categories