I am trying to determine the limits of an arch for a couple of days now without much successes.I know this is more of a geometry type question than programming but here it goes.Let me first show this image to elaborate on what I am trying to achieve in C#.
In the image above you can see a Green Arc, I am trying to determine where the ‘Left Most’ point is on the X axis (and the 'right most' eventually, but for the sake of simplicity I will focus on the ‘left most’ point)
The answer of this image ‘left most’ in the X axis is 5,note: even if the arch has a greater sweep angle the answer is still 5, but if the sweep angle is less than the answer will be more than 5.
I am reading this information from a text based G-code file and here is a sample of the arc drawn in the G-code file.
G1 X10. Y15.
G3 X5. Y10. I10. J10.
The first line indicates the starting-point of the arch, witch is in this case X 10 and Y 15. The second line indicates the end-point, arch-center-point and rotation.
The G3 indicates a Counter-Clockwise rotation of the arch (G2 indicates a Clockwise Rotation).
The X & Y indicates the End-Point and the I & J is the (X & Y respectively) arch-center-point values.The first thing that I have tried is to see if I can detect the arch crosses the 180* red line without much successes mainly because I cannot seem to get angle calculations working correctly when I try to process different types of coordinates.Here is a sample of code I’m unable to finish:
else if (Gval == 3)
{
//Values read from G-Code File
double startX = Convert.ToDouble(oldXval);
double startY = Convert.ToDouble(oldYval);
double endX = Convert.ToDouble(Xval);
double endY = Convert.ToDouble(Yval);
double midX = Convert.ToDouble(Ival);
double midY = Convert.ToDouble(Jval);
//Get Start angle of Line
double startAngle = Math.Atan2(startY - midY, startX - midX);
startAngle = Math.Round(startAngle * (180.0 / Math.PI), 5);//Radiants to Degrees
startAngle = ((startAngle % 360) + 360) % 360;//Normalise
//Get End angle of line
double EndAngle = Math.Atan2(endY - midY, endX - midX);
EndAngle = Math.Round(EndAngle * (180.0 / Math.PI), 5);//Radiants to Degrees
EndAngle = ((EndAngle % 360) + 360) % 360;//Normalise
if (EndAngle == 0) EndAngle = 360;
//Get Raiduis
double raduis = Math.Round((Math.Sqrt(Math.Pow(Math.Abs(startX - midX), 2) + Math.Pow(Math.Abs(startY - midY), 2))),5);
double deltaY = (midY) - (startX);
double deltaX = (midX) - (startY);
double angleInDegrees = Math.Atan(deltaY / deltaX)*180/Math.PI;
if (startAngle <= 180 && EndAngle >= 180)
{
double LeftValue = midX - raduis;
}
}
The code above only works for some specific arcs.
I have Googled around and found mainly topics on Lines intersections and line and circle intersections but only one specifically about lines intersecting arcs, the answer is too vague to make out what is supposed to happen here is the Link
In addition to that there is also a type of arch that I think will have to be processed differently probably by some sort of Pathegorem, but I have not started on how I can do that one. But here is an image of it:
Here is the G-code :
G1 X30. Y15.
G3 X25.4 Y11.96 I30. J10.
And I think the ‘Left most’ X value is 25.4
I would like to know, if you know of a Method or a Library that can help out with this one .Thanks
This should calculate the X and Y bounds of an arc. There are many optimizations that could be made for better performance, but I think this is easier to understand.
class Bounds
{
public double MinX, MinY, MaxX, MaxY;
}
Bounds GetArcBounds(float cx, float cy, float x1, float y1, float x2, float y2)
{
var a1 = GetAngle(y1 - cy, x1 - cx);
var a2 = GetAngle(y2 - cy, x2 - cx);
var r = (float)Math.Sqrt(Math.Pow(y1 - cy, 2) + Math.Pow(x1 - cx, 2));
var bounds = new Bounds();
bounds.MinX = double.MaxValue;
bounds.MinY = double.MaxValue;
bounds.MaxX = double.MinValue;
bounds.MaxY = double.MinValue;
ExpandBounds(bounds, x1, y1);
ExpandBounds(bounds, x2, y2);
if (IsAngleInArc(a1, a2, 0))
ExpandBounds(bounds, cx + r, cy);
if (IsAngleInArc(a1, a2, (float)Math.PI * 0.5f))
ExpandBounds(bounds, cx, cy + r);
if (IsAngleInArc(a1, a2, (float)Math.PI))
ExpandBounds(bounds, cx - r, cy);
if (IsAngleInArc(a1, a2, (float)Math.PI * 1.5f))
ExpandBounds(bounds, cx, cy - r);
return bounds;
}
float GetAngle(float dy, float dx)
{
var a = (float)Math.Atan2(dy, dx);
if (a < 0) a += (float)Math.PI * 2.0f;
return a;
}
void ExpandBounds(Bounds bounds, float x, float y)
{
if (x < bounds.MinX) bounds.MinX = x;
if (y < bounds.MinY) bounds.MinY = y;
if (x > bounds.MaxX) bounds.MaxX = x;
if (y > bounds.MaxY) bounds.MaxY = y;
}
bool IsAngleInArc(float a1, float a2, float test)
{
if (a2 < a1)
{
a2 += (float)Math.PI * 2.0f;
}
if (test < a1)
{
test += (float)Math.PI * 2.0f;
}
return a1 <= test && test <= a2;
}
If you wanted to be able to do both counter-clockwise and clockwise, I believe you could change the logic to the following, although I have not tested this yet.
if (IsAngleInArc(a1, a2, 0) ^ clockwise)
ExpandBounds(bounds, cx + r, cy);
if (IsAngleInArc(a1, a2, (float)Math.PI * 0.5f) ^ clockwise)
ExpandBounds(bounds, cx, cy + r);
if (IsAngleInArc(a1, a2, (float)Math.PI) ^ clockwise)
ExpandBounds(bounds, cx - r, cy);
if (IsAngleInArc(a1, a2, (float)Math.PI * 1.5f) ^ clockwise)
ExpandBounds(bounds, cx, cy - r);
Related
I am trying to do a digging tool for my game, I have x and y coordinates of point A and B, what I want to do is create a curve between these points, nothing graphical I just need loop through the coordinates (float x, float y).
I am not good at explaining so here is a visual example;
The first image is what's happen if I just use a for loop to decrease the y value until middle and then increase it from the middle to end.
//Very specific code for my example
//I wrote it just for this example so I am not sure if it works
float y;
float x;
public void Example(float startX, float endX, float startY, float endY, float depth)
{
y = startY;
x = startX;
float changeAmountOfY = depth / (endX - startX);
for (int i = (int)startX; i < (startX + endX) / 2; i++)
{
x++;
y -= changeAmountOfY;
}
for (int i = (int)(startX + endX) / 2; i < endX; i++)
{
x++;
y += changeAmountOfY;
}
}
public void ChangeCoordinates()
{
Example(100f, 200f, 100f, 100f, 50f);
}
The second image is what I need.
I am developing the game on unity and I am using Vector2 for the coordinates but it is not important.
Pure C# or even C++ is welcome.
It is also fine if someone can just explain the math behind what I am trying to do.
Maybe this can help:
// Calculate radius
int radius = (B.X - A.X) / 2;
// Calculate middle
int middle_x = A.X + radius;
int middle_y = A.Y;
// or
int middle_y = (A.Y + B.Y) / 2;
// Coordinates for a semicircle
// 0 to 180 degree
for (int i = 0; i <= 180; i++)
{
double x_coordinate = middle_x + radius * Math.Cos(i * Math.PI / 180);
// Opened to bottom
double y_coordinate = middle_y + radius * Math.Sin(i * Math.PI / 180);
// or opened to top
double y_coordinate = middle_y - radius * Math.Sin(i * Math.PI / 180);
}
Take a look at unit circle.
.. a square whose opposite ends are given by (x1,y1), (x3, y3).
For example, see the image
(x1,y1)=(2,6), (x3,y3)=(8,4)
I'm thinking in terms of basic "y = mx + b" Algebra 1 stuff.
public void DrawSquare(double x1, double y1, double x3, double y3)
{
// Increment input coordinates so that they now are
// at the center of the squares
x1 += 0.5;
y1 += 0.5;
x3 += 0.5;
y3 += 0.5;
// Ensure x1 <= x2
if(x1 > x3)
{
SwapDoubles(ref x1, ref x3);
SwapDoubles(ref y1, ref y3);
}
// Get midpoints of x-y pairs
double midx = (x1 + x3) / 2;
double midy = (y1 + y3) / 2;
// Get the two lines f(x) = m1*x + b1 and g(x) = m3*x + b2
// that parallel the sides of the square and run through the center.
double m = (y3 - y1) / (x3 - x1);
if (m == 0)
m = double.Epsilon; // better way to do this?
double m1 = -m;
double m3 = 1 / m;
double b1 = midy - m1 * midx;
double b3 = midy - m3 * midx;
// Get distance from center to lines that run across the sides of the square
double d = Math.Sqrt(Math.Pow((double)x1 - midx, 2) + Math.Pow((double)y1 - midy, 2)) / Math.Sqrt(2);
DrawInRange((Coordinate<int> coord) =>
{
// distance from middle of coordinate to line 1
double d1 = ClosestDistanceToLine(m1, b1, coord.X + 0.5, coord.Y + 0.5);
// distance from middle coordinate to line 2
double d2 = ClosestDistanceToLine(m3, b3, coord.X + 0.5, coord.Y + 0.5);
return d1 <= d && d2 <= d;
});
}
// finds the closest distance beteen the line y = mx + b and the point (x0, y0)
// http://www.intmath.com/plane-analytic-geometry/perpendicular-distance-point-line.php
static double ClosestDistanceToLine(double m, double b, double x0, double y0)
{
double A = m;
double B = -1;
double C = b;
double numerator = Math.Abs(A * x0 + B * y0 + C);
double denominator = Math.Sqrt(Math.Pow(A, 2.0) + Math.Pow(B, 2.0));
return numerator / denominator;
}
Any idea why this isn't getting the proper coordinates for me?
So here's my goal: I want to stop at each pixel on a line and do some processing on those pixels. Currently i'm using EmguCV for my image processing library. In openCV there is a method called LineIterator which you can use to iterate through the pixel in a line. However, I haven't found a method similar to this in EmguCV which is where I am getting stuck.
Currently, I can get the pixel values of all the pixels on a line between two predefined points using the Image.Sample method. For a grayscale image Image this returns a n-by-1 matrix with n being the number of pixels on that line. However, I am not able to get the coordinates of each pixel on that particular line corresponding to the pixel values in the n-by-1 matrix mentioned above. Hence, I am not able to do image processing on these pixels, even though I have their pixel values. Is there a way to do this on EmguCV?
Thank you.
I implemented the bresenham line algoritm for my own project
(converted to C# from the wikipedia article)
public static List<Point> GetBresenhamLine(Point p0, Point p1)
{
int x0 = p0.X;
int y0 = p0.Y;
int x1 = p1.X;
int y1 = p1.Y;
int dx = Math.Abs(x1 - x0);
int dy = Math.Abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
var points = new List<Point>();
while (true)
{
points.Add(new Point(x0, y0));
if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if (e2 > -dy)
{
err = err - dy;
x0 = x0 + sx;
}
if (e2 < dx)
{
err = err + dx;
y0 = y0 + sy;
}
}
return points;
}
I implemented my own "Point" struct, but think it matches Emgu's.
I think this should take care of any special cases.
If (x1, y1) and (x2, y2) are two end points.
(x1, y1) ___________________ (x2, y2)
then you can get intermediate points by
for (int i = x1, i < x2; i++)
{
int x = i;
int y = (y1 + (y2-y1)/(x2-x1) * (x - x1)))
cout << "Points : " << x << " " << y << endl;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I have a Line Segment (x1, y1, x2, y2) intersecting a circle of radius r. How can I determine which intersection point is closest to (x1, y1)?
To do that first find the intersection points with the circle and then take the closest one to the line start point
So Check this code
//cx,cy is center point of the circle
public PointF ClosestIntersection(float cx, float cy, float radius,
PointF lineStart, PointF lineEnd)
{
PointF intersection1;
PointF intersection2;
int intersections = FindLineCircleIntersections(cx, cy, radius, lineStart, lineEnd, out intersection1, out intersection2);
if (intersections == 1)
return intersection1; // one intersection
if (intersections == 2)
{
double dist1 = Distance(intersection1, lineStart);
double dist2 = Distance(intersection2, lineStart);
if (dist1 < dist2)
return intersection1;
else
return intersection2;
}
return PointF.Empty; // no intersections at all
}
private double Distance(PointF p1, PointF p2)
{
return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
}
// Find the points of intersection.
private int FindLineCircleIntersections(float cx, float cy, float radius,
PointF point1, PointF point2, out
PointF intersection1, out PointF intersection2)
{
float dx, dy, A, B, C, det, t;
dx = point2.X - point1.X;
dy = point2.Y - point1.Y;
A = dx * dx + dy * dy;
B = 2 * (dx * (point1.X - cx) + dy * (point1.Y - cy));
C = (point1.X - cx) * (point1.X - cx) + (point1.Y - cy) * (point1.Y - cy) - radius * radius;
det = B * B - 4 * A * C;
if ((A <= 0.0000001) || (det < 0))
{
// No real solutions.
intersection1 = new PointF(float.NaN, float.NaN);
intersection2 = new PointF(float.NaN, float.NaN);
return 0;
}
else if (det == 0)
{
// One solution.
t = -B / (2 * A);
intersection1 = new PointF(point1.X + t * dx, point1.Y + t * dy);
intersection2 = new PointF(float.NaN, float.NaN);
return 1;
}
else
{
// Two solutions.
t = (float)((-B + Math.Sqrt(det)) / (2 * A));
intersection1 = new PointF(point1.X + t * dx, point1.Y + t * dy);
t = (float)((-B - Math.Sqrt(det)) / (2 * A));
intersection2 = new PointF(point1.X + t * dx, point1.Y + t * dy);
return 2;
}
}
Intersection Code form here LINK
I need to draw an arc using GraphicsPath and having initial, median and final points. The arc has to pass on them.
I tried .DrawCurve and .DrawBezier but the result isn't exactly an arc.
What can I do?
SOLUTION:
After a couple of hours of code writing I managed to draw what I wanted with this algorithm (give 3 Point a,b,c and a GraphicsPath path):
double d = 2 * (a.X - c.X) * (c.Y - b.Y) + 2 * (b.X - c.X) * (a.Y - c.Y);
double m1 = (Math.Pow(a.X, 2) - Math.Pow(c.X, 2) + Math.Pow(a.Y, 2) - Math.Pow(c.Y, 2));
double m2 = (Math.Pow(c.X, 2) - Math.Pow(b.X, 2) + Math.Pow(c.Y, 2) - Math.Pow(b.Y, 2));
double nx = m1 * (c.Y - b.Y) + m2 * (c.Y - a.Y);
double ny = m1 * (b.X - c.X) + m2 * (a.X - c.X);
double cx = nx / d;
double cy = ny / d;
double dx = cx - a.X;
double dy = cy - a.Y;
double distance = Math.Sqrt(dx * dx + dy * dy);
Vector va = new Vector(a.X - cx, a.Y - cy);
Vector vb = new Vector(b.X - cx, b.Y - cy);
Vector vc = new Vector(c.X - cx, c.Y - cy);
Vector xaxis = new Vector(1, 0);
float startAngle = (float)Vector.AngleBetween(xaxis, va);
float sweepAngle = (float)(Vector.AngleBetween(va, vb) + Vector.AngleBetween(vb, vc));
path.AddArc(
(float)(cx - distance), (float)(cy - distance),
(float)(distance * 2), (float)(distance * 2),
startAngle, sweepAngle);
I would use DrawArc() as suggested by ANC_Michael. To find an arc that passes through 3 points you want to calculate the circumcircle of the triangle formed by the points.
Once you have the circumcircle calculate a bounding box for the circle to use with DrawArc using the min/max dimensions (center +/- radius). Now calculate your start and stop angles by translating the points so that the circumcircle is centered on the origin (translate by -circumcenter) and take the dot-product of the normalized start and end vectors with the X-axis:
double startAngle = Math.Acos(VectorToLeftPoint.Dot(XAxis));
double stopAngle = Math.Acos(VectorToRightPoint.Dot(XAxis));
Note that DrawArc expects angles clockwise from the X-axis so you should add Math.PI if the calculated vector is above the x-axis. That should be enough information to call DrawArc().
Edit: This method will find a circular arc and not necessarily the 'best fit' arc depending on your expected endpoint behavior.
Have you tried the DrawArc method and seeing if u can manipulate your 3 points somehow?
maybe
Pen blackPen= new Pen(Color.Black, 3);
// Create rectangle to bound ellipse.
Rectangle rect = new Rectangle(initial x, initial y, final x, median y);
// Create start and sweep angles on ellipse.
float startAngle = 0F;
float sweepAngle = 270.0F;
// Draw arc to screen.
e.Graphics.DrawArc(blackPen, rect, startAngle, sweepAngle);
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.drawarc%28VS.71%29.aspx