Mako 9.0.0 API
MakoCore SDK API Documentation
Loading...
Searching...
No Matches
edlgeom.h
Go to the documentation of this file.
1/*
2 * edlgeom.h
3 *
4 * Copyright (C) 2007-2026 Hybrid Software Helix Ltd. All rights reserved.
5 */
6
12
13#ifndef EDLGEOM_H
14#define EDLGEOM_H
15
16#include <algorithm>
17#include <edl/edltypes.h>
18#include <edl/edlmath.h>
19#include <edl/edlvector.h>
20#include <edl/edlerrors.h>
21
23
29template <typename PointType>
31{
32 public:
33 PointTmpl() : x(0), y(0)
34 {
35 }
36
37 PointTmpl(PointType ax, PointType ay) : x(ax), y(ay)
38 {
39 }
40
41 PointTmpl(const PointTmpl<PointType>& p) = default;
42
44
46
48 {
49 x += pt.x;
50 y += pt.y;
51 return *this;
52 }
53
55 {
56 x -= pt.x;
57 y -= pt.y;
58 return *this;
59 }
60
61 bool equal(const PointTmpl& point) const
62 {
63 return ((x == point.x) && (y == point.y));
64 }
65
66 bool operator == (const PointTmpl& point) const
67 {
68 return ((x == point.x) && (y == point.y));
69 }
70
71 bool operator!= (const PointTmpl& point) const
72 {
73 return !(*this == point);
74 }
75
82 {
83 return PointTmpl<PointType>((PointType)(x + (pt.x - x) / 2.0), (PointType)(y + (pt.y - y) / 2.0));
84 }
85
91 double getDistance(const PointTmpl<PointType>& pt) const
92 {
93 return hypot(pt.x - x, pt.y - y);
94 }
95
96 PointType x;
97 PointType y;
98};
99
100template <typename PointType>
102{
103 return PointTmpl<PointType>(lhp.x + rhp.x, lhp.y + rhp.y);
104}
105template <typename PointType>
107{
108 return PointTmpl<PointType>(lhp.x - rhp.x, lhp.y - rhp.y);
109}
110
116
117// Point type may not be an unsigned type
118template <typename PointType>
120{
121 public:
123 x(0), y(0), dX(-1), dY(-1)
124 {}
125
126 RectTmpl(PointType ax, PointType ay, PointType adX, PointType adY) :
127 x(ax), y(ay), dX(adX), dY(adY)
128 {}
129
130 RectTmpl(const RectTmpl<PointType>& r) = default;
131
133
135
136 PointType x;
137 PointType y;
138 PointType dX;
139 PointType dY;
140
141 void setEmpty()
142 {
143 dX = (PointType)-1;
144 dY = (PointType)-1;
145 }
146
147 bool isEmpty() const
148 {
149 return (dX < (PointType)0 || dY < (PointType)0);
150 }
151
152 bool equal(const RectTmpl& rect) const
153 {
154 return ((x == rect.x) && (y == rect.y) &&
155 (dX == rect.dX) && (dY == rect.dY));
156 }
157
158 bool operator== (const RectTmpl& rect) const
159 {
160 return ((x == rect.x) && (y == rect.y) &&
161 (dX == rect.dX) && (dY == rect.dY));
162 }
163
164 bool operator!= (const RectTmpl& rect) const
165 {
166 return !(*this == rect);
167 }
168
169 bool similar(const RectTmpl& rect, float epsilon) const
170 {
171 return (fabs(x - rect.x) < epsilon &&
172 fabs(y - rect.y) < epsilon &&
173 fabs(dX - rect.dX) < epsilon &&
174 fabs(dY - rect.dY) < epsilon);
175 }
176
177 RectTmpl& offset(PointType offX, PointType offY)
178 {
179 if (!isEmpty())
180 {
181 x += offX;
182 y += offY;
183 }
184 return *this;
185 }
186
191 RectTmpl& inset(PointType insetX, PointType insetY)
192 {
193 if (!isEmpty())
194 {
195 if (dX < insetX * 2)
196 {
197 x += dX / 2;
198 dX = 0;
199 }
200 else
201 {
202 dX -= insetX * 2;
203 x += insetX;
204 }
205 if (dY < insetY * 2)
206 {
207 y += dY / 2;
208 dY = 0;
209 }
210 else
211 {
212 dY -= insetY * 2;
213 y += insetY;
214 }
215 }
216 return *this;
217 }
218
224 {
225 bool result = false;
226 if (isEmpty())
227 {
228 x = point.x; y = point.y;
229 dX = 0; dY = 0;
230 result = true;
231 }
232 else
233 {
234 if (point.x < x)
235 {
236 dX += (x - point.x);
237 x = point.x;
238 result = true;
239 }
240 if (point.y < y)
241 {
242 dY += (y - point.y);
243 y = point.y;
244 result = true;
245 }
246 if (point.x > x + dX)
247 {
248 dX = point.x - x;
249 result = true;
250 }
251 if (point.y > y + dY)
252 {
253 dY = point.y - y;
254 result = true;
255 }
256 }
257 return result;
258 }
259
264 {
265 if (!isEmpty() && !rect.isEmpty())
266 {
267 PointType llX = std::max<PointType>(x, rect.x);
268 PointType urX = std::min<PointType>(x + dX, rect.x + rect.dX);
269 PointType llY = std::max<PointType>(y, rect.y);
270 PointType urY = std::min<PointType>(y + dY, rect.y + rect.dY);
271 x = llX; y = llY; dX = urX - x; dY = urY - y;
272 }
273 else
274 {
275 setEmpty(); // Empty result
276 }
277 }
278
281 {
282 if (!isEmpty())
283 {
284 if (containsRect(rect))
285 {
286 // We completely contain the input rect; no need to grow
287 }
288 else if (!rect.isEmpty())
289 {
290 PointType llX = std::min<PointType>(x, rect.x);
291 PointType urX = std::max<PointType>(x + dX, rect.x + rect.dX);
292 PointType llY = std::min<PointType>(y, rect.y);
293 PointType urY = std::max<PointType>(y + dY, rect.y + rect.dY);
294 x = llX; y = llY; dX = urX - x; dY = urY - y;
295 }
296 }
297 else
298 {
299 x = rect.x; y = rect.y; dX = rect.dX; dY = rect.dY;
300 }
301 }
302
305 {
306 RectTmpl<PointType> copy = rect;
307 copy.intersectRect(*this);
308 return !copy.isEmpty();
309 }
310
312 bool containsRect(const RectTmpl<PointType>& rect) const
313 {
314 if (rect.isEmpty() || isEmpty())
315 {
316 return false;
317 }
318 if (x <= rect.x && // We start at or to the left of the input rect
319 y <= rect.y && // We start at or above the top of the input rect
320 (x + dX) >= (rect.x + rect.dX) && // We extend to or beyond the rect to the right
321 (y + dY) >= (rect.y + rect.dY)) // We extend to or beyond the rect to the bottom
322 {
323 return true;
324 }
325 else
326 {
327 return false;
328 }
329 }
330
331 bool containsPoint(PointType px, PointType py) const
332 {
333 return x <= px && px <= getRight() && y <= py && py <= getBottom();
334 }
335
336 PointType getRight() const
337 {
338 return x + dX;
339 }
340
341 PointType getBottom() const
342 {
343 return y + dY;
344 }
345};
346
350
357template <typename PointType>
359{
360 public:
361 BoxTmpl() : left(0), bottom(0), right(0), top(0)
362 {}
363
364 BoxTmpl(PointType _left, PointType _bottom, PointType _right, PointType _top) :
365 left(_left), bottom(_bottom), right(_right), top(_top)
366 {}
367
369 left(b.left), bottom(b.bottom), right(b.right), top(b.top)
370 {}
371
373 {
374 if (rect.isEmpty())
375 {
376 left = rect.x;
377 bottom = rect.y;
378 right = rect.x;
379 top = rect.y;
380 }
381 else
382 {
383 left = rect.x;
384 bottom = rect.y;
385 right = rect.x + rect.dX;
386 top = rect.y + rect.dY;
387 }
388 }
389
391
393
395 {
396 RectTmpl<PointType> result;
397 result.x = left < right ? left : right;
398 result.y = top < bottom ? top : bottom;
399 result.dX = left < right ? (right - left) : (left - right);
400 result.dY = top < bottom ? (bottom - top) : (top - bottom);
401 return result;
402 }
403
405 {
406 if (left > right)
407 {
408 PointType tmp = left;
409 left = right;
410 right = tmp;
411 }
412 if (bottom > top)
413 {
414 PointType tmp = bottom;
415 bottom = top;
416 top = tmp;
417 }
418 }
419
420 void offset(PointType x, PointType y)
421 {
422 left += x;
423 right += x;
424 top += y;
425 bottom += y;
426 }
427
428 void scale(PointType s)
429 {
430 left *= s;
431 right *= s;
432 top *= s;
433 bottom *= s;
434 }
435
436 bool equal(const BoxTmpl<PointType>& other) const
437 {
438 return (left == other.left)
439 && (bottom == other.bottom)
440 && (top == other.top)
441 && (right == other.right);
442 }
443
444 PointType left;
445 PointType bottom;
446 PointType top;
447 PointType right;
448};
449
453
455template <typename TItem>
457{
458 public:
463 typedef enum {
469
474 {
475 set();
476 }
477
488 CTransformMatrix(TItem _xx, TItem _xy, TItem _yx, TItem _yy, TItem _dx, TItem _dy)
489 {
490 set(_xx, _xy, _yx, _yy, _dx, _dy);
491 }
492
498 {
499 *this = m;
500 }
501
508 {
509 if (this != &m)
510 {
511 m_xx = m.m_xx;
512 m_xy = m.m_xy;
513 m_yx = m.m_yx;
514 m_yy = m.m_yy;
515 m_dx = m.m_dx;
516 m_dy = m.m_dy;
517 }
518 return *this;
519 }
520
530 CTransformMatrix(const RectTmpl<TItem>& sourceRect, const RectTmpl<TItem>& destRect, bool allowZeroWidthRect = false)
531 {
532 set();
533 if (sourceRect.dX > 0 && destRect.dX > 0 && sourceRect.dY > 0 && destRect.dY > 0)
534 {
535 m_xx = destRect.dX / sourceRect.dX;
536 m_yy = destRect.dY / sourceRect.dY;
537 m_dx = destRect.x - sourceRect.x * m_xx;
538 m_dy = destRect.y - sourceRect.y * m_yy;
539 }
540 else if (allowZeroWidthRect &&
541 sourceRect.dX > 0 && destRect.dX > 0 && sourceRect.dY == 0 && destRect.dY == 0)
542 {
543 m_xx = destRect.dX / sourceRect.dX;
544 m_yy = 1.0;
545 m_dx = destRect.x - sourceRect.x * m_xx;
546 m_dy = destRect.y - sourceRect.y * m_yy;
547 }
548 else if (allowZeroWidthRect &&
549 sourceRect.dX == 0 && destRect.dX == 0 && sourceRect.dY > 0 && destRect.dY > 0)
550 {
551 m_xx = 1.0;
552 m_yy = destRect.dY / sourceRect.dY;
553 m_dx = destRect.x - sourceRect.x * m_xx;
554 m_dy = destRect.y - sourceRect.y * m_yy;
555 }
556 }
557
568 void set(TItem _xx = 1, TItem _xy = 0, TItem _yx = 0, TItem _yy = 1, TItem _dx = 0, TItem _dy = 0)
569 {
570 m_xx = _xx; m_xy = _xy; m_yx = _yx; m_yy = _yy; m_dx = _dx; m_dy = _dy;
571 }
572
577 TItem xx() const { return m_xx; }
578
583 TItem xy() const { return m_xy; }
584
589 TItem yx() const { return m_yx; }
590
595 TItem yy() const { return m_yy; }
596
601 TItem dx() const { return m_dx; }
602
607 TItem dy() const { return m_dy; }
608
613 void setXX(TItem x) { m_xx = x; }
614
619 void setXY(TItem x) { m_xy = x; }
620
625 void setYX(TItem x) { m_yx = x; }
626
631 void setYY(TItem x) { m_yy = x; }
632
637 void setDX(TItem x) { m_dx = x; }
638
643 void setDY(TItem x) { m_dy = x; }
644
651 bool equal(const CTransformMatrix<TItem>& matrix, bool ignoreDXDY = false) const
652 {
653 return (m_xx == matrix.xx()) &&
654 (m_xy == matrix.xy()) &&
655 (m_yx == matrix.yx()) &&
656 (m_yy == matrix.yy()) &&
657 (ignoreDXDY || (
658 (m_dx == matrix.dx()) &&
659 (m_dy == matrix.dy())));
660 }
661
667 bool identity(bool ignoreDXDY = false) const
668 {
669 return (m_xx == 1.0) &&
670 (m_xy == 0.0) &&
671 (m_yx == 0.0) &&
672 (m_yy == 1.0) &&
673 (ignoreDXDY || (
674 (m_dx == 0.0) &&
675 (m_dy == 0.0)));
676 }
677
687 bool ortho(bool &rotated) const
688 {
689 rotated = false; // Until proven otherwise
690 if (m_xy == 0 && m_yx == 0)
691 {
692 return true;
693 }
694 else if (m_xx == 0 && m_yy == 0)
695 {
696 rotated = true;
697 return true;
698 }
699 else
700 {
701 return false;
702 }
703 }
704
711 {
712 TItem a = matrix.xx() * m_xx + matrix.xy() * m_yx;
713 TItem b = matrix.xx() * m_xy + matrix.xy() * m_yy;
714 TItem c = matrix.yx() * m_xx + matrix.yy() * m_yx;
715 TItem d = matrix.yx() * m_xy + matrix.yy() * m_yy;
716 TItem e = matrix.dx() * m_xx + matrix.dy() * m_yx + m_dx;
717 TItem f = matrix.dx() * m_xy + matrix.dy() * m_yy + m_dy;
718 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
719 return *this;
720 }
721
728 TItem a = m_xx * matrix.xx() + m_xy * matrix.yx();
729 TItem b = m_xx * matrix.xy() + m_xy * matrix.yy();
730 TItem c = m_yx * matrix.xx() + m_yy * matrix.yx();
731 TItem d = m_yx * matrix.xy() + m_yy * matrix.yy();
732 TItem e = m_dx * matrix.xx() + m_dy * matrix.yx() + matrix.dx();
733 TItem f = m_dx * matrix.xy() + m_dy * matrix.yy() + matrix.dy();
734 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
735 return *this;
736 }
737
742 bool degenerate () const
743 {
744 // Find the determinant
745 TItem det = m_xx * m_yy - m_yx * m_xy;
746
747 // A zero determinant indicates a degenerate matrix.
748 return (det == 0.0);
749 }
750
755 bool invert()
756 {
757 TItem det;
758
759 // Find the determinant
760 det = m_xx * m_yy - m_yx * m_xy;
761 if (det == 0.0)
762 {
763 // This matrix cannot be inverted
764 return false;
765 }
766
767 TItem a = m_yy / det;
768 TItem b = -m_xy / det;
769 TItem c = -m_yx / det;
770 TItem d = m_xx / det;
771 TItem e = -(m_dx * m_yy - m_dy * m_yx) / det;
772 TItem f = (m_dx * m_xy - m_dy * m_xx) / det;
773 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
774 return true;
775 }
776
778
784 void transform(PointTmpl<TItem>& result, const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
785 {
786 TItem x = point.x * m_xx + point.y * m_yx;
787 TItem y = point.x * m_xy + point.y * m_yy;
788 if (!ignoreDXDY)
789 {
790 x += m_dx;
791 y += m_dy;
792 }
793 result.x = x;
794 result.y = y;
795 }
796
803 PointTmpl<TItem> transform(const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
804 {
805 PointTmpl<TItem> result;
806
807 TItem x = point.x * m_xx + point.y * m_yx;
808 TItem y = point.x * m_xy + point.y * m_yy;
809 if (!ignoreDXDY)
810 {
811 x += m_dx;
812 y += m_dy;
813 }
814 result.x = x;
815 result.y = y;
816
817 return result;
818 }
819
827 bool iTransform(PointTmpl<TItem>& result, const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
828 {
829 TItem det = m_xx * m_yy - m_yx * m_xy;
830 if (det == 0.0)
831 {
832 // This matrix cannot be inverted
833 return false;
834 }
835 TItem iDet = 1 / det;
836
837 TItem x = point.x;
838 TItem y = point.y;
839 if (!ignoreDXDY)
840 {
841 x -= m_dx;
842 y -= m_dy;
843 }
844
845 result.x = ((x * m_yy - y * m_yx) * iDet);
846 result.y = ((-x * m_xy + y * m_xx) * iDet);
847
848 return true;
849 }
850
858 std::pair<bool, PointTmpl<TItem> > iTransform(const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
859 {
860 PointTmpl<TItem> result;
861
862 TItem det = m_xx * m_yy - m_yx * m_xy;
863 if (det == 0.0)
864 {
865 // This matrix cannot be inverted
866 return std::pair<bool, PointTmpl<TItem> >(false, result);
867 }
868 TItem iDet = 1 / det;
869
870 TItem x = point.x;
871 TItem y = point.y;
872 if (!ignoreDXDY)
873 {
874 x -= m_dx;
875 y -= m_dy;
876 }
877
878 result.x = ((x * m_yy - y * m_yx) * iDet);
879 result.y = ((-x * m_xy + y * m_xx) * iDet);
880
881 return std::pair<bool, PointTmpl<TItem> >(true, result);
882 }
883
888 void rotate(double radians)
889 {
890 constexpr double rad_90 = PI / 2.0;
891 constexpr double rad_180 = PI;
892 constexpr double rad_270 = 3.0 * PI / 2.0;
893 constexpr double rad_360 = 2.0 * PI;
894 constexpr double eps = 1.0e-6;
895
896 // Clamp to between 0 and 2*PI
897 while (radians >= rad_360)
898 radians -= rad_360;
899 while (radians < 0.0)
900 radians += rad_360;
901
903
904 if (fabs(radians) < 1.0e-6); // 0 degrees
905 else if (fabs(radians - rad_90) < eps) // 90 degrees
906 rotate = CTransformMatrix(0.0, 1.0, -1.0, 0.0, 0.0, 0.0);
907 else if (fabs(radians - rad_180) < eps) // 180 degrees
908 rotate = CTransformMatrix(-1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
909 else if (fabs(radians - rad_270) < eps) // 270 degrees
910 rotate = CTransformMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0);
911 else
912 rotate = CTransformMatrix(cos(radians), sin(radians), -sin(radians), cos(radians), 0.0, 0.0);
913
914 preMul(rotate);
915 }
916
922 void scale(TItem xscale, TItem yscale)
923 {
924 CTransformMatrix mat(xscale, 0.0, 0.0, yscale, 0.0, 0.0);
925 preMul(mat);
926 }
927
933 void translate(TItem dx, TItem dy)
934 {
935 CTransformMatrix mat(1.0, 0.0, 0.0, 1.0, dx, dy);
936 preMul(mat);
937 }
938
943 TItem determinant() const
944 {
945 return m_xx * m_yy - m_yx * m_xy;
946 }
947
953 void transformRect(RectTmpl<TItem>& rect, bool ignoreDXDY = false) const
954 {
955 TItem llX, llY, urX, urY;
956 PointTmpl<TItem> point, transformedPoint;
957
958 if (rect.isEmpty())
959 return;
960#define EDLTMIN(a, b) (a) < (b) ? (a) : (b)
961#define EDLTMAX(a, b) (a) < (b) ? (b) : (a)
962 // Transform each of the points that make up the corners,
963 // and find the extremes.
964 point.x = rect.x;
965 point.y = rect.y;
966 transform(transformedPoint, point, ignoreDXDY);
967 llX = urX = transformedPoint.x;
968 llY = urY = transformedPoint.y;
969 point.x = rect.x + rect.dX;
970 transform(transformedPoint, point, ignoreDXDY);
971 llX = EDLTMIN(llX, transformedPoint.x);
972 llY = EDLTMIN(llY, transformedPoint.y);
973 urX = EDLTMAX(urX, transformedPoint.x);
974 urY = EDLTMAX(urY, transformedPoint.y);
975 point.y = rect.y + rect.dY;
976 transform(transformedPoint, point, ignoreDXDY);
977 llX = EDLTMIN(llX, transformedPoint.x);
978 llY = EDLTMIN(llY, transformedPoint.y);
979 urX = EDLTMAX(urX, transformedPoint.x);
980 urY = EDLTMAX(urY, transformedPoint.y);
981 point.x = rect.x;
982 transform(transformedPoint, point, ignoreDXDY);
983 llX = EDLTMIN(llX, transformedPoint.x);
984 llY = EDLTMIN(llY, transformedPoint.y);
985 urX = EDLTMAX(urX, transformedPoint.x);
986 urY = EDLTMAX(urY, transformedPoint.y);
987#undef EDLTMIN
988#undef EDLTMAX
989 rect.x = llX; rect.y = llY; rect.dX = urX - llX; rect.dY = urY - llY;
990 }
991
997 {
998 uint32 operationFlags = 0;
999
1000 if ((m_dx != 0.0) || (m_dy != 0))
1001 operationFlags |= eDoesTranslate;
1002
1003 if ((m_xy == 0) && (m_yx == 0))
1004 operationFlags |= eDoesScale;
1005
1006 if ((m_xx == m_yy) && (m_xy == -m_yx)) {
1007 operationFlags |= eDoesRotate;
1008
1009 double det = m_xx * m_yy - m_yx * m_xy;
1010 double eps = 1.0e-06;
1011
1012 if (fabs(det - 1.0) > eps)
1013 operationFlags |= eDoesScale;
1014
1015 }
1016 else {
1017
1018 operationFlags |= eIsComplex;
1019
1020 }
1021
1022 return operationFlags;
1023 }
1024
1025
1035 void decompose(PointTmpl<TItem>& translate, FPoint& scale, FPoint& shear, double& rotationAngle, double eps = 1.0e-06) const
1036 {
1037 // unit square decomposition of matrix ...
1038 // A={a,c}, B={b,d}, Q=angle between vectors (ie PI/2-shear angle)!
1039 // |A|=sqrt(aa+cc)
1040 // |B|=sqrt(bb+dd)
1041 // AxB=|A||B|sinQ=ad-bc=(new area of unit square)
1042 // A.B=|A||B|cosQ=ab+cd
1043
1044 // ScaleX = |A|
1045 // ScaleY = |B|
1046 // Scale = ScaleY*cos(PI/2-Q) = ScaleY*sinQ = AxB/|A|
1047 // AbsScale = abs(Scale) // effectively remove any mirror
1048 // Aspect = ScaleX/abs(Scale)
1049 // Shear = PI/2-Q = PI/2-acos((A.B)/(|A||B|))
1050 // Rotate = atan2(c,a)
1051
1052 double a = m_xx;
1053 double b = m_xy;
1054 double c = m_yx;
1055 double d = m_yy;
1056
1057 // Determine the cross product (determinant), modulus (length) of A and scale
1058 double AdotB = a * b + c * d;
1059 double ModA = ::sqrt(a * a + c * c);
1060 double ModB = ::sqrt(b * b + d * d);
1061 double pi = PI;
1062 double Shear = (pi / 2 - ::acos(AdotB / (ModB * ModA)));
1063
1064 // Set the translate
1065 translate.x = m_dx;
1066 translate.y = m_dy;
1067
1068 // Set the rotation angle
1069 if ((b == 0) || (c == 0))
1070 rotationAngle = 0;
1071 else {
1072 rotationAngle = ::atan2(c, a);
1073 if (fabs(rotationAngle) < eps)
1074 rotationAngle = 0.0;
1075 }
1076
1077 //Set the scale
1078 scale.x = ((a != 0) && (a > 0)) || ((a == 0) && (c * b <= 0)) ? ModA : -ModA;
1079 scale.y = ((d != 0) && (d > 0)) || ((d == 0) && (c * b <= 0)) ? ModB : -ModB;
1080
1081 // Set shear
1082 if (fabs(Shear) < eps) {
1083
1084 // Case: no shear
1085 shear.x = 0;
1086 shear.y = 0;
1087
1088 }
1089 else {
1090
1091 // Case: shear present.
1092 shear.x = -tan(Shear);
1093 shear.y = 0;
1094
1095 if (a == d) {
1096
1097 // Shear will handle differential x and y scaling
1098 scale.x = a;
1099 scale.y = d;
1100
1101 }
1102 }
1103
1104 }
1105
1113
1121 DecomposeInfo decompose(double eps = 1.0e-06) const
1122 {
1123 DecomposeInfo info;
1124
1125 decompose(info.translate, info.scale, info.shear, info.rotationAngle, eps);
1126
1127 return info;
1128 }
1129
1134 double getScale() const
1135 {
1136 double a = m_xx;
1137 double b = m_xy;
1138 double c = m_yx;
1139 double d = m_yy;
1140
1141 double AxB = a * d - b * c;
1142 double ModA = ::sqrt(a * a + c * c);
1143
1144 return ::fabs(AxB / ModA);
1145 }
1146
1152 bool isSimpleScaled(TItem& scale) const
1153 {
1154 bool isSimple = ((m_xx == m_yy) && (m_xy == 0) && (m_yx == 0));
1155
1156 if (isSimple)
1157 scale = m_xx;
1158
1159 return isSimple;
1160 }
1161
1167 std::pair<bool, TItem> isSimpleScaled() const
1168 {
1169 TItem scale;
1170 bool val = isSimpleScaled(scale);
1171
1172 return std::pair<bool, TItem>(val, scale);
1173 }
1174
1199 void decompose(PointTmpl<TItem>& translate, double& rotationAngle, double& shearAngle, FPoint& scale) const
1200 {
1201 CTransformMatrix<TItem> r = *this;
1202 translate = PointTmpl<TItem>(r.dx(), r.dy());
1203 r.setDX(0);
1204 r.setDY(0);
1205 {
1206 PointTmpl<TItem> point(1, 0);
1207 r.transform(point, point);
1208 rotationAngle = atan2(point.y, point.x);
1209 {
1211 rotate.rotate(-rotationAngle);
1212 r.postMul(rotate);
1213 }
1214 r.setXY(0);
1215 }
1216 {
1217 PointTmpl<TItem> point(0, 1);
1218 r.transform(point, point);
1219 shearAngle = (PI / 2.0) - atan2(point.y, point.x);
1220 if (shearAngle < -(PI / 2.0))
1221 {
1222 shearAngle += PI;
1223 }
1224 else if (shearAngle > (PI / 2.0))
1225 {
1226 shearAngle -= PI;
1227 }
1228 r.setYX(0);
1229 }
1230 scale = FPoint(r.xx(), r.yy());
1231 }
1232
1247 void compose(const PointTmpl<TItem>& translateAmount, double rotationAngle, double shearAngle, const FPoint& scaleAmount)
1248 {
1249 // Reset
1250 set();
1251
1252 // First translate
1253 translate(translateAmount.x, translateAmount.y);
1254
1255 // Then rotate
1256 rotate(rotationAngle);
1257
1258 // Then the shear. Must be less than +/- PI/2.
1259 if (shearAngle < -(PI / 2.0) || shearAngle >(PI / 2.0))
1260 {
1262 }
1263 double shearAmount = tan(shearAngle);
1264 CTransformMatrix<TItem> shearMat(1, 0, (TItem)shearAmount, 1, 0, 0);
1265 preMul(shearMat);
1266
1267 // Finally scale
1268 scale((TItem)scaleAmount.x, (TItem)scaleAmount.y);
1269 }
1270
1275 template <typename AType>
1276 void asArray(AType* array) const
1277 {
1278 if (!array)
1279 {
1281 }
1282 array[0] = (AType)m_xx;
1283 array[1] = (AType)m_xy;
1284 array[2] = (AType)m_yx;
1285 array[3] = (AType)m_yy;
1286 array[4] = (AType)m_dx;
1287 array[5] = (AType)m_dy;
1288 }
1289
1290 private:
1291 TItem m_xx, m_xy, m_yx, m_yy, m_dx, m_dy;
1292};
1293
1295
1297
1298#endif /* EDLGEOM_H */
Template for a PDF-style box. Similar to a rectangle but specified using a left, bottom,...
Definition edlgeom.h:359
void scale(PointType s)
Definition edlgeom.h:428
void normalize()
Definition edlgeom.h:404
void offset(PointType x, PointType y)
Definition edlgeom.h:420
bool equal(const BoxTmpl< PointType > &other) const
Definition edlgeom.h:436
double top
Definition edlgeom.h:446
BoxTmpl(const RectTmpl< PointType > &rect)
Definition edlgeom.h:372
BoxTmpl(BoxTmpl< PointType > &&p)=default
RectTmpl< PointType > asRect() const
Definition edlgeom.h:394
BoxTmpl()
Definition edlgeom.h:361
double bottom
Definition edlgeom.h:445
BoxTmpl(PointType _left, PointType _bottom, PointType _right, PointType _top)
Definition edlgeom.h:364
BoxTmpl(const BoxTmpl< PointType > &b)
Definition edlgeom.h:368
double right
Definition edlgeom.h:447
BoxTmpl< PointType > & operator=(const BoxTmpl< PointType > &other)=default
double left
Definition edlgeom.h:444
Definition edlvector.h:30
Matrix class - special 3x2 matrix.
Definition edlgeom.h:457
CTransformMatrix< TItem > & preMul(const CTransformMatrix< TItem > &matrix)
Premultiply by the given matrix.
Definition edlgeom.h:710
CTransformMatrix< TItem > & postMul(const CTransformMatrix< TItem > &matrix)
Postmultiply by the given matrix.
Definition edlgeom.h:727
TItem xy() const
Fetch the xy component.
Definition edlgeom.h:583
void decompose(PointTmpl< TItem > &translate, double &rotationAngle, double &shearAngle, FPoint &scale) const
Similar to the other form of decompose, but does the decomposition in a different,...
Definition edlgeom.h:1199
void transform(PointTmpl< TItem > &result, const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point.
Definition edlgeom.h:784
bool equal(const CTransformMatrix< TItem > &matrix, bool ignoreDXDY=false) const
Compare to another matrix.
Definition edlgeom.h:651
void decompose(PointTmpl< TItem > &translate, FPoint &scale, FPoint &shear, double &rotationAngle, double eps=1.0e-06) const
Decompose the transform into an equivalent set of translate + scale + shear + rotate.
Definition edlgeom.h:1035
CTransformMatrix(const CTransformMatrix< TItem > &m)
Copy constructor.
Definition edlgeom.h:497
bool invert()
Invert the matrix.
Definition edlgeom.h:755
TItem yy() const
Fetch the yy component.
Definition edlgeom.h:595
bool identity(bool ignoreDXDY=false) const
Determine if identity matrix.
Definition edlgeom.h:667
CTransformMatrix()
Initializes the matrix to identity.
Definition edlgeom.h:473
CTransformMatrix(TItem _xx, TItem _xy, TItem _yx, TItem _yy, TItem _dx, TItem _dy)
Initializes the matrix.
Definition edlgeom.h:488
double getScale() const
Determine the average scale of the transform.
Definition edlgeom.h:1134
TItem dy() const
Fetch the dy component.
Definition edlgeom.h:607
void translate(TItem dx, TItem dy)
Translate.
Definition edlgeom.h:933
TItem xx() const
Fetch the xx component.
Definition edlgeom.h:577
void compose(const PointTmpl< TItem > &translateAmount, double rotationAngle, double shearAngle, const FPoint &scaleAmount)
Undo the second form of decompose above. It starts with an identity matrix and applies the transforms...
Definition edlgeom.h:1247
void set(TItem _xx=1, TItem _xy=0, TItem _yx=0, TItem _yy=1, TItem _dx=0, TItem _dy=0)
Set the matrix parameters.
Definition edlgeom.h:568
bool isSimpleScaled(TItem &scale) const
Determine if the transform is merely a scale, and if so, populate the scale.
Definition edlgeom.h:1152
TItem dx() const
Fetch the dx component.
Definition edlgeom.h:601
PointTmpl< TItem > transform(const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point.
Definition edlgeom.h:803
void setDX(TItem x)
Sets the dx component.
Definition edlgeom.h:637
DecomposeInfo decompose(double eps=1.0e-06) const
Decompose the transform into an equivalent set of translate + scale + shear + rotate but return the r...
Definition edlgeom.h:1121
void transformRect(RectTmpl< TItem > &rect, bool ignoreDXDY=false) const
Transform a rectangle.
Definition edlgeom.h:953
CTransformMatrix & operator=(const CTransformMatrix< TItem > &m)
Assignment operator.
Definition edlgeom.h:507
bool ortho(bool &rotated) const
Determine if the matrix is orthogonal. That is, if the matrix is aligned to the x and y axes....
Definition edlgeom.h:687
void setYY(TItem x)
Sets the yy component.
Definition edlgeom.h:631
std::pair< bool, PointTmpl< TItem > > iTransform(const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point by the inverse of the matrix.
Definition edlgeom.h:858
TItem determinant() const
Find the determinant of the matrix.
Definition edlgeom.h:943
void setXX(TItem x)
Sets the xx component.
Definition edlgeom.h:613
void scale(TItem xscale, TItem yscale)
Scale.
Definition edlgeom.h:922
void setXY(TItem x)
Sets the xy component.
Definition edlgeom.h:619
std::pair< bool, TItem > isSimpleScaled() const
Determine if the transform is merely a scale, and if so, return that scale.
Definition edlgeom.h:1167
void rotate(double radians)
Add a rotation, clockwise, in radians.
Definition edlgeom.h:888
void setDY(TItem x)
Sets the dy component.
Definition edlgeom.h:643
bool iTransform(PointTmpl< TItem > &result, const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point by the inverse of the matrix.
Definition edlgeom.h:827
uint32 classify() const
Classify the transform.
Definition edlgeom.h:996
void asArray(AType *array) const
Retrieve the matrix as an array of the given type.
Definition edlgeom.h:1276
bool degenerate() const
Check to see if the matrix is degenerate (0 scale).
Definition edlgeom.h:742
TItem yx() const
Fetch the yx component.
Definition edlgeom.h:589
CTransformMatrix(const RectTmpl< TItem > &sourceRect, const RectTmpl< TItem > &destRect, bool allowZeroWidthRect=false)
Creates a matrix that transforms from one rectangle to another.
Definition edlgeom.h:530
void setYX(TItem x)
Sets the yx component.
Definition edlgeom.h:625
Geometry primitives including: point, rectangle and matrix types supporting both integer and floating...
Definition edlgeom.h:31
double y
Definition edlgeom.h:97
PointTmpl< PointType > & operator-=(const PointTmpl< PointType > &pt)
Definition edlgeom.h:54
PointTmpl< PointType > & operator+=(const PointTmpl< PointType > &pt)
Definition edlgeom.h:47
PointTmpl(PointType ax, PointType ay)
Definition edlgeom.h:37
PointTmpl()
Definition edlgeom.h:33
bool operator!=(const PointTmpl &point) const
Definition edlgeom.h:71
double x
Definition edlgeom.h:96
bool operator==(const PointTmpl &point) const
Definition edlgeom.h:66
PointTmpl< PointType > & operator=(const PointTmpl< PointType > &other)=default
bool equal(const PointTmpl &point) const
Definition edlgeom.h:61
PointTmpl< PointType > getMidPoint(const PointTmpl< PointType > &pt) const
Find the mid-point between this and another point.
Definition edlgeom.h:81
PointTmpl(const PointTmpl< PointType > &p)=default
double getDistance(const PointTmpl< PointType > &pt) const
Find the distance to another point.
Definition edlgeom.h:91
PointTmpl(PointTmpl< PointType > &&p)=default
Definition edlgeom.h:120
void setEmpty()
Definition edlgeom.h:141
RectTmpl(RectTmpl< PointType > &&p)=default
double dX
Definition edlgeom.h:138
void intersectRect(const RectTmpl< PointType > &rect)
Intersect this rect with another rect. If the rects do not intersect, the result is an empty rect.
Definition edlgeom.h:263
double y
Definition edlgeom.h:137
RectTmpl(const RectTmpl< PointType > &r)=default
RectTmpl & offset(PointType offX, PointType offY)
Definition edlgeom.h:177
void unionRect(const RectTmpl< PointType > &rect)
Unite this rect with another rect.
Definition edlgeom.h:280
bool similar(const RectTmpl &rect, float epsilon) const
Definition edlgeom.h:169
RectTmpl< PointType > & operator=(const RectTmpl< PointType > &other)=default
bool isEmpty() const
Definition edlgeom.h:147
bool containsPoint(PointType px, PointType py) const
Definition edlgeom.h:331
PointType getBottom() const
Definition edlgeom.h:341
RectTmpl & inset(PointType insetX, PointType insetY)
Inset a rectangle by the given values. Will collapse to a point if the rectangle is not enough to ser...
Definition edlgeom.h:191
double dY
Definition edlgeom.h:139
PointType getRight() const
Definition edlgeom.h:336
bool operator==(const RectTmpl &rect) const
Definition edlgeom.h:158
bool equal(const RectTmpl &rect) const
Definition edlgeom.h:152
RectTmpl()
Definition edlgeom.h:122
RectTmpl(PointType ax, PointType ay, PointType adX, PointType adY)
Definition edlgeom.h:126
bool operator!=(const RectTmpl &rect) const
Definition edlgeom.h:164
bool expandToPoint(const PointTmpl< PointType > &point)
Expand this rect if necessary to include point.
Definition edlgeom.h:223
bool intersectsWithRect(const RectTmpl< PointType > &rect) const
Does this rect intersect with another rect?
Definition edlgeom.h:304
double x
Definition edlgeom.h:136
bool containsRect(const RectTmpl< PointType > &rect) const
Does this rectangle completely contain the given rect?
Definition edlgeom.h:312
EDL_API void throwEDLError(uint32 errorcode)
Utility - Throw an IEDLError exception with the given error code.
const PointTmpl< PointType > operator-(const PointTmpl< PointType > &lhp, const PointTmpl< PointType > &rhp)
Definition edlgeom.h:106
#define EDLTMIN(a, b)
PointTmpl< double > FPoint
Definition edlgeom.h:111
#define EDLTMAX(a, b)
CTransformMatrix< double > FMatrix
Definition edlgeom.h:1294
BoxTmpl< double > FBox
Definition edlgeom.h:450
RectTmpl< double > FRect
Definition edlgeom.h:347
RectTmpl< int64 > Int64Rect
Definition edlgeom.h:349
RectTmpl< int32 > IntRect
Definition edlgeom.h:348
const PointTmpl< PointType > operator+(const PointTmpl< PointType > &lhp, const PointTmpl< PointType > &rhp)
Definition edlgeom.h:101
BoxTmpl< int32 > IntBox
Definition edlgeom.h:451
CEDLVector< FPoint > CFPointVect
Definition edlgeom.h:115
PointTmpl< int32 > IntPoint
Definition edlgeom.h:112
PointTmpl< uint32 > UIntPoint
Definition edlgeom.h:113
PointTmpl< int64 > Int64Point
Definition edlgeom.h:114
BoxTmpl< int64 > Int64Box
Definition edlgeom.h:452
(very thin) portability layer around operating system provided math functionality but also includes a...
#define PI
Local definition of PI to 20 decimal places.
Definition edlmath.h:25
#define _BEGIN_EDL_NAMESPACE
Definition edlnamespaces.h:75
#define _END_EDL_NAMESPACE
Definition edlnamespaces.h:76
EDL "standard" types including known bit-length signed and unsigned integer type[def]s and definition...
unsigned int uint32
Definition edltypes.h:34
Simple template vector class for general use.
@ EDL_ERR_BAD_ARGUMENTS
General error for bad arguments passed to an API function.
Definition edlerrors.h:44
eOperationTypes
Classification of operation type flags of the transform.
Definition edlgeom.h:463
@ eIsComplex
Definition edlgeom.h:467
@ eDoesScale
Definition edlgeom.h:465
@ eDoesTranslate
Definition edlgeom.h:464
@ eDoesRotate
Definition edlgeom.h:466
Definition edlgeom.h:1107
double rotationAngle
Definition edlgeom.h:1111
FPoint scale
Definition edlgeom.h:1109
PointTmpl< TItem > translate
Definition edlgeom.h:1108
FPoint shear
Definition edlgeom.h:1110