iOS - Ayuda matemática: los zooms de imagen base con gesto de pellizco necesitan imágenes superpuestas para ajustar las coordenadas X/Y relativas

Tengo una aplicación para iPad que tiene una imagen base UIImageView (en este caso, un edificio grande o un plano o diagrama del sitio) y luego se pueden agregar varios 'pins' encima del plano (visualmente similar a Google Maps). Estos pines también son UIImageViews y se agregan a la vista principal con gestos de toque. La imagen base también se agrega a la vista principal en viewDidLoad.

Tengo la imagen base trabajando con el gesto de pellizcar para hacer zoom, pero obviamente cuando haces zoom en la imagen base, todos los pines permanecen en las mismas coordenadas x e y de la vista principal y pierden el posicionamiento relativo en la imagen base (cuyos x, y y las coordenadas de ancho y alto han cambiado).

Hasta ahora tengo esto...

- (IBAction)planZoom:(UIPinchGestureRecognizer *) recognizer;
{
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    recognizer.scale = 1;

    for (ZonePin *pin in planContainer.subviews) {
        if ([pin isKindOfClass:[ZonePin class]]){
            CGRect pinFrame = pin.frame;

            // ****************************************
            // code to reposition the pins goes here...
            // ****************************************

            pin.frame = pinFrame;
        }
    }
}

Necesito ayuda para calcular las matemáticas para reposicionar las coordenadas x/y de los pines para retener la posición relativa en el plano/diagrama ampliado o alejado. Los pines obviamente no quieren ser escalados/ampliados en términos de su ancho o alto; solo necesitan nuevas coordenadas x e y que sean relativas a sus posiciones iniciales en el plan.

He intentado resolver las matemáticas yo mismo, pero he tenido problemas para resolverlo y, lamentablemente, aún no estoy lo suficientemente familiarizado con el SDK para saber si hay una disposición disponible incorporada para ayudar o no.

¡La ayuda con este problema relacionado con las matemáticas sería muy apreciada! :)

Muchas gracias, Miguel. InNeedOfMathTuition.com

preguntado el 22 de mayo de 12 a las 20:05

2 Respuestas

En primer lugar, puede intentar incrustar su UIImageView en un parche de UIScrollView por lo que el zoom se logra en gran medida para usted. Luego puede configurar la escala máxima y mínima fácilmente, y puede desplazarse por la imagen ampliada como desee (especialmente si sus pines son subvistas de la UIImageView o algo más dentro de la UIScrollView).

En cuanto a escalar las ubicaciones de los pines, creo que funcionaría almacenar las coordenadas x e y originales de cada pin (es decir, cuando la vista se carga por primera vez, cuando se colocan por primera vez, a escala 1.0). Luego, cuando la vista esté ampliada, configure x = (originalX * zoomScale) y y = (originalY * zoomScale).

Tuve el mismo problema en una aplicación de iOS hace un par de años, y si no recuerdo mal, así fue como lo logré.

EDITAR: A continuación hay más detalles sobre cómo logré esto (ahora estoy buscando mi código anterior).

Yo tenía un UIScrollView como una subvista de mi vista principal, y mi UIImageView como una subvisión de eso. Mis botones se agregaron a la vista de desplazamiento y mantuve sus ubicaciones originales (en zoom 1.0) almacenadas como referencia.

In -(void)scrollViewDidScroll:(UIScrollView *)scrollView método:

for (id element in myButtons)
{
   UIButton *theButton = (UIButton *)element;
   CGPoint originalPoint = //get original location however you want
   [theButton setFrame:CGRectMake(
       (originalPoint.x - theButton.frame.size.width / 2) * scrollView.zoomScale,
       (originalPoint.y - theButton.frame.size.height / 2) * scrollView.zoomScale,
       theButton.frame.size.width, theButton.frame.size.height)];
}

Para el -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView método, devolví mi UIImageView. Mis botones escalaron en tamaño, pero no los incluí en el código anterior. Si descubre que los pines se escalan en tamaño automáticamente, es posible que deba almacenar sus tamaños originales, así como las coordenadas originales, y usar eso en el setFrame llamada.

contestado el 23 de mayo de 12 a las 16:05

Desafortunadamente, esto no funciona del todo. (Ya había probado esto). Funciona parcialmente en el sentido de que los pines se escalan entre sí, pero no se posicionan correctamente contra el plano. El plan se escala hacia el centro, pero los pines se escalan hacia la parte superior/izquierda de la vista del contenedor. De alguna manera, necesito calcular x, y para escalar también contra el punto central en lugar de la esquina superior/izquierda. Intenté configurar el origen del marco de la vista para que sea el centro, pero esto no tiene ningún efecto, como era de esperar. Creo que esto es más un problema de matemáticas puras. ¿Algunas ideas? - Michael

...para mayor claridad... No puedo usar una vista de desplazamiento para manejar el zoom ya que esto en realidad no resuelve nada de lo que ya sucede. Si hiciera esto, los pines también escalarían en ancho y alto, lo que no quiero que suceda. Anteriormente hice esto para que los pines se agreguen como subvistas a la imagen base y se escalan correctamente en términos de x/y, pero también se escalan en su ancho y alto, ¡lo que obviamente no es lo deseado! - Michael

@Michael: actualicé mi respuesta con más detalles. Es posible que pueda resolver el problema de escalado del tamaño de la vista de desplazamiento configurando el ancho y la altura explícitamente en el UIScrollView's scrollViewDidScroll método delegado. - tom hamming

Gracias por su ayuda, Sr. Jefferson, ¡me puso en el camino correcto! He agregado mi implementación a continuación para beneficio de otros. Como referencia, una cosa que se tuvo que incorporar en el cálculo fue el hecho de que las imágenes de mis pines no se escalaban en ancho y alto. escalar las coordenadas x e y incluía el efecto de que el ancho y la altura también crecían y esto debe contrarrestarse al calcular las nuevas coordenadas. ej.. newX = (pin.originalX * scrollView.zoomScale) + (((pin.frame.size.width * scrollView.zoomScale) - pin.frame.size.width) / 2); Muchas gracias de nuevo por tu ayuda. :) - Michael

ACTUALIZAR...

Gracias a 'Sr. La ayuda de Jefferson en su respuesta anterior, aunque con una implementación diferente, pude resolver esto de la siguiente manera ...

Tengo un scrollView que tiene una imagen de plano/diagrama como subvista. El scrollView está configurado para hacer zoom/panorámica, etc., esto incluye agregar UIScrollViewDelegate al ViewController.

Cuando el usuario toca dos veces el plano/diagrama, se agrega una imagen de alfiler como una subvista a la vista de desplazamiento en el punto de contacto. La imagen del pin es una clase 'ZonePin' personalizada que hereda de UIImageView y tiene un par de propiedades adicionales que incluyen 'baseX' y 'baseY'.

El código para agregar los pines...

- (IBAction)planDoubleTap:(UITapGestureRecognizer *) recognizer;
{
    UIImage *image = [UIImage imageNamed:@"Pin.png"];
    ZonePin *newPin = [[ZonePin alloc] initWithImage:image];

    CGPoint touchPoint = [recognizer locationInView:planContainer];
    CGFloat placementX = touchPoint.x - (image.size.width / 2);
    CGFloat placementY = touchPoint.y - image.size.height;

    newPin.frame = CGRectMake(placementX, placementY, image.size.width, image.size.height);
    newPin.zoneRef = [NSString stringWithFormat:@"%@%d", @"BF", pinSeq++];
    newPin.baseX = placementX;
    newPin.baseY = placementY;
    [planContainer addSubview:newPin];
}

Luego tengo dos funciones para manejar la interacción scrollView y esto maneja el escalado/reposicionamiento de los pines en relación con la imagen del plan. Estos métodos son los siguientes...

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return planImage;
}


- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    for (ZonePin *pin in planContainer.subviews) {
        if ([pin isKindOfClass:[ZonePin class]]){
            CGFloat newX, newY;

            newX = (pin.baseX * scrollView.zoomScale) + (((pin.frame.size.width * scrollView.zoomScale) - pin.frame.size.width) / 2);
            newY = (pin.baseY * scrollView.zoomScale) + ((pin.frame.size.height * scrollView.zoomScale) - pin.frame.size.height);

            CGRect pinFrame = pin.frame;
            pinFrame.origin.x = newX;
            pinFrame.origin.y = newY;
            pin.frame = pinFrame;
        }
    }
}

Como referencia, los cálculos para posicionar los pines, por su naturaleza de pines, centran la imagen del pin en el eje x pero tienen la parte inferior del eje y alineada.

Lo único que me queda por hacer con esto es revertir los cálculos utilizados en el método scrollViewDidScroll cuando agrego pines cuando hago zoom. El código para agregar pines arriba solo funcionará correctamente cuando scrollView.zoomScale sea 1.0.

Aparte de eso, ¡ahora funciona muy bien! :)

contestado el 25 de mayo de 12 a las 10:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.