How to find which rectangle is closest to a point - c#

If I have two System.Drawing.Rectangle objects on a canvas and a Point, what is the best way to calculate which Rectangle (any part of the Rectangle, not just its Location Point) is closest to that Point?
An example from a unit test:
Rectangle one = new Rectangle (0, 0, 10, 10);
Rectangle two = new Rectangle (20, 20, 10, 10);
Point point = new Point(14, 14);
Rectangle actual = ClosestToPoint(point, one, two);
// should be closer to one since one's bottom right is at (10, 10)
Assert.That(actual, Is.SameAs(one));
// method to write
public Rectangle ClosestToPoint(Point p, params Rectangle[] rectangles) { }

distance to rectangle = min (distance
to each of the 4 line segments that
are the edges of the rectangle)
For distance to line segment, see this question

This is for measuring distance between 2 points, so take the coordinate point from your rectangle (which is up to you to decide be cause I dont know what closest means for you):
public int Distance2D(int x1, int y1, int x2, int y2)
{
int result = 0;
double part1 = Math.Pow((x2 - x1), 2);
double part2 = Math.Pow((y2 - y1), 2);
double underRadical = part1 + part2;
result = (int)Math.Sqrt(underRadical);
return result;
}

Hmm. I'm thinking of looping through your rectangle array and storing each X and Y index in a list. You could then loops through the list and do something abs(min(i.getX() - point)). If they are equal then check for min(y).

Related

how to draw polygon including negative points ? in C#

i am doing c# project. i have found a problem and unable to find answer of this problem that's why i am posting here/
i am implementing procedural floor plan generation in c#. at first i need to draw a polygon to on given points to generate grid. points can be positive or negative. points will be in floating.
From the Microsoft Documentation i am able to draw polygon for the floating positive points, but when i change points to negative it does not draw anything on form.
this method id drawing x,y coordinates 0,0 in the corner .
code example
public void DrawPolygonPointF(PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create points that define polygon.
PointF point1 = new PointF(50.0F, 50.0F);
PointF point2 = new PointF(100.0F, 25.0F);
PointF point3 = new PointF(200.0F, 5.0F);
PointF point4 = new PointF(250.0F, 50.0F);
PointF point5 = new PointF(300.0F, 100.0F);
PointF point6 = new PointF(350.0F, 200.0F);
PointF point7 = new PointF(250.0F, 250.0F);
PointF[] curvePoints =
{
point1,
point2,
point3,
point4,
point5,
point6,
point7
};
// Draw polygon curve to screen.
e.Graphics.DrawPolygon(blackPen, curvePoints);
}
i have negative coordinates value for example pointF(300,-250) this method is not drawing nothing for negative coordinates value.
So please give me brief solution because i don't know much about drawing.
Thank you
In C# 0,0 is the top left corner of the screen. So negative values are off the left or top edge of your form. You need to transform your coordinates from your coordinate space to the form's. To place 0,0 dead center, you would do this:
int screenX = myX + windowWidth / 2;
int screenY = myY + windowHeight / 2;
Building off of the answer #pquest gave, and your newly added sample code, doing a "real" GDI transformation would look like this:
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create points that define polygon.
PointF point1 = new PointF(50.0F, 50.0F);
PointF point2 = new PointF(100.0F, 25.0F);
PointF point3 = new PointF(200.0F, 5.0F);
<...snip...>
//Apply a translation Transformation to move 0,0 to the center of the
//window. You can now draw your points with negative values, without doing
//any addition to them.
int screenX = windowWidth / 2;
int screenY = windowHeight / 2;
e.Graphics.TranslateTransform((float) screenX, (float) screenY);
// Draw polygon curve to screen.
e.Graphics.DrawPolygon(blackPen, curvePoints);
GDI Transformations are very powerful. You can use them to move points around, flip points horizontally or vertically, scale things bigger or smaller, distort like a parallelogram, and even do rotations. All of these can be combined in to what is called a transformation matrix to get some very cool results.
More examples can be found on MSDN.
That's working for me to this problem.
you just need to add couple lines of code in your code.
int windowWidth = this.ClientSize.Width;
int windowHeight = this.ClientSize.Height;
int screenX = windowWidth / 2;
int screenY = windowHeight / 2;
e.Graphics.TranslateTransform((float)screenX, (float)screenY);

How to increase the height of curve in windows forms

I want to increase the height of the curve but its left and right position should remain same. Just want to lift up from center to give it a shape like curve as height changes.
Pen blackPen = new Pen(Color.Black, 3);
// Create coordinates of rectangle to bound ellipse.
int x = 93;
int y = 136;
int width = 320;
int height = 50;
// Create start and sweep angles on ellipse.
int startAngle = 0;
int sweepAngle = -180;
// Draw arc to screen.
e.Graphics.DrawArc(blackPen, x, y, width, height, startAngle, sweepAngle);
In the most direct way your problem can be solved like this:
int change = 0;
e.Graphics.DrawArc(blackPen, x, y-change, width, height+change, startAngle, sweepAngle);
By increasing the variable change the ellipse will curve up more and more:
private void button1_Click(object sender, EventArgs e)
{
change += 10;
panel1.Invalidate();
}
But maybe you want more control over the shape? Let's have a look at the options:
Here are examples of the three 'curve' drawing methods:
Curves, Beziers & Ellipses
And here is the code to draw that image.
Please ignore the Graphics.xxxTransform calls! They only are meant to shift the curves a little bit upwards so they don't overlap too much to see them properly.
Also note that the curves in the first image are not completely convex. See the last part of the answer to see a DrawCurve call that avoids the concave segments!
The important part are the Points! And just as the comments suggest, in the third part the ellipses are being changed by making the height larger and moving the top of the Rectangle up by the same amount.
The complexity DrawArc of and DrawCurve is pretty much equal; both are controlled by four integers with a rather clear meaning: They either make one rectangle or the corners of a symmetrical triangle. (Plus one counterpoint for the convex call.)
DrawBezier is more complex, especially since the controls point(s) are not actually on the resulting curve. They can be thought of force vectors that pull the line into a curved shape and are harder to calculate.
private void panel1_Paint(object sender, PaintEventArgs e)
{
Point a = new Point(0, 200);
Point c = new Point(200, 200);
for (int i = 0; i< 10; i++)
{
e.Graphics.TranslateTransform(0, -5);
Point b = new Point(100, 50 + i * 10);
e.Graphics.DrawCurve(Pens.Maroon, new[] { a, b, c }, 0.7f);
}
e.Graphics.ResetTransform();
Point pa = new Point(250, 200);
Point pb = new Point(450, 200);
for (int i = 0; i < 10; i++)
{
e.Graphics.TranslateTransform(0, -5);
Point pc = new Point(350, 200 - i * 10);
e.Graphics.DrawBezier(Pens.ForestGreen, pa, pc, pc, pb);
}
e.Graphics.ResetTransform();
int x = 500;
int y0 = 200;
int w = 200;
for (int i = 0; i < 10; i++)
{
e.Graphics.TranslateTransform(0, -5);
Rectangle rect = new Rectangle(x, y0 - i * 10, w, 10 + i * 10);
e.Graphics.DrawArc(Pens.DarkBlue, rect, -0, -180);
}
e.Graphics.ResetTransform();
}
Notes:
The Curve (1st image) can be further controlled by the Tension parameter. The lower the tension the more pointed it gets, approaching 1f it makes the curve broader..
The Bezier curve (2nd image) is using only one control point. (Twice.) The curve gets a little pointed this way. You can make it broader and broader by using two different points the move apart little by little..
The Ellipse can't be controlled; it will always fill the bounding Rectangle.
Here is an example of varying the Curves and the Beziers:
The Curves are drawn with varying Tensions. Also I have used an overload that helps to get rid of the concave part at the start and end of the curve. The trick is to add a suitable extra point to the start and end and to tell the DrawCurve to leave out these 1st and last segments.
The simplest point to use (for both ends actually) is the counterpoint of the one at the top.
The Beziers are drawn using two control points, moving out and up a little.
Here is the code for the variations:
Point a = new Point(0, 200);
Point c = new Point(200, 200);
for (int i = 1; i < 10; i++)
{
e.Graphics.TranslateTransform(0, -5);
Point b = new Point(100, 50);
Point b0 = new Point(b.X, a.Y + (a.Y - b.Y));
e.Graphics.DrawCurve(Pens.Maroon, new[] { b0, a, b, c, b0 }, 1, 2, 0.1f * i);
}
e.Graphics.ResetTransform();
Point pa = new Point(250, 200);
Point pb = new Point(450, 200);
for (int i = 0; i < 10; i++)
{
e.Graphics.TranslateTransform(0, -5);
Point ca = new Point(350 - i * 9, 100 - i * 5);
Point cb = new Point(350 + i * 9, 100 - i * 5);
e.Graphics.DrawBezier(Pens.ForestGreen, pa, ca, cb, pb);
}
e.Graphics.ResetTransform();
here was the solution just increase value of y0 as u increase the value of
y0-i here i=20
int x = 96;
int y0 = 260;
int w = 320;
e.Graphics.TranslateTransform(0, -5);
Rectangle rect = new Rectangle(x, y0 - 20 * 10, w, 10 + 20 * 10);
e.Graphics.DrawArc(Pens.DarkBlue, rect, -0, -180);
e.Graphics.ResetTransform();

how to find edge of an image with most distance from center?

i writing a sample program in c# who drawing some point in page
i set center point with calculate distance of point
but how can found most distance point from center point ?
sample code :
void draw(string label,float x,float y)
{
Graphics g = panel1.CreateGraphics();
Pen p = new Pen(Color.YellowGreen, 5);
Random randomGen = new Random(Convert.ToInt32(label));
KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
KnownColor randomColorName = names[randomGen.Next(names.Length)];
Color randomColor = Color.FromKnownColor(randomColorName);
SolidBrush s = new SolidBrush(randomColor);
g.FillEllipse(s, x * 1, y * 1, 10, 10);
}
The best and simplest approach for this problem what I can think of is:
1) scan the image/coordinate system horizontally and vertically
2) For each row/column store the lowest and the highest coordinates with non-zero intensity
that will be your boundary points
You can define the furthest point of an angle. This can solve the problem of convex hull, but this technique fits well only in a circle space, very like yours.
for each angle you have to find the furthest point and then assign it the red color.
You can Use as much angle as you want.
PSEUDO...
npoints = 10;
furthestPts = zeros(npoints );//Initialize vectors with 0
distances = zeros(npoints );
for each pt in points
angle = atan((pt.y - c.y)/pt.x - c.x) * 360 / ( 2 * pi); //degres
angle = (int) (angle/npoints); //we will have only 10 points separated by 36 degrees
d = distance(pt,center);
if(distances[angle] < d){
distances[angle] = d; //Updating furthest point
furthestPts.[angle] = (pt); //Updating furthest point
}
You will see that this algoritm has a few problems if the point are to far from center or if the points are to far from each other.

Calculate Minimum Bounding Rectangle Of 2D Shape By Coordinates

I have a solution that uses spatial data to represent a cluster of points on a map. I have the need to used the coordinates that represent the extents of a cluster to find the minimum bounding rectangle that can contain said cluster of points.
Does any simple algorithm exist to be able to calculate this or is there any built in functionality in C# to achieve this. I am aware of the NetTopologySuite but am not sure how/if I could use this to achieve the same goal. I have a list of coordinates so I would need to pass this list of strings into it and get the MBR out.
The easiest solution, and I assume the one you're most likely to be looking for, is to calculate the axis-aligned bounding box, which is simply a case of finding the min/max x & y values, then constructing a box from those.
I'll give you pseudo-code for that, given that you haven't posted the types that your geometry is expressed in...
type point { float x; float y; }
type box { point topleft; point topright; point bottomleft; point bottomright; }
function bounding_box(points)
{
xmin = min(points.x)
xmax = max(points.x)
ymin = min(points.y)
ymax = max(points.y)
return new box{
topleft = { x = xmin, y = ymax },
topright = { x = xmax, y = ymax },
bottomleft = { x = xmin, y = ymin },
bottomright = { x = xmax, y = ymin }
};
}
So given these:
point[] points = [[x = -2, y = 0], [x = 1, y = 2], [x = 1, y = 1], [x = -1, y = -2]];
box bounds = bounding_box(points);
All of the following will be true:
bounds.topleft == [x = -2, y = 2];
bounds.topright == [x = 1, y = 2];
bounds.bottomleft == [x = -2, y = -2];
bounds.bottomright == [x = -1, y = -2];
Of course, if the coordinate system has the lowest coordinates at the top (e.g. like a typical display) - then you have to invert the calculation; or calculate the result in object-space first and then translate to logical space afterwards.
Notice I've gone for a type for the box that expresses all four corners, in case you decide in the future to update to an arbitrarily aligned box in the future (although by the same token you could just use a point + 2 vectors for that).
One possible, though simple, way to do it could be like this:
public Rectangle Test(List<Point> points)
{
// Add checks here, if necessary, to make sure that points is not null,
// and that it contains at least one (or perhaps two?) elements
var minX = points.Min(p => p.X);
var minY = points.Min(p => p.Y);
var maxX = points.Max(p => p.X);
var maxY = points.Max(p => p.Y);
return new Rectangle(new Point(minX, minY), new Size(maxX-minX, maxY-minY));
}
This does of course assume that you're looking for a rectangle that is aligned vertically and horizontally. So if you're looking for the smallest possible rectangle, no matter how it is rotated, this is not for you.
Try G# at http://www.ceometric.com/products/g.html
It has minimum area and minimum perimeter enclosing rectangles and also minimum enclosing circles.

How do I draw a directed line in .Net?

Any suggestions on how to draw a directed line in .Net? I'm currently using Graphics.DrawLine with a Pen with dashes. But the dashes point in both directions. I want them to all point in a single direction.
using (var p = new Pen(Color.FromArgb(190, Color.Green), 5))
{
p.StartCap = LineCap.Round;
p.EndCap = LineCap.ArrowAnchor;
p.CustomEndCap = new AdjustableArrowCap(3, 3);
p.DashStyle = DashStyle.Dash;
p.DashCap = DashCap.Triangle;
e.Graphics.DrawLine(p, startPt, pt);
}
This might not be very helpful, but the way that we accomplished this type of thing on other projects that I have been involved with is to implement a custom "pen" that accepts the line to be drawn, calculates the actual dashes, and then draws each dash as an individual line with a "real" Pen. If you were to do something like this, then you could actually apply a "pen" level StartCap and/or EndCap to each dash.
The custom "pen" would have to accept an array or sequence of dash/gap lengths (or maybe an enumeration of standard pen styles that would be interpreted internally as specific dash/gap lengths).
We did this many years ago with a GDI-based drawing system where we had to support more line styles than the built in line styles that GDI supported.
It is an interesting exercise, but it is also probably more trouble than it is worth unless you REALLY have to have the dashes drawn as you describe.
[EDIT]
Here is some sample code for how you might do this, if you are so inclined.
First is an extension method on the Graphics object. It takes a pen, dash length, gap length, start point, and end point. It interpolates along the line p1->p2, drawing a "dash" length segment and then skipping a "gap" length segment. The passed-in pen should be solid with an arrow endcap (to achieve the effect you were asking for).
The code is pretty rough, but the behavior is, more or less, like this:
If the input line is shorter then the total dash+gap length, then the line is drawn as-is using the input pen.
If the input line is longer than the total dash+gap length, then "dash" length lines are drawn until the "remainder" of the line is less than the dash+gap length, at which point the remainder is drawn as-is with the input pen.
If you wanted to implement Path drawing, then you would have to interpolate around the intermediate vertices (unless you wanted to cheap out and just compute dashes for each segment indepdently).
public static void DrawDashedLine(this Graphics g, Pen p, float dash, float gap, PointF s, PointF e)
{
float dx = e.X - s.X;
float dy = e.Y - s.Y;
float len = (float)Math.Sqrt(dx * dx + dy * dy);
float remainder = len;
float vx = dx / len;
float vy = dy / len;
if (len <= dash + gap)
{
g.DrawLine(p, s, e);
return;
}
PointF last = s;
while (remainder > dash + gap)
{
PointF p1 = new PointF(last.X, last.Y);
PointF p2 = new PointF(p1.X + vx*dash, p1.Y + vy*dash);
g.DrawLine(p, p1, p2);
last = new PointF(p2.X + vx*gap, p2.X + vy*gap);
remainder = remainder - dash - gap;
}
if (remainder > 0)
{
g.DrawLine(p, last, e);
}
}
}
Here is how you would call it:
private void button1_Click(object sender, EventArgs e)
{
using (var p = new Pen(Color.FromArgb(190, Color.Green), 5))
{
p.StartCap = LineCap.Round;
p.EndCap = LineCap.ArrowAnchor;
p.CustomEndCap = new AdjustableArrowCap(3, 3);
p.DashStyle = DashStyle.Solid;
var graph = this.CreateGraphics();
graph.DrawDashedLine(p, 20, 10, new PointF(20, 20), new PointF(500, 500));
}
}
I don't claim that the code is great (or even necessarily good ;-), but it should give you a good starting point if you are really interested in drawing your directed line.
Good luck!
Hmm... maybe I am missing something, but when I use this (almost) exact same code, I get a directed arrow with only one point.
Here is my code:
private void button2_Click(object sender, EventArgs e)
{
using (var p = new Pen(Color.FromArgb(190, Color.Green), 5))
{
p.StartCap = LineCap.Round;
p.EndCap = LineCap.ArrowAnchor;
p.CustomEndCap = new AdjustableArrowCap(3, 3);
p.DashStyle = DashStyle.Dash;
p.DashCap = DashCap.Triangle;
var graph = this.CreateGraphics();
graph.DrawLine(p, new Point(20, 20), new Point(150, 150));
}
}
And the output:

Categories

Resources