简体   繁体   中英

Bitmap rotating about the wrong pivot

I'm adding a compass overlay to my mapping application. I've decided to create a fairly complicated compass rose and have that drawn to a bitmap in the overlay's constructor just once, rather than on every draw. In the overlay's draw I just rotate the bitmap according to the magnetic sensor's value with a Matrix.

In short, it is incorrect when the rotation is anything other than 90, 180 or 270 degrees - it appears not to rotate about the centre.

I've created a minimal sample which reproduces the problem which is shown below together with screen shots of the 0, 45 and 90 degree rotations that I see. The overlay shape is much simpler than the real version and some values have been hard coded to cut down the post size, but this uses the same principles as the real app.

public class BasicMapOverlayActivity extends MapActivity {

    private MapController mMapCtrlr;
    private MapView mMapVw;
    private int mStartLat = 53500000;
    private int mStartLon = -3000000; 
    private float mBearing = 0.0f;
    private static final int COMPASS_OVL_SIZE = 100;
    private Bitmap mCompassRoseBmap;
    private Canvas mCompassRoseCanvas;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mMapVw = (MapView) findViewById(R.id.map);
        mMapCtrlr = mMapVw.getController();
        mMapCtrlr.setZoom(14);
        mMapVw.setSatellite(true);
        mMapVw.setBuiltInZoomControls(true);
        GeoPoint startGpt = new GeoPoint(mStartLat, mStartLon);
        mMapCtrlr.setCenter(startGpt);
        mCompassRoseCanvas = new Canvas();
        mCompassRoseBmap = Bitmap.createBitmap(COMPASS_OVL_SIZE, COMPASS_OVL_SIZE, Bitmap.Config.ARGB_8888);
        mCompassRoseCanvas.setBitmap(mCompassRoseBmap);
        List<Overlay> listOfOverlays = mMapVw.getOverlays();
        CompassOverlay compassOverlay = new CompassOverlay(mCompassRoseCanvas);
        listOfOverlays.add(compassOverlay);
    }
    public void myClickHandler(View target) {

        switch (target.getId()) {
            case R.id.TurnZeroButton:
                mBearing = 0;
                break;
            case R.id.TurnThirtyButton:
                mBearing = 30;
                break;
            case R.id.Turn45Button:
                mBearing = 45;
                break;
            case R.id.TurnNinetyButton:
                mBearing = 90;
                break;
            case R.id.Turn180Button:
                mBearing = 180;
                break;
        }
        EditText et = (EditText) findViewById(R.id.editText1);
        NumberFormat formatter = new DecimalFormat("##0");
        et.setText(formatter.format(mBearing));
        mMapVw.invalidate();
    }
    @Override
    protected boolean isRouteDisplayed() {return false;}

    public class CompassOverlay extends com.google.android.maps.Overlay {

        private Paint overlayPaint;
        private RectF oRec;

        public CompassOverlay(Canvas canvas) {
            super();
            createRose(canvas, COMPASS_OVL_SIZE);
        }

        public void createRose(Canvas canvas, int overlaySize) {

            float scale = (float) overlaySize;
            canvas.scale(scale, scale);
            overlayPaint = new Paint();
            overlayPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            overlayPaint.setColor(Color.YELLOW);
            overlayPaint.setAntiAlias(true);
            oRec = new RectF();
            oRec.set(0.0f, 0.0f, 1.0f, 1.0f);
            // draw rectangle edges and diagonals
            canvas.drawLine(oRec.left, oRec.top, oRec.right, oRec.bottom, overlayPaint);
            canvas.drawLine(oRec.left, oRec.bottom, oRec.right, oRec.top, overlayPaint);
            canvas.drawLine(oRec.left, oRec.top, oRec.right, oRec.top, overlayPaint);
            canvas.drawLine(oRec.right, oRec.top, oRec.right, oRec.bottom, overlayPaint);
            canvas.drawLine(oRec.right, oRec.bottom, oRec.left, oRec.bottom, overlayPaint);
            canvas.drawLine(oRec.left, oRec.bottom, oRec.left, oRec.top, overlayPaint);
            // draw red vertical line as a direction indicator
            overlayPaint.setColor(Color.RED);
            canvas.drawLine(0.5f, oRec.top, 0.5f, oRec.bottom/2, overlayPaint);// vertical line
            overlayPaint.setColor(Color.YELLOW);
        }
        @Override
        public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {

            Bitmap rBitmap = rotateCompassBitmap(mBearing);
            canvas.drawBitmap(rBitmap, 160, 70, null);
            rBitmap.recycle();
            return false;
        }

        private Bitmap rotateCompassBitmap(float rotationDegrees) {
            Matrix matrix = new Matrix();
            matrix.postRotate(rotationDegrees);
            Bitmap rotatedBitmap = Bitmap.createBitmap(mCompassRoseBmap, 0, 0,
                     mCompassRoseBmap.getWidth(), mCompassRoseBmap.getHeight(), matrix, true); 
            return  rotatedBitmap;
        }
    }
}

The layout is just a simple map, with some buttons which apply a rotation by means of a clickListener. The rotation applied is shown in an EditText.

Zero rotation 零旋转

45 degrees 45度

90 degrees 90度

Any help would be much appreciated, as I'm the first to admit that I'm not the world's best when it comes to graphics.

使用postRotate旋转一个点。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM