/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "gfx_utils/transform.h" #include "gfx_utils/graphic_math.h" namespace OHOS { constexpr uint8_t VERTEX_NUM_MIN = 3; TransformMap::TransformMap() { scale_ = Matrix4::Scale(Vector3(1.0f, 1.0f, 1.0f), Vector3(0, 0, 0)); rotate_ = Matrix4::Rotate(0, Vector3(0, 0, 0), Vector3(0, 0, 0)); shear_ = Matrix4::Shear(Vector2(0, 0), Vector2(0, 0), Vector2(0, 0)); translate_ = Matrix4::Translate(Vector3(0, 0, 0)); trans_[ROTATE] = &rotate_; trans_[SCALE] = &scale_; trans_[SHEAR] = &shear_; trans_[TRANSLATE] = &translate_; opOrder_[ROTATE] = ROTATE; opOrder_[SCALE] = SCALE; opOrder_[SHEAR] = SHEAR; opOrder_[TRANSLATE] = TRANSLATE; UpdateMap(); } TransformMap::TransformMap(const Rect& rect) { rect_ = rect; polygon_ = rect; scale_ = Matrix4::Scale(Vector3(1.0f, 1.0f, 1.0f), Vector3(0, 0, 0)); rotate_ = Matrix4::Rotate(0, Vector3(0, 0, 0), Vector3(0, 0, 0)); shear_ = Matrix4::Shear(Vector2(0, 0), Vector2(0, 0), Vector2(0, 0)); translate_ = Matrix4::Translate(Vector3(0, 0, 0)); trans_[ROTATE] = &rotate_; trans_[SCALE] = &scale_; trans_[SHEAR] = &shear_; trans_[TRANSLATE] = &translate_; opOrder_[ROTATE] = ROTATE; opOrder_[SCALE] = SCALE; opOrder_[SHEAR] = SHEAR; opOrder_[TRANSLATE] = TRANSLATE; UpdateMap(); } bool TransformMap::GetClockWise() const { int16_t count = 0; uint8_t vertexNum = polygon_.GetVertexNum(); if (vertexNum < VERTEX_NUM_MIN) { return false; } for (uint8_t i = 0; i < vertexNum; i++) { uint8_t j = (i + 1) % vertexNum; // 1: the next vertex uint8_t k = (i + 2) % vertexNum; // 2: the after next vertex int32_t c = (static_cast(polygon_[j].x_ - polygon_[i].x_) * (polygon_[k].y_ - polygon_[j].y_)) - (static_cast(polygon_[j].y_ - polygon_[i].y_) * (polygon_[k].x_ - polygon_[j].x_)); if (c < 0) { count--; } else if (c > 0) { count++; } } if (count > 0) { return true; } return false; } void TransformMap::SetTransMapRect(const Rect& rect) { rect_ = rect; polygon_ = rect; if (isInternalMatrix_) { UpdateMap(); } else { SetMatrix(matrixOrig_); } } void TransformMap::Scale(const Vector2& scale, const Vector2& pivot) { Scale(Vector3(scale.x_, scale.y_, 1.0f), Vector3(pivot.x_, pivot.y_, 0)); } void TransformMap::Scale(const Vector3& scale, const Vector3& pivot) { scaleCoeff_ = scale; scalePivot_ = pivot; AddOp(SCALE); UpdateMap(); } bool TransformMap::IsInvalid() const { if (isInvalid_ || isIdentity_) { return true; } for (uint8_t i = 0; i < polygon_.GetVertexNum(); i++) { if (polygon_[i].x_ != 0 || polygon_[i].y_ != 0) { return false; } } return true; } void TransformMap::Rotate(int16_t angle, const Vector2& pivot) { Rotate(angle, Vector3(pivot.x_, pivot.y_, 0), Vector3(pivot.x_, pivot.y_, 1.0f)); } void TransformMap::Rotate(int16_t angle, const Vector3& rotatePivotStart, const Vector3& rotatePivotEnd) { angle_ = angle; rotatePivotStart_ = rotatePivotStart; rotatePivotEnd_ = rotatePivotEnd; AddOp(ROTATE); UpdateMap(); } void TransformMap::Translate(const Vector2& trans) { Translate(Vector3(trans.x_, trans.y_, 0)); } void TransformMap::Translate(const Vector3& trans) { translate_ = Matrix4::Translate(Vector3(trans.x_, trans.y_, trans.z_)); AddOp(TRANSLATE); UpdateMap(); } void TransformMap::Translate(const Vector2& trans) { Translate(Vector3(trans.x_, trans.y_, 0)); } void TransformMap::Translate(const Vector3& trans) { translate_ = Matrix4::Translate(trans); AddOp(TRANSLATE); UpdateMap(); } void TransformMap::Shear(const Vector2& shearX, const Vector2& shearY, const Vector2& shearZ) { shearX_ = shearX; shearY_ = shearY; shearZ_ = shearZ; AddOp(SHEAR); UpdateMap(); } Point TransformMap::GetOrigPoint(const Point& point, const Rect& relativeRect) { Rect rect = Rect(point.x, point.y, point.x, point.y); Rect rectTemp = rect_; Polygon polygonTemp = polygon_; short rectX = relativeRect.GetX(); short rectY = relativeRect.GetY(); rect_ = rect; polygon_ = rect; trans_[ROTATE] = &rotate_; trans_[SCALE] = &scale_; trans_[SHEAR] = &shear_; trans_[TRANSLATE] = &translate_; rotate_ = Matrix4::Rotate( angle_, Vector3(rotatePivotStart_.x_ + rectX, rotatePivotStart_.y_ + rectY, rotatePivotStart_.z_), Vector3(rotatePivotEnd_.x_ + rectX, rotatePivotEnd_.y_ + rectY, rotatePivotEnd_.z_)); scale_ = Matrix4::Scale(Vector3(1.0f / scaleCoeff_.x_, 1.0f / scaleCoeff_.y_, scaleCoeff_.z_), Vector3(scalePivot_.x_ + rectX, scalePivot_.y_ + rectY, scalePivot_.z_)); shear_ = Matrix4::Shear(shearX_, shearY_, shearZ_); shear_ = shear_ * Matrix4::Translate(Vector3(-rectX, -rectY, 0)); shear_ = Matrix4::Translate(Vector3(rectX, rectY, 0)) * shear_; matrix_ = (*trans_[opOrder_[TRANSLATE]]) * (*trans_[opOrder_[SHEAR]]) * (*trans_[opOrder_[SCALE]]) * (*trans_[opOrder_[ROTATE]]); float x = rectX + cameraPosition_.x_; float y = rectY + cameraPosition_.y_; float z = 0; Matrix4 translateFromCamera = Matrix4::Translate(Vector3(-x, -y, -z)); Matrix4 translateToCamera = Matrix4::Translate(Vector3(x, y, z)); Matrix4 perspectiveMatrix; perspectiveMatrix[2][2] = 0; // 2 : index if (!FloatEqual(cameraDistance_, 0)) { perspectiveMatrix[2][3] = -1.0f / cameraDistance_; // 2 3 : index } perspectiveMatrix_ = translateToCamera * (perspectiveMatrix * translateFromCamera); matrix_ = perspectiveMatrix_ * matrix_; SetMatrix(matrix_, true); Rect r = polygon_.MakeAABB(); rect_ = rectTemp; polygon_ = polygonTemp; scale_ = Matrix4::Scale(scaleCoeff_, Vector3(scalePivot_.x_ + rectX, scalePivot_.y_ + rectY, scalePivot_.z_)); return {r.GetRight(), r.GetBottom()}; } bool TransformMap::operator==(const TransformMap& other) const { if (rotate_ == other.rotate_ && translate_ == other.translate_ && scale_ == other.scale_ && rect_ == other.rect_ && matrix_ == other.matrix_) { return true; } return false; } void TransformMap::SetCameraDistance(int16_t distance) { cameraDistance_ = distance; UpdateMap(); } void TransformMap::SetCameraPosition(const Vector2& position) { cameraPosition_ = position; UpdateMap(); } bool TransformMap::Is3DTransform() const { return is3d_; } void TransformMap::UpdateMap() { trans_[ROTATE] = &rotate_; trans_[SCALE] = &scale_; trans_[SHEAR] = &shear_; trans_[TRANSLATE] = &translate_; rotate_ = Matrix4::Rotate(angle_, Vector3(rotatePivotStart_.x_ + rect_.GetX(), rotatePivotStart_.y_ + rect_.GetY(), rotatePivotStart_.z_), Vector3(rotatePivotEnd_.x_ + rect_.GetX(), rotatePivotEnd_.y_ + rect_.GetY(), rotatePivotEnd_.z_)); scale_ = Matrix4::Scale(scaleCoeff_, Vector3(scalePivot_.x_ + rect_.GetX(), scalePivot_.y_ + rect_.GetY(), scalePivot_.z_)); shear_ = Matrix4::Shear(shearX_, shearY_, shearZ_); shear_ = shear_ * Matrix4::Translate(Vector3(-rect_.GetX(), -rect_.GetY(), 0)); shear_ = Matrix4::Translate(Vector3(rect_.GetX(), rect_.GetY(), 0)) * shear_; matrix_ = (*trans_[opOrder_[TRANSLATE]]) * (*trans_[opOrder_[SHEAR]]) * (*trans_[opOrder_[SCALE]]) * (*trans_[opOrder_[ROTATE]]); float x = rect_.GetX() + cameraPosition_.x_; float y = rect_.GetY() + cameraPosition_.y_; float z = 0; Matrix4 translateFromCamera = Matrix4::Translate(Vector3(-x, -y, -z)); Matrix4 translateToCamera = Matrix4::Translate(Vector3(x, y, z)); Matrix4 perspectiveMatrix; perspectiveMatrix[2][2] = 0; // 2 : index if (!FloatEqual(cameraDistance_, 0)) { perspectiveMatrix[2][3] = -1.0f / cameraDistance_; // 2 3 : index } perspectiveMatrix_ = translateToCamera * (perspectiveMatrix * translateFromCamera); matrix_ = perspectiveMatrix_ * matrix_; SetMatrix(matrix_, true); } void TransformMap::SetMatrix(const Matrix4& matrix, bool isInternalMatrix) { isInternalMatrix_ = isInternalMatrix; polygon_ = rect_; matrixOrig_ = matrix; uint8_t vertexNum = polygon_.GetVertexNum(); Vector4 imgPoint4; is3d_ = false; for (uint8_t i = 0; i < vertexNum; i++) { Vector4 point(polygon_[i].x_, polygon_[i].y_, 0, 1.0f); imgPoint4 = matrix * point; if (!FloatEqual(imgPoint4.w_, 1)) { is3d_ = true; } if (!FloatEqual(imgPoint4.w_, 0)) { imgPoint4.x_ /= imgPoint4.w_; imgPoint4.y_ /= imgPoint4.w_; } if (imgPoint4.x_ < COORD_MIN) { polygon_[i].x_ = COORD_MIN; } else if (imgPoint4.x_ > COORD_MAX) { polygon_[i].x_ = COORD_MAX; } else { polygon_[i].x_ = MATH_ROUND(imgPoint4.x_); } if (imgPoint4.y_ < COORD_MIN) { polygon_[i].y_ = COORD_MIN; } else if (imgPoint4.y_ > COORD_MAX) { polygon_[i].y_ = COORD_MAX; } else { polygon_[i].y_ = MATH_ROUND(imgPoint4.y_); } } isIdentity_ = IsIdentity(const_cast&>(matrix)); Matrix4 translate = Matrix4::Translate(Vector3(rect_.GetX(), rect_.GetY(), 0)); matrix_ = matrix * translate; /* 0 1 2 3 : index of matrix */ Matrix3 matrix3(matrix_[0][0], matrix_[0][1], matrix_[0][3], matrix_[1][0], matrix_[1][1], matrix_[1][3], matrix_[3][0], matrix_[3][1], matrix_[3][3]); invMatrix_ = matrix3.Inverse(); } void TransformMap::AddOp(uint8_t op) { uint8_t index = 0; for (; index < TRANS_NUM; index++) { if (opOrder_[index] == op) { break; } } for (; index < TRANSLATE; index++) { opOrder_[index] = opOrder_[index + 1]; } opOrder_[TRANSLATE] = op; } void Rotate(const Vector2& point, int16_t angle, const Vector2& pivot, Vector2& out) { float sinma = Sin(angle); float cosma = Sin(angle + 90); // 90: cos int16_t xt = point.x_ - pivot.x_; int16_t yt = point.y_ - pivot.y_; /* 0.5: round up */ float temp = cosma * xt - sinma * yt; out.x_ = static_cast((temp > 0) ? (temp + 0.5f) : (temp - 0.5f)) + pivot.x_; temp = sinma * xt + cosma * yt; out.y_ = static_cast((temp > 0) ? (temp + 0.5f) : (temp - 0.5f)) + pivot.y_; } void Rotate(const Line& origLine, int16_t angle, const Vector2& pivot, Line& out) { Vector2 pt1 = origLine[0]; Vector2 pt2 = origLine[1]; Rotate(pt1, angle, pivot, out[1]); // 1: the first point of line Rotate(pt2, angle, pivot, out[2]); // 2: the second point of line } void Rotate(const Rect& origRect, int16_t angle, const Vector2& pivot, Polygon& out) { Vector2 pt1 = {origRect.GetLeft(), origRect.GetTop()}; Vector2 pt2 = {origRect.GetRight(), origRect.GetTop()}; Vector2 pt3 = {origRect.GetRight(), origRect.GetBottom()}; Vector2 pt4 = {origRect.GetLeft(), origRect.GetBottom()}; Rotate(pt1, angle, pivot, out[1]); // 1: the first point Rotate(pt2, angle, pivot, out[2]); // 2: the second point Rotate(pt3, angle, pivot, out[3]); // 3: the third point Rotate(pt4, angle, pivot, out[4]); // 4: the fourth point out.SetVertexNum(4); // 4: number of vertex } } // namespace OHOS