2012-11-28 110 views
4

我目前正在嘗試創建一個可以在填充百分比中進行調整的儀表。我遇到的問題是我一點都不擅長數學。我想在「北」(第一幅圖像)中開始繪製弧線,而不是在「東側」(如第二幅圖像所示)中具有0度角的正常弧線。垂直軸的旋轉角度

Image 1 Image 2

我希望能夠通過拖動/沿着屏幕觸摸它來增加的藍色區域中的圖像1的大小(角度)。現在,這些是我現在能夠以某種時尚方式做的事情。我現在面臨的真正的問題是這樣的:

我用下面的代碼繪製的藍色區域:

mStart = -90; 
int degree = (int)((theta + Math.PI) * 180/Math.PI); 
mSweep = degree; 

RectF mOvals = new RectF(c.x - outerRadius + circleThickness, c.y - outerRadius + circleThickness, c.x + outerRadius - circleThickness, c.y + outerRadius - circleThickness); 

mArcSetLevel = new Path(); 

if(mArcSetLevel != null) { 
    canvas.drawArc(mOvals, mStart, mSweep, true, arcPaint); 
} 

在-90設定啓動使得人們開始90度前面。爲了跟蹤觸摸我用這個公式的角度,但是這是它出錯:

int py = (int)event.getY() - c.y; 
int px = (int)event.getX() - c.x; 

theta = (float) ((float) Math.atan2(py, px) - (Math.PI/2)); // - Math.PI/2 to correct -90 start 

當我進一步去比藍色區域被重置正好270度,從北到西更吸引自己角度更小(因爲-90的「錯誤」開始,如第三張圖所示)。我的數學技能根本不夠好,因爲我不能解決這個問題,儘管我能想到它爲什麼會發生,我似乎找不到解決方案。

Image 3

(非常雜亂)代碼,我所做的全部觀點如下:

private Canvas canvas; 

//Canvas width and height 
private int h = -1; 
private int w = -1; 

//circle properties 
private Paint paint; 
private Paint arcPaint; 
private Path circle; 
private Point c; 
private int outerRadius; 
private int circleThickness = 20; 

//point click in wheel 
private float theta = 0; 

private float mStart; 
private float mSweep; 
private Paint mBgPaints = new Paint(); 
private Path mArcSetLevel; 

int padding = 10; 

OnMeterWheelChangeListener onMeterWheelChangeListener = null; 

public MeterWheel(Context context){ 
    super(context); 
    initCircleSeekBar(); 
} 

public MeterWheel(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    initCircleSeekBar(); 
} 

private void initCircleSeekBar() { 

    canvas = new Canvas(); 
    circle = new Path(); 
    paint = new Paint(); 
    arcPaint = new Paint(); 
    c = new Point(); 

    mBgPaints.setAntiAlias(true); 
    mBgPaints.setStyle(Paint.Style.FILL); 
    mBgPaints.setColor(0x88FF0000); 
    mBgPaints.setStrokeWidth(0.5f); 

    mArcSetLevel = new Path(); 

    this.draw(canvas); 
} 


@Override 
protected void onSizeChanged(int width, int height, int oldw, int oldh) { 
    // TODO Auto-generated method stub 
    super.onSizeChanged(width, height, oldw, oldh); 

    w = width; 
    h = height; 
    Log.i("POWERWHEEL", String.valueOf(w) + " " + String.valueOf(h)); 
    c.set(w/2, h/2); 
    drawCircle(); 
} 

private void drawCircle() { 
    outerRadius = Math.min(h,w)/2; 
    circleThickness = (int) (outerRadius*0.15); 

    circle.addArc(new RectF(c.x - outerRadius + circleThickness/2, c.y - outerRadius + circleThickness/2, c.x + outerRadius - circleThickness/2, c.y + outerRadius - circleThickness/2), 0, 360); 
    circle.moveTo(c.x, c.y); 
    //paint.setShader(new SweepGradient(w/2,h/2, colourarry, null)); 
    paint.setColor(Color.GRAY); 
    paint.setStyle(Style.STROKE); 
    paint.setStrokeWidth(circleThickness); 
    paint.setAntiAlias(true); 

    arcPaint.setColor(Color.BLUE); 
    arcPaint.setStyle(Style.FILL); 
    arcPaint.setStrokeWidth(circleThickness); 
    arcPaint.setAntiAlias(true); 
} 


@SuppressLint("DrawAllocation") 
@Override 
protected void onDraw(Canvas canvas) { 
    // TODO Auto-generated method stub 
    super.onDraw(canvas); 

    if(circle != null){ 
    //draw circle 
     canvas.drawPath(circle, paint); 

     mStart = -90; 

     int degree = (int)((theta + Math.PI) * 180/Math.PI); 
     Log.d("POWERWHEEL", "" + degree); 
     mSweep = degree; 

     RectF mOvals = new RectF(c.x - outerRadius + circleThickness, c.y - outerRadius + circleThickness, c.x + outerRadius - circleThickness, c.y + outerRadius - circleThickness); 

     mArcSetLevel = new Path(); 

     if(mArcSetLevel != null) { 
      canvas.drawArc(mOvals, mStart, mSweep, true, arcPaint); 
     } 
    } 

} 


@Override 
public boolean onTouchEvent(MotionEvent event) { 

    if (!isEnabled()) { 
     return false; 
    } 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      setPressed(true); 
      onStartTrackingTouch(event); 
      trackTouchEvent(event); 
      break; 

     case MotionEvent.ACTION_MOVE: 
      trackTouchEvent(event); 
      break; 

     case MotionEvent.ACTION_UP: 
      trackTouchEvent(event); 
      onStopTrackingTouch(); 
      setPressed(false); 
      invalidate(); 
      break; 

     case MotionEvent.ACTION_CANCEL: 
      onStopTrackingTouch(); 
      setPressed(false); 
      invalidate(); 
      break; 
    } 

    return true; 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

    int width = MeasureSpec.getSize(widthMeasureSpec); 
    int height = MeasureSpec.getSize(heightMeasureSpec); 

    setMeasuredDimension(width,height); 
} 

private void onStartTrackingTouch(MotionEvent event) { 

} 

private void onStopTrackingTouch() { 

} 

private void trackTouchEvent(MotionEvent event) { 

    int py = (int)event.getY() - c.y; 
    int px = (int)event.getX() - c.x; 

    theta = (float) ((float) Math.atan2(py, px) - (Math.PI/2)); 
    Log.d("POWERWHEEL", "theta: " + theta); 

    this.invalidate(); 
} 



public void setSize(int x, int y){ 
    h = y; 
    w = x; 
} 

public void setCirleThickness(int t){ 
    circleThickness = t; 
} 


public void setOnMeterWheelChangeListener (OnMeterWheelChangeListener listener) { 
    onMeterWheelChangeListener = listener; 
} 

public interface OnMeterWheelChangeListener{ 
    public void onStartTrackingTouch (MeterWheel colourWheel); 
    public void onStopTrackingTouch (MeterWheel colourWheel); 
} 

提前感謝萬分!

回答

1

在計算theta時,您使用atan2,它返回+/- pi中的角度。因此,當它位於左上象限時,它將返回範圍-pi/2到-pi的範圍內的值(假設y正向下,x向右)。你直接減去pi/2,給出一個-pi到-3pi/2的範圍。在onDraw中,您再次添加pi(令人困惑),爲該象限提供0到-pi/2的掃描範圍。這意味着它將從頂部的起始位置逆時針繪製圓弧0到pi/2(或0到90度)。您必須確保您的掃描始終保持在0到pi的範圍內。最好的解決方案是通過-pi/2移動座標,以便代替Math.atan2(py,px),執行Math.atan2(px,-py),然後如果theta爲負數,則添加2 * pi。喜歡的東西(我不寫的android)

theta = (float) Math.atan2(px, -py); 
if (theta < 0) theta += 2 * Math.PI; 

,然後在onDraw有

int degree = (int)(theta * 180/Math.PI); 
Log.d("POWERWHEEL", "" + degree); 
mSweep = degree; 

如果您仍然遇到問題檢查mSweep始終範圍爲0〜360度。

+1

就是這樣!非常感謝。像這樣的純數學真的是我的弱點,我把事情弄糟了。再次感謝一百萬:) –

+0

@Marcel沒問題,很高興它解決了!祝你的應用程序好運:) – joaerl