2012-03-02 11 views
9

En iOS, estoy tratando de determinar el punto en un rectángulo intersecado por una línea imaginaria desde el punto central hasta el perímetro de el rectángulo en un ángulo predeterminado.Encuentra el CGPoint en un rectángulo UIView intersectado por una línea recta en un ángulo determinado desde el punto central

Digamos que conozco el punto central, el tamaño del rectángulo y el ángulo (comenzando desde 0 grados hacia el este e ir hacia la izquierda 90 hacia el norte y 180 hacia el oeste y 270 hacia el sur hasta 360 grados hacia el este nuevamente) . Necesito saber las coordenadas del punto de intersección.

La respuesta algo confusa (para mí) matemática pero presumiblemente precisa en Finding points on a rectangle at a given angle me llevó a probar el siguiente código, pero no funciona correctamente. Esta pregunta es similar a esa, pero estoy buscando un método corregido de Objective-C/iOS en lugar de una respuesta matemática general.

Creo que una parte del problema del código tiene que ver con el uso del ángulo de 0 a 360 grados (en radianes sin posibilidad de un número negativo) de entrada, pero es probable que haya otros problemas. El siguiente código utiliza principalmente la notación definida en the answer from belisarius, incluido mi intento de calcular los puntos de intersección para cada una de las cuatro regiones definidas allí.

Este código está en mi subclase UIImageView:

- (CGPoint) startingPointGivenAngleInDegrees:(double)angle { 
    double angleInRads = angle/180.0*M_PI; 
    float height = self.frame.size.height; 
    float width = self.frame.size.width; 
    float x0 = self.center.x; 
    float y0 = self.center.y; 
    // region 1 
    if (angleInRads >= -atan2(height, width) && angleInRads <= atan2(height, width)) { 
     return CGPointMake(x0 + width/2, y0 + width/2 * tan(angleInRads)); 
    } 
    // region 2 
    if (angleInRads >= atan2(height, width) && angleInRads <= M_PI - atan2(height, width)) { 
     return CGPointMake(x0 + height/(2*tan(angleInRads)),y0+height/2); 
    } 
    // region 3 
    if (angleInRads >= M_PI - atan2(height, width) && angleInRads <= M_PI + atan2(height, width)) { 
     return CGPointMake(x0 - width/2, y0 + width/2 * tan(angleInRads)); 
    } 
    // region 4 
    return CGPointMake(x0 + height/(2*tan(angleInRads)),y0-height/2);  
} 

Respuesta

17

En lugar de depurar el código, sólo voy a explicar cómo iba a hacer esto.

Primero, algunos términos. Definamos xRadius como la mitad del ancho del marco y yRadius como la mitad de la altura del marco.

Ahora considere los cuatro bordes del marco y extiéndalos como líneas infinitas. En la parte superior de estas cuatro líneas, había una línea que pasa por el centro de la trama a su ángulo especificado:

diagram of rectangle with overlaid line

Digamos que la trama se centra en el origen - el centro de la imagen es en las coordenadas (0,0). Podemos calcular fácilmente dónde se cruza la línea diagonal con el borde derecho del marco: las coordenadas son (xRadius, xRadius * tan(angle)). Y podemos calcular fácilmente dónde se cruza la línea diagonal con el borde superior del marco: las coordenadas son (-yRadius/tan(angle), -yRadius).

(¿Por qué nos niegan las coordenadas de la intersección-borde superior? Debido a que el UIView sistema de coordenadas se volcó desde el sistema normal de matemática de coordenadas. En matemáticas, las coordenadas Y aumento hacia la parte superior de la página. En un UIView, y las coordenadas aumentan hacia la parte inferior de la vista.)

Así que podemos simplemente calcular la intersección de la línea con el borde derecho del marco. Si esa intersección está fuera del marco, entonces sabemos que la línea debe intersecarse con el borde superior antes de intersecta el borde derecho. ¿Cómo podemos saber si la intersección del borde derecho está fuera de límites? Si su coordenada y (xRadius * tan(angle)) es mayor que yRadius (o menor que -yRadius), está fuera de límites.

Así que para poner todo junto en un método, comenzamos calculando xRadius y yRadius:

- (CGPoint)radialIntersectionWithConstrainedRadians:(CGFloat)radians { 
    // This method requires 0 <= radians < 2 * π. 

    CGRect frame = self.frame; 
    CGFloat xRadius = frame.size.width/2; 
    CGFloat yRadius = frame.size.height/2; 

A continuación, calcular la coordenada y de la intersección con el borde derecho:

CGPoint pointRelativeToCenter; 
    CGFloat tangent = tanf(radians); 
    CGFloat y = xRadius * tangent; 

Comprobamos si la intersección está en el marco:

if (fabsf(y) <= yRadius) { 

Una vez que sabemos que está en el cuadro, tenemos que determinar si queremos la intersección con el borde derecho o el izquierdo. Si el ángulo es menor que π/2 (90 °) o mayor que 3π/2 (270 °), queremos el borde derecho. De lo contrario, queremos el borde izquierdo.

 if (radians < (CGFloat)M_PI_2 || radians > (CGFloat)(M_PI + M_PI_2)) { 
      pointRelativeToCenter = CGPointMake(xRadius, y); 
     } else { 
      pointRelativeToCenter = CGPointMake(-xRadius, -y); 
     } 

Si la coordenada y de la intersección borde derecho • * fue fuera de límites, se calcula la coordenada x de la intersección con el borde inferior.

} else { 
     CGFloat x = yRadius/tangent; 

continuación a determinar si queremos que el borde superior o el borde inferior. Si el ángulo es menor que π (180 °), queremos el borde inferior. De lo contrario, queremos el borde superior.

 if (radians < (CGFloat)M_PI) { 
      pointRelativeToCenter = CGPointMake(x, yRadius); 
     } else { 
      pointRelativeToCenter = CGPointMake(-x, -yRadius); 
     } 
    } 

Finalmente, compensamos el punto calculado por el centro real del cuadro y lo devolvemos. proyecto

return CGPointMake(pointRelativeToCenter.x + CGRectGetMidX(frame), 
     pointRelativeToCenter.y + CGRectGetMidY(frame)); 
} 

aquí el test: https://github.com/mayoff/stackoverflow-radial-intersection

se ve así:

edgepoint screen shot

+0

fabuloso! Gracias. Tuve un problema con esto porque en mi caso no me di cuenta de que tenía que [self.superview convertPoint: thePoint toView: self] en mi subclase UIImageview (para otros principiantes que vienen aquí). –

+0

¡Fantástica respuesta! – mrvincenzo

+0

Estoy estudiando su código que es excelente, tratando de entender qué hacer si quería rotar la imagen y aún así mantener la detección de bordes. ¿Alguna idea? – flooie

Cuestiones relacionadas