2012-11-28 3 views
4

현재 채우기 백분율로 조정할 수있는 미터를 만들려고합니다. 내가 가진 문제는 내가 수학에 능숙하지 않다는 것입니다. 저는 '북쪽'(첫 번째 이미지)에서 호를 그리기 시작합니다. 두 번째 이미지에서 볼 수 있듯이 '동쪽'에 0도 지점이있는 일반적인 호와 반대입니다. Image 2세로 축에서 회전 각도

Image 1

나는 화면을 따라 터치/드래그하여 크기 (각도)에 이미지 하나에 파란색 영역을 증가시킬 수 있어야합니다. 이제 이것들은 지금 내가 어떤 종류의 패션에서 할 수있는 것들입니다.

나는 파란색 영역을 그리려면 다음 코드를 사용 : -90에서 시작을 설정

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도 일찍 시작하게 내가 직면하고 진짜 문제는 이것이다. 잘못 어디로 가는지 나는이 공식을 사용하여 터치의 각도를 추적하지만이되는 :

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

시타를 계산할 때 atan2를 사용하여 각도를 +/- pi로 반환합니다. 따라서 왼쪽 위 사분면에있을 때 -pi/2 ~ -pi 범위의 값을 반환합니다 (y는 양수이고 x는 오른쪽으로 나타남). -pi ~ -3pi/2의 범위를 주어 pi/2를 직접 빼냅니다. 그런 다음 onDraw에서이 사분면에 대해 스윕의 0 ~ -pi/2 범위를 제공하는 pi를 다시 추가합니다 (혼동). 이것은 맨 위의 시작 위치에서 시계 반대 방향으로 원호 0을 π/2 (또는 0 ~ 90도)로 칠한다는 것을 의미합니다. 스윕이 항상 0에서 pi까지 유지되는지 확인해야합니다. 가장 좋은 해결책은 좌표를 -pi/2만큼 이동하는 것입니다. Math.atan2 (py, px) 대신 Math.atan2 (px, -py)를 수행하고 theta가 음수이면 2 * pi를 추가합니다. 같은 뭔가 (나는 안드로이드를 쓰지 않는다)

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

후 문제가 계속 발생하는 경우

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

된 onDraw

으로는 mSweep의 범위는 0에서 360도 항상 확인하십시오.

+1

그게 전부 야! 고마워. 이런 순수한 수학은 내 약점이다. 나는 모든 것을 엉망으로 만든다. 다시 한번 감사드립니다. –

+0

@Marcel 문제 없습니다. 다행이었습니다. 행운을 빌어 요 앱과 함께 :) – joaerl