Android problem with Image Rotate and Matrix

2019-08-12 05:02发布

问题:

Hopefully this is an easy one because I've been trying all sorts of different ways to get rid of this.

I am making an android app which incorporates a clock animation. I've got everything working really well except one very annoying thing.

I have a second hand on the clock and I'm using the following code to rotate it around a the second hand center point. As you'll probably notice I'm trying to make this look like an analogue second hand so it sweeps instead of just ticking.

        public float secdegrees, secondwidth, secondheight;

        secondMatrix = new Matrix();
        secondwidth = secondHand.getWidth();
        secondheight = secondHand.getHeight();
        secdegrees = anglepersec * secnow;
        secdegrees += anglepluspermilli * millis;
        secondMatrix.setRotate(secdegrees, secondwidth/2, secondheight / 2);
        newSecond = Bitmap.createBitmap(secondHand, 0, 0,
               (int) secondwidth, (int) secondheight, secondMatrix, true);
        c.drawBitmap(newSecond, (centrex - newSecond.getWidth()/2),
               ((face.getHeight()/2) - newSecond.getHeight()/2), null);

It actually does just the job I want... almost.

The problem is the hand shakes/jiggles around the center point ever so slightly, but it's really noticeable and really spoils the aesthetics.

I pretty much suspect that it's the way that it's rounding the float value, but I was hoping that someone had experienced this before and had any ideas on how to get rid of it.

For reference the second hand image was originally 74 px x 28 px and is (currently) 74 x 74 pixels .png with the middle of the second hand exactly crossing the crossing point. I've also tried making it 75 x 75 so that there is actually a central pixel too but no luck.

Any help at all would be appreciated.

** UPDATE

I've tried to change the code in case the decimals were getting dropped but still no luck I'm afraid. Here is option 2 I've tried and failed with;

        secondMatrix = new Matrix();
        secondwidth = secondHand.getWidth();
        secondheight = secondHand.getHeight();
        secdegrees = anglepersec * secnow;
        secdegrees += anglepluspermilli * millis;
        secondMatrix.setRotate(secdegrees, secondwidth/2, secondheight / 2);
        newSecond = Bitmap.createBitmap(secondHand, 0, 0, (int) secondwidth,
              (int) secondheight, secondMatrix, true);
        float secW = newSecond.getWidth()/2;
        float secH = newSecond.getHeight()/2;

        // NEW CODE HERE
        float calcdeg = secdegrees % 90;
        calcdeg = (float) Math.toRadians(calcdeg);
        float NegY = (float) ((secondwidth*Math.cos(calcdeg)) +
             (secondwidth * Math.sin(calcdeg)));
        c.drawBitmap(newSecond, centrex - NegY/2,
              ((face.getHeight()/2) - NegY/2), null);

回答1:

I understand your problem, I have never encountered it mysleft, but it sounds pretty obvious to me. Since the rotations changes the width and height of the image, your imprecision comes from centrex - NegX/2

I have not tested, but I suggest you try:

Matrix matrix=new Matrix()
//first translate to place the center of the hand at Point(0,0)
matrix.setTranslate(-secondWidth/2,-secondHeight/2);
matrix.setRotate(secdegrees);
//now place the pivot Point(0,0) at its expected location
matrix.setTranslate(centreX,centreY);
newSecond = Bitmap.createBitmap(secondHand, 0, 0, secondWidth, secondHeight, matrix, false);
c.drawBitmap(newSecond,0,0,null);

Of course, this is suboptimal, since the newSecond bitmap is much larger than it actually needs to be. So if your centrex and centrey are big, you might want to translate less than that, and then draw with a translation of the difference.

//now place the pivot to a position where the hand can be fully drawn without imprecion on the future location of Point(0,0)
matrix.setTranslate(secondWith,secondHeight);
newSecond = Bitmap.createBitmap(secondHand, 0, 0, secondWidth, secondHeight, matrix, false);
c.drawBitmap(newSecond,centrex-secondWidth,centrey-secondHeight,null);

Hope this helps.