c# - saber - determine si los puntos yacen en una linea recta
¿Cómo puedo saber si un punto pertenece a una determinada línea? (11)
¿Podría ser más específico?
¿De qué lenguaje de programación estás hablando?
¿De qué entorno estás hablando?
¿De qué "líneas" estás hablando? ¿Texto? ¿Que punto? XY en la pantalla?
¿Cómo puedo saber si un punto pertenece a una determinada línea?
Los ejemplos son apreciados, si es posible.
Acabo de escribir una función que maneja algunos requisitos adicionales ya que uso esta comprobación en una aplicación de dibujo:
- Falta de claridad: debe haber un margen de error, ya que la función se utiliza para seleccionar líneas haciendo clic en ellas.
- La línea tiene un EndPoint y un StartPoint, no hay líneas infinitas.
- Debe manejar líneas rectas verticales y horizontales, (x2 - x1) == 0 causa división por cero en las otras respuestas.
private const double SELECTION_FUZZINESS = 3;
internal override bool ContainsPoint(Point point)
{
LineGeometry lineGeo = geometry as LineGeometry;
Point leftPoint;
Point rightPoint;
// Normalize start/end to left right to make the offset calc simpler.
if (lineGeo.StartPoint.X <= lineGeo.EndPoint.X)
{
leftPoint = lineGeo.StartPoint;
rightPoint = lineGeo.EndPoint;
}
else
{
leftPoint = lineGeo.EndPoint;
rightPoint = lineGeo.StartPoint;
}
// If point is out of bounds, no need to do further checks.
if (point.X + SELECTION_FUZZINESS < leftPoint.X || rightPoint.X < point.X - SELECTION_FUZZINESS)
return false;
else if (point.Y + SELECTION_FUZZINESS < Math.Min(leftPoint.Y, rightPoint.Y) || Math.Max(leftPoint.Y, rightPoint.Y) < point.Y - SELECTION_FUZZINESS)
return false;
double deltaX = rightPoint.X - leftPoint.X;
double deltaY = rightPoint.Y - leftPoint.Y;
// If the line is straight, the earlier boundary check is enough to determine that the point is on the line.
// Also prevents division by zero exceptions.
if (deltaX == 0 || deltaY == 0)
return true;
double slope = deltaY / deltaX;
double offset = leftPoint.Y - leftPoint.X * slope;
double calculatedY = point.X * slope + offset;
// Check calculated Y matches the points Y coord with some easing.
bool lineContains = point.Y - SELECTION_FUZZINESS <= calculatedY && calculatedY <= point.Y + SELECTION_FUZZINESS;
return lineContains;
}
Como alternativa al método de slope/y-intercept
, elegí este enfoque usando Math.Atan2
:
// as an extension method
public static bool Intersects(this Vector2 v, LineSegment s) {
// check from line segment start perspective
var reference = Math.Atan2(s.Start.Y - s.End.Y, s.Start.X - s.End.X);
var aTanTest = Math.Atan2(s.Start.Y - v.Y, s.Start.X - v.X);
// check from line segment end perspective
if (reference == aTanTest) {
reference = Math.Atan2(s.End.Y - s.Start.Y, s.End.X - s.Start.X);
aTanTest = Math.Atan2(s.End.Y - v.Y, s.End.X - v.X);
}
return reference == aTanTest;
}
La primera reference
verificación determina el ArcTan desde el punto de inicio del segmento de línea hasta su punto final. Luego, desde la perspectiva del punto de inicio, determinamos el ArcTan al vector v
.
Si esos valores son iguales, verificamos desde la perspectiva del punto final.
Simple y maneja horizontal, vertical y todo lo demás en el medio.
Creo que el Sr. Patrick McDonald puso la respuesta casi correcta y esta es la corrección de su respuesta:
public bool IsOnLine(Point endPoint1, Point endPoint2, Point checkPoint)
{
return (((double)checkPoint.Y - endPoint1.Y)) / ((double)(checkPoint.X - endPoint1.X))
== ((double)(endPoint2.Y - endPoint1.Y)) / ((double)(endPoint2.X - endPoint1.X));
}
y, por supuesto, hay muchas otras respuestas correctas, especialmente el Sr. Josh, pero encontré que esta es la mejor.
Gracias por evryone.
Dados dos puntos en la línea L0
y L1
y el punto para probar P
(L1 - L0) * (P - L0)
n = (P - L0) - --------------------- (L1 - L0)
(L1 - L0) * (L1 - L0)
La norma del vector n
es la distancia del punto P
desde la línea hasta L0
y L1
. Si esta distancia es cero o lo suficientemente pequeña (en el caso de errores de redondeo), el punto se encuentra en la línea.
El símbolo *
representa el producto punto.
Ejemplo
P = (5, 5)
L0 = (0, 10)
L1 = (20, -10)
L1 - L0 = (20, -20)
P - L0 = (5, -5)
(20, -20) * (5, -5)
n = (5, -5) - --------------------- (20, -20)
(20, -20) * (20, -20)
200
= (5, -5) - --- (20, -20)
800
= (5, -5) - (5, -5)
= (0, 0)
En la forma más simple, simplemente inserte las coordenadas en la ecuación de línea y verifique la igualdad.
Dado:
Point p (X=4, Y=5)
Line l (Slope=1, YIntersect=1)
Enchufe X e Y:
Y = Slope * X + YIntersect
=> 5 = 1 * 4 + 1
=> 5 = 5
Así que sí, el punto está en la línea.
Si sus líneas están representadas en forma (X1, Y1), (X2, Y2), entonces puede calcular la pendiente con:
Slope = (y1 - y2) / (x1-x2)
Y luego obtener el Y-Intersect con esto:
YIntersect = - Slope * X1 + Y1;
Edición: arreglé la intersección en Y (que ha sido X1 / Y1 ...)
Tendrás que comprobar que x1 - x2
no es 0
. Si es así, verificar si el punto está en la línea es simplemente una cuestión de verificar si el valor de Y en tu punto es igual a x1
o x2
. Además, verifique que la X del punto no sea ''x1'' o ''x2''.
La ecuación de la línea es:
y = mx + c
Entonces, un punto (a, b) está en esta línea si satisface esta ecuación, es decir, b = ma + c
La mejor manera de determinar si un punto R = (rx, ry) se encuentra en la línea que conecta los puntos P = (px, py) y Q = (qx, qy) es verificar si el determinante de la matriz
{{qx - px, qy - py}, {rx - px, ry - py}},
es decir, (qx - px) * (ry - py) - (qy - py) * (rx - px) está cerca de 0. Esta solución tiene varias ventajas relacionadas con las demás: primero, no requiere un caso especial para líneas verticales , segundo, no se divide (generalmente una operación lenta), tercero, no desencadena un mal comportamiento de punto flotante cuando la línea es casi, pero no del todo vertical.
Si tienes una línea definida por sus puntos finales
PointF pt1, pt2;
y tienes un punto que quieres comprobar
PointF checkPoint;
entonces podría definir una función de la siguiente manera:
bool IsOnLine(PointF endPoint1, PointF endPoint2, PointF checkPoint)
{
return (checkPoint.Y - endPoint1.Y) / (endPoint2.Y - endPoint1.Y)
== (checkPoint.X - endPoint1.X) / (endPoint2.X - endPoint1.X);
}
y llámalo como sigue:
if (IsOnLine(pt1, pt2, checkPoint) {
// Is on line
}
Sin embargo, tendrá que verificar la división por cero.
Una línea 2D se representa generalmente usando una ecuación en dos variables x e y aquí es una ecuación bien conocida
Ahora imagine que su línea GDI + se dibuja de (0,0) a (100, 100), luego el valor de m = (0-100) / (0-100) = 1, por lo tanto, la ecuación para su línea es y-0 = 1 * (x-0) => y = x
Ahora que tenemos una ecuación para la línea en cuestión, es fácil de probar si un punto pertenece a esta línea. Un punto dado (x3, y3) pertenece a esta línea si satisface la ecuación de línea cuando sustituyas x = x3 e y = y3. Por ejemplo, el punto (10, 10) pertenece a esta línea ya que 10 = 10 pero (10,12) no pertenece a esta línea ya que 12! = 10.
NOTA: Para una línea vertical, el valor de la pendiente (m) es infinito, pero para este caso especial puede usar la ecuación para una línea vertical directamente x = c donde c = x1 = x2.
Aunque tengo que decir que no estoy seguro de si esta es la forma más eficiente de hacerlo. Intentaré encontrar una manera más eficiente cuando tenga más tiempo disponible.
Espero que esto ayude.
y = m * x + c
Esta es la ecuación de una recta. x y y son las coordenadas. Cada línea se caracteriza por su pendiente (m) y donde intersecta el eje y (c).
Por lo tanto, dado m & c para una línea, puedes determinar si el punto (x1, y1) está en la línea verificando si la ecuación se cumple para x = x1 y y = y1