2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 inline float VMatrix::determinant() const
32 return m11 * (m33 * m22 - mty * m23) - m21 * (m33 * m12 - mty * m13) +
33 mtx * (m23 * m12 - m22 * m13);
36 bool VMatrix::isAffine() const
38 return type() < MatrixType::Project;
41 bool VMatrix::isIdentity() const
43 return type() == MatrixType::None;
46 bool VMatrix::isInvertible() const
48 return !vIsZero(determinant());
51 bool VMatrix::isScaling() const
53 return type() >= MatrixType::Scale;
55 bool VMatrix::isRotating() const
57 return type() >= MatrixType::Rotate;
60 bool VMatrix::isTranslating() const
62 return type() >= MatrixType::Translate;
65 VMatrix &VMatrix::operator*=(float num)
67 if (num == 1.) return *this;
78 if (dirty < MatrixType::Scale) dirty = MatrixType::Scale;
83 VMatrix &VMatrix::operator/=(float div)
85 if (div == 0) return *this;
88 return operator*=(div);
91 VMatrix::MatrixType VMatrix::type() const
93 if (dirty == MatrixType::None || dirty < mType) return mType;
96 case MatrixType::Project:
97 if (!vIsZero(m13) || !vIsZero(m23) || !vIsZero(m33 - 1)) {
98 mType = MatrixType::Project;
101 case MatrixType::Shear:
102 case MatrixType::Rotate:
103 if (!vIsZero(m12) || !vIsZero(m21)) {
104 const float dot = m11 * m12 + m21 * m22;
106 mType = MatrixType::Rotate;
108 mType = MatrixType::Shear;
111 case MatrixType::Scale:
112 if (!vIsZero(m11 - 1) || !vIsZero(m22 - 1)) {
113 mType = MatrixType::Scale;
116 case MatrixType::Translate:
117 if (!vIsZero(mtx) || !vIsZero(mty)) {
118 mType = MatrixType::Translate;
121 case MatrixType::None:
122 mType = MatrixType::None;
126 dirty = MatrixType::None;
130 VMatrix &VMatrix::translate(float dx, float dy)
132 if (dx == 0 && dy == 0) return *this;
135 case MatrixType::None:
139 case MatrixType::Translate:
143 case MatrixType::Scale:
147 case MatrixType::Project:
148 m33 += dx * m13 + dy * m23;
150 case MatrixType::Shear:
151 case MatrixType::Rotate:
152 mtx += dx * m11 + dy * m21;
153 mty += dy * m22 + dx * m12;
156 if (dirty < MatrixType::Translate) dirty = MatrixType::Translate;
160 VMatrix &VMatrix::scale(float sx, float sy)
162 if (sx == 1 && sy == 1) return *this;
165 case MatrixType::None:
166 case MatrixType::Translate:
170 case MatrixType::Project:
174 case MatrixType::Rotate:
175 case MatrixType::Shear:
179 case MatrixType::Scale:
184 if (dirty < MatrixType::Scale) dirty = MatrixType::Scale;
188 VMatrix &VMatrix::shear(float sh, float sv)
190 if (sh == 0 && sv == 0) return *this;
193 case MatrixType::None:
194 case MatrixType::Translate:
198 case MatrixType::Scale:
202 case MatrixType::Project: {
203 float tm13 = sv * m23;
204 float tm23 = sh * m13;
209 case MatrixType::Rotate:
210 case MatrixType::Shear: {
211 float tm11 = sv * m21;
212 float tm22 = sh * m12;
213 float tm12 = sv * m22;
214 float tm21 = sh * m11;
222 if (dirty < MatrixType::Shear) dirty = MatrixType::Shear;
226 static const float deg2rad = float(0.017453292519943295769); // pi/180
227 static const float inv_dist_to_plane = 1. / 1024.;
229 VMatrix &VMatrix::rotate(float a, Axis axis)
231 if (a == 0) return *this;
235 if (a == 90. || a == -270.)
237 else if (a == 270. || a == -90.)
242 float b = deg2rad * a; // convert to radians
243 sina = std::sin(b); // fast and convenient
247 if (axis == Axis::Z) {
249 case MatrixType::None:
250 case MatrixType::Translate:
256 case MatrixType::Scale: {
257 float tm11 = cosa * m11;
258 float tm12 = sina * m22;
259 float tm21 = -sina * m11;
260 float tm22 = cosa * m22;
267 case MatrixType::Project: {
268 float tm13 = cosa * m13 + sina * m23;
269 float tm23 = -sina * m13 + cosa * m23;
274 case MatrixType::Rotate:
275 case MatrixType::Shear: {
276 float tm11 = cosa * m11 + sina * m21;
277 float tm12 = cosa * m12 + sina * m22;
278 float tm21 = -sina * m11 + cosa * m21;
279 float tm22 = -sina * m12 + cosa * m22;
287 if (dirty < MatrixType::Rotate) dirty = MatrixType::Rotate;
290 if (axis == Axis::Y) {
292 result.m13 = -sina * inv_dist_to_plane;
295 result.m23 = -sina * inv_dist_to_plane;
297 result.mType = MatrixType::Project;
298 *this = result * *this;
304 VMatrix VMatrix::operator*(const VMatrix &m) const
306 const MatrixType otherType = m.type();
307 if (otherType == MatrixType::None) return *this;
309 const MatrixType thisType = type();
310 if (thisType == MatrixType::None) return m;
313 MatrixType type = vMax(thisType, otherType);
315 case MatrixType::None:
317 case MatrixType::Translate:
319 t.mty += mty + m.mty;
321 case MatrixType::Scale: {
322 float m11v = m11 * m.m11;
323 float m22v = m22 * m.m22;
325 float m31v = mtx * m.m11 + m.mtx;
326 float m32v = mty * m.m22 + m.mty;
334 case MatrixType::Rotate:
335 case MatrixType::Shear: {
336 float m11v = m11 * m.m11 + m12 * m.m21;
337 float m12v = m11 * m.m12 + m12 * m.m22;
339 float m21v = m21 * m.m11 + m22 * m.m21;
340 float m22v = m21 * m.m12 + m22 * m.m22;
342 float m31v = mtx * m.m11 + mty * m.m21 + m.mtx;
343 float m32v = mtx * m.m12 + mty * m.m22 + m.mty;
353 case MatrixType::Project: {
354 float m11v = m11 * m.m11 + m12 * m.m21 + m13 * m.mtx;
355 float m12v = m11 * m.m12 + m12 * m.m22 + m13 * m.mty;
356 float m13v = m11 * m.m13 + m12 * m.m23 + m13 * m.m33;
358 float m21v = m21 * m.m11 + m22 * m.m21 + m23 * m.mtx;
359 float m22v = m21 * m.m12 + m22 * m.m22 + m23 * m.mty;
360 float m23v = m21 * m.m13 + m22 * m.m23 + m23 * m.m33;
362 float m31v = mtx * m.m11 + mty * m.m21 + m33 * m.mtx;
363 float m32v = mtx * m.m12 + mty * m.m22 + m33 * m.mty;
364 float m33v = mtx * m.m13 + mty * m.m23 + m33 * m.m33;
384 VMatrix &VMatrix::operator*=(const VMatrix &o)
386 const MatrixType otherType = o.type();
387 if (otherType == MatrixType::None) return *this;
389 const MatrixType thisType = type();
390 if (thisType == MatrixType::None) return operator=(o);
392 MatrixType t = vMax(thisType, otherType);
394 case MatrixType::None:
396 case MatrixType::Translate:
400 case MatrixType::Scale: {
401 float m11v = m11 * o.m11;
402 float m22v = m22 * o.m22;
404 float m31v = mtx * o.m11 + o.mtx;
405 float m32v = mty * o.m22 + o.mty;
413 case MatrixType::Rotate:
414 case MatrixType::Shear: {
415 float m11v = m11 * o.m11 + m12 * o.m21;
416 float m12v = m11 * o.m12 + m12 * o.m22;
418 float m21v = m21 * o.m11 + m22 * o.m21;
419 float m22v = m21 * o.m12 + m22 * o.m22;
421 float m31v = mtx * o.m11 + mty * o.m21 + o.mtx;
422 float m32v = mtx * o.m12 + mty * o.m22 + o.mty;
432 case MatrixType::Project: {
433 float m11v = m11 * o.m11 + m12 * o.m21 + m13 * o.mtx;
434 float m12v = m11 * o.m12 + m12 * o.m22 + m13 * o.mty;
435 float m13v = m11 * o.m13 + m12 * o.m23 + m13 * o.m33;
437 float m21v = m21 * o.m11 + m22 * o.m21 + m23 * o.mtx;
438 float m22v = m21 * o.m12 + m22 * o.m22 + m23 * o.mty;
439 float m23v = m21 * o.m13 + m22 * o.m23 + m23 * o.m33;
441 float m31v = mtx * o.m11 + mty * o.m21 + m33 * o.mtx;
442 float m32v = mtx * o.m12 + mty * o.m22 + m33 * o.mty;
443 float m33v = mtx * o.m13 + mty * o.m23 + m33 * o.m33;
463 VMatrix VMatrix::adjoint() const
465 float h11, h12, h13, h21, h22, h23, h31, h32, h33;
466 h11 = m22 * m33 - m23 * mty;
467 h21 = m23 * mtx - m21 * m33;
468 h31 = m21 * mty - m22 * mtx;
469 h12 = m13 * mty - m12 * m33;
470 h22 = m11 * m33 - m13 * mtx;
471 h32 = m12 * mtx - m11 * mty;
472 h13 = m12 * m23 - m13 * m22;
473 h23 = m13 * m21 - m11 * m23;
474 h33 = m11 * m22 - m12 * m21;
486 res.mType = MatrixType::None;
487 res.dirty = MatrixType::Project;
492 VMatrix VMatrix::inverted(bool *invertible) const
498 case MatrixType::None:
500 case MatrixType::Translate:
504 case MatrixType::Scale:
506 inv &= !vIsZero(m22);
508 invert.m11 = 1. / m11;
509 invert.m22 = 1. / m22;
510 invert.mtx = -mtx * invert.m11;
511 invert.mty = -mty * invert.m22;
516 float det = determinant();
518 if (inv) invert = (adjoint() /= det);
519 // TODO Test above line
523 if (invertible) *invertible = inv;
526 // inverting doesn't change the type
527 invert.mType = mType;
528 invert.dirty = dirty;
534 bool VMatrix::operator==(const VMatrix &o) const
536 return fuzzyCompare(o);
539 bool VMatrix::operator!=(const VMatrix &o) const
541 return !operator==(o);
544 bool VMatrix::fuzzyCompare(const VMatrix &o) const
546 return vCompare(m11, o.m11) && vCompare(m12, o.m12) &&
547 vCompare(m21, o.m21) && vCompare(m22, o.m22) &&
548 vCompare(mtx, o.mtx) && vCompare(mty, o.mty);
551 #define V_NEAR_CLIP 0.000001
555 #define MAP(x, y, nx, ny) \
560 case MatrixType::None: \
564 case MatrixType::Translate: \
568 case MatrixType::Scale: \
569 nx = m11 * FX_ + mtx; \
570 ny = m22 * FY_ + mty; \
572 case MatrixType::Rotate: \
573 case MatrixType::Shear: \
574 case MatrixType::Project: \
575 nx = m11 * FX_ + m21 * FY_ + mtx; \
576 ny = m12 * FX_ + m22 * FY_ + mty; \
577 if (t == MatrixType::Project) { \
578 float w = (m13 * FX_ + m23 * FY_ + m33); \
579 if (w < V_NEAR_CLIP) w = V_NEAR_CLIP; \
587 VRect VMatrix::map(const VRect &rect) const
589 VMatrix::MatrixType t = type();
590 if (t <= MatrixType::Translate)
591 return rect.translated(std::round(mtx), std::round(mty));
593 if (t <= MatrixType::Scale) {
594 int x = std::round(m11 * rect.x() + mtx);
595 int y = std::round(m22 * rect.y() + mty);
596 int w = std::round(m11 * rect.width());
597 int h = std::round(m22 * rect.height());
607 } else if (t < MatrixType::Project) {
608 // see mapToPolygon for explanations of the algorithm.
610 MAP(rect.left(), rect.top(), x, y);
615 MAP(rect.right() + 1, rect.top(), x, y);
616 xmin = vMin(xmin, x);
617 ymin = vMin(ymin, y);
618 xmax = vMax(xmax, x);
619 ymax = vMax(ymax, y);
620 MAP(rect.right() + 1, rect.bottom() + 1, x, y);
621 xmin = vMin(xmin, x);
622 ymin = vMin(ymin, y);
623 xmax = vMax(xmax, x);
624 ymax = vMax(ymax, y);
625 MAP(rect.left(), rect.bottom() + 1, x, y);
626 xmin = vMin(xmin, x);
627 ymin = vMin(ymin, y);
628 xmax = vMax(xmax, x);
629 ymax = vMax(ymax, y);
630 return VRect(std::round(xmin), std::round(ymin),
631 std::round(xmax) - std::round(xmin),
632 std::round(ymax) - std::round(ymin));
639 VRegion VMatrix::map(const VRegion &r) const
641 VMatrix::MatrixType t = type();
642 if (t == MatrixType::None) return r;
644 if (t == MatrixType::Translate) {
646 copy.translate(std::round(mtx), std::round(mty));
650 if (t == MatrixType::Scale && r.rectCount() == 1)
651 return VRegion(map(r.boundingRect()));
652 // handle mapping of region properly
657 VPointF VMatrix::map(const VPointF &p) const
664 VMatrix::MatrixType t = type();
666 case MatrixType::None:
670 case MatrixType::Translate:
674 case MatrixType::Scale:
678 case MatrixType::Rotate:
679 case MatrixType::Shear:
680 case MatrixType::Project:
681 x = m11 * fx + m21 * fy + mtx;
682 y = m12 * fx + m22 * fy + mty;
683 if (t == MatrixType::Project) {
684 float w = 1. / (m13 * fx + m23 * fy + m33);
691 static std::string type_helper(VMatrix::MatrixType t)
694 case VMatrix::MatrixType::None:
695 return "MatrixType::None";
697 case VMatrix::MatrixType::Translate:
698 return "MatrixType::Translate";
700 case VMatrix::MatrixType::Scale:
701 return "MatrixType::Scale";
703 case VMatrix::MatrixType::Rotate:
704 return "MatrixType::Rotate";
706 case VMatrix::MatrixType::Shear:
707 return "MatrixType::Shear";
709 case VMatrix::MatrixType::Project:
710 return "MatrixType::Project";
715 std::ostream &operator<<(std::ostream &os, const VMatrix &o)
718 << "type =" << type_helper(o.type()) << ", Data : " << o.m11 << " "
719 << o.m12 << " " << o.m13 << " " << o.m21 << " " << o.m22 << " " << o.m23
720 << " " << o.mtx << " " << o.mty << " " << o.m33 << " "