Проблема Android с поворотом изображения и матрицей

Надеюсь, это легко, потому что я пробовал всевозможные способы избавиться от этого.

Я делаю приложение для Android, которое включает анимацию часов. У меня все работает очень хорошо, кроме одной очень раздражающей вещи.

У меня есть секундная стрелка на часах, и я использую следующий код, чтобы повернуть ее вокруг центральной точки секундной стрелки. Как вы, наверное, заметили, я пытаюсь сделать это похожим на аналоговую секундную стрелку, чтобы она двигалась, а не просто тикала.

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

На самом деле он выполняет именно ту работу, которую я хочу... почти.

Проблема в том, что руки слегка дрожат/покачиваются вокруг центральной точки, но это действительно заметно и действительно портит эстетику.

Я в значительной степени подозреваю, что это способ округления значения с плавающей запятой, но я надеялся, что кто-то сталкивался с этим раньше и имел какие-либо идеи о том, как от этого избавиться.

Для справки, изображение секундной стрелки изначально имело размер 74 x 28 пикселей и (в настоящее время) 74 x 74 пикселей в формате .png, при этом середина секундной стрелки точно пересекает точку пересечения. Я также пытался сделать его 75 x 75, чтобы на самом деле был центральный пиксель, но не повезло.

Любая помощь вообще будет оценена по достоинству.

** ОБНОВИТЬ

Я пытался изменить код на случай, если десятичные знаки пропадали, но, боюсь, все равно не повезло. Вот вариант 2, который я пробовал и потерпел неудачу;

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

person Dean    schedule 15.11.2010    source источник
comment
Являются ли secondwidth и secondheight числами с плавающей запятой или целыми числами?   -  person Reuben Scratton    schedule 16.11.2010
comment
Они поплавки. Я обновил код выше.   -  person Dean    schedule 16.11.2010
comment
Я думаю, что этот вопрос является дубликатом stackoverflow.com/q/3603646/94363.   -  person rds    schedule 06.12.2010


Ответы (1)


Я понимаю вашу проблему, я никогда не сталкивался с ней сам, но для меня это звучит довольно очевидно. Поскольку повороты изменяют ширину и высоту изображения, ваша неточность исходит из centrex - NegX/2

Я не проверял, но предлагаю вам попробовать:

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

Конечно, это неоптимально, поскольку растровое изображение newSecond намного больше, чем должно быть на самом деле. Поэтому, если ваш centerx и centery большие, вы можете перевести меньше, чем это, а затем нарисовать с переводом разницы.

//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);

Надеюсь это поможет.

person rds    schedule 06.12.2010
comment
Спасибо за подробный отзыв. Я попробую это решение и вернусь к вам. - person Dean; 07.12.2010