Rotation angle from the vertical axis

I'm currently trying to create a counter that can be set as a percentage of filling. The problem is that I don’t understand mathematics at all. I want to start drawing an arc in the “north” (first image), unlike a regular arc with a “0 degree” point in the east (as shown in the second image).

Image 1Image 2

I want to be able to enlarge the blue area in image 1 in size (in angle) by dragging / touching it along the screen. Now this is what I can do in some way. The real problem I came across is this:

I use the following code to draw a blue area:

mStart = -90; int degree = (int)((theta + Math.PI) * 180 / Math.PI); mSweep = degree; RectF mOvals = new RectF(cx - outerRadius + circleThickness, cy - outerRadius + circleThickness, cx + outerRadius - circleThickness, cy + outerRadius - circleThickness ); mArcSetLevel = new Path(); if(mArcSetLevel != null ) { canvas.drawArc(mOvals, mStart, mSweep, true, arcPaint); } 

Setting the start from -90 causes it to start 90 degrees earlier. To keep track of the angle of contact, I use this formula, but this does not work correctly:

 int py = (int)event.getY() - cy; int px = (int)event.getX() - cx; theta = (float) ((float) Math.atan2(py, px) - (Math.PI / 2)); // - Math.PI / 2 to correct -90 start 

When I go exactly 270 degrees further, the blue area gets reset and pulls itself from north to west to a much smaller angle (due to the “false” start -90 shown in the third image). My math skills are simply not good enough for me to be able to solve this problem, although I can think about why this is happening. I can not find a solution.

Image 3

The (very dirty) code for the whole view I made looks like this:

  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(cx - outerRadius + circleThickness/2, cy - outerRadius + circleThickness/2, cx + outerRadius - circleThickness/2, cy + outerRadius - circleThickness/2 ), 0, 360); circle.moveTo(cx, cy); //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(cx - outerRadius + circleThickness, cy - outerRadius + circleThickness, cx + outerRadius - circleThickness, cy + 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() - cy; int px = (int)event.getX() - cx; 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); } 

Thanks for the million!

+4
source share
1 answer

When calculating theta, you use atan2, which returns the angle at +/- pi. Therefore, being in the upper left quadrant, it will return a value in the range from -pi / 2 to -pi (provided that y is positive down and x is right). You set pi / 2 directly, giving a range from -pi to -3pi / 2. In onDraw, you then add pi again (confused), giving a range from 0 to -pi / 2 sweep for this quadrant. This means that it will draw an arc 0 to pi / 2 (or 0 to 90 degrees) counterclockwise from your original position at the top. You must make sure that your sweep always stays between 0 and pi. The best solution is to shift the coordinates by -pi / 2, so instead of Math.atan2 (py, px) you do Math.atan2 (px, -py), and then if theta is negative, you add 2 * pi. Something like (I am not writing Android)

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

and then in onDraw

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

If you are still experiencing problems, check that mSweep is always in the range of 0 to 360 degrees.

+1
source

All Articles