2011-10-17 10 views
26

Mi chiedo come utilizzare una matrice per ottenere la nuova posizione di una coordinata all'interno di un rettangolo dopo la rotazione. Quello che vorrei fare è:Ottieni nuova posizione di coordinate dopo la rotazione con Matrix

  1. definire un rettangolo
  2. Definire una coordinata all'interno di tale rettangolo
  3. Ruotare il rettangolo
  4. Prendi la nuova posizione del punto dopo la rotazione

Le parti che non riesco a capire sono 2 & 4. Qualche idea?

risposta

32

Ho creato una semplice demo per questo. Ha un piccolo extra, quindi puoi anche vedere come usarlo in Disegno.

main.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/container" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <SeekBar 
     android:id="@+id/seekBar1" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_centerHorizontal="true" /> 
</RelativeLayout> 

e l'attività:

package nl.entreco.android.testrotation; 

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Matrix; 
import android.graphics.Paint; 
import android.graphics.Point; 
import android.graphics.Rect; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.widget.RelativeLayout; 
import android.widget.SeekBar; 
import android.widget.SeekBar.OnSeekBarChangeListener; 

public class RotationActivity extends Activity implements OnSeekBarChangeListener { 


    private MyDrawing myDrawing; 
    private SeekBar mSeekbar; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     Rect rect = new Rect(150,150,440,630); 

     int x = (int) (rect.left + Math.random() * rect.width()); 
     int y = (int) (rect.top + Math.random() * rect.height()); 
     Point coordinate = new Point(x, y); 


     // To draw the rect we create a CustomView 
     myDrawing = new MyDrawing(this, rect, coordinate); 

     RelativeLayout rl = (RelativeLayout)findViewById(R.id.container); 
     rl.addView(myDrawing); 


     mSeekbar = (SeekBar)findViewById(R.id.seekBar1); 
     mSeekbar.setMax(360); 
     mSeekbar.setOnSeekBarChangeListener(this); 
    } 

    private class MyDrawing extends View 
    { 
     private Rect myRect; 
     private Point myPoint; 
     private Paint rectPaint; 
     private Paint pointPaint; 

     private Matrix transform; 

     public MyDrawing(Context context, Rect rect, Point point) 
     { 
      super(context); 

      // Store the Rect and Point 
      myRect = rect; 
      myPoint = point; 

      // Create Paint so we can see something :) 
      rectPaint = new Paint(); 
      rectPaint.setColor(Color.GREEN); 
      pointPaint = new Paint(); 
      pointPaint.setColor(Color.YELLOW); 

      // Create a matrix to do rotation 
      transform = new Matrix(); 

     } 


     /** 
     * Add the Rotation to our Transform matrix. 
     * 
     * A new point, with the rotated coordinates will be returned 
     * @param degrees 
     * @return 
     */ 
     public Point rotate(float degrees) 
     { 
      // This is to rotate about the Rectangles center 
      transform.setRotate(degrees, myRect.exactCenterX(),  myRect.exactCenterY()); 

      // Create new float[] to hold the rotated coordinates 
      float[] pts = new float[2]; 

      // Initialize the array with our Coordinate 
      pts[0] = myPoint.x; 
      pts[1] = myPoint.y; 

      // Use the Matrix to map the points 
      transform.mapPoints(pts); 

      // NOTE: pts will be changed by transform.mapPoints call 
      // after the call, pts will hold the new cooridnates 

      // Now, create a new Point from our new coordinates 
      Point newPoint = new Point((int)pts[0], (int)pts[1]); 

      // Return the new point 
      return newPoint; 
     } 

     @Override 
     public void onDraw(Canvas canvas) 
     { 
      if(myRect != null && myPoint != null) 
      { 
       // This is an easy way to apply the same transformation (e.g. rotation) 
       // To the complete canvas. 
       canvas.setMatrix(transform); 

       // With the Canvas being rotated, we can simply draw 
       // All our elements (Rect and Point) 
       canvas.drawRect(myRect, rectPaint); 
       canvas.drawCircle(myPoint.x, myPoint.y, 5, pointPaint); 
      } 
     } 
    } 

    @Override 
    public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) { 

     Point newCoordinates = myDrawing.rotate(progress); 


     // Now -> our float[] pts contains the new x,y coordinates 
     Log.d("test", "Before Rotate myPoint("+newCoordinates.x+","+newCoordinates.y+")"); 
     myDrawing.invalidate(); 

    } 

    @Override 
    public void onStartTrackingTouch(SeekBar seekBar) {} 

    @Override 
    public void onStopTrackingTouch(SeekBar seekBar) {} 
} 
+0

rl.addView (myDrawing); ho ricevuto l'errore in questa riga –

6

Utilizzare Matrix.mapPoints per trasformare i punti 2D per matrice.

+0

Grazie per la risposta, ma ho guardato questo e ancora non capisco come impostare una coordinata e quindi ottenerla dopo la rotazione. – DecodeGnome

+0

Ho lo stesso problema :( – donmj

+0

per favore leggi 'public Point ruotare (gradi float)' della risposta di Entreco –

0

Molto tempo ritardo lo so, ma questo era qualcosa di troppo ero ancora confuso circa. L'intera area dell'API sembra più concentrata sul fare le cose per noi piuttosto che farci capire cosa sta realmente accadendo, senza dubbio perché sta facendo cose davvero intelligenti dietro le quinte.

I punti di impostazione e il recupero sono abbastanza separati.

Ci sono vari modi per impostare un punto particolare, l'eccellente risposta di Entreco mostra un modo.

Per tornare indietro di un punto è necessario ottenere i valori di una matrice collegata a quel punto e quindi prelevarne le parti corrette. Questa, anche eccellente, risposta (Android Matrix, what does getValues() return?) spiega molto chiaramente cosa sta succedendo con la matrice, e puoi vedere che i valori x, y che vuoi sono elementi indicizzati da 2 e 5.

Quanto segue è (leggermente pseudo-) codice che uso per ottenere a loro.

float [] theArray = { <nine float zeroes> } 
Matrix m = new Matrix(); 
boolean success = myPathMeasure.getMatrix(m, theArray, Matrix.MTRANS_X+Matrix.MTRANS_Y); 
m.getValues(theArray); 
x = theArray[2]; 
y = theArray[5]; 

io non sono terribilmente contento di questo, ma non sembra essere un modo più formale per farlo.

Problemi correlati