Estoy buscando una solución mejor que los 2 algoritmos que he escrito actualmente (en C) para verificar si un punto en la circunferencia de un círculo se encuentra en el arco corto creado < em> entre otros dos puntos en el mismo círculo.

Por ejemplo: p1 = 358 grados, p2 = 1 grado en la circunferencia, y necesito saber si p3 = .5 grados se encuentra entre p1 y p2 (la solución debería considerarlo como tal).

Aclaración : para este caso de uso, solo verifico "entremedio" si p1! = p3 o p2! = p3. En esos casos extremadamente raros (números de coma flotante) ya tengo la respuesta que necesito.

Este problema se complica por el hecho de que a veces el movimiento retrógrado significa p2

El caso de uso del mundo real es determinar cuándo continuar y aplicar un algoritmo de interpolación para encontrar el tiempo exacto de conjunción (ocultación) entre dos cuerpos en el espacio, uno representado por p1 y p2 en dos tiempos conocidos y un objeto diferente en p3.

1
Cliff Ribaudo 11 may. 2017 a las 20:07

3 respuestas

La mejor respuesta
bool within_arc(double p1, double p2, double p3) {
  double cw_p1_to_p2, cw_p1_to_p3;
  cw_p1_to_p2 = fmod(p2 - p1 + 360, 360);
  cw_p1_to_p3 = fmod(p3 - p1 + 360, 360);

  return (cw_p1_to_p2 <= 180) != (cw_p1_to_p3 > cw_p1_to_p2);
}

Actualización: Esta solución no maneja consistentemente ciertos casos límite, como cuando p3 es exactamente igual a uno de los otros puntos o cuando p1 y p2 están exactamente a 180 grados de separación.

1
Cliff Ribaudo 11 may. 2017 a las 21:02

Basado en la respuesta de chux, esto es lo mejor que se me ocurre que es agnóstico de dirección:

bool within_arc(double p1, double p2, double p3) {
    double d21, d31, d32;

    p1 = fmod(p1, 360);
    p2 = fmod(p2, 360);
    p3 = fmod(p3, 360);
    d21 = fmod(p2 - p1 + 2 * 360, 360);
    d31 = fmod(p3 - p1 + 2 * 360, 360);
    d32 = fmod(p3 - p2 + 2 * 360, 360);
    if (d21 > 180)
        d21 = 360 - d21;
    if (d31 > 180)
        d31 = 360 - d31;
    if (d32 > 180)
        d32 = 360 - d32;
    return d21 >= d31 && d21 >= d32;
}
0
Ian Abbott 11 may. 2017 a las 18:47

Usando la implicación de que p1 a p2 marca un sector de manera en sentido horario :

[Editar] OP ha aclarado desde entonces que el objetivo está entre p1,p2 en la dirección más corta, en sentido horario o antihorario. Dejar esta respuesta como es para representar una solución para el caso de dirección única.

Si suponemos que p1,p2,p3 están en el rango [-360 ... 360]:

#include <math.h>
bool within_arc1(double p1, double p2, double p3) {
  return fmod(p2 - p1 + 2*360, 360) >= fmod(p3 - p1 + 2*360, 360);
}

Sin fmod()

bool within_arc2(double p1, double p2, double p3) {
  p3 -= p1;
  while (p3 < 0) p3 += 360;
  while (p3 > 360) p3 -= 360;
  p2 -= p1;
  while (p2 < 0) p2 += 360;
  while (p2 > 360) p2 -= 360;
  return p2 >= p3;
}

Si p1,p2,p3 puede ser cualquier valor

bool within_arc3(double p1, double p2, double p3) {
  p1 = fmod(p1, 360);
  return fmod(fmod(p2, 360) - p1 + 2*360, 360) >= fmod(fmod(p3, 360) - p1 + 2*360, 360);
}
1
chux - Reinstate Monica 11 may. 2017 a las 19:55