I'm calculating the angle using 2 points of a square.
The angle works well but it gives me values from -180 to 180 and it's hard for me to code the direction of my robot. I wanted the angle only with position values ex: 0 - 360;
var deltay = pontos_quadrado[0].Y - pontos_quadrado[1].Y;
var deltax = pontos_quadrado[1].X - pontos_quadrado[0].X;
angulo = Math.Atan2(deltay, deltax) * 180 / Math.PI;
angulo = Math.Round(angulo, 0);
You can force the angle to be in the range of 0 to 360 by adding 360 and taking the remainder modulo 360.
var deltay = pontos_quadrado[0].Y - pontos_quadrado[1].Y;
var deltax = pontos_quadrado[1].X - pontos_quadrado[0].X;
angulo = Math.Atan2(deltay, deltax) * 180 / Math.PI;
angulo = (angulo + 360) % 360; // note this line
angulo = Math.Round(angulo, 0);
Related
In android , I have drawn an arc based on startangle, sweepangle and radius. Let width be 400 and height be 500 as rectangle bounds in which radius is calculated as
var radius = Math.Min(Width,Height)/2;
Also if centre is calculated as
var x = (float)(Width * 0.5);
var y = (float)(Height * 0.5);
var centre = new PointF(x,y);
If above centre value is used, centre remains same for all start angle and sweepangle for rectangle. I need to change the centre if startangle and sweep angle changes
In the below image, rectangle bounds is 400,500 and the startangle is 0 and sweepangle is 360
If I change start angle to 180 and sweepangle to 180, centre remains same
I need the below image output,if I change startangle and sweepangle based on circle bounds, centre point should vary
I have done calculations for the above ,
private SystemPointF GetActualCenter(float x, float y, float radius)
{
SystemPointF actualCenter = new SystemPointF(x, y);
double startAngle1 = GetWrapAngle(StartAngle, -630, 630);
double endAngle1 = GetWrapAngle(EndAngle, -630, 630);
float[] regions = new float[] { -630, -540, -450, -360, -270, -180, -90, 0, 90, 180, 270, 360, 450, 540, 630 };
List<int> region = new List<int>();
if (startAngle1 < endAngle1)
{
for (int i = 0; i < regions.Length; i++)
{
if (regions[i] > startAngle1 && regions[i] < endAngle1)
region.Add((int)((regions[i] % 360) < 0 ? (regions[i] % 360) + 360 : (regions[i] % 360)));
}
}
else
{
for (int i = 0; i < regions.Length; i++)
{
if (regions[i] < startAngle1 && regions[i] > endAngle1)
region.Add((int)((regions[i] % 360) < 0 ? (regions[i] % 360) + 360 : (regions[i] % 360)));
}
}
double startRadian = 2 * Math.PI * (startAngle1) / 360;
double endRadian = 2 * Math.PI * (endAngle1) / 360;
SystemPointF startPoint = new SystemPointF((float)(x + radius * Math.Cos(startRadian)),
(float)(y + radius * Math.Sin(startRadian)));
SystemPointF endPoint = new SystemPointF((float)(x + radius * Math.Cos(endRadian)),
(float)(y + radius * Math.Sin(endRadian)));
switch (region.Count)
{
case 0:
float longX = Math.Abs(x - startPoint.X) > Math.Abs(x - endPoint.X) ? startPoint.X : endPoint.X;
float longY = Math.Abs(y - startPoint.Y) > Math.Abs(y - endPoint.Y) ? startPoint.Y : endPoint.Y;
SystemPointF midPoint = new SystemPointF(Math.Abs((x + longX)) / 2, Math.Abs((y + longY)) / 2);
actualCenter.X = x + (x - midPoint.X);
actualCenter.Y = y + (y - midPoint.Y);
break;
case 1:
SystemPointF point1 = new SystemPointF(), point2 = new SystemPointF();
float maxRadian = (float)(2 * Math.PI * region[0] / 360);
SystemPointF maxPoint = new SystemPointF((float)(x + radius * Math.Cos(maxRadian)),
(float)(y + radius * Math.Sin(maxRadian)));
switch (region[0])
{
case 270:
point1 = new SystemPointF(startPoint.X, maxPoint.Y);
point2 = new SystemPointF(endPoint.X, y);
break;
case 0:
case 360:
point1 = new SystemPointF(x, endPoint.Y);
point2 = new SystemPointF(maxPoint.X, startPoint.Y);
break;
case 90:
point1 = new SystemPointF(endPoint.X, y);
point2 = new SystemPointF(startPoint.X, maxPoint.Y);
break;
case 180:
point1 = new SystemPointF(maxPoint.X, startPoint.Y);
point2 = new SystemPointF(x, endPoint.Y);
break;
}
midPoint = new SystemPointF((point1.X + point2.X) / 2, (point1.Y + point2.Y) / 2);
actualCenter.X = x + ((x - midPoint.X) >= radius ? 0 : (x - midPoint.X));
actualCenter.Y = y + ((y - midPoint.Y) >= radius ? 0 : (y - midPoint.Y));
break;
case 2:
float minRadian = (float)(2 * Math.PI * region[0] / 360);
maxRadian = (float)(2 * Math.PI * (region[1]) / 360);
maxPoint = new SystemPointF((float)(x + radius * Math.Cos(maxRadian)),
(float)(y + radius * Math.Sin(maxRadian)));
SystemPointF minPoint = new SystemPointF((float)(x + radius * Math.Cos(minRadian)),
(float)(y + radius * Math.Sin(minRadian)));
if (region[0] == 0 && region[1] == 90 || region[0] == 180
&& region[1] == 270)
point1 = new SystemPointF(minPoint.X, maxPoint.Y);
else
point1 = new SystemPointF(maxPoint.X, minPoint.Y);
if (region[0] == 0 || region[0] == 180)
point2 = new SystemPointF(GetMinMaxValue(startPoint, endPoint, region[0]),
GetMinMaxValue(startPoint, endPoint, region[1]));
else
point2 = new SystemPointF(GetMinMaxValue(startPoint, endPoint, region[1]),
GetMinMaxValue(startPoint, endPoint, region[0]));
midPoint = new SystemPointF(Math.Abs(point1.X - point2.X) / 2 >= radius ? 0 : (point1.X + point2.X) / 2,
Math.Abs(point1.Y - point2.Y) / 2 >= radius ? 0 : (point1.Y + point2.Y) / 2);
actualCenter.X = x + (midPoint.X == 0 ? 0 : (x - midPoint.X) >= radius ? 0 : (x - midPoint.X));
actualCenter.Y = y + (midPoint.Y == 0 ? 0 : (y - midPoint.Y) >= radius ? 0 : (y - midPoint.Y));
break;
}
return actualCenter;
}
This works when startangle and sweep angle changed for all cases except the case startangle 179 and sweep angle changed to above 180. case 3 includes the region 180,270,0 . how to write calculations for regions 3.
Any help is really appreciated.
Thanks in advance
When you want to draw an object in the center of something you should do this :
Object.Point =
new Point((something.Width / 2) - (object.Widht /2) ,(something.Height / 2) - object.Height / 2));
I need to calculate Longitude and Latitude based on an old Longitude and Latitude, with distance and direction from that point.
From this link: http://www.movable-type.co.uk/scripts/latlong.html
I got these Formulae:
newLatitude = Math.Asin(Math.Sin(oldLatitude) * Math.Cos(distanceTravelled / earthRadius) + Math.Cos(oldLatitude) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(currentDirection));
newLongitude = oldLongitude + Math.Atan2(Math.Sin(currentDirection) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(oldLatitude), Math.Cos(distanceTravelled / earthRadius) - Math.Sin(oldLatitude) * Math.Sin(oldLatitude));
I have Acceleration e.g. 0.1 m/sec2
time travelled: Calculated from current time - start time.
Then I calculate the Distance travelled:
distanceTravelled = distanceTravelled/1000;
I also have movement of direction in degrees: e.g. 90 degree. (East)
But I am getting Error in new Latitude see-image:
Do I have to enter direction in Radian?
Distance in KM instead of meter?
Please help me get the right Latitude?
I found at the solution.
I was using degree and decimal of latitude and longitude in above formulae.
We have to use Radians
so convert Latitude, Longitude and Direction to Radians:
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
currentDirection = Math.PI * currentDirection / 180.0;
then convert new Longitude and latitude from Radians to Degree again
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
I have a ellipse with center point is at origin(0,0)
double dHalfwidthEllipse = 10;
double dHalfheightEllipse = 20;
double dAngle = 30;//Its in degree
PointF ptfPoint = new PointF();//To be found
PointF ptfOrigin = new PointF(0, 0);//Origin
Angle of point with respect to origin = 30 degree;
How to get the point now given the above values using C#?
See http://www.mathopenref.com/coordparamellipse.html
The parametric equation for an ellipse with center point at the origin, half width a and half height b is
x(t) = a cos t,
y(t) = b sin t
If you simply wish to draw an ellipse, given
double dHalfwidthEllipse = 10; // a
double dHalfheightEllipse = 20; // b
PointF ptfOrigin = new PointF(0, 0); // Origin
all you need is
PointF ptfPoint =
new PointF(ptfOrigin.X + dHalfwidthEllipse * Math.Cos(t * Math.Pi/180.0),
ptfOrigin.Y + dHalfheightEllipse * Math.Sin(t * Math.Pi/180.0) );
with t varying between -180 and 180 degrees.
However, as #Sebastian points out, if you wish to compute the exact intersection with a line through the center with angle theta, it gets a bit more complicated, since we need to find a t that corresponds to theta:
y(t)/x(t) = tan θ
b sin t / (a cos t) = tan θ
b/a tan t = tan θ
t= arctan(a tan θ / b) + n * π
So if we add
double dAngle = 30; // theta, between -90 and 90 degrees
We can compute t and ptfPoint:
double t = Math.Atan( dHalfwidthEllipse * Math.Tan( dAngle * Math.Pi/180.0 )
/ dHalfheightEllipse);
PointF ptfPoint =
new PointF(ptfOrigin.X + dHalfwidthEllipse * Math.Cos(t),
ptfOrigin.Y + dHalfheightEllipse * Math.Sin(t) );
This works fine for the area around the positive x axis.
For theta between 90 and 180 degrees, add π:
double t = Math.Atan( dHalfwidthEllipse * Math.Tan( dAngle * Math.Pi/180.0 )
/ dHalfheightEllipse) + Math.Pi;
For theta between -180 and -90 degrees, subtract π:
double t = Math.Atan( dHalfwidthEllipse * Math.Tan( dAngle * Math.Pi/180.0 )
/ dHalfheightEllipse) - Math.Pi;
As you get close to the y axis, x(t) approaches zero and the above calculation divides by zero, but there you can use the opposite:
x(t)/y(t) = tan (90 - θ)
a cos t / (b sin t) = tan (90 - θ)
a/b tan t = tan (90 - θ)
t = arctan ( b tan (90 - θ) / a ) + n * π
I am having some trouble trying to implement drawing an arc. Basically it's supposed to be drawn exactly like how you can draw a 3 point arc in AutoCAD. I can get the arc to draw with start and end angles from from -180 degrees to 360, but if I try to go more than -180, the arc flips around to +180 degrees. My problem is that I need the arc to continue when the angle passes -180. I have everything right in the code (I think) except for calculating the start and end angles. Thanks in advance for any help. Here is my code:
private void DrawArc()
{
//fyi linept is of type List<Point3D>();
Point3D currentPoint = (Point3D)GetPoints(e);
double rad;
Point3D center = GetCenterOfCircle(linept.ElementAt(0), linept.ElementAt(1), currentPoint, out rad);
PieSliceVisual3D circle = new PieSliceVisual3D();
circle.Center = center;
circle.OuterRadius = rad;
circle.InnerRadius = circle.OuterRadius + 3;
circle.StartAngle = (Math.Atan2(linept.ElementAt(0).Y - center.Y, linept.ElementAt(0).X - center.X) * 180 / Math.PI);
circle.EndAngle = (Math.Atan2(currentPoint.Y - center.Y, currentPoint.X - center.X) * 180 / Math.PI);
//I've also tried these next 4 lines to no avail
double startAngle = (Math.Atan2(linept.ElementAt(0).Y - center.Y, linept.ElementAt(0).X - center.X) * 180 / Math.PI);
circle.StartAngle = (startAngle > 0.0 ? startAngle : (360.0 + startAngle));
double endAngle = (Math.Atan2(currentPoint.Y - center.Y, currentPoint.X - center.X) * 180 / Math.PI);
circle.EndAngle = (endAngle > 0.0 ? endAngle : (360.0 + endAngle));
}
I have two functions that are intended to contain angles between (-180,180] and (-π,π]. The intent is that given any angle from -inf to +inf it will retain the equivalent angle in the intervals specified. For example the angle for 1550° is 110°.
public double WrapBetween180(double angle)
{
return angle - 360d * Math.Round(angle / 360d, MidpointRounding.AwayFromZero);
}
public double WrapBetweenPI(double angle)
{
const double twopi = 2d * Math.PI;
return angle - twopi * Math.Round(angle / twopi, MidpointRounding.AwayFromZero);
}
which yields the following results
WrapBetween180(-180) = -180
WrapBetween180( 180) = 180
WrapBetweenPI(-Math.PI) = Math.PI
WrapBetweenPI( Math.PI) = -Math.PI
none of which is what I want. What I wanted is:
WrapBetween180(-180) = 180
WrapBetween180( 180) = 180
WrapBetweenPI(-Math.PI) = Math.PI
WrapBetweenPI( Math.PI) = Math.PI
I tryied playing around with the rounding methods, but still cannot get the desired results. The problem is pronounced because sometimes the angles I deal with are only approximately close to -π or π and I am getting discontinuities it my results.
Any suggestions on how to best implement angle wrapping functions with non-inclusive low limit and inclusive high limits?
For the angle in degrees, if x is between -180 and 180, then 180 - x is between 0 and 360. What you want is equivalent to asking that 180 - x is between 0 (inclusive), and 360 (exclusive). So, as soon as 180 - x reaches 360, we want to add 360 to the angle. This gives us:
return angle + 360d * Math.Floor((180d - angle) / 360d);
Same thing for the angle in radians:
return angle + twopi * Math.Floor((Math.PI - angle) / twopi);
It does not address the rounding issue, but here is how I would to what you want to do :
private static double ConvertAngle(double angle)
{
bool isNegative = angle < 0;
if (isNegative)
angle *= -1;
angle = angle % 360;
if (isNegative)
angle = -1 * angle + 360;
if (angle > 180)
angle = (angle - 360);
return angle;
}
Note: This way supposes you want "behind" to be 180 degrees, not -180 degrees.
Isn't this a case for a modulo operation?
private double Wrap180(double value)
{
// exact rounding of corner values
if (value == 180) return 180.0;
if (value == -180) return 180.0;
// "shift" by 180 and use module, then shift back.
double wrapped = ((Math.Abs(value) + 180.0) % 360.0) - 180.0;
// handle negative values correctly
if (value < 0) return -wrapped;
return wrapped;
}
It passes this tests
Assert.AreEqual(170.0, wrap(-190.0));
Assert.AreEqual(180.0, wrap(-180.0));
Assert.AreEqual(-170.0, wrap(-170.0));
Assert.AreEqual(0.0, wrap(0.0));
Assert.AreEqual(10.0, wrap(10.0));
Assert.AreEqual(170.0, wrap(170.0));
Assert.AreEqual(180.0, wrap(180.0));
Assert.AreEqual(-170.0, wrap(190.0));