2011-11-18 13 views
28

Vedere ciascuna sezione di seguito per una descrizione del problema descritta in tre modi diversi. Si spera che dovrebbe aiutare le persone a rispondere.Come trovare la posizione assoluta del clic durante lo zoom

Problema: Come si fa a trovare un paio di coordinata espressa in tela/userspace quando hai solo la coordinata espresso in termini di una foto ingrandita, dato il punto di scala & fattore di scala originale?

Problema nella pratica:

Attualmente sto cercando di replicare la funzionalità di zoom utilizzato in applicazioni come ad esempio la galleria/mappe, quando si può pizzicare per ingrandire/rimpicciolire con lo zoom si muove verso il punto mediano del pizzico.

In basso salvi il punto centrale dello zoom (che è in coordinate X, Y in base alla schermata corrente). Allora ho questa funzione atto quando viene rilevato un gesto "scale":

class ImageScaleGestureDetector extends SimpleOnScaleGestureListener { 
    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     if(mScaleAllowed) 
      mCustomImageView.scale(detector.getScaleFactor(), mCenterX, mCenterY); 
     return true; 
    } 
} 

La funzione scala del CustomImageView questo aspetto:

public boolean scale(float scaleFactor, float focusX, float focusY) { 
    mScaleFactor *= scaleFactor; 

    // Don't let the object get too small or too large. 
    mScaleFactor = Math.max(MINIMUM_SCALE_VALUE, Math.min(mScaleFactor, 5.0f)); 

    mCenterScaleX = focusX; 
    mCenterScaleY = focusY; 

    invalidate(); 

    return true; 
} 

Il disegno dell'immagine scalata si ottiene sovrascrivendo i Metodo onDraw che ridimensiona la tela attorno al centro e disegna l'immagine su di essa.

@Override 
public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    canvas.save(); 
    canvas.translate(mCenterScaleX, mCenterScaleY); 
    canvas.scale(mScaleFactor, mScaleFactor); 
    canvas.translate(-mCenterScaleX, -mCenterScaleY); 
    mIcon.draw(canvas); 
    canvas.restore(); 
} 

Questo tutto funziona bene quando scalare da ScaleFactor 1, questo è perché l'iniziale mCenterX e mCenterY sono coordinate che si basano sullo schermo del dispositivo. 10, 10 sul dispositivo è 10, 10 sulla tela.

Tuttavia, dopo aver già eseguito lo zoom, la volta successiva che si fa clic sulla posizione 10, 10 non corrisponderà più a 10, 10 nell'area di disegno a causa del ridimensionamento della trasformazione & già eseguita.

Problema astraendo:

L'immagine seguente è un esempio di un'operazione di zoom attorno punto centrale A. Ogni casella rappresenta la posizione e le dimensioni della vista quando quel fattore di scala (1, 2, 3 , 4, 5).

Example

Nell'esempio se scalato di un fattore di 2 attorno A allora si è fatto clic nella posizione B, X, Y, presentate come B sarebbe basato sulla posizione schermo - non sulla posizione relativa alla 0,0 della tela iniziale.

ho bisogno di trovare un modo di ottenere la posizione assoluta di B.

+0

Il ridimensionamento della vista standard di Android + che imposta il punto di articolazione non eseguirà il lavoro? –

+0

Non sai cosa intendi per "ridimensionamento e impostazione standard del punto di articolazione"? Se tu potessi ampliarlo, sarebbe fantastico. – Graeme

+1

Quello che intendevo è usare 'setScaleX()' e 'setScaleY (()' per il ridimensionamento e 'setPivotX()' e 'setPivotY()' per impostare il centro del ridimensionamento.Sono tutti metodi di una Vista ma io leggi solo che la versione minSdk di questi metodi è 11 (Honeycomb), quindi forse questa informazione è inutile se ti rivolgi alle versioni precedenti. –

risposta

12

Quindi, dopo aver ridisegnato il problema, ho trovato la soluzione che stavo cercando.E 'passato attraverso un paio di iterazione del ma ecco come ho lavorato fuori:

Solution Description

B - Point, centro dell'operazione scala

A1, A2, A3 - Punti, pari a dall'utente spazio ma diverso nello spazio-tela.

si conoscono i valori per Bx e By perché sono sempre costante a prescindere dal fattore di scala (Tu sai che questo valore sia in canvas-spazio e in user-space).

Sai Ax & Ay in user-space in modo da poter trovare la distanza tra Ax-Bx e Ay a By. Questa misura si trova nello spazio utente, per convertirlo in una misurazione dello spazio su tela è sufficiente dividerlo per il fattore di scala. (Una volta convertiti nello spazio su tela, puoi vedere queste linee in rosso, arancione e giallo).

Poiché il punto B è costante, la distanza tra questo e i bordi è costante (sono rappresentati da linee blu). Questo valore è uguale in user-space e canvas-space.

Voi sapete la larghezza di tela in tela-spazio in modo sottraendo queste misurazioni spazio a due tele (Ax a Bx e Bx a Edge) dalla larghezza totale si sono lasciati con le coordinate per il punto A in canvas-space:

public float[] getAbsolutePosition(float Ax, float Ay) { 

    float fromAxToBxInCanvasSpace = (mCenterScaleX - Ax)/mScaleFactor; 
    float fromBxToCanvasEdge = mCanvasWidth - Bx; 
    float x = mCanvasWidth - fromAxToBxInCanvasSpace - fromBxToCanvasEdge; 

    float fromAyToByInCanvasSpace = (mCenterScaleY - Ay)/mScaleFactor; 
    float fromByToCanvasEdge = mCanvasHeight - By; 
    float y = mCanvasHeight - fromAyToByInCanvasSpace - fromByToCanvasEdge; 

    return new float[] { x, y }; 
} 

il codice e immagine sopra descrivono quando stai cliccando in alto a sinistra del nucleo originario. Ho usato la stessa logica per trovare A, non importa quale quadrante si trovava in e refactoring al seguente:

public float[] getAbsolutePosition(float Ax, float Ay) { 

    float x = getAbsolutePosition(mBx, Ax); 
    float y = getAbsolutePosition(mBy, Ay); 

    return new float[] { x, y }; 
} 

private float getAbsolutePosition(float oldCenter, float newCenter, float mScaleFactor) { 
    if(newCenter > oldCenter) { 
     return oldCenter + ((newCenter - oldCenter)/mScaleFactor); 
    } else { 
     return oldCenter - ((oldCenter - newCenter)/mScaleFactor); 
    } 
} 
+0

Hey Graeme Sto affrontando un problema simile e questo mi sta divorando la testa dall'ultimo mese. Finalmente ho trovato una domanda che Ho avuto il tuo aiuto per risolvere il problema? Ho capito la tua logica di sopra, ma ho bisogno del tuo aiuto ... dove dovrei contattarti? Grazie in anticipo – user1169079

+0

Sono uno dei proprietari di la chat room 'Android' - ci sarò – Graeme

+0

Ma in chat solo gli utenti nominati dal proprietario possono chattare? Si prega di accettare la richiesta..grazie – user1169079

1

Davvero dispiace questa è una breve risposta, in una corsa. Ma l'ho visto anche di recente - ho trovato http://code.google.com/p/android-multitouch-controller/ per fare quello che vuoi (penso - ho dovuto leggere il tuo post). Spero che questo ti aiuti. Avrò un aspetto corretto stasera se questo non aiuta e vedere se posso aiutare ulteriormente.

+0

Devo scusarmi perché sono abbastanza stanco a questo punto, ma in questo codice sorgente di ragazzi che usa e interfaccia chiamato "MultiTouchObjectCanvas "In questa interfaccia ci sono s un metodo chiamato "getPositionAndScale" descritto come "Ottieni le schermate dello schermo dell'origine dell'oggetto trascinato e il moltiplicatore di scala per convertire i coord delle schermate in coordina."che è esattamente quello che voglio - sfortunatamente non riesco a vedere dove viene implementata questa interfaccia .... – Graeme

+0

Dai un'occhiata alla sua demo - http://code.google.com/p/android-multitouch-controller/source /browse/trunk/demo/MTPhotoSortr/src/org/metalev/multitouch/photosortr/PhotoSortrView.java – Martyn

2

Qui è la mia soluzione basata sulla risposta di Graeme:

public float[] getAbsolutePosition(float Ax, float Ay) { 
    MatrixContext.drawMatrix.getValues(mMatrixValues); 

    float x = mWidth - ((mMatrixValues[Matrix.MTRANS_X] - Ax)/mMatrixValues[Matrix.MSCALE_X]) 
      - (mWidth - getTranslationX()); 

    float y = mHeight - ((mMatrixValues[Matrix.MTRANS_Y] - Ay)/mMatrixValues[Matrix.MSCALE_X]) 
      - (mHeight - getTranslationY()); 

    return new float[] { x, y }; 
} 

i parametri Ax e Ay sono i punti che l'utente tocca tramite onTouch(), ho posseduto la mia istanza di matrice statica nella classe MatrixContext per conservare i precedenti valori convertiti in scala/tradotti.

Problemi correlati