旋转在画布上绘制的圆圈以触摸标记的点

时间:2019-03-27 22:55:23

标签: java android

我正在尝试让我的应用显示一个圆圈,用户可以通过触摸和拖动该圆圈来将其旋转到一定程度。说圆的最大可旋转角度为60度。

我扩展了View类以创建自定义View。 我已经使用drawCircle()方法在画布上绘制了一个圆圈。 要旋转它,我知道我必须做一个canvas.rotate(),但是我不确定将中心固定为什么。 如何测量这个角度? 我要旋转什么?

public class DrawingView extends View {

    Paint paint;
    Canvas canvas;
    int originalX = 100;
    int originalY = 50;
    int radius = 75;
    // ... some code ...
    // paint, canvas initialised in constructors

    @Override
    protected void onDraw(Canvas canvas){
        canvas.drawCircle(originalX, originalY, radius, paint);
        // some more code ...
    }

   @Override
   public boolean onTouchEvent(MotionEvent event){
       int x = (int)event.getX();         
       int y = (int)event.getY();
       case MotionEvent.ACTION_DOWN:
           // Detect if touch in my circle
       break;             
       case MotionEvent.ACTION_MOVE: 
          double tx = x - originalX;
          double ty = y - originalY;                         
          double tlength = Math.sqrt(tx*tx + ty*ty);
          double angle = Math.acos(radius/tlength);
          double degrees = (angle * 180)/Math.PI;
          System.out.println("Degrees " + (angle*180)/Math.PI);
       break;
   }
}

我显示的代码似乎给我的值不正确。 就像,如果我一直触摸并拖动到屏幕末端,它会为我提供大约70度的值。我不认为我在计算正确的角度,但是我也不知道该怎么做。


我遵循所选答案的找到角度的方法。 然后,我在绘制圆之前使用了canvas.rotate()。

1 个答案:

答案 0 :(得分:0)

我不确定您是否知道该如何正确运行。但是那里的几何形状肯定很奇怪。 tlength是从圆心到指尖的半径,您正在对其进行acos。但是,那是错误的。 acos是哪个值赋予您该值的余弦。从理论上讲,这将是不同角度的余弦波。这可能很有趣,但听起来并不像您想要的。听起来您想呼叫距0中心的距离以-60度旋转,半径以0度旋转,半径为2 *半径以+60度旋转。所以就那样做。您可以线性插入距离(60°*(距离/半径))-60°或其他值。

尽管实际上从UI的角度来看,最好还是让用户通过将手指移动到该角度来更改圆上的实际角度。然后将这些值放在atan2()中,并在超出允许范围时对其进行限制。


有很多方法可以做到这一点。您可以基于手指按压来计算角度。因此,您可以使用已知点,例如中心点和当前极坐标。因此,如果您当前的角度为r,则另一端的点为cos(x)*rsin(y)*r如果您拥有该端点的x和y,则距中心的距离为sqrt(dx*dx + dy*dy),它的角度为atan2(dy, dx)。因此,您可以通过一点点尝试从极地转到笛卡尔式。如果您想将中心和半径之差称为角度,则可以对其进行线性插值。


这里是一个快速渲染视图的视图。还有其他UI选择可以替代,例如,不进行实际角度调整,而是进行角度更改,因此您可以像使用旋钮一样移动圆。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class RotateCircleView extends View {
    static final double TAU = Math.PI * 2;
    Paint paint;
    double angle = 0;
    double radius = 0;
    double ix = Double.NaN, iy = Double.NaN;

    public RotateCircleView(Context context) {
        super(context);
        init();
    }
    public RotateCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public RotateCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    public void init() {
        paint = new Paint();
        paint.setAlpha(100);
        paint.setStrokeWidth(20);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        ix = w / 2.0;
        iy = h / 2.0;
        radius = Math.min(ix, iy) / 2.0;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (Double.isNaN(ix)) return;
        super.onDraw(canvas);
        canvas.save();
        canvas.rotate((float) ((TAU * -angle) / 360.0), (float) ix, (float) iy);
        canvas.drawCircle((float) ix, (float) iy, (float) radius, paint);
        double limit = TAU / 6.0;
        if (angle > limit) angle = limit;
        if (angle < -limit) angle = -limit;
        double tx = ix + Math.cos(angle) * radius;
        double ty = iy + Math.sin(angle) * radius;
        canvas.drawLine((float) ix, (float) iy, (float) tx, (float) ty, paint);
        canvas.restore();
    }

    public boolean onTouchEvent(MotionEvent event) {
        double mx = event.getX();
        double my = event.getY();
        double dx = mx - ix;
        double dy = my - iy;
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                //radius = Math.sqrt(dx * dx + dy * dy);
                angle = Math.atan2(dy, dx);
                invalidate();
                break;
        }
        return true;
    }
}