I have 2 Points a and b. Point a is inside the Bitmap but point b is not!
Show
here.
How can I calculate the x and y values of Point c?
I have tried this:
double ratio = Math.Abs(a.x - b.x) / Math.Abs(a.y - b.y);
b.x = bm.Width;
b.y = a.y + 1 / ratio * Math.Abs(a.x - b.x);
Graphics.FromImage(bm).DrawLine(new Pen(Color.Gray), (float)a.x, (float)a.y, (float)b.x, (float)b.y);
but it only worked with Points like
these
All other 3 Directions did not work :(
Thanks in advance!
First of all, you don't need coordinates inside the bounds of image to draw a line. You can use
Graphics.FromImage(bm).DrawLine(new Pen(Color.Gray), (float)a.x, (float)a.y, (float)b.x, (float)b.y);
without modifying b.
If you really want to find C coordinates, you have to compute segment crossing points between [A; B] and four edge segments [0:0 ; Width:0] [Width:0 ; Width:Height], [Width:Height ; 0:Height] and [0:Height ; 0:0].
Here is a function of mine (founded and adapted a few years ago...) that you can adapt (it will be easy to understand what is Segment struct) to check every segment for an intersection :
public static PointF? GetCrossingPoint(Segment segment1, Segment segment2)
{
PointF output = null;
double x1, x2, x3, x4, y1, y2, y3, y4;
x1 = segment1.StartPoint.X;
x2 = segment1.EndPoint.X;
x3 = segment2.StartPoint.X;
x4 = segment2.EndPoint.X;
y1 = segment1.StartPoint.Y;
y2 = segment1.EndPoint.Y;
y3 = segment2.StartPoint.Y;
y4 = segment2.EndPoint.Y;
double den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (den != 0)
{
double t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
double u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;
if (t > 0 && t < 1 && u > 0 && u < 1)
{
output = new PointF(x1 + t * (x2 - x1), y1 + t * (y2 - y1)));
}
}
return output;
}
Related
What kind of formula I need to use that I can determine that point P3 is negative side of P1-P2 line?
//x0, y0 is point P3 and x1,y1,x2,y2 is line P1-P2
static double ADist(double x0,double y0,double x1,double y1,double x2,double y2)
{
double Dx = (x2 - x1);
double Dy = (y2 - y1);
double numerator = (Dy * x0 - Dx * y0 - x1 * y2 + x2 * y1);
double denominator = Math.Sqrt(Dx * Dx + Dy * Dy);
double b2 = numerator / denominator;
double dx = x0 - x1;
double dy = y0 - y1;
double dxy = Math.Sqrt(dx * dx + dy * dy);
double a = Math.Sqrt(dxy * dxy - b2 * b2);
return a;
}
this is more math question (there is a stack for that if you don't know it : you may make a scalar product (or dot product) of vectors (P1-P2) and vector (P1-P3). If dot product is negative, so it is on "negative side" ( = 0 if the vectors are perpendicular).
public double ScalarProduct (Vector v1,Vector v2)
{
return v1.x*v2.x + v1.y*v2.y;
}
You just need to convert your points to vectors.
In your case, it would be (dx*Dx + dy*Dy)
Then to determinate the value of distance :
private double getDistance2(double x0,double y0,double x1,double y1,double x2,double y2)
{
double A = x2 * x2 + y2 * y2;
double B = 2 * (x1 - x0) * x2 + 2 * (y1 - y0) * y2;
double C = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
double s0 = -B / (2 * A);
double d2 = Math.Round((A * s0 * s0 + B * s0 + C), 3);
return Math.Sqrt(d2);
}
this method returns the distance between P3, and the line P1-P2.
Then you just need to calculate distance between P1 and P3, and using Pythagore you will find your distance.
.. 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?
I have locations of three points along the circle. pt1(x1, y1,z1), pt2(x2, y2, z2), pt3(x3, y3,z3). and want to find the radius of the circle. Already I have a function to compute radius in 2d space, which I am copying it here
public static double ComputeRadius(Location a, Location b, Location c)
{
double x1 = a.x;
double y1 = a.y;
double x2 = b.x;
double y2 = b.y;
double x3 = c.x;
double y3 = c.y;
double mr = (double)((y2 - y1) / (x2 - x1));
double mt = (double)((y3 - y2) / (x3 - x2));
double xc = (double)((mr * mt * (y3 - y1) + mr * (x2 + x3) - mt * (x1 + x2)) / (2 * (mr - mt)));
double yc = (double)((-1 / mr) * (xc - (x1 + x2) / 2) + (y1 + y2) / 2);
double d = (xc - x1) * (xc - x1) + (yc - y1) * (yc - y1);
return Math.Sqrt(d);
}
If you know the order of points pt1,pt2,pt3 along the circle then you can use graphical method:
cast normal axises from middle of each line segment in the plane of circle
your circle plane is defined by your 3 points. so the normal vector is
n = (pt2-pt1) x (pt3-pt2)
where the x is cross product so you have 2 lines (pt1,pt2) and (pt2,pt3) in black. The mid points are easy
p0=0.5*(pt1+pt2)
p1=0.5*(pt2+pt3)
the axis directions can be obtained also by cross product
dp0=(pt2-pt1) x n
dp1=(pt3-pt2) x n
so you got 2 axises:
pnt0(t)=p0+dp0*t
pnt1(u)=p1+dp1*u
Where t,u are scalar parameters t,u=(-inf,+inf) it is just position in axis from the starting mid point ...
the intersection is center of circle
So find the intersection of 2 axises and call it pt0
compute distance between center and any of your points
r=|pt1-pt0|
Sorry the image is for any curve (too lazy to repaint for circle as it is almost the same). If you do not know the order of points then the 2 points that are most distant to each other are the outer points ... In case they are equidistant the order does not matter any is OK
I have been trying to figure this out for sometime now..
The problem to solve..
Say I have 3 Points..
P1 ---------- P2, and P3 can be anywhere around P1 and P2
What is the formula to calculate so that P3 is interpolated onto the line between P1 and P2?
I need a formula that calculates new X,Y coordinates for P3 that falls on the line between P1 and P2..
My code as of so far..
public Point lerp(Point P0, Point P1, Point P)
{
double y1 = P0.Y + (P1.Y - P0.Y) * ((P.X - P0.X) / (P1.X - P0.X));
double x1 = P.X;
double y2 = P.Y;
double x2 = P0.X + (P1.X - P0.X) * ((P.Y - P0.Y) / (P1.Y - P0.Y));
return new Point((x1 + x2) / 2, (y1 + y2) / 2);
}
And my reference..
http://en.wikipedia.org/wiki/Linear_interpolation
The above code gets it close, but its slightly off...
Here is the converted javascript code from Corey Ogburn
public Point _pointOnLine(Point pt1, Point pt2, Point pt)
{
bool isValid = false;
var r = new Point(0, 0);
if (pt1.Y == pt2.Y && pt1.X == pt2.X) { pt1.Y -= 0.00001; }
var U = ((pt.Y - pt1.Y) * (pt2.Y - pt1.Y)) + ((pt.X - pt1.X) * (pt2.X - pt1.X));
var Udenom = Math.Pow(pt2.Y - pt1.Y, 2) + Math.Pow(pt2.X - pt1.X, 2);
U /= Udenom;
r.Y = pt1.Y + (U * (pt2.Y - pt1.Y));
r.X = pt1.X + (U * (pt2.X - pt1.X));
double minx, maxx, miny, maxy;
minx = Math.Min(pt1.X, pt2.X);
maxx = Math.Max(pt1.X, pt2.X);
miny = Math.Min(pt1.Y, pt2.Y);
maxy = Math.Max(pt1.Y, pt2.Y);
isValid = (r.X >= minx && r.X <= maxx) && (r.Y >= miny && r.Y <= maxy);
return isValid ? r : new Point();
}
Here's some javascript code we've used here at work (a GIS company) to figure out the closest point on a line the mouse is next to in a situation where a user wants to split the line by adding a vertex to it. Should be easy to move over to C#:
function _pointOnLine(line1, line2, pt) {
var isValid = false;
var r = new Microsoft.Maps.Location(0, 0);
if (line1.latitude == line2.latitude && line1.longitude == line2.longitude) line1.latitude -= 0.00001;
var U = ((pt.latitude - line1.latitude) * (line2.latitude - line1.latitude)) + ((pt.longitude - line1.longitude) * (line2.longitude - line1.longitude));
var Udenom = Math.pow(line2.latitude - line1.latitude, 2) + Math.pow(line2.longitude - line1.longitude, 2);
U /= Udenom;
r.latitude = line1.latitude + (U * (line2.latitude - line1.latitude));
r.longitude = line1.longitude + (U * (line2.longitude - line1.longitude));
var minx, maxx, miny, maxy;
minx = Math.min(line1.latitude, line2.latitude);
maxx = Math.max(line1.latitude, line2.latitude);
miny = Math.min(line1.longitude, line2.longitude);
maxy = Math.max(line1.longitude, line2.longitude);
isValid = (r.latitude >= minx && r.latitude <= maxx) && (r.longitude >= miny && r.longitude <= maxy);
return isValid ? r : null;
}
line1 is a point with a latitude and longitude to represent one of the endpoints of the line, equivalent to your P1. line2 is the other endpoint: P2. pt is your P3. This will return the point on the line that P3 is perpendicular through. If P3 is past either end of the line, this will return null which means that one of the two end points is the closest point to P3.
For clarity:
The problem is that you Point has integer values for X and Y and therefore you are doing integer division. Try to cast your values into float or double, do the calculations and then return them back to the integers.
Note that when you are doing this:
(P1.Y - P0.Y) * ((P.X - P0.X) / (P1.X - P0.X))
you are actualy loosing the precision since the result of 5/2 is 2, not 2.5 but when your values are real numbers then 5.0/2.0 is indeed 2.5.
You should try this:
double y1 = P0.Y + (double)(P1.Y - P0.Y) * ((double)(P.X - P0.X) / (double)(P1.X - P0.X));
double x1 = P.X; //these two are implicit casts
double y2 = P.Y;
double x2 = P0.X + (double)(P1.X - P0.X) * ((double)(P.Y - P0.Y) / (double)(P1.Y - P0.Y));
return new Point((x1 + x2) / 2.0, (y1 + y2) / 2.0); //put 2.0 for any case even though x1+x2 is `double`
Also, then you are converting from double to int, decimal part of the number is automatically cut off so for instance 3.87 will become 3. Than your last line should be more precise if you could use this:
return new Point((x1 + x2) / 2.0 + 0.5, (y1 + y2) / 2.0 + 0.5);
which will effectively round double values to the closer integer value.
EDIT:
But if you just want to find the point p3 on the line between the two points, than it is easier to use this approach:
public Point lerp(Point P0, Point P1)
{
double x = ((double)P0.X + P1.X)/2.0;
double y = (double)P0.Y + (double)(P1.Y - P0.Y) * ((double)(x - P0.X) / (double)(P1.X - P0.X));
return new Point(x + 0.5, y + 0.5);
}
This is an old question and I found the Corey Ogburn solution quite useful. But I thought it might be helpful for others to post a less "map" version of the javascript code - which I used in canvas drawing.
export const pointOnLine = (p0, p1, q) => {
// p0 and p1 define the line segment
// q is the reference point (aka mouse)
// returns point on the line closest to px
if (p0.x == p1.x && p0.y == p1.y) p0.x -= 0.00001;
const Unumer = ((q.x - p0.x) * (p1.x - p0.x)) + ((q.y - p0.y) * (p1.y - p0.y));
const Udenom = Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2);
const U = Unumer / Udenom;
const r = {
x: p0.x + (U * (p1.x - p0.x)),
y: p0.y + (U * (p1.y - p0.y))
}
const minx = Math.min(p0.x, p1.x);
const maxx = Math.max(p0.x, p1.x);
const miny = Math.min(p0.y, p1.y);
const maxy = Math.max(p0.y, p1.y);
const isValid = (r.x >= minx && r.x <= maxx) && (r.y >= miny && r.y <= maxy);
return isValid ? r : null;
}
This is Similar to a previous question I asked about the Cubic Bezier. I've got a start point, an endpoint, and a point that is meant to lie along a Quadratic Bezier. Given these three points I want to be able to draw a QuadraticBezierSegment in WPF, but I need the single ControlPoint value (in the QuadraticBezierSegment it's Point1) in order to draw it.
Is there a calculation or means whereby I can determine that value and thus draw my QuadraticBezier?
Thanks!
The best quadratic fit is simpler than the best cubic fit. Here's some code:
static class DrawingUtility
{
static void bez3pts1(double x0, double y0, double x3, double y3, double x2, double y2, out double x1, out double y1)
{
// find chord lengths
double c1 = Math.Sqrt((x3 - x0) * (x3 - x0) + (y3 - y0) * (y3 - y0));
double c2 = Math.Sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2));
// guess "best" t
double t = c1 / (c1 + c2);
// quadratic Bezier is B(t) = (1-t)^2*P0 + 2*t*(1-t)*P1 + t^2*P2
// solving gives P1 = [B(t) - (1-t)^2*P0 - t^2*P2] / [2*t*(1-t)] where P3 is B(t)
x1 = (x3 - (1 - t) * (1 - t) * x0 - t * t * x2) / (2 * t * (1 - t));
y1 = (y3 - (1 - t) * (1 - t) * y0 - t * t * y2) / (2 * t * (1 - t));
}
// pass in a PathFigure and it will append a QuadraticBezierSegment connecting the previous point to int1 and endPt
static public void QuadraticBezierFromIntersection(PathFigure path, Point startPt, Point int1, Point endPt)
{
double x1, y1;
bez3pts1(startPt.X, startPt.Y, int1.X, int1.Y, endPt.X, endPt.Y, out x1, out y1);
path.Segments.Add(new QuadraticBezierSegment { Point1 = new Point(x1, y1), Point2 = endPt } );
}
}