【问题标题】:Bitmap rotating about the wrong pivot位图围绕错误的枢轴旋转
【发布时间】:2011-11-17 19:56:23
【问题描述】:

我正在向我的地图应用程序添加一个罗盘叠加层。我决定创建一个相当复杂的罗盘,并在叠加层的构造函数中将其绘制到位图上一次,而不是每次绘制。在叠加层的绘制中,我只是根据磁传感器的值使用矩阵旋转位图。

简而言之,当旋转不是 90、180 或 270 度时,这是不正确的 - 它似乎没有围绕中心旋转。

我创建了一个最小示例,它重现了下面显示的问题以及我看到的 0、45 和 90 度旋转的屏幕截图。叠加形状比真实版本简单得多,并且一些值已被硬编码以减小帖子大小,但这使用与真实应用相同的原理。

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;
        }
    }
}

布局只是一个简单的地图,带有一些通过 clickListener 应用旋转的按钮。应用的旋转显示在 EditText 中。

零旋转

45 度

90 度

任何帮助都将不胜感激,因为我是第一个承认在图形方面我不是世界上最好的人。

【问题讨论】:

    标签: android


    【解决方案1】:

    postRotate 与要旋转的点一起使用。

    【讨论】:

    • 我很确定我尝试过,将 x 和 y 的叠加层中心设为它,但我会再试一次。
    • 我尝试了 matrix.postRotate(rotationDegrees, 50, 50) 和 matrix.postRotate(rotationDegrees, 160 + 50, 70 + 50) (位图的中心和中心的屏幕坐标) - 几乎相同结果。我认为这与“规模”有关,但我不确定是什么
    • rotateCompassBitmap 不会将旋转矩阵应用于rotatedBitmap。为每次绘制创建一个新的位图会消耗大量内存和 CPU。保留一个rotatedBitmap,让矩阵在绘制位图时对其进行变换。
    • 我可以用什么其他语句来旋转已经创建的位图?我只能找到在 createBitmap 中应用矩阵的示例
    • [Canvas.drawBitmap(...)](developer.android.com/reference/android/graphics/…, android.graphics.Matrix, android.graphics.Paint)) 有一个使用矩阵的重载方法。
    猜你喜欢
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    • 2018-08-03
    • 2015-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多