Преобразования матрицы в SkiaSharpMatrix Transforms in SkiaSharp

Загрузить образец загрузить примерDownload Sample Download the sample

Погрузитесь глубже в преобразование skiasharp с матрица универсальный преобразованияDive deeper into SkiaSharp transforms with the versatile transform matrix

Всех преобразований, применяемых к SKCanvas объекта объединены в один экземпляр SKMatrix структуры.All the transforms applied to the SKCanvas object are consolidated in a single instance of the SKMatrix structure. Это стандартный 3 x 3 матрицу преобразования аналогична семантике во всех системах современных двумерной графики.This is a standard 3-by-3 transform matrix similar to those in all modern 2D graphics systems.

Как вы убедились, преобразования можно использовать в SkiaSharp не зная о преобразовании матрицы, но матрица преобразования важна с теоретической точки зрения, и очень важно при использовании преобразования для изменения пути или для обработки сложных сенсорный ввод, оба которой описаны в этой статье, а также следующие.As you've seen, you can use transforms in SkiaSharp without knowing about the transform matrix, but the transform matrix is important from a theoretical perspective, and it is crucial when using transforms to modify paths or for handling complex touch input, both of which are demonstrated in this article and the next.

Применяется к текущей матрице преобразования SKCanvas доступна в любое время, обратившись к доступной только для чтения TotalMatrix свойство.The current transform matrix applied to the SKCanvas is available at any time by accessing the read-only TotalMatrix property. Можно задать новый матрицы преобразования с помощью SetMatrix метод и можно восстановить данную матрицу преобразования в значения по умолчанию путем вызова ResetMatrix .You can set a new transform matrix using the SetMatrix method, and you can restore that transform matrix to default values by calling ResetMatrix.

Единственным других SKCanvas член, который работает непосредственно с полотна к матрице преобразования является Concat который Сцепляет двух матриц путем умножения их друг с другом.The only other SKCanvas member that directly works with the canvas's matrix transform is Concat which concatenates two matrices by multiplying them together.

Матрица преобразования по умолчанию — единичная матрица и состоит из 1 в диагонали ячеек и значение 0 во всех остальных:The default transform matrix is the identity matrix and consists of 1's in the diagonal cells and 0's everywhere else:

| 1  0  0 |
| 0  1  0 |
| 0  0  1 |

Можно создать с помощью статического единичной матрицей SKMatrix.MakeIdentity метод:You can create an identity matrix using the static SKMatrix.MakeIdentity method:

SKMatrix matrix = SKMatrix.MakeIdentity();

SKMatrix Конструктор по умолчанию не не возвращают единичной матрицей.The SKMatrix default constructor does not return an identity matrix. Он возвращает матрицу с все ячейки, равным нулю.It returns a matrix with all of the cells set to zero. Не используйте SKMatrix конструктор, если вы планируете вручную настроить эти ячейки.Do not use the SKMatrix constructor unless you plan to set those cells manually.

При визуализации графического объекта SkiaSharp каждой точки (x, y) эффективно преобразуется в матрицу с 1 по 3 с 1 в третьем столбце:When SkiaSharp renders a graphical object, each point (x, y) is effectively converted to a 1-by-3 matrix with a 1 in the third column:

| x  y  1 |

Эта матрица с 1 по 3 представляет точку трехмерного с значение координаты Z, равным 1.This 1-by-3 matrix represents a three-dimensional point with the Z coordinate set to 1. Есть математические причин, (рассматривается далее), почему Двухмерная матрица преобразования требуется работать в трех измерениях.There are mathematical reasons (discussed later) why a two-dimensional matrix transform requires working in three dimensions. Можно представить данной матрицы 1 x 3, представляющего точку в трехмерной системе координат, но всегда на двумерную плоскость где значение Z равно 1.You can think of this 1-by-3 matrix as representing a point in a 3D coordinate system, but always on the 2D plane where Z equals 1.

Эта матрица с 1 по 3 затем умножается матрица преобразования, а результат является точкой, отображается на холсте:This 1-by-3 matrix is then multiplied by the transform matrix, and the result is the point rendered on the canvas:

              | 1  0  0 |
| x  y  1 | × | 0  1  0 | = | x'  y'  z' |
              | 0  0  1 |

Используется стандартный матрицы умножение, преобразованный точки являются следующим образом:Using standard matrix multiplication, the converted points are as follows:

x' = x

y' = y

z' = 1

Это преобразование по умолчанию.That's the default transform.

При Translate вызывается метод SKCanvas объекта, tx и ty аргументы Translate метод становятся двух первых ячейках в третьей строке матрицы преобразования:When the Translate method is called on the SKCanvas object, the tx and ty arguments to the Translate method become the first two cells in the third row of the transform matrix:

|  1   0   0 |
|  0   1   0 |
| tx  ty   1 |

Умножение является теперь следующим образом:The multiplication is now as follows:

              |  1   0   0 |
| x  y  1 | × |  0   1   0 | = | x'  y'  z' |
              | tx  ty   1 |

Ниже приведены преобразования формулы.Here are the transform formulas:

x' = x + tx

y' = y + ty

Коэффициенты масштабирования имеет значения по умолчанию 1.Scaling factors have a default value of 1. При вызове Scale новый метод SKCanvas объекта содержит матрицу преобразования результирующий sx и sy аргументов в диагонали ячеек:When you call the Scale method on a new SKCanvas object, the resultant transform matrix contains the sx and sy arguments in the diagonal cells:

              | sx   0   0 |
| x  y  1 | × |  0  sy   0 | = | x'  y'  z' |
              |  0   0   1 |

Преобразование формул, следующим образом:The transform formulas are as follows:

x' = sx · x

y' = sy · y

Матрица преобразования после вызова метода Skew содержит два аргумента в ячейках матрицы рядом коэффициенты масштабирования:The transform matrix after calling Skew contains the two arguments in the matrix cells adjacent to the scaling factors:

              │   1   ySkew   0 │
| x  y  1 | × │ xSkew   1     0 │ = | x'  y'  z' |
              │   0     0     1 │

Преобразование формул:The transform formulas are:

x' = x + xSkew · y

y' = ySkew · x + y

Для вызова RotateDegrees или RotateRadians для угол α, матрица преобразования выглядит следующим образом:For a call to RotateDegrees or RotateRadians for an angle of α, the transform matrix is as follows:

              │  cos(α)  sin(α)  0 │
| x  y  1 | × │ –sin(α)  cos(α)  0 │ = | x'  y'  z' |
              │    0       0     1 │

Ниже приведены преобразования формулы.Here are the transform formulas:

x' = cos(α) · x - sin(α) · y

y' = sin(α) · x - cos(α) · y

Α-0 градусов, при единичной матрицей.When α is 0 degrees, it's the identity matrix. Когда α 180 градусов, матрица преобразования выглядит следующим образом:When α is 180 degrees, the transform matrix is as follows:

| –1   0   0 |
|  0  –1   0 |
|  0   0   1 |

Поворот на 180 градусов соответствует переворот объекта по горизонтали и вертикали, который также выполняется путем коэффициенты масштабирования параметр – 1.A 180-degree rotation is equivalent to flipping an object horizontally and vertically, which is also accomplished by setting scale factors of –1.

Все эти типы преобразований классифицируются как аффинные преобразования.All these types of transforms are classified as affine transforms. Аффинные преобразования никогда не включать в себя третий столбец матрицы, которое остается в значения по умолчанию 0, 0 и 1.Affine transforms never involve the third column of the matrix, which remains at the default values of 0, 0, and 1. Статья Non-аффинных преобразований обсуждаются неаффинные преобразования.The article Non-Affine Transforms discusses non-affine transforms.

Умножение матрицMatrix Multiplication

Одним из значительных преимуществ с помощью матрицы преобразования — что составных преобразований можно получить, Перемножение матриц, который часто упоминается в документации как SkiaSharp объединение.One significant advantage with using the transform matrix is that composite transforms can be obtained by matrix multiplication, which is often referred to in the SkiaSharp documentation as concatenation. Многие методы, связанные с преобразованием в SKCanvas см. «предварительного объединения» или «pre-concat.»Many of the transform-related methods in SKCanvas refer to "pre-concatenation" or "pre-concat." Это относится порядку умножения, что важно, поскольку умножение матриц не является коммутативной.This refers to the order of multiplication, which is important because matrix multiplication is not commutative.

Например, в документации по Translate метод говорит, что он «Pre-concats текущей матрицы с помощью заданного сдвига» при документации для Scale метод говорит, что он «Pre-concats Текущая матрица с заданным масштабом.»For example, the documentation for the Translate method says that it "Pre-concats the current matrix with the specified translation," while the documentation for the Scale method says that it "Pre-concats the current matrix with the specified scale."

Это означает, что указаны путем вызова метода преобразования — множитель (левый операнд) и текущая матрица преобразования множитель (правый операнд).This means that the transform specified by the method call is the multiplier (the left-hand operand) and the current transform matrix is the multiplicand (the right-hand operand).

Предположим, что Translate вызывается следуют Scale:Suppose that Translate is called followed by Scale:

canvas.Translate(tx, ty);
canvas.Scale(sx, sy);

Scale Умножается на преобразование Translate составным преобразованием матрицы преобразования:The Scale transform is multiplied by the Translate transform for the composite transform matrix:

| sx   0   0 |   |  1   0   0 |   | sx   0   0 |
|  0  sy   0 | × |  0   1   0 | = |  0  sy   0 |
|  0   0   1 |   | tx  ty   1 |   | tx  ty   1 |

Scale может быть вызван перед Translate следующим образом:Scale could be called before Translate like this:

canvas.Scale(sx, sy);
canvas.Translate(tx, ty);

В этом случае изменять порядок умножения и коэффициенты масштабирования эффективно применяются к translation factors:In that case, the order of the multiplication is reversed, and the scaling factors are effectively applied to the translation factors:

|  1   0   0 |   | sx   0   0 |   |  sx      0    0 |
|  0   1   0 | × |  0  sy   0 | = |   0     sy    0 |
| tx  ty   1 |   |  0   0   1 |   | tx·sx  ty·sy  1 |

Вот Scale метод с точкой вращения:Here is the Scale method with a pivot point:

canvas.Scale(sx, sy, px, py);

Это эквивалентно следующие вызовы translate и масштабирования:This is equivalent to the following translate and scale calls:

canvas.Translate(px, py);
canvas.Scale(sx, sy);
canvas.Translate(–px, –py);

Три матрицы преобразования умножаются в обратном порядке из как методы отображаются в коде:The three transform matrices are multiplied in reverse order from how the methods appear in code:

|  1    0   0 |   | sx   0   0 |   |  1   0  0 |   |    sx         0     0 |
|  0    1   0 | × |  0  sy   0 | × |  0   1  0 | = |     0        sy     0 |
| –px  –py  1 |   |  0   0   1 |   | px  py  1 |   | px–px·sx  py–py·sy  1 |

Структура SKMatrixThe SKMatrix Structure

SKMatrix Структура определяет девять свойств чтения и записи типа float соответствующий девять ячеек матрицы преобразования:The SKMatrix structure defines nine read/write properties of type float corresponding to the nine cells of the transform matrix:

│ ScaleX  SkewY   Persp0 │
│ SkewX   ScaleY  Persp1 │
│ TransX  TransY  Persp2 │

SKMatrix также определяет свойство, именуемое Values типа float[].SKMatrix also defines a property named Values of type float[]. Это свойство может использоваться для задания или получения девять значений за один раз в порядке ScaleX, SkewX, TransX, SkewY, ScaleY, TransY, Persp0, Persp1, и Persp2.This property can be used to set or obtain the nine values in one shot in the order ScaleX, SkewX, TransX, SkewY, ScaleY, TransY, Persp0, Persp1, and Persp2.

Persp0, Persp1, И Persp2 ячеек рассматриваются в этой статье Non-аффинных преобразований.The Persp0, Persp1, and Persp2 cells are discussed in the article Non-Affine Transforms. Если эти ячейки имеют значения по умолчанию 0, 0 и 1, преобразование умножается координаты точки следующим образом:If these cells have their default values of 0, 0, and 1, then the transform is multiplied by a coordinate point like this:

              │ ScaleX  SkewY   0 │
| x  y  1 | × │ SkewX   ScaleY  0 │ = | x'  y'  z' |
              │ TransX  TransY  1 │

x' = ScaleX · x + SkewX · y + TransX

y' = SkewX · x + ScaleY · y + TransY

z' = 1

Это полный двухмерный аффинного преобразования.This is the complete two-dimensional affine transform. Аффинные преобразования сохраняет параллельные линии, это означает, что прямоугольник никогда не преобразуются в строки, отличное от параллелограмм.The affine transform preserves parallel lines, which means that a rectangle is never transformed into anything other than a parallelogram.

SKMatrix Структура определяет несколько статических методов для создания SKMatrix значения.The SKMatrix structure defines several static methods to create SKMatrix values. Они возвращают SKMatrix значения:These all return SKMatrix values:

SKMatrix также определяет несколько статических методов, осуществляющие сцепление двух матриц, что означает умножать их.SKMatrix also defines several static methods that concatenate two matrices, which means to multiply them. Эти методы называются Concat , PostConcat , и PreConcat , и существуют две версии каждого из них.These methods are named Concat, PostConcat, and PreConcat, and there are two versions of each. Эти методы имеют нет возвращаемых значений; Вместо этого они ссылаются существующие SKMatrix значения через ref аргументы.These methods have no return values; instead, they reference existing SKMatrix values through ref arguments. В следующем примере A, B, и R (для «результат»), все SKMatrix значения.In the following example, A, B, and R (for "result") are all SKMatrix values.

Два Concat методы вызываются следующим образом:The two Concat methods are called like this:

SKMatrix.Concat(ref R, A, B);

SKMatrix.Concat(ref R, ref A, ref B);

Они выполняют следующие умножения:These perform the following multiplication:

R = B × A

Другие методы имеют только два параметра.The other methods have only two parameters. Первый параметр изменены и при возврате из вызова метода, содержит произведение двух матриц.The first parameter is modified, and on return from the method call, contains the product of the two matrices. Два PostConcat методы вызываются следующим образом:The two PostConcat methods are called like this:

SKMatrix.PostConcat(ref A, B);

SKMatrix.PostConcat(ref A, ref B);

Эти вызовы выполнить следующую операцию:These calls perform the following operation:

A = A × B

Два PreConcat методы похожи:The two PreConcat methods are similar:

SKMatrix.PreConcat(ref A, B);

SKMatrix.PreConcat(ref A, ref B);

Эти вызовы выполнить следующую операцию:These calls perform the following operation:

A = B × A

Версии этих методов со всеми ref аргументы немного более эффективны с точки вызова базовых реализаций, но он может ввести в заблуждение кто-то читает этот код и при условии, что-либо с ref изменяется после аргумента метод.The versions of these methods with all ref arguments are slightly more efficient in calling the underlying implementations, but it might be confusing to someone reading your code and assuming that anything with a ref argument is modified by the method. Кроме того, часто бывает удобно для передачи аргумент, который является результатом одного из Make методы, например:Moreover, it's often convenient to pass an argument that is a result of one of the Make methods, for example:

SKMatrix result;
SKMatrix.Concat(result, SKMatrix.MakeTranslation(100, 100),
                        SKMatrix.MakeScale(3, 3));

Это создает приведенной ниже таблице:This creates the following matrix:

│   3    0  0 │
│   0    3  0 │
│ 100  100  1 │

Это преобразование масштабирования, умноженное на преобразования переноса.This is the scale transform multiplied by the translate transform. В данном конкретном случае SKMatrix структура предоставляет ярлык с методом SetScaleTranslate :In this particular case, the SKMatrix structure provides a shortcut with a method named SetScaleTranslate:

SKMatrix R = new SKMatrix();
R.SetScaleTranslate(3, 3, 100, 100);

Это одна из несколько раз, когда можно безопасно использовать SKMatrix конструктор.This is one of the few times when it's safe to use the SKMatrix constructor. SetScaleTranslate Метод задает все девять ячеек матрицы.The SetScaleTranslate method sets all nine cells of the matrix. Также можно безопасно использовать SKMatrix конструктор с помощью статического Rotate и RotateDegrees методов:It is also safe to use the SKMatrix constructor with the static Rotate and RotateDegrees methods:

SKMatrix R = new SKMatrix();

SKMatrix.Rotate(ref R, radians);

SKMatrix.Rotate(ref R, radians, px, py);

SKMatrix.RotateDegrees(ref R, degrees);

SKMatrix.RotateDegrees(ref R, degrees, px, py);

Эти методы выполняют не сцепления поворота преобразование, существующее преобразование.These methods do not concatenate a rotate transform to an existing transform. Методы задать все ячейки матрицы.The methods set all the cells of the matrix. Они являются функционально идентичен MakeRotation и MakeRotationDegrees методы за исключением того, что они не создавайте экземпляр SKMatrix значение.They are functionally identical to the MakeRotation and MakeRotationDegrees methods except that they don't instantiate the SKMatrix value.

Предположим, что у вас есть SKPath объект, который будет отображаться, но вы хотите использовать, что он имеет несколько по-разному ориентации или другая центральная точка.Suppose you have an SKPath object that you want to display, but you would prefer that it have a somewhat different orientation, or a different center point. Все координаты этот путь можно изменить, вызвав Transform метод SKPath с SKMatrix аргумент.You can modify all the coordinates of that path by calling the Transform method of SKPath with an SKMatrix argument. Путь преобразования странице рассказывается, как это сделать.The Path Transform page demonstrates how to do this. PathTransform Класса ссылки HendecagramPath объекта в поле но использует свой конструктор, чтобы применить преобразование к этому пути:The PathTransform class references the HendecagramPath object in a field but uses its constructor to apply a transform to that path:

public class PathTransformPage : ContentPage
{
    SKPath transformedPath = HendecagramArrayPage.HendecagramPath;

    public PathTransformPage()
    {
        Title = "Path Transform";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;

        SKMatrix matrix = SKMatrix.MakeScale(3, 3);
        SKMatrix.PostConcat(ref matrix, SKMatrix.MakeRotationDegrees(360f / 22));
        SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(300, 300));

        transformedPath.Transform(matrix);
    }
    ...
}

HendecagramPath Объект имеет центр в (0, 0) и 11 очков звезды наружу расширения центра на 100 единиц по всем направлениям.The HendecagramPath object has a center at (0, 0), and the 11 points of the star extend outward from that center by 100 units in all directions. Это означает, что путь имеет положительных и отрицательных координат.This means that the path has both positive and negative coordinates. Путь преобразования предпочитает star трижды как большие и все координаты положительное работе страницы.The Path Transform page prefers to work with a star three times as large, and with all positive coordinates. Кроме того он не хочет одну точку из типа "звезда", чтобы они указывали вверх.Moreover, it doesn't want one point of the star to point straight up. Компания хочет вместо этого для одной точки звезды пункт вниз.It wants instead for one point of the star to point straight down. (Поскольку звездочка имеет 11 очков, оба правила применить невозможно.) Этот сценарий требует поворот звездочки на 360 градусов деленное 22.(Because the star has 11 points, it can't have both.) This requires rotating the star by 360 degrees divided by 22.

Конструктор создает SKMatrix объект из трех отдельных операций преобразования, использующих PostConcat метод в следующем формате, где A, B и C являются экземплярами SKMatrix:The constructor builds an SKMatrix object from three separate transforms using the PostConcat method with the following pattern, where A, B, and C are instances of SKMatrix:

SKMatrix matrix = A;
SKMatrix.PostConcat(ref A, B);
SKMatrix.PostConcat(ref A, C);

Это ряд последовательных операции умножения, поэтому результат выглядит следующим образом:This is a series of successive multiplications, so the result is as follows:

A × B × C

Последовательные операции умножения помогают лучше понять назначение каждого преобразования.The consecutive multiplications aid in understanding what each transform does. Преобразование масштаба увеличивает размер координат путь с коэффициентом 3, поэтому координаты в диапазоне от –300 до 300.The scale transform increases the size of the path coordinates by a factor of 3, so the coordinates range from –300 to 300. Преобразование циклического сдвига вращается вокруг начала координат типа "звезда".The rotate transform rotates the star around its origin. Преобразование переноса затем перемещает его с 300 пикселей вправо и вниз, поэтому все координаты, становятся положительными.The translate transform then shifts it by 300 pixels right and down, so all the coordinates become positive.

Существуют другие последовательности, которые создают и та же матрица.There are other sequences that produce the same matrix. Ниже приведен еще один.Here's another one:

SKMatrix matrix = SKMatrix.MakeRotationDegrees(360f / 22);
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeTranslation(100, 100));
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(3, 3));

Это сначала поворачивает пути вокруг его центра и затем преобразовать его 100 пикселей вправо и вниз, так что все координаты имеют положительное значение.This rotates the path around its center first, and then translates it 100 pixels to the right and down so all the coordinates are positive. Затем типа "звезда" увеличивается размер относительно новых верхнего левого угла, который является точкой (0, 0).The star is then increased in size relative to its new upper-left corner, which is the point (0, 0).

PaintSurface Обработчик может просто отображать этот путь:The PaintSurface handler can simply render this path:

public class PathTransformPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Magenta;
            paint.StrokeWidth = 5;

            canvas.DrawPath(transformedPath, paint);
        }
    }
}

Он отображается в левом верхнем углу холста:It appears in the upper-left corner of the canvas:

Конструктор эта программа применяет матрицы к пути, вызвав:The constructor of this program applies the matrix to the path with the following call:

transformedPath.Transform(matrix);

Путь не сохранить эту матрицу как свойство.The path does not retain this matrix as a property. Вместо этого преобразование применяется ко всем координат пути.Instead, it applies the transform to all of the coordinates of the path. Если Transform вызывается снова, применяется преобразование и является единственным способом, вы можете вернуться, применив другой матрицу, которая отменяет преобразование.If Transform is called again, the transform is applied again, and the only way you can go back is by applying another matrix that undoes the transform. К счастью SKMatrix структура определяет TryInvert метод, который получает матрицу, которая отменяет заданной матрицы:Fortunately, the SKMatrix structure defines a TryInvert method that obtains the matrix that reverses a given matrix:

SKMatrix inverse;
bool success = matrix.TryInverse(out inverse);

Вызывается метод TryInverse , так как не все матрицы обратимой, но матрицу необратимым вряд ли будут использоваться для преобразования графики.The method is called TryInverse because not all matrices are invertible, but a non-invertible matrix is not likely to be used for a graphics transform.

Также можно применить преобразование матрицы SKPoint значение, массив точек, SKRect, или даже просто одно число в программе.You can also apply a matrix transform to an SKPoint value, an array of points, an SKRect, or even just a single number within your program. SKMatrix Структура поддерживает эти операции с коллекцией методов, которые начинаются со слова Map, такие:The SKMatrix structure supports these operations with a collection of methods that begin with the word Map, such as these:

SKPoint transformedPoint = matrix.MapPoint(point);

SKPoint transformedPoint = matrix.MapPoint(x, y);

SKPoint[] transformedPoints = matrix.MapPoints(pointArray);

float transformedValue = matrix.MapRadius(floatValue);

SKRect transformedRect = matrix.MapRect(rect);

Если вы используете последним методом, не забывайте, что SKRect структура не может представлять поворачивается прямоугольник.If you use that last method, keep in mind that the SKRect structure is not capable of representing a rotated rectangle. Метод имеет смысл только SKMatrix значение, представляющее перевода и масштабирование.The method only makes sense for an SKMatrix value representing translation and scaling.

Интерактивные службы "Экспериментирование"Interactive Experimentation

Одним из способов, чтобы почувствовать аффинного преобразования является интерактивного перемещения трех углов растрового изображения по экрану и видеть, какие преобразования результатов.One way to get a feel for the affine transform is by interactively moving three corners of a bitmap around the screen and seeing what transform results. Это идея Показать аффинное страницы.This is the idea behind the Show Affine Matrix page. Для этой страницы требуется два класса, которые также используются в других демонстрационных роликов:This page requires two other classes that are also used in other demonstrations:

TouchPoint Класс отображает прозрачные круг, который можно перетаскивать по экрану.The TouchPoint class displays a translucent circle that can be dragged around the screen. TouchPoint необходимо, SKCanvasView либо элемент, который является родительским элементом SKCanvasView имеют TouchEffect подключен.TouchPoint requires that an SKCanvasView or an element that is a parent of an SKCanvasView have the TouchEffect attached. Задайте для свойства Capture значение true.Set the Capture property to true. В TouchAction обработчик событий, необходимо вызвать программу ProcessTouchEvent метод в TouchPoint для каждого TouchPoint экземпляр.In the TouchAction event handler, the program must call the ProcessTouchEvent method in TouchPoint for each TouchPoint instance. Этот метод возвращает true Если событие сенсорного ввода привело к перемещении сенсорной точки.The method returns true if the touch event resulted in the touch point moving. Кроме того PaintSurface необходимо вызвать обработчик Paint метод в каждом TouchPoint экземпляра, передавая ему SKCanvas объекта.Also, the PaintSurface handler must call the Paint method in each TouchPoint instance, passing to it the SKCanvas object.

TouchPoint Демонстрирует общий способ, что визуальный элемент SkiaSharp можно инкапсулировать в отдельном классе.TouchPoint demonstrates a common way that a SkiaSharp visual can be encapsulated in a separate class. В классе можно определить свойства для задания характеристики визуального элемента, и метод, именуемый Paint с SKCanvas аргумент можно визуализировать его.The class can define properties for specifying characteristics of the visual, and a method named Paint with an SKCanvas argument can render it.

Center Свойство TouchPoint возвращает расположение объекта.The Center property of TouchPoint indicates the location of the object. Это свойство может задаваться для инициализации расположение; изменения свойств, когда пользователь перетаскивает круг вокруг холста.This property can be set to initialize the location; the property changes when the user drags the circle around the canvas.

Показать страницу аффинные матрицы также требуется MatrixDisplay класса.The Show Affine Matrix Page also requires the MatrixDisplay class. Этот класс отображает ячейки SKMatrix объекта.This class displays the cells of an SKMatrix object. Он имеет два открытых метода: Measure получить размеры подготовленной матрицы и Paint для его отображения.It has two public methods: Measure to obtain the dimensions of the rendered matrix, and Paint to display it. Этот класс содержит MatrixPaint свойство типа SKPaint , можно заменить другой размер шрифта или цвета.The class contains a MatrixPaint property of type SKPaint that can be replaced for a different font size or color.

ShowAffineMatrixPage.xaml файл экземпляр SKCanvasView и присоединяет TouchEffect.The ShowAffineMatrixPage.xaml file instantiates the SKCanvasView and attaches a TouchEffect. ShowAffineMatrixPage.xaml.cs создает файл с выделенным кодом трех TouchPoint объектов, а затем устанавливает их в соответствующих углам три растрового изображения, которые загружаются из встроенного положения ресурс:The ShowAffineMatrixPage.xaml.cs code-behind file creates three TouchPoint objects and then sets them to positions corresponding to three corners of a bitmap that it loads from an embedded resource:

public partial class ShowAffineMatrixPage : ContentPage
{
    SKMatrix matrix;
    SKBitmap bitmap;
    SKSize bitmapSize;

    TouchPoint[] touchPoints = new TouchPoint[3];

    MatrixDisplay matrixDisplay = new MatrixDisplay();

    public ShowAffineMatrixPage()
    {
        InitializeComponent();

        string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
        Assembly assembly = GetType().GetTypeInfo().Assembly;

        using (Stream stream = assembly.GetManifestResourceStream(resourceID))
        {
            bitmap = SKBitmap.Decode(stream);
        }

        touchPoints[0] = new TouchPoint(100, 100);                  // upper-left corner
        touchPoints[1] = new TouchPoint(bitmap.Width + 100, 100);   // upper-right corner
        touchPoints[2] = new TouchPoint(100, bitmap.Height + 100);  // lower-left corner

        bitmapSize = new SKSize(bitmap.Width, bitmap.Height);
        matrix = ComputeMatrix(bitmapSize, touchPoints[0].Center,
                                           touchPoints[1].Center,
                                           touchPoints[2].Center);
    }
    ...
}

Аффинной матрицей однозначно определяется тремя точками.An affine matrix is uniquely defined by three points. Три TouchPoint соответствуют объектам верхнего левого, правого верхнего и нижнего левого угла растрового изображения.The three TouchPoint objects correspond to the upper-left, upper-right, and lower-left corners of the bitmap. Так как только аффинной матрицей способен преобразование прямоугольника в параллелограмму, четвертый точки подразумевается других трех.Because an affine matrix is only capable of transforming a rectangle into a parallelogram, the fourth point is implied by the other three. Конструктор завершается вызов ComputeMatrix, которая вычисляет ячейки SKMatrix объект из этих трех точек.The constructor concludes with a call to ComputeMatrix, which calculates the cells of an SKMatrix object from these three points.

TouchAction Вызовов обработчика ProcessTouchEvent метод каждого TouchPoint.The TouchAction handler calls the ProcessTouchEvent method of each TouchPoint. scale Значение преобразуется из координат Xamarin.Forms пикселей:The scale value converts from Xamarin.Forms coordinates to pixels:

public partial class ShowAffineMatrixPage : ContentPage
{
    ...
    void OnTouchEffectAction(object sender, TouchActionEventArgs args)
    {
        bool touchPointMoved = false;

        foreach (TouchPoint touchPoint in touchPoints)
        {
            float scale = canvasView.CanvasSize.Width / (float)canvasView.Width;
            SKPoint point = new SKPoint(scale * (float)args.Location.X,
                                        scale * (float)args.Location.Y);
            touchPointMoved |= touchPoint.ProcessTouchEvent(args.Id, args.Type, point);
        }

        if (touchPointMoved)
        {
            matrix = ComputeMatrix(bitmapSize, touchPoints[0].Center,
                                               touchPoints[1].Center,
                                               touchPoints[2].Center);
            canvasView.InvalidateSurface();
        }
    }
    ...
}

При наличии TouchPoint были перемещены, а затем вызывает метод ComputeMatrix еще раз и делает недействительной поверхность.If any TouchPoint has moved, then the method calls ComputeMatrix again and invalidates the surface.

ComputeMatrix Метод определяет, содержится в разрешении этих трех точек матрицы.The ComputeMatrix method determines the matrix implied by those three points. Матрица называется A преобразования один пиксель square прямоугольника в параллелограмму на основе трех точек, хотя преобразование масштаба вызывается S Масштабирующее растровое изображение в один пиксель square прямоугольник.The matrix called A transforms a one-pixel square rectangle into a parallelogram based on the three points, while the scale transform called S scales the bitmap to a one-pixel square rectangle. Составной матрица является S × A:The composite matrix is S × A:

public partial class ShowAffineMatrixPage : ContentPage
{
    ...
    static SKMatrix ComputeMatrix(SKSize size, SKPoint ptUL, SKPoint ptUR, SKPoint ptLL)
    {
        // Scale transform
        SKMatrix S = SKMatrix.MakeScale(1 / size.Width, 1 / size.Height);

        // Affine transform
        SKMatrix A = new SKMatrix
        {
            ScaleX = ptUR.X - ptUL.X,
            SkewY = ptUR.Y - ptUL.Y,
            SkewX = ptLL.X - ptUL.X,
            ScaleY = ptLL.Y - ptUL.Y,
            TransX = ptUL.X,
            TransY = ptUL.Y,
            Persp2 = 1
        };

        SKMatrix result = SKMatrix.MakeIdentity();
        SKMatrix.Concat(ref result, A, S);
        return result;
    }
    ...
}

Наконец PaintSurface метод отображает точечный рисунок, на основе на данную матрицу, отображает матрицу, в нижней части экрана и отображает точки касания в трех углов растрового изображения:Finally, the PaintSurface method renders the bitmap based on that matrix, displays the matrix at the bottom of the screen, and renders the touch points at the three corners of the bitmap:

public partial class ShowAffineMatrixPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Display the bitmap using the matrix
        canvas.Save();
        canvas.SetMatrix(matrix);
        canvas.DrawBitmap(bitmap, 0, 0);
        canvas.Restore();

        // Display the matrix in the lower-right corner
        SKSize matrixSize = matrixDisplay.Measure(matrix);

        matrixDisplay.Paint(canvas, matrix,
            new SKPoint(info.Width - matrixSize.Width,
                        info.Height - matrixSize.Height));

        // Display the touchpoints
        foreach (TouchPoint touchPoint in touchPoints)
        {
            touchPoint.Paint(canvas);
        }
    }
  }

На экране iOS показано растрового изображения, при первой загрузке страницы, он показан двумя другими экранами после некоторые манипуляции.The iOS screen below shows the bitmap when the page is first loaded, while the two other screens show it after some manipulation:

Несмотря на то, что кажется, будто точки касания перетащите углы растрового изображения, — это имитация изменений.Although it seems as if the touch points drag the corners of the bitmap, that's only an illusion. Матрица, вычисленные на основе точки касания преобразует растрового изображения, так, чтобы углы совпадало с точки касания.The matrix calculated from the touch points transforms the bitmap so that the corners coincide with the touch points.

Более естественно пользователям перемещать, масштабировать и поворачивать точечные рисунки не перетаскивая углов, но с помощью одним или двумя пальцами непосредственно в объекте, чтобы перетащить, сжатия и поворот.It is more natural for users to move, resize, and rotate bitmaps not by dragging the corners, but by using one or two fingers directly on the object to drag, pinch, and rotate. Это рассматривается в следующей статье Touch манипуляции.This is covered in the next article Touch Manipulation.

Причина матрица 3 x 3The Reason for the 3-by-3 Matrix

Можно ожидать, что система двухмерной графики потребует только матрицу преобразования 2 x 2:It might be expected that a two-dimensional graphics system would require only a 2-by-2 transform matrix:

           │ ScaleX  SkewY  │
| x  y | × │                │ = | x'  y' |
           │ SkewX   ScaleY │

Для масштабирования, поворота и наклона даже это работает, но он не может быть основная преобразований, в которой — это преобразование.This works for scaling, rotation, and even skewing, but it is not capable of the most basic of transforms, which is translation.

Проблема в том, что матрица 2 x 2 представляет линейной преобразования в двух направлениях.The problem is that the 2-by-2 matrix represents a linear transform in two dimensions. Линейное преобразование сохраняет некоторые основные арифметические операции, однако его влияние на что линейного преобразования никогда не изменяет точки (0, 0).A linear transform preserves some basic arithmetic operations, but one of the implications is that a linear transform never alters the point (0, 0). Преобразование линейной делает преобразование невозможно.A linear transform makes translation impossible.

В трех измерениях матрицу линейного преобразования выглядит следующим образом:In three dimensions, a linear transform matrix looks like this:

              │ ScaleX  SkewYX  SkewZX │
| x  y  z | × │ SkewXY  ScaleY  SkewZY │ = | x'  y'  z' |
              │ SkewXZ  SkewYZ  ScaleZ │

Ячейки с меткой SkewXY означает, что значение Наклоняет координату по оси X на основе значений Y; ячейки SkewXZ означает, что значение Наклоняет координату по оси X на основе значений Z; и значения наклона аналогичным образом для других Skew ячеек.The cell labeled SkewXY means that the value skews the X coordinate based on values of Y; the cell SkewXZ means that the value skews the X coordinate based on values of Z; and values skew similarly for the other Skew cells.

Можно ограничить данной матрицы трехмерные преобразования в двумерной плоскости, задав SkewZX и SkewZY 0, и ScaleZ 1:It's possible to restrict this 3D transform matrix to a two-dimensional plane by setting SkewZX and SkewZY to 0, and ScaleZ to 1:

              │ ScaleX  SkewYX   0 │
| x  y  z | × │ SkewXY  ScaleY   0 │ = | x'  y'  z' |
              │ SkewXZ  SkewYZ   1 │

Если двухмерной графики отображаются полностью в плоскость в трехмерном пространстве, где значение Z равно 1, преобразование умножения выглядит следующим образом:If the two-dimensional graphics are drawn entirely on the plane in 3D space where Z equals 1, the transform multiplication looks like this:

              │ ScaleX  SkewYX   0 │
| x  y  1 | × │ SkewXY  ScaleY   0 │ = | x'  y'  1 |
              │ SkewXZ  SkewYZ   1 │

Все, что остается на двумерной плоскости Z равно 1, но SkewXZ и SkewYZ ячеек приобретает коэффициенты двумерного преобразования.Everything stays on the two-dimensional plane where Z equals 1, but the SkewXZ and SkewYZ cells effectively become two-dimensional translation factors.

Это, как трехмерные преобразования линейной служит в качестве двухмерный нелинейные преобразования.This is how a three-dimensional linear transform serves as a two-dimensional non-linear transform. (Используя аналогию, преобразований в 3D-графики основаны на матрицу 4 на 4.)(By analogy, transforms in 3D graphics are based on a 4-by-4 matrix.)

SKMatrix Структуры в SkiaSharp определяет свойства для этой третьей строки:The SKMatrix structure in SkiaSharp defines properties for that third row:

              │ ScaleX  SkewY   Persp0 │
| x  y  1 | × │ SkewX   ScaleY  Persp1 │ = | x'  y'  z` |
              │ TransX  TransY  Persp2 │

Ненулевые значения Persp0 и Persp1 привести преобразований, которые перемещают объекты вне двумерной плоскости, где значение Z равно 1.Non-zero values of Persp0 and Persp1 result in transforms that move objects off the two-dimensional plane where Z equals 1. Что произойдет, если эти объекты перемещаются назад к этой плоскости рассматривается в статье на Non-аффинных преобразований.What happens when those objects are moved back to that plane is covered in the article on Non-Affine Transforms.