In my application user points two points PointA and PointB on the same row (could be at any angle). So I have the following information
PointA coordinates
pointB coordinates
Distance between PointA and Point B
An Across distance (taken from user as input to draw other points)
Angle (calculated from pointA and pointB).
Based on this information, another application draws four points (vertices of rectangle).
What I have to do is, I have to find the centre point of those four points (rectangle) to be able to properly draw the rectangle bounded between those 4 points.
Right now I am able to draw the rectangle taking the centre as the pointA which obviously is incorrect. What formula should I use to calculate the centre of Rectangle so that I can draw a bounded rectangle?
Image 1:
Image 2:
Image 3:
Image 4:
Image 5:
As seen in the attached images, in every case rectangle is getting drawn with pointA as centroid. While I want the centroid to the centre of the FOUR points.
P.S: All angles are measured 0 degrees North.
I think:
Let P0 = {x0,y0} and P1 = {x1,y1}
Let the vector V01 = P1 - P0 == {V01x = P1x - P0x, V01y = P1y - P0y}
Let the vector V03 = {V01x * Cos(PI/2) - V01y * Sin(PI/2) , V01x* Sin(PI/2) + V01y * Cos(PI/2)
Width = Sqrt(V03x * V03x + V03y * V03y)
VN = V03 / Width == {V03x / Width, V03y / Width}
P3 = P0 + VN * Height
P4 = P1 + VN * Height
PC = (P0 + P1 + P2 + P3) / 4
In case you have two points p1, p2 and you need to draw a rectange (get other 2 points a1, a2) from these:
a1.x = p1.x;
a1.y = p2.y;
a2.x = p2.x;
a2.y = p1.y;
There you go, four points p1, a2, p2, a1 (clockwise order) describe your rectangle.
Update:
var width = p2.x - p1.x;
var height = p2.y - p1.y;
var angle = 0;
var center = new Point(p1.x + width / 2, p1.y + height / 2);
Update:
var center = new Point();
var angle = //you have it. Radians.
var height = // you have this as well.
var halfSegment = new Point((p2.x - p1.x) / 2, (p2.y - p1.y) / 2);
center.x = halfSegment.x + Math.Cos(angle - Math.PI / 2) * height / 2;
center.y = halfSegment.y + Math.Sin(angle - Math.PI / 2) * height / 2;
Related
I have a circle and want to draw a line inside that circle from the center (50|50) to the edge of the circle through the point i clicked on.
To test things, I already added this to my Circle.MouseDown event which draws the line from the center to the point I clicked on:
var PosX2 = e.GetPosition(MyCircle).X;
var PosY2 = e.GetPosition(MyCircle).Y;
CircleLine.X1 = 50;
CircleLine.Y1 = 50;
CircleLine.X2 = PosX2;
CircleLine.Y2 = PosY2;
What do I need to add to "stretch" my line to the edge of the Circle?
Think of it as a problem of lengthening a vector.
Suppose that you are given a circle with center (a,b) and radius r and that the point (c,d) lies in the circle at a point other than the center.
Then, the vector from (a,b) to (c,d) is (c-a, d-b). Its length is
L = sqrt((c-a)^2 + (d-b)^2)
But then the vector r/L * (c-a,d-b) has length r and points in the same direction as the ray from (a,b) to (c,d). Simply translate this vector by the center, and you get the desired point on the circle:
(a + r/L * (c-a), b + r/L * (d-b))
Just connect the center with the above point.
Johns comment got me the right answer, thank you!
I just wanted to post the solution:
double X1 = 75;
double Y1 = 75;
double X2 = e.GetPosition(CircleButtonCanvas).X;
double Y2 = e.GetPosition(CircleButtonCanvas).Y;
double startPoint = 17;
double endPoint = 48;
double xDiff = X2 - X1;
double yDiff = Y2 - Y1;
double Angle = Math.Atan2(yDiff, xDiff) * (180 / Math.PI);
CircleLine.X1 = 75 + (endPoint* Math.Cos(Angle * (Math.PI / 180)));
CircleLine.X2 = 75 + (startPoint * Math.Cos(Angle* (Math.PI / 180)));
CircleLine.Y1 = 75 + (endPoint * Math.Sin(Angle* (Math.PI / 180)));
CircleLine.Y2 = 75 + (startPoint * Math.Sin(Angle* (Math.PI / 180)));
With 75|75 beeing the center of my circle
I need to render a 2D image in which the axises are latitude (φ) representing the X-axis and longitude (λ) for Y-axis. Assuming the viewpoint is always at the origin(0,0,0) then a 3D line segment in Cartesian coordinate is a 2D curve segment in this image. Here each point along the curve represents φ and λ angles. Having a 3D line segment from P1 to P2, and knowing the equation of the corresponding 2D curve segment, λ= f(φ), the curve can be drawn from φ1 to φ2. Three lines make a triangle. Therefore a triangle is drawn as three curve segments which makes a closed shape.
The problem is that this shape is drawn like in wire-frame mode and the enclosed area is not filled. I can't think of any way to somehow fill in the area. Is it possible to achieve this? I appreciate any help and like to discuses it with other. Thanks
*Edit:
This cube has been drawn in Autocad:
The equation for a 3D line from P1(x1,y1,z1) to P2(x2,y2,z2) is:
(x-x1)/(x2-x1) = (y-y1)/(y2-y1) = (z-z1)/(z2-z1)
And This image(with latitude(φ) and longitude(λ) as axises) shows the same cube viewed from the origin:
The equation that gives λ along a 2D curved from φ1 to φ2(calculated from P1 and P2) is gained in this way:
λ= f(φ) = Atan((u/tan(φ)+z1)/ Sqrt((u/tan(φ)^2 + ((u/tan(φ))*w + y1)^2 ))
u and w are constants and are calculated thought P1 and P2 coordinates.
Here is the code for the above equation:
for (double tetha = φ1; tetha <= φ2; tetha += step){
double a = p1.X - p0.X;
double b = p1.Y - p0.Y;
double c = p1.Z - p0.Z;
double x = (a * p0.Y - b * p0.X) / (a * Math.Tan(tetha) - b);
double z = (((x - p0.X) * c) / a) + p0.Z;
double y = (((x - p0.X) * b) / a) + p0.Y;
if (a == 0)
{
y = (Math.Tan(tetha) * (b * p0.X - a * p0.Y)) / (b - a * Math.Tan(tetha));
z = (((y - p0.Y) * c) / b) + p0.Z;
x = (((y - p0.Y) * a) / b) + p0.X;
}
double landa = Math.Atan2(z, Math.Sqrt(x * x + y * y));
}
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
I'm drawing a custom diagram of business objects using .NET GDI+. Among other things, the diagram consists of several lines that are connecting the objects.
In a particular scenario, I need to shorten a line by a specific number of pixels, let's say 10 pixels, i.e. find the point on the line that lies 10 pixels before the end point of the line.
Imagine a circle with radius r = 10 pixels, and a line with start point (x1, y1) and end point (x2, y2). The circle is centered at the end point of the line, as in the following illustration.
How do I calculate the point marked with a red circle, i.e. the intersection between circle and line? This would give me the new end point of the line, shortening it by 10 pixels.
Solution
Thank you for your answers from which I was able to put together the following procedure. I named it LengthenLine, since I find it more natural to pass a negative number of pixels if I want the line shortened.
Specifically, I was trying to put together a function that could draw a line with rounded corners, which can be found here.
public void LengthenLine(PointF startPoint, ref PointF endPoint, float pixelCount)
{
if (startPoint.Equals(endPoint))
return; // not a line
double dx = endPoint.X - startPoint.X;
double dy = endPoint.Y - startPoint.Y;
if (dx == 0)
{
// vertical line:
if (endPoint.Y < startPoint.Y)
endPoint.Y -= pixelCount;
else
endPoint.Y += pixelCount;
}
else if (dy == 0)
{
// horizontal line:
if (endPoint.X < startPoint.X)
endPoint.X -= pixelCount;
else
endPoint.X += pixelCount;
}
else
{
// non-horizontal, non-vertical line:
double length = Math.Sqrt(dx * dx + dy * dy);
double scale = (length + pixelCount) / length;
dx *= scale;
dy *= scale;
endPoint.X = startPoint.X + Convert.ToSingle(dx);
endPoint.Y = startPoint.Y + Convert.ToSingle(dy);
}
}
Find the direction vector, i.e. let the position vectors be (using floats) B = (x2, y2) and A = (x1, y1), then AB = B - A. Normalize that vector by dividing by its length ( Math.Sqrt(xx + yy) ). Then multiply the direction vector AB by the original length minus the circle's radius, and add back to the lines starting position:
double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.Sqrt(dx * dx + dy * dy);
if (length > 0)
{
dx /= length;
dy /= length;
}
dx *= length - radius;
dy *= length - radius;
int x3 = (int)(x1 + dx);
int y3 = (int)(y1 + dy);
Edit: Fixed the code, aaand fixed the initial explanation (thought you wanted the line to go out from the circle's center to its perimeter :P)
I'm not sure why you even had to introduce the circle. For a line stretching from (x2,y2) to (x1,y1), you can calculate any point on that line as:
(x2+p*(x1-x2),y2+p*(y1-y2))
where p is the percentage along the line you wish to go.
To calculate the percentage, you just need:
p = r/L
So in your case, (x3,y3) can be calculated as:
(x2+(10/L)*(x1-x2),y2+(10/L)*(y1-y2))
For example, if you have the two points (x2=1,y2=5) and (x1=-6,y1=22), they have a length of sqrt(72 + 172 or 18.38477631 and 10 divided by that is 0.543928293. Putting all those figures into the equation above:
(x2 + (10/l) * (x1-x2) , y2 + (10/l) * (y1-y2))
= (1 + 0.543928293 * (-6- 1) , 5 + 0.543928293 * (22- 5))
= (1 + 0.543928293 * -7 , 5 + 0.543928293 * 17 )
= (x3=-2.807498053,y3=14.24678098)
The distance between (x3,y3) and (x1,y1) is sqrt(3.1925019472 + 7.7532190152) or 8.384776311, a difference of 10 to within one part in a thousand million, and that's only because of rounding errors on my calculator.
You can use similar triangles. For the main triangle, d is the hypotenuses and the extension of r is the vertical line that meets the right angle. Inside the circle you will have a smaller triangle with a hypotenuses of length r.
r/d = (x2-a0)/(x2-x1) = (y2-b0)/(y2-y1)
a0 = x2 + (x2-x1)r/d
b0 = y2 + (y2-y1)r/d
I am trying to use System.Drawing.Drawing2D.GraphicsPath.AddArc to draw an arc of an ellipse starting at 0 degrees and sweeping to 135 degrees.
The issue I am running in to is that for an ellipse, the arc drawn does not match up with what I would expect.
For example, the following code generates the image below. The green circles are where I would expect the end points of the arc to be using the formula for a point along an ellipse. My formula works for circles but not for ellipses.
Does this have something to do with polar versus Cartesian coordinates?
private PointF GetPointOnEllipse(RectangleF bounds, float angleInDegrees)
{
float a = bounds.Width / 2.0F;
float b = bounds.Height / 2.0F;
float angleInRadians = (float)(Math.PI * angleInDegrees / 180.0F);
float x = (float)(( bounds.X + a ) + a * Math.Cos(angleInRadians));
float y = (float)(( bounds.Y + b ) + b * Math.Sin(angleInRadians));
return new PointF(x, y);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle circleBounds = new Rectangle(250, 100, 500, 500);
e.Graphics.DrawRectangle(Pens.Red, circleBounds);
System.Drawing.Drawing2D.GraphicsPath circularPath = new System.Drawing.Drawing2D.GraphicsPath();
circularPath.AddArc(circleBounds, 0.0F, 135.0F);
e.Graphics.DrawPath(Pens.Red, circularPath);
PointF circlePoint = GetPointOnEllipse(circleBounds, 135.0F);
e.Graphics.DrawEllipse(Pens.Green, new RectangleF(circlePoint.X - 5, circlePoint.Y - 5, 10, 10));
Rectangle ellipseBounds = new Rectangle(50, 100, 900, 500);
e.Graphics.DrawRectangle(Pens.Blue, ellipseBounds);
System.Drawing.Drawing2D.GraphicsPath ellipticalPath = new System.Drawing.Drawing2D.GraphicsPath();
ellipticalPath.AddArc(ellipseBounds, 0.0F, 135.0F);
e.Graphics.DrawPath(Pens.Blue, ellipticalPath);
PointF ellipsePoint = GetPointOnEllipse(ellipseBounds, 135.0F);
e.Graphics.DrawEllipse(Pens.Green, new RectangleF(ellipsePoint.X - 5, ellipsePoint.Y - 5, 10, 10));
}
I was getting confused about how GraphicsPath.AddArc worked & I couldn't find any decent diagrams, so I drew one. Just in case anyone else has been suffering similarly! http://imgur.com/lNBewKZ
GraphicsPath.AddArc does exactly what you ask it to do -- it the arc up to a line projecting from the ellipse center, at an exact angle of 135 degrees clockwise from the x axis.
Unfortunately, this doesn't help when you're using the angle as a direct proportion of a pie chart slice you want to draw. To find out the angle B you need to use with AddArc, given an angle A that works on a circle, in radians, use:
B = Math.Atan2(sin(A) * height / width, cos(A))
Where width and height are those of the ellipse.
In your sample code, try adding the following at the end of Form1_Paint:
ellipticalPath = new System.Drawing.Drawing2D.GraphicsPath();
ellipticalPath.AddArc(
ellipseBounds,
0.0F,
(float) (180.0 / Math.PI * Math.Atan2(
Math.Sin(135.0 * Math.PI / 180.0) * ellipseBounds.Height / ellipseBounds.Width,
Math.Cos(135.0 * Math.PI / 180.0))));
e.Graphics.DrawPath(Pens.Black, ellipticalPath);
The result should look as follows:
alt text http://img216.imageshack.us/img216/1905/arcs.png