web-dev-qa-db-fra.com

Obtenir une nouvelle position de coordonnée après rotation avec Matrix

Je me demande comment utiliser une matrice pour obtenir la nouvelle position d'une coordonnée dans un rectangle après la rotation. Ce que j'aimerais faire, c'est: 

  1. Définir un rectangle
  2. Définir une coordonnée dans ce rectangle
  3. Faire pivoter le rectangle
  4. Obtenir la nouvelle position de la coordonnée après la rotation

Les parties que je ne peux pas comprendre sont les 2 et 4. Des idées?

27
DecodeGnome

J'ai créé une démo simple pour cela. Elle a un petit plus, vous pouvez donc voir comment l'utiliser dans Dessin. 

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>

Et l'activité:

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) {}
}
32
Entreco

Utilisez Matrix.mapPoints pour transformer des points 2D par matrice.

6
Pointer Null

Il y a longtemps que je sais, mais c'était quelque chose qui me troublait encore. Tout ce domaine de l’API semble plus centré sur le fait de faire des choses pour nous que de nous laisser comprendre ce qui se passe réellement, sans aucun doute parce qu’il fait des choses vraiment intelligentes dans les coulisses.

Les points de réglage et de les récupérer sont assez séparés.

Il existe différentes manières de définir un point particulier, l'excellente réponse d'Entreco montre un moyen.

Pour récupérer un point, vous devez obtenir les valeurs d'une matrice liée à ce point, puis en extraire les parties correctes. C’est aussi une excellente réponse ( Android Matrix, que retourne getValues ​​()? ) explique très clairement ce qui se passe avec la matrice, et vous pouvez voir que les valeurs x, y que vous voulez sont des éléments indexés par 2 et 5.

Ce qui suit est un code (légèrement pseudo) que j'utilise pour les obtenir.

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];

Je ne suis pas très heureux de cela, mais il ne semble pas y avoir de moyen plus formel de le faire.

0
Markers