Средство просмотра изображений direct2d Как преобразовать координаты экрана в координаты изображения?

Я пытаюсь понять, как преобразовать положение мыши (экранные координаты) в соответствующую точку на базовом преобразованном изображении, нарисованном на поверхности direct2d. код здесь следует рассматривать как псевдокод, поскольку я использую модифицированную оболочку C++/CLI вокруг Direct2D для C#, вы не сможете скомпилировать это ни в чем, кроме моего собственного проекта.

Render()
{
    //The transform matrix combines a rotation, followed by a scaling then a translation
    renderTarget.Transform = _rotate * _scale * _translate;
    RectF imageBounds = new RectF(0, 0, _imageSize.Width, _imageSize.Height);
    renderTarget.DrawBitmap(this._image, imageBounds, 1, BitmapInterpolationMode.Linear);
}
Zoom(float zoomfactor, PointF mousepos)
{
    //mousePos is in screen coordinates. I need to convert it to image coordinates.
    Matrix3x2 t = _translate.Invert();
    Matrix3x2 s = _scale.Invert();
    Matrix3x2 r = _rotate.Invert();
    PointF center = (t * s * r).TransformPoint(mousePos); 
    _scale = Matrix3x2.Scale(zoomfactor, zoomfactor, center);    
}

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

Если я установлю центральную точку масштаба как (imagewidth/2, imageheight/2), результирующее масштабирование будет плавным, но всегда центрируется по центру изображения, поэтому я почти уверен, что мерцание не связано с какой-то другой ошибочной частью программа.

Спасибо.


person philvanzu    schedule 01.12.2013    source источник
comment
Попробуйте заменить t * s * r на r * s * t. И убедитесь, что точка экрана находится в координатах клиента и учитывается (возможно, пользовательский) DPI.   -  person CodeAngry    schedule 02.12.2013
comment
Я уже пробовал это, и мерцание стало хуже, а мышка просто для того, чтобы лучше проиллюстрировать мою цель; Я зафиксировал его в клиентском центре для целей тестирования, пока у меня нет надежного решения.   -  person philvanzu    schedule 02.12.2013


Ответы (2)


Я наконец понял это правильно

это дает мне совершенно плавное (пошаговое?, относительное?) масштабирование с центром в центре клиента (я отказался от идеи положения мыши, так как хотел использовать ввод движения мыши для управления масштабированием)

     protected float zoomf
    {
        get
        {
            //extract scale factor from scale matrix
            return (float)Math.Sqrt((double)((_scale.M11 * _scale.M11) 
                                              + (_scale.M21 * _scale.M21)));
        }
    }

    public void Zoom(float factor)
    {

        factor = Math.Min(zoomf, 1) * 0.006f * factor;
        factor += 1;

        Matrix3x2 t = _translation;
        t.Invert();
        PointF center = t.TransformPoint(_clientCenter);


        Matrix3x2 m = Matrix3x2.Scale(new SizeF(factor, factor), center);
        _scale = _scale * m;
        Invalidate();
    }
person philvanzu    schedule 08.12.2013

Шаг 1. Поместите android:scaleType="matrix" в XML-файл ImageView. Шаг 2. Преобразуйте точки касания экрана в значение Matrix. Шаг 3. Разделите каждое значение матрицы на параметр плотности экрана, чтобы получить одинаковое значение координат на всех экранах.

**XML**
<ImageView
  android:id="@+id/myImage"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:scaleType="matrix"
  android:src="@drawable/ga"/>

**JAVA**
 @Override
  public boolean onTouchEvent(MotionEvent event) {
    float[] point = new float[]{event.getX(), event.getY()};
    Matrix inverse = new Matrix();
    getImageMatrix().invert(inverse);
    inverse.mapPoints(point);
    float density = getResources().getDisplayMetrics().density;
    int[] imagePointArray = new int[2];
    imagePointArray[0] = (int) (point[0] / density);
    imagePointArray[1] = (int) (point[1] / density);
    Rect rect = new Rect( imagePointArray[0] - 20, imagePointArray[1]  - 20,  imagePointArray[0] + 20, imagePointArray[1]  + 20);//20 is the offset value near to the touch point
        boolean b = rect.contains(267, 40);//267,40 are the predefine image coordiantes
        Log.e("Touch inside ", b + "");
    return true;

}
person vishnuc156    schedule 03.10.2016