1/*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "gfx_utils/transform.h"
17
18#include "gfx_utils/graphic_math.h"
19namespace OHOS {
20constexpr uint8_t VERTEX_NUM_MIN = 3;
21
22TransformMap::TransformMap()
23{
24    scale_ = Matrix4<float>::Scale(Vector3<float>(1.0f, 1.0f, 1.0f), Vector3<float>(0, 0, 0));
25    rotate_ = Matrix4<float>::Rotate(0, Vector3<float>(0, 0, 0), Vector3<float>(0, 0, 0));
26    shear_ = Matrix4<float>::Shear(Vector2<float>(0, 0), Vector2<float>(0, 0), Vector2<float>(0, 0));
27    translate_ = Matrix4<float>::Translate(Vector3<float>(0, 0, 0));
28    trans_[ROTATE] = &rotate_;
29    trans_[SCALE] = &scale_;
30    trans_[SHEAR] = &shear_;
31    trans_[TRANSLATE] = &translate_;
32    opOrder_[ROTATE] = ROTATE;
33    opOrder_[SCALE] = SCALE;
34    opOrder_[SHEAR] = SHEAR;
35    opOrder_[TRANSLATE] = TRANSLATE;
36
37    UpdateMap();
38}
39
40TransformMap::TransformMap(const Rect& rect)
41{
42    rect_ = rect;
43    polygon_ = rect;
44    scale_ = Matrix4<float>::Scale(Vector3<float>(1.0f, 1.0f, 1.0f), Vector3<float>(0, 0, 0));
45    rotate_ = Matrix4<float>::Rotate(0, Vector3<float>(0, 0, 0), Vector3<float>(0, 0, 0));
46    shear_ = Matrix4<float>::Shear(Vector2<float>(0, 0), Vector2<float>(0, 0), Vector2<float>(0, 0));
47    translate_ = Matrix4<float>::Translate(Vector3<float>(0, 0, 0));
48    trans_[ROTATE] = &rotate_;
49    trans_[SCALE] = &scale_;
50    trans_[SHEAR] = &shear_;
51    trans_[TRANSLATE] = &translate_;
52    opOrder_[ROTATE] = ROTATE;
53    opOrder_[SCALE] = SCALE;
54    opOrder_[SHEAR] = SHEAR;
55    opOrder_[TRANSLATE] = TRANSLATE;
56
57    UpdateMap();
58}
59
60bool TransformMap::GetClockWise() const
61{
62    int16_t count = 0;
63
64    uint8_t vertexNum = polygon_.GetVertexNum();
65    if (vertexNum < VERTEX_NUM_MIN) {
66        return false;
67    }
68
69    for (uint8_t i = 0; i < vertexNum; i++) {
70        uint8_t j = (i + 1) % vertexNum; // 1: the next vertex
71        uint8_t k = (i + 2) % vertexNum; // 2: the after next vertex
72        int32_t c = (static_cast<int32_t>(polygon_[j].x_ - polygon_[i].x_) * (polygon_[k].y_ - polygon_[j].y_)) -
73            (static_cast<int32_t>(polygon_[j].y_ - polygon_[i].y_) * (polygon_[k].x_ - polygon_[j].x_));
74        if (c < 0) {
75            count--;
76        } else if (c > 0) {
77            count++;
78        }
79    }
80    if (count > 0) {
81        return true;
82    }
83    return false;
84}
85
86void TransformMap::SetTransMapRect(const Rect& rect)
87{
88    rect_ = rect;
89    polygon_ = rect;
90    if (isInternalMatrix_) {
91        UpdateMap();
92    } else {
93        SetMatrix(matrixOrig_);
94    }
95}
96
97void TransformMap::Scale(const Vector2<float>& scale, const Vector2<float>& pivot)
98{
99    Scale(Vector3<float>(scale.x_, scale.y_, 1.0f), Vector3<float>(pivot.x_, pivot.y_, 0));
100}
101
102void TransformMap::Scale(const Vector3<float>& scale, const Vector3<float>& pivot)
103{
104    scaleCoeff_ = scale;
105    scalePivot_ = pivot;
106    AddOp(SCALE);
107    UpdateMap();
108}
109
110bool TransformMap::IsInvalid() const
111{
112    if (isInvalid_ || isIdentity_) {
113        return true;
114    }
115
116    for (uint8_t i = 0; i < polygon_.GetVertexNum(); i++) {
117        if (polygon_[i].x_ != 0 || polygon_[i].y_ != 0) {
118            return false;
119        }
120    }
121    return true;
122}
123
124void TransformMap::Rotate(int16_t angle, const Vector2<float>& pivot)
125{
126    Rotate(angle, Vector3<float>(pivot.x_, pivot.y_, 0), Vector3<float>(pivot.x_, pivot.y_, 1.0f));
127}
128
129void TransformMap::Rotate(int16_t angle, const Vector3<float>& rotatePivotStart, const Vector3<float>& rotatePivotEnd)
130{
131    angle_ = angle;
132    rotatePivotStart_ = rotatePivotStart;
133    rotatePivotEnd_ = rotatePivotEnd;
134    AddOp(ROTATE);
135    UpdateMap();
136}
137
138void TransformMap::Translate(const Vector2<int16_t>& trans)
139{
140    Translate(Vector3<int16_t>(trans.x_, trans.y_, 0));
141}
142
143void TransformMap::Translate(const Vector3<int16_t>& trans)
144{
145    translate_ = Matrix4<float>::Translate(Vector3<float>(trans.x_, trans.y_, trans.z_));
146    AddOp(TRANSLATE);
147    UpdateMap();
148}
149
150void TransformMap::Translate(const Vector2<float>& trans)
151{
152    Translate(Vector3<float>(trans.x_, trans.y_, 0));
153}
154
155void TransformMap::Translate(const Vector3<float>& trans)
156{
157    translate_ = Matrix4<float>::Translate(trans);
158    AddOp(TRANSLATE);
159    UpdateMap();
160}
161
162void TransformMap::Shear(const Vector2<float>& shearX, const Vector2<float>& shearY, const Vector2<float>& shearZ)
163{
164    shearX_ = shearX;
165    shearY_ = shearY;
166    shearZ_ = shearZ;
167    AddOp(SHEAR);
168    UpdateMap();
169}
170
171Point TransformMap::GetOrigPoint(const Point& point, const Rect& relativeRect)
172{
173    Rect rect = Rect(point.x, point.y, point.x, point.y);
174    Rect rectTemp = rect_;
175    Polygon polygonTemp = polygon_;
176    short rectX = relativeRect.GetX();
177    short rectY = relativeRect.GetY();
178
179    rect_ = rect;
180    polygon_ = rect;
181    trans_[ROTATE] = &rotate_;
182    trans_[SCALE] = &scale_;
183    trans_[SHEAR] = &shear_;
184    trans_[TRANSLATE] = &translate_;
185    rotate_ = Matrix4<float>::Rotate(
186        angle_, Vector3<float>(rotatePivotStart_.x_ + rectX, rotatePivotStart_.y_ + rectY, rotatePivotStart_.z_),
187        Vector3<float>(rotatePivotEnd_.x_ + rectX, rotatePivotEnd_.y_ + rectY, rotatePivotEnd_.z_));
188    scale_ = Matrix4<float>::Scale(Vector3<float>(1.0f / scaleCoeff_.x_, 1.0f / scaleCoeff_.y_, scaleCoeff_.z_),
189                                   Vector3<float>(scalePivot_.x_ + rectX, scalePivot_.y_ + rectY, scalePivot_.z_));
190
191    shear_ = Matrix4<float>::Shear(shearX_, shearY_, shearZ_);
192    shear_ = shear_ * Matrix4<float>::Translate(Vector3<float>(-rectX, -rectY, 0));
193    shear_ = Matrix4<float>::Translate(Vector3<float>(rectX, rectY, 0)) * shear_;
194    matrix_ = (*trans_[opOrder_[TRANSLATE]]) * (*trans_[opOrder_[SHEAR]]) * (*trans_[opOrder_[SCALE]]) *
195              (*trans_[opOrder_[ROTATE]]);
196
197    float x = rectX + cameraPosition_.x_;
198    float y = rectY + cameraPosition_.y_;
199    float z = 0;
200    Matrix4<float> translateFromCamera = Matrix4<float>::Translate(Vector3<float>(-x, -y, -z));
201    Matrix4<float> translateToCamera = Matrix4<float>::Translate(Vector3<float>(x, y, z));
202    Matrix4<float> perspectiveMatrix;
203    perspectiveMatrix[2][2] = 0;                           // 2 : index
204    if (!FloatEqual(cameraDistance_, 0)) {
205        perspectiveMatrix[2][3] = -1.0f / cameraDistance_; // 2 3 : index
206    }
207    perspectiveMatrix_ = translateToCamera * (perspectiveMatrix * translateFromCamera);
208    matrix_ = perspectiveMatrix_ * matrix_;
209    SetMatrix(matrix_, true);
210    Rect r = polygon_.MakeAABB();
211    rect_ = rectTemp;
212    polygon_ = polygonTemp;
213    scale_ = Matrix4<float>::Scale(scaleCoeff_,
214                                   Vector3<float>(scalePivot_.x_ + rectX, scalePivot_.y_ + rectY, scalePivot_.z_));
215    return {r.GetRight(), r.GetBottom()};
216}
217
218bool TransformMap::operator==(const TransformMap& other) const
219{
220    if (rotate_ == other.rotate_ && translate_ == other.translate_ && scale_ == other.scale_ &&
221        rect_ == other.rect_ && matrix_ == other.matrix_) {
222        return true;
223    }
224    return false;
225}
226
227void TransformMap::SetCameraDistance(int16_t distance)
228{
229    cameraDistance_ = distance;
230    UpdateMap();
231}
232
233void TransformMap::SetCameraPosition(const Vector2<float>& position)
234{
235    cameraPosition_ = position;
236    UpdateMap();
237}
238
239bool TransformMap::Is3DTransform() const
240{
241    return is3d_;
242}
243
244void TransformMap::UpdateMap()
245{
246    trans_[ROTATE] = &rotate_;
247    trans_[SCALE] = &scale_;
248    trans_[SHEAR] = &shear_;
249    trans_[TRANSLATE] = &translate_;
250    rotate_ =
251        Matrix4<float>::Rotate(angle_,
252            Vector3<float>(rotatePivotStart_.x_ + rect_.GetX(), rotatePivotStart_.y_ + rect_.GetY(),
253                           rotatePivotStart_.z_),
254            Vector3<float>(rotatePivotEnd_.x_ + rect_.GetX(), rotatePivotEnd_.y_ + rect_.GetY(), rotatePivotEnd_.z_));
255
256    scale_ = Matrix4<float>::Scale(scaleCoeff_,
257        Vector3<float>(scalePivot_.x_ + rect_.GetX(), scalePivot_.y_ + rect_.GetY(), scalePivot_.z_));
258
259    shear_ = Matrix4<float>::Shear(shearX_, shearY_, shearZ_);
260    shear_ = shear_ * Matrix4<float>::Translate(Vector3<float>(-rect_.GetX(), -rect_.GetY(), 0));
261    shear_ = Matrix4<float>::Translate(Vector3<float>(rect_.GetX(), rect_.GetY(), 0)) * shear_;
262
263    matrix_ = (*trans_[opOrder_[TRANSLATE]]) * (*trans_[opOrder_[SHEAR]]) * (*trans_[opOrder_[SCALE]]) *
264              (*trans_[opOrder_[ROTATE]]);
265
266    float x = rect_.GetX() + cameraPosition_.x_;
267    float y = rect_.GetY() + cameraPosition_.y_;
268    float z = 0;
269    Matrix4<float> translateFromCamera = Matrix4<float>::Translate(Vector3<float>(-x, -y, -z));
270    Matrix4<float> translateToCamera = Matrix4<float>::Translate(Vector3<float>(x, y, z));
271    Matrix4<float> perspectiveMatrix;
272    perspectiveMatrix[2][2] = 0; // 2 : index
273    if (!FloatEqual(cameraDistance_, 0)) {
274        perspectiveMatrix[2][3] = -1.0f / cameraDistance_; // 2 3 : index
275    }
276    perspectiveMatrix_ = translateToCamera * (perspectiveMatrix * translateFromCamera);
277    matrix_ = perspectiveMatrix_ * matrix_;
278    SetMatrix(matrix_, true);
279}
280
281void TransformMap::SetMatrix(const Matrix4<float>& matrix, bool isInternalMatrix)
282{
283    isInternalMatrix_ = isInternalMatrix;
284    polygon_ = rect_;
285    matrixOrig_ = matrix;
286    uint8_t vertexNum = polygon_.GetVertexNum();
287    Vector4<float> imgPoint4;
288    is3d_ = false;
289    for (uint8_t i = 0; i < vertexNum; i++) {
290        Vector4<float> point(polygon_[i].x_, polygon_[i].y_, 0, 1.0f);
291        imgPoint4 = matrix * point;
292        if (!FloatEqual(imgPoint4.w_, 1)) {
293            is3d_ = true;
294        }
295        if (!FloatEqual(imgPoint4.w_, 0)) {
296            imgPoint4.x_ /= imgPoint4.w_;
297            imgPoint4.y_ /= imgPoint4.w_;
298        }
299        if (imgPoint4.x_ < COORD_MIN) {
300            polygon_[i].x_ = COORD_MIN;
301        } else if (imgPoint4.x_ > COORD_MAX) {
302            polygon_[i].x_ = COORD_MAX;
303        } else {
304            polygon_[i].x_ = MATH_ROUND(imgPoint4.x_);
305        }
306
307        if (imgPoint4.y_ < COORD_MIN) {
308            polygon_[i].y_ = COORD_MIN;
309        } else if (imgPoint4.y_ > COORD_MAX) {
310            polygon_[i].y_ = COORD_MAX;
311        } else {
312            polygon_[i].y_ = MATH_ROUND(imgPoint4.y_);
313        }
314    }
315    isIdentity_ = IsIdentity(const_cast<Matrix4<float>&>(matrix));
316    Matrix4<float> translate = Matrix4<float>::Translate(Vector3<float>(rect_.GetX(), rect_.GetY(), 0));
317    matrix_ = matrix * translate;
318    /* 0 1 2 3  : index of matrix */
319    Matrix3<float> matrix3(matrix_[0][0], matrix_[0][1], matrix_[0][3],
320                           matrix_[1][0], matrix_[1][1], matrix_[1][3],
321                           matrix_[3][0], matrix_[3][1], matrix_[3][3]);
322    invMatrix_ = matrix3.Inverse();
323}
324
325void TransformMap::AddOp(uint8_t op)
326{
327    uint8_t index = 0;
328    for (; index < TRANS_NUM; index++) {
329        if (opOrder_[index] == op) {
330            break;
331        }
332    }
333    for (; index < TRANSLATE; index++) {
334        opOrder_[index] = opOrder_[index + 1];
335    }
336    opOrder_[TRANSLATE] = op;
337}
338
339void Rotate(const Vector2<int16_t>& point, int16_t angle, const Vector2<int16_t>& pivot, Vector2<int16_t>& out)
340{
341    float sinma = Sin(angle);
342    float cosma = Sin(angle + 90); // 90: cos
343
344    int16_t xt = point.x_ - pivot.x_;
345    int16_t yt = point.y_ - pivot.y_;
346
347    /* 0.5: round up */
348    float temp = cosma * xt - sinma * yt;
349    out.x_ = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f)) + pivot.x_;
350    temp = sinma * xt + cosma * yt;
351    out.y_ = static_cast<int16_t>((temp > 0) ? (temp + 0.5f) : (temp - 0.5f)) + pivot.y_;
352}
353
354void Rotate(const Line& origLine, int16_t angle, const Vector2<int16_t>& pivot, Line& out)
355{
356    Vector2<int16_t> pt1 = origLine[0];
357    Vector2<int16_t> pt2 = origLine[1];
358
359    Rotate(pt1, angle, pivot, out[1]); // 1: the first point of line
360    Rotate(pt2, angle, pivot, out[2]); // 2: the second point of line
361}
362
363void Rotate(const Rect& origRect, int16_t angle, const Vector2<int16_t>& pivot, Polygon& out)
364{
365    Vector2<int16_t> pt1 = {origRect.GetLeft(), origRect.GetTop()};
366    Vector2<int16_t> pt2 = {origRect.GetRight(), origRect.GetTop()};
367    Vector2<int16_t> pt3 = {origRect.GetRight(), origRect.GetBottom()};
368    Vector2<int16_t> pt4 = {origRect.GetLeft(), origRect.GetBottom()};
369
370    Rotate(pt1, angle, pivot, out[1]); // 1: the first point
371    Rotate(pt2, angle, pivot, out[2]); // 2: the second point
372    Rotate(pt3, angle, pivot, out[3]); // 3: the third point
373    Rotate(pt4, angle, pivot, out[4]); // 4: the fourth point
374
375    out.SetVertexNum(4); // 4: number of vertex
376}
377} // namespace OHOS
378