Value of expression doesn't change - c#

I'm trying to move the cursor using linear interpolation. My problem is that the value of y0 + (y1 - y0) * ((x - x0) / (x1 - x0)) never changes despite the fact that x changes. I can't figure out what I'm missing.
public void MoveCursor(int x1, int y1)
{
int y, y0, x, x0;
y0 = Cursor.Position.Y;
x0 = Cursor.Position.X;
for (x = x0; x > x1; x--)
{
y = y0 + (y1 - y0) * ((x - x0) / (x1 - x0));
this.Cursor = new Cursor(Cursor.Current.Handle);
Cursor.Position = new Point(x,y);
Cursor.Clip = new Rectangle(this.Location, this.Size);
Console.Out.WriteLine("X:{0} Y:{1}", x, y);
System.Threading.Thread.Sleep(100);
}
}

Try using floats:
y = (int)(y0 + (float)(y1 - y0) * (x - x0) / (x1 - x0));

Related

Determining if a point is inside a circle on an isometric map

I'm trying to figure out a way to check if a certain point is inside or outside a circle on an isometric map. I'm currently using the following method to draw the circle:
public static List<Coords> GetBrushCircleCoords(int x0, int y0, int radius)
{
List<Coords> coords = new List<Coords>();
int x = radius;
int y = 0;
int err = 0;
while (x >= y)
{
coords.Add(new Coords(x0 + x, y0 + y));
coords.Add(new Coords(x0 + y, y0 + x));
coords.Add(new Coords(x0 - y, y0 + x));
coords.Add(new Coords(x0 - x, y0 + y));
coords.Add(new Coords(x0 - x, y0 - y));
coords.Add(new Coords(x0 - y, y0 - x));
coords.Add(new Coords(x0 + y, y0 - x));
coords.Add(new Coords(x0 + x, y0 - y));
y += 1;
err += 1 + 2 * y;
if (2 * (err - x) + 1 > 0)
{
x -= 1;
err += 1 - 2 * x;
}
}
return coords;
}
And the approach I'm trying to determine if the point is inside the circle is basically taking the desired point, determine its distance to the center and checking if it's bigger than the radius with the following method:
public static int GetDistance(Coords _from, Coords _to)
{
return Math.Max(Math.Abs(_from.X - _to.X), Math.Abs(_from.Y - _to.Y));
}
However, it seems the GetDistance method isn't the best way to calculate this as the distance calculated by it is fairly shorter than the one used on the GetBrushCircleCoords. What would be the correct way of determining if a certain point is inside/outside this circle?
On a Euclidean plane distance function (metric) is given by the Pythagorean Theorem. So shouldn't GetDistance be something like:
public static double GetDistance(Coords from, Coords to)
{
//a^2 + b^2 = c^2
var a = from.X - to.X;
var b = from.Y - to.Y;
var c = Math.Sqrt(a*a+b*b);
return c;
}

Given bounding rectangle, starting angle, and sweep angle, how to determine points of the arc endpoints

Given a bounding rectangle, starting angle and the sweep angle, how do I determine the points of each end of the arc?
private void myPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rc = new Rectangle(242, 299, 200, 300);
Pen penRed = new Pen(Color.Red, 1);
g.DrawArc(penRed, rc, 18, -108);
// TODO - Determine Point of each end of arc
// Point pt1 = ???
// Point pt2 = ???
}
Using the equation of an ellipse from this excellent Mathematics answer We can calculate the start and end points of your ellipse, given the start angle and sweep.
First, we need the center of the bounding box, so we know how to shift the coordinates. That's simply
Rectangle rc = new Rectangle(242, 299, 200, 300);
int cX = (rc.Left + rc.Right) / 2;
int cY = (rc.Bottom + rc.Top) / 2;
// For debugging purposes, let's mark that point.
g.FillRectangle(Brushes.Yellow, Rectangle.FromLTRB(cX - 3, cY - 3, cX + 3, cY + 3));
We then need to convert the angles from degrees into radians, and change the clockwise angle to a counter-clockwise angle like so:
double minTheta = (Math.PI / 180) * (360 - start);
double maxTheta = (Math.PI / 180) * (360 - (start + sweep));
We'll also define 2 helper functions, the first to normalize an angle (map arbitrary angles into the range 0-360) and the second to adjust the calculated (x, y) coordinates into the correct quadrant. (Given that positive y is actually down on the form)
public double NormalizeAngle(double angle)
{
while (angle >= 360) angle -= 360;
while (angle < 0) angle += 360;
return angle;
}
public void AdjustCoordinatesForAngle(double angle, ref double x, ref double y)
{
if (angle > 0 && angle <= 90)
{
x *= 1;
y *= 1;
}
else if (angle >= 90 && angle < 180)
{
x *= -1;
y *= 1;
}
else if (angle >= 180 && angle < 270)
{
x *= -1;
y *= -1;
}
else if (angle >= 270 && angle < 360)
{
x *= 1;
y *= -1;
}
}
We now have enough information to calculate the start and end points.
double minTheta = (Math.PI / 180) * (360 - start);
double maxTheta = (Math.PI / 180) * (360 - (start + sweep));
double a = width / 2.0;
double b = height / 2.0;
double denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(minTheta), 2);
denom = denom / Math.Pow(b, 2);
denom = Math.Sqrt(denom + 1);
double x = Math.Abs(a / denom);
double y = Math.Abs((a * Math.Tan(minTheta)) / denom);
start = NormalizeAngle(start);
this.AdjustCoordinatesForAngle(start, ref x, ref y);
Those coordinates are relative to the bounding box's center, so we offset it using the center point we calculated above:
x += cX;
y += cY;
We can now draw the point:
g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6));
All together the paint function looks like this:
private void myPaint(object sender, PaintEventArgs e)
{
double start = 18;
double sweep = -108;
Graphics g = e.Graphics;
g.Clear(Color.Black);
Rectangle rc = new Rectangle(200, 10, 200, 300);
int cX = (rc.Left + rc.Right) / 2;
int cY = (rc.Bottom + rc.Top) / 2;
g.FillRectangle(Brushes.Yellow, Rectangle.FromLTRB(cX - 3, cY - 3, cX + 3, cY + 3));
int width = rc.Width;
int height = rc.Height;
if (start >= 360) start -= 360;
double minTheta = (Math.PI / 180) * (360 - start);
double maxTheta = (Math.PI / 180) * (360 - (start + sweep));
double a = width / 2.0;
double b = height / 2.0;
double denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(minTheta), 2);
denom = denom / Math.Pow(b, 2);
denom = Math.Sqrt(denom + 1);
double x = Math.Abs(a / denom);
double y = Math.Abs((a * Math.Tan(minTheta)) / denom);
start = NormalizeAngle(start);
this.AdjustCoordinatesForAngle(start, ref x, ref y);
x += cX;
y += cY;
g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6));
denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(maxTheta), 2);
denom = denom / Math.Pow(b, 2);
denom = Math.Sqrt(denom + 1);
x = Math.Abs(a / denom);
y = Math.Abs((a * Math.Tan(maxTheta)) / denom);
double endAngle = (start + sweep);
endAngle = NormalizeAngle(endAngle);
this.AdjustCoordinatesForAngle(endAngle, ref x, ref y);
x += cX;
y += cY;
g.FillRectangle(Brushes.Blue, new Rectangle((int)x - 3, (int)y - 3, 6, 6));
Pen penRed = new Pen(Color.Red, 1);
g.DrawRectangle(Pens.Green, rc);
g.DrawArc(penRed, rc, (float)start, (float)sweep);
}
I painted the window background black to make the boxes and lines stand out better, and I left in some additional drawing elements, so it is easier to see what's happening in the calculations above.
Placing the code into a form, and associating with the form's paint event produces this result:
One final note, due to rounding, the start and end points may be off by a pixel or two. If you want more accuracy, you'd have to draw the arc yourself.

Iteration of an Unknown Number in C#

Let's say I have a formula which contains a variable that user has to guess. But at the end of formula, that variable is calculated again and if the first one and second one doesn't match, formulation has to be solved again with a new value. Shortly assume that I have a formula like this (mine is much more complex and longer than this);
double y1 = Convert.ToDouble(txtboxPredefinedY.Text);
double x, z, Ort;
double y2 = 0;
while (y1 != y2)
{
x = (Math.Pow(y1, 2)) + 10;
z = (y1 - 2) / 3;
y2 = (x / z);
Ort = (y2 + y1)/2;
y1 = Ort;
if (y1 == y2)
break;
}
txtboxResult.Text = r.ToString();
So the y1 variable I defined first has to match the last variable y2. To achieve this I calculate the whole formula and find a new y1, re-calculate formula.
I want to define a y1 value and let the application correct me. For example this code should return me a value of 3.3158. If first input is 3.3158 than y1 becomes equal to y2.
I couldn't use while iteration correctly. How can I fix this? Or maybe, how should I build my while block to give me exact equation?
When working with Double you should compare with tolerance:
double y1 = Convert.ToDouble(txtboxPredefinedY.Text);
double x, z, Ort;
double y2 = 0;
double tolerance = 0.001;
while (Math.Abs(y1 - y2) >= tolerance) {
x = (Math.Pow(y1, 2)) + 10;
z = (y1 - 2) / 3;
y2 = (x / z);
Ort = (y2 + y1)/2;
y1 = Ort;
}
Comparisons like y1 != y2 as well as y1 == y2 may fail because of round-up errors.

representing 3d objects asp.net c# using a drawing lib

I'm currently working on a 3d bin packing problem to which I want to represent my results as an image.
I have the results stored as a list of packing objects as follows
public class LoadedPackage
{
private PackingObject packingObject;
private int xloc, yloc, zloc;
private bool flipped = false;
}
public class PackingObject
{
private int ID, checkerMaster, height, width, depth, number;
}
I want to use the xloc,yloc,zloc and dimensions to draw the packages 1 at a time to build up an image. Is there some sort of image library way of doing this or am I going to be forced to use an openGL solution which seems a little overkill to me for just a simple image.
I was thinking of maybe using a isometric method using 2d gdi lib
In the end I opted for an isometric approach and added a method to each package to convert itself from a 3d coordinates over to isometric. I hope the following code helps someone else with a similar predicament!
An Isometric cube has 6 points so I return an array of 6 points. In reality i use 3 sub methods to return the 3 isometric polygons for the GDI lib to process but for the sake of this answer I'll just post the more general 6 point method.
public PointF[] convertCoords()
{
float x;
float y;
PointF p;
PointF[] pointFs = new PointF[7];
int x1 = 0;
int y1 = 0;
int z1 = 0;
double rads = Helpers.DegreeToRadian(30);
//point 0 in iso
x = ((float)Math.Cos(rads) * xloc) + ((float)Math.Cos(rads) * yloc);
y = ((float)Math.Sin(rads) * yloc) + zloc - ((float)Math.Sin(rads) * xloc);
y = (-y) + 250;
p = new PointF(x,y);
pointFs[0] = new PointF(p.X,p.Y);
//point 1 in iso
x1 = xloc + packingObject.Depth;
y1 = yloc;
z1 = zloc;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = ((float)Math.Sin(rads) * y1) + z1 - ((float)Math.Sin(rads) * x1);
y = (-y) + 250;
p = new PointF(x, y);
pointFs[1] = new PointF(p.X, p.Y);
//point 2 in iso
x1 = xloc + packingObject.Depth;
y1 = yloc;
z1 = zloc + packingObject.Height;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = (-((float)Math.Sin(rads) * x1)) + ((float)Math.Sin(rads) * y1) + z1;
y = (-y) + 250;
p = new PointF(x, y);
pointFs[2] = new PointF(p.X, p.Y);
//point 3 in iso
x1 = xloc;
y1 = yloc;
z1 = zloc + packingObject.Height;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = (-((float)Math.Sin(rads) * x1)) + ((float)Math.Sin(rads) * y1) + z1;
y = (-y) + 250;
p = new PointF(x, y);
pointFs[3] = new PointF(p.X, p.Y);
//point 4 in iso
x1 = xloc;
y1 = yloc + packingObject.Width;
z1 = zloc + packingObject.Height;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = (-((float)Math.Sin(rads) * x1)) + ((float)Math.Sin(rads) * y1) + z1;
y = (-y) + 250;
p = new PointF(x, y);
pointFs[4] = new PointF(p.X, p.Y);
//point 5 in iso
x1 = xloc + packingObject.Depth;
y1 = yloc + packingObject.Width;
z1 = zloc + packingObject.Height;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = (-((float)Math.Sin(rads) * x1)) + ((float)Math.Sin(rads) * y1) + z1;
y = (-y) + 250;
p = new PointF(x, y);
pointFs[5] = new PointF(p.X, p.Y);
//point 6 in iso
x1 = xloc + packingObject.Depth;
y1 = yloc + packingObject.Width;
z1 = zloc;
x = ((float)Math.Cos(rads) * x1) + ((float)Math.Cos(rads) * y1);
y = (-((float)Math.Sin(rads) * x1)) + ((float)Math.Sin(rads) * y1) + z1;
y = (-y) + 250;
p = new PointF(x, y);
pointFs[6] = new PointF(p.X, p.Y);
return pointFs;
}

Find if point lies on line segment

I have line segment defined by these two points: A(x1,y1,z1) and B(x2,y2,z2). I have point p(x,y,z). How can I check if the point lies on the line segment?
Find the distance of point P from both the line end points A, B. If AB = AP + PB, then P lies on the line segment AB.
AB = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
AP = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1));
PB = sqrt((x2-x)*(x2-x)+(y2-y)*(y2-y)+(z2-z)*(z2-z));
if(AB == AP + PB)
return true;
If the point is on the line then:
(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1) = (z - z1) / (z2 - z1)
Calculate all three values, and if they are the same (to some degree of tolerance), your point is on the line.
To test if the point is in the segment, not just on the line, you can check that
x1 < x < x2, assuming x1 < x2, or
y1 < y < y2, assuming y1 < y2, or
z1 < z < z2, assuming z1 < z2
First take the cross product of AB and AP. If they are colinear, then it will be 0.
At this point, it could still be on the greater line extending past B or before A, so then I think you should be able to just check if pz is between az and bz.
This appears to be a duplicate, actually, and as one of the answers mentions, it is in Beautiful Code.
in case if someone looks for inline version:
public static bool PointOnLine2D (this Vector2 p, Vector2 a, Vector2 b, float t = 1E-03f)
{
// ensure points are collinear
var zero = (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y);
if (zero > t || zero < -t) return false;
// check if x-coordinates are not equal
if (a.x - b.x > t || b.x - a.x > t)
// ensure x is between a.x & b.x (use tolerance)
return a.x > b.x
? p.x + t > b.x && p.x - t < a.x
: p.x + t > a.x && p.x - t < b.x;
// ensure y is between a.y & b.y (use tolerance)
return a.y > b.y
? p.y + t > b.y && p.y - t < a.y
: p.y + t > a.y && p.y - t < b.y;
}
Your segment is best defined by parametric equation
for all points on your segment, following equation holds:
x = x1 + (x2 - x1) * p
y = y1 + (y2 - y1) * p
z = z1 + (z2 - z1) * p
Where p is a number in [0;1]
So, if there is a p such that your point coordinates satisfy those
3 equations, your point is on this line. And it p is between 0 and 1 -
it is also on line segment
Here's some C# code for the 2D case:
public static bool PointOnLineSegment(PointD pt1, PointD pt2, PointD pt, double epsilon = 0.001)
{
if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon ||
Math.Min(pt1.X, pt2.X) - pt.X > epsilon ||
pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon ||
Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
return false;
if (Math.Abs(pt2.X - pt1.X) < epsilon)
return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;
double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);
return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
}
Or let the dotnet do the heavy lifting for you if using visual studio use a GraphicsPath
this will also allow you to add tolerances for if just clicked outside the line.
using (Drawing2D.GraphicsPath gp = new Drawing2D.GraphicsPath())
{
gp.AddLine(new Point(x1, y1), new Point(x2, y2));
// Make the line as wide as needed (make this larger to allow clicking slightly outside the line)
using (Pen objPen = new Pen(Color.Black, 6))
{
gp.Widen(objPen);
}
if (gp.IsVisible(Mouse.x, Mouse.y))
{
// The line was clicked
}
}
The cross product (B - A) × (p - A) should be much much shorter than B - A. Ideally, the cross product is zero, but that's unlikely on finite-precision floating-point hardware.
I use this to calculate the distance AB between points a and b.
static void Main(string[] args)
{
double AB = segment(0, 1, 0, 4);
Console.WriteLine("Length of segment AB: {0}",AB);
}
static double segment (int ax,int ay, int bx, int by)
{
Vector a = new Vector(ax,ay);
Vector b = new Vector(bx,by);
Vector c = (a & b);
return Math.Sqrt(c.X + c.Y);
}
struct Vector
{
public readonly float X;
public readonly float Y;
public Vector(float x, float y)
{
this.X = x;
this.Y = y;
}
public static Vector operator &(Vector a, Vector b)
{
return new Vector((b.X - a.X) * (b.X - a.X), (b.Y - a.Y) * (b.Y - a.Y));
}
}
based on Calculate a point along the line A-B at a given distance from A
Let V1 be the vector (B-A), and V2 = (p-A), normalize both V1 and V2.
If V1==(-V2) then the point p is on the line, but preceding A, & therefore not in the segment.
If V1==V2 the point p is on the line. Get the length of (p-A) and check if this is less-or-equal to length of (B-A), if so the point is on the segment, else it is past B.
This is my code which can run in WPF
public static class Math2DExtensions
{
public static bool CheckIsPointOnLineSegment(Point point, Line line, double epsilon = 0.1)
{
// Thank you #Rob Agar
// (x - x1) / (x2 - x1) = (y - y1) / (y2 - y1)
// x1 < x < x2, assuming x1 < x2
// y1 < y < y2, assuming y1 < y2
var minX = Math.Min(line.APoint.X, line.BPoint.X);
var maxX = Math.Max(line.APoint.X, line.BPoint.X);
var minY = Math.Min(line.APoint.Y, line.BPoint.Y);
var maxY = Math.Max(line.APoint.Y, line.BPoint.Y);
if (!(minX <= point.X) || !(point.X <= maxX) || !(minY <= point.Y) || !(point.Y <= maxY))
{
return false;
}
if (Math.Abs(line.APoint.X - line.BPoint.X) < epsilon)
{
return Math.Abs(line.APoint.X - point.X) < epsilon || Math.Abs(line.BPoint.X - point.X) < epsilon;
}
if (Math.Abs(line.APoint.Y - line.BPoint.Y) < epsilon)
{
return Math.Abs(line.APoint.Y - point.Y) < epsilon || Math.Abs(line.BPoint.Y - point.Y) < epsilon;
}
if (Math.Abs((point.X - line.APoint.X) / (line.BPoint.X - line.APoint.X) - (point.Y - line.APoint.Y) / (line.BPoint.Y - line.APoint.Y)) < epsilon)
{
return true;
}
else
{
return false;
}
}
}
public record Line
{
public Point APoint { get; init; }
public Point BPoint { get; init; }
}
My code is in github
Thank you #Rob Agar and #MetaMapper
You could check if the point lies between the two planes defined by point1 and point2 and the line direction:
/// Returns the closest point from #a point to this line on this line.
vector3 <Type>
line3d <Type>::closest_point (const vector3 <Type> & point) const
{
return this -> point () + direction () * dot (point - this -> point (), direction ());
}
/// Returns true if #a point lies between point1 and point2.
template <class Type>
bool
line_segment3 <Type>::is_between (const vector3 <Type> & point) const
{
const auto closest = line () .closest_point (point);
return abs ((closest - point0 ()) + (closest - point1 ())) <= abs (point0 () - point1 ());
}

Categories