2009-05-25 25 views

Respuesta

28

En la forma más simple , simplemente conecte 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í, es el punto en la línea.

Si las líneas están representados en (X1, Y1), (X2 Y2) forma, a continuación, se puede calcular la pendiente con:

Slope = (y1 - y2)/(x1-x2) 

Y a continuación, obtener la Y-Intersección con esto:

YIntersect = - Slope * X1 + Y1; 

Edición: he arreglado el Y-Intersección (que ha sido X1/Y1 ...)

Vas a tener que comprobar que no es x1 - x20. Si es así, entonces verificar si el punto está en la línea es una simple cuestión de verificar si el valor Y en tu punto es igual a x1 o x2. Además, verifique que la X del punto no sea 'x1' o 'x2'.

+0

¿Qué biblioteca de idiomas es esta? –

+2

No es, es solo un pseudocódigo. – Eclipse

+23

Ni siquiera es pseudocódigo: solo son matemáticos. – configurator

0

¿Podría ser más específico?

¿De qué lenguaje de programación está hablando?

¿De qué entorno está hablando?

¿De qué "líneas" está hablando? ¿Texto? ¿Que punto? XY en la pantalla?

+1

Disculpe, debería haber comentado sobre la pregunta original – joshcomley

+5

Aún puede eliminar su publicación y publicar el comentario:) –

4
y = m * x + c 

Esta es la ecuación de una línea. x & y son las coordenadas. Cada línea se caracteriza por su pendiente (m) y donde se cruza con el eje y (c).

Así dado m & c para una línea, se puede determinar si el punto (x1, y1) está en la línea mediante la comprobación de si la ecuación es válida para x = x1 y y = y1

+0

Excepto que esta ecuación no puede describir una línea vertical, y salvo que no mencionó la posibilidad de la la línea tiene grosor distinto de cero. – ChrisW

+4

Una línea no tiene grosor. –

+1

"Una línea no tiene grosor": lo hace cuando se dibuja en una pantalla (es decir, cuando se trata de una cuestión de programación): su grosor es de al menos un píxel y puede ser mayor. – ChrisW

1

ecuación de la recta es:

y = mx + c 

lo tanto, un punto (a, b) está en esta línea si satisface esta ecuación es decirb = ma + c

línea
2

A 2D se representa generalmente mediante una ecuación en dos variables X e Y aquí es una ecuación bien conocida

y-y1 = (y1-y2)/(x1-x2) (x-x1)

Ahora imaginar su GDI + línea se dibuja a partir de (0,0) a (100, 100) entonces 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 sustituyes x = x3 ey = 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 desde 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. Trataré de encontrar una forma más eficiente cuando tenga más tiempo disponible.

Espero que esto ayude.

3

Si usted tiene una línea definida por sus puntos finales

PointF pt1, pt2; 

y tiene un punto que desea comprobar

PointF checkPoint; 

entonces se 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ámelo de la siguiente manera:

if (IsOnLine(pt1, pt2, checkPoint) { 
    // Is on line 
} 

Sin embargo, deberá verificar la división por cero.

+0

Muchas gracias mucho. –

+3

Esto no puede ser correcto ... Dado que las coordenadas de punto son entradas, tendría (una pérdida de precisión crítica) cuando el punto de comprobación está cerca de endPoint1 y lejos de endPoint2. Quizás si lo cambiaras a decimal o doble funcionaría bien para ambos lados, pero aún no confiaría en la exactitud de este equasion. – configurator

+0

Fair Point (juego de palabras intencionado), las cambió a PointF –

5

Dado dos puntos en la línea L0 y L1 y el punto a prueba P.

   (L1 - L0) * (P - L0) 
n = (P - L0) - --------------------- (L1 - L0) 
       (L1 - L0) * (L1 - L0) 

La norma del vector n es la distancia del punto de P desde la línea a través de 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 escalar.

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) 
+3

+1 por mencionar errores de redondeo. Usar la igualdad exacta en la aritmética de coma flotante hará que las otras soluciones propuestas fallen en muchos casos. No estoy seguro de la solidez numérica del algoritmo propuesto, pero la solidez numérica es lo suficientemente complicada como para que, si la precisión es importante, sea aconsejable consultar la literatura científica sobre el tema. O al menos use una biblioteca donde es probable que el autor haya realizado la investigación. –

+0

No creo que su ejemplo sea correcto, porque después de algunas transformaciones 'n = (p - L0) - (p - L0)' y en todos los casos que tenga, obtendrá siempre 'n = (0, 0)' . – nenito

18

La mejor manera de determinar si un punto R = (rx, ry) se encuentra en la línea que une los puntos P = (px, py) y Q = (qx, qy) es comprobar si el determinante de la matriz

{{qx - px, qy - py}, {rx - px, ry - py}}, 

a saber (qx - px) * (RY - py) - (QY - py) * (rx - px) está cerca de 0.Esta solución tiene varias ventajas relacionadas con las otras publicadas: primero, no requiere ningún caso especial para las líneas verticales, en segundo lugar, no se divide (generalmente una operación lenta), en tercer lugar, no desencadena un comportamiento de coma flotante malo cuando el la línea es casi, pero no completamente vertical.

+0

Para una línea de 0,0 a 10,10 con un punto 5.1, 5.1, el determinante es cero. Pero el punto no está en la línea. – Andy

+0

¿qué significa exactamente "cerca de 0"? – Leggy7

+0

Esta es una respuesta mucho mejor que la "aceptada". Lo único que falta es una definición de "cerca de". Esto debe entenderse en el contexto de los números que se restan: dado que hay 5 sustracciones, hay 5 oportunidades para "pérdida significativa de precisión", lo que significa que en realidad es algo difícil colocar una buena especificación "cerca de". – Floris

5

creo 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 en especial Mr.Josh, pero he encontrado que este es el el mejor.

Gracias por evryone.

+0

Le da un div por cero si checkPoint.x == endPoint.x o si los puntos finales tienen el mismo valor x – ThiefMaster

22

acabo de escribieron una función que se ocupa de algunos requisitos adicionales ya que utilizar este control en una aplicación de dibujo:

  • Tolerancia - Tiene que haber un cierto margen de error, ya que la función se utiliza para seleccionar líneas haciendo clic en ellos.
  • La línea tiene un EndPoint y un StartPoint, no hay líneas infinitas.
  • Debe manejar líneas verticales y horizontales rectas, (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;    
} 
+5

¿Por qué no es esta la respuesta aceptada? Todos los demás son solo matemáticas y bla. Este es un mundo real, una función endurecida por la batalla y debería ser el preferido. Quiero decir que esto es StackOverflow por los dioses, no por MathOverflow. –

+0

esta es la mejor respuesta gracias a que funciona. pero ¿cuál sería el mejor valor para SELECTION_FUZZINESS? –

0

Como una alternativa al método slope/y-intercept, he elegido este enfoque utilizando 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 comprobación reference determina el arctan desde el punto de inicio del segmento de línea a es End- punto. Luego, desde la perspectiva del punto de inicio, determinamos el arco al vector v.

Si esos valores son iguales, lo comprobamos desde la perspectiva del punto final.

Simple y maneja horizontal, vertical y todo lo demás.

Cuestiones relacionadas