gpt4 book ai didi

java - 将旋转对象对应到数值

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:53:51 25 4
gpt4 key购买 nike

我有一个 360 度旋转的组合锁。

密码锁上面有数值,这些是纯图形的。

我需要一种方法将图像的旋转转换为图形上的 0-99 值。

在第一个图形中,值应该可以告诉我“0”

在此图形中,用户旋转图像后,该值应该可以告诉我“72”

代码如下:

package co.sts.combinationlock;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.support.v4.app.NavUtils;

public class ComboLock extends Activity{

private static Bitmap imageOriginal, imageScaled;
private static Matrix matrix;

private ImageView dialer;
private int dialerHeight, dialerWidth;

private GestureDetector detector;

// needed for detecting the inversed rotations
private boolean[] quadrantTouched;

private boolean allowRotating;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_combo_lock);

// load the image only once
if (imageOriginal == null) {
imageOriginal = BitmapFactory.decodeResource(getResources(), R.drawable.numbers);
}

// initialize the matrix only once
if (matrix == null) {
matrix = new Matrix();
} else {
// not needed, you can also post the matrix immediately to restore the old state
matrix.reset();
}

detector = new GestureDetector(this, new MyGestureDetector());

// there is no 0th quadrant, to keep it simple the first value gets ignored
quadrantTouched = new boolean[] { false, false, false, false, false };

allowRotating = true;

dialer = (ImageView) findViewById(R.id.locknumbers);
dialer.setOnTouchListener(new MyOnTouchListener());
dialer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

@Override
public void onGlobalLayout() {
// method called more than once, but the values only need to be initialized one time
if (dialerHeight == 0 || dialerWidth == 0) {
dialerHeight = dialer.getHeight();
dialerWidth = dialer.getWidth();

// resize
Matrix resize = new Matrix();
//resize.postScale((float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getWidth(), (float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getHeight());
imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);

// translate to the image view's center
float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
matrix.postTranslate(translateX, translateY);

dialer.setImageBitmap(imageScaled);
dialer.setImageMatrix(matrix);
}
}
});

}

/**
* Rotate the dialer.
*
* @param degrees The degrees, the dialer should get rotated.
*/
private void rotateDialer(float degrees) {
matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);

//need to print degrees

dialer.setImageMatrix(matrix);
}

/**
* @return The angle of the unit circle with the image view's center
*/
private double getAngle(double xTouch, double yTouch) {
double x = xTouch - (dialerWidth / 2d);
double y = dialerHeight - yTouch - (dialerHeight / 2d);

switch (getQuadrant(x, y)) {
case 1:
return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;

case 2:
case 3:
return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);

case 4:
return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;

default:
// ignore, does not happen
return 0;
}
}

/**
* @return The selected quadrant.
*/
private static int getQuadrant(double x, double y) {
if (x >= 0) {
return y >= 0 ? 1 : 4;
} else {
return y >= 0 ? 2 : 3;
}
}

/**
* Simple implementation of an {@link OnTouchListener} for registering the dialer's touch events.
*/
private class MyOnTouchListener implements OnTouchListener {

private double startAngle;

@Override
public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

// reset the touched quadrants
for (int i = 0; i < quadrantTouched.length; i++) {
quadrantTouched[i] = false;
}

allowRotating = false;

startAngle = getAngle(event.getX(), event.getY());
break;

case MotionEvent.ACTION_MOVE:
double currentAngle = getAngle(event.getX(), event.getY());
rotateDialer((float) (startAngle - currentAngle));
startAngle = currentAngle;
break;

case MotionEvent.ACTION_UP:
allowRotating = true;
break;
}

// set the touched quadrant to true
quadrantTouched[getQuadrant(event.getX() - (dialerWidth / 2), dialerHeight - event.getY() - (dialerHeight / 2))] = true;

detector.onTouchEvent(event);

return true;
}
}

/**
* Simple implementation of a {@link SimpleOnGestureListener} for detecting a fling event.
*/
private class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

// get the quadrant of the start and the end of the fling
int q1 = getQuadrant(e1.getX() - (dialerWidth / 2), dialerHeight - e1.getY() - (dialerHeight / 2));
int q2 = getQuadrant(e2.getX() - (dialerWidth / 2), dialerHeight - e2.getY() - (dialerHeight / 2));

// the inversed rotations
if ((q1 == 2 && q2 == 2 && Math.abs(velocityX) < Math.abs(velocityY))
|| (q1 == 3 && q2 == 3)
|| (q1 == 1 && q2 == 3)
|| (q1 == 4 && q2 == 4 && Math.abs(velocityX) > Math.abs(velocityY))
|| ((q1 == 2 && q2 == 3) || (q1 == 3 && q2 == 2))
|| ((q1 == 3 && q2 == 4) || (q1 == 4 && q2 == 3))
|| (q1 == 2 && q2 == 4 && quadrantTouched[3])
|| (q1 == 4 && q2 == 2 && quadrantTouched[3])) {

dialer.post(new FlingRunnable(-1 * (velocityX + velocityY)));
} else {
// the normal rotation
dialer.post(new FlingRunnable(velocityX + velocityY));
}

return true;
}
}

/**
* A {@link Runnable} for animating the the dialer's fling.
*/
private class FlingRunnable implements Runnable {

private float velocity;

public FlingRunnable(float velocity) {
this.velocity = velocity;
}

@Override
public void run() {
if (Math.abs(velocity) > 5 && allowRotating) {
//rotateDialer(velocity / 75);
//velocity /= 1.0666F;

// post this instance again
dialer.post(this);
}
}
}
}

我想我需要将一些信息从矩阵转换为 0-99 值。

最佳答案

您应该完全重新组织您的代码。一遍又一遍地将新的旋转后乘到矩阵中是一种数值不稳定的计算。最终位图将变得扭曲。尝试从矩阵中检索旋转角度过于复杂且没有必要。

首先注意this是一篇关于绘制位图并围绕选定点旋转的有用的先前文章。

只需维护一个double dialAngle = 0,即刻度盘的当前旋转角度。

您正在做太多工作来检索触摸位置的角度。让 (x0,y0) 成为触摸开始的位置。当时,

// Record the angle at initial touch for use in dragging.
dialAngleAtTouch = dialAngle;
// Find angle from x-axis made by initial touch coordinate.
// y-coordinate might need to be negated due to y=0 -> screen top.
// This will be obvious during testing.
a0 = Math.atan2(y0 - yDialCenter, x0 - xDialCenter);

这是起始角度。当触摸拖动到 (x,y) 时,使用此坐标调整表盘相对于初始触摸。然后更新矩阵并重绘:

// Find new angle to x-axis. Same comment as above on y coord.
a = Math.atan2(y - yDialCenter, x - xDialCenter);
// New dial angle is offset from the one at initial touch.
dialAngle = dialAngleAtTouch + (a - a0);
// normalize angles to the interval [0..2pi)
while (dialAngle < 0) dialAngle += 2 * Math.PI;
while (dialAngle >= 2 * Math.PI) dialAngle -= 2 * Math.PI;

// Set the matrix for every frame drawn. Matrix API has a call
// for rotation about a point. Use it!
matrix.setRotate((float)dialAngle * (180 / 3.1415926f), xDialCenter, yDialCenter);

// Invalidate the view now so it's redrawn in with the new matrix value.

请注意 Math.atan2(y, x) 可以完成您使用象限和反正弦所做的所有操作。

要得到当前角度的“刻度”,需要2个pi弧度对应100,所以很简单:

double fractionalTick = dialAngle / (2 * Math.Pi) * 100;

要找到作为整数的实际最近刻度,请将分数四舍五入并取模 100。请注意,您可以忽略矩阵!

 int tick = (int)(fractionalTick + 0.5) % 100;

这将始终有效,因为 dialAngle 在 [0..2pi) 中。需要 mod 将舍入值 100 映射回 0。

关于java - 将旋转对象对应到数值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11459300/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com