Mako 8.4.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
54 bool equal(const PointTmpl& point) const
55 {
56 return ((x == point.x) && (y == point.y));
57 }
58
59 bool operator == (const PointTmpl& point) const
60 {
61 return ((x == point.x) && (y == point.y));
62 }
63
64 bool operator!= (const PointTmpl& point) const
65 {
66 return !(*this == point);
67 }
68
75 {
76 return PointTmpl<PointType>((PointType)(x + (pt.x - x) / 2.0), (PointType)(y + (pt.y - y) / 2.0));
77 }
78
84 double getDistance(const PointTmpl<PointType>& pt) const
85 {
86 return hypot(pt.x - x, pt.y - y);
87 }
88
89 PointType x;
90 PointType y;
91};
92
93template <typename PointType>
95{
96 return PointTmpl<PointType>(lhp.x + rhp.x, lhp.y + rhp.y);
97}
98template <typename PointType>
100{
101 return PointTmpl<PointType>(lhp.x - rhp.x, lhp.y - rhp.y);
102}
103
109
110// Point type may not be an unsigned type
111template <typename PointType>
113{
114 public:
116 x(0), y(0), dX(-1), dY(-1)
117 {}
118
119 RectTmpl(PointType ax, PointType ay, PointType adX, PointType adY) :
120 x(ax), y(ay), dX(adX), dY(adY)
121 {}
122
123 RectTmpl(const RectTmpl<PointType>& r) = default;
124
126
128
129 PointType x;
130 PointType y;
131 PointType dX;
132 PointType dY;
133
134 void setEmpty()
135 {
136 dX = (PointType)-1;
137 dY = (PointType)-1;
138 }
139
140 bool isEmpty() const
141 {
142 return (dX < (PointType)0 || dY < (PointType)0);
143 }
144
145 bool equal(const RectTmpl& rect) const
146 {
147 return ((x == rect.x) && (y == rect.y) &&
148 (dX == rect.dX) && (dY == rect.dY));
149 }
150
151 bool operator== (const RectTmpl& rect) const
152 {
153 return ((x == rect.x) && (y == rect.y) &&
154 (dX == rect.dX) && (dY == rect.dY));
155 }
156
157 bool operator!= (const RectTmpl& rect) const
158 {
159 return !(*this == rect);
160 }
161
162 bool similar(const RectTmpl& rect, float epsilon) const
163 {
164 return (fabs(x - rect.x) < epsilon &&
165 fabs(y - rect.y) < epsilon &&
166 fabs(dX - rect.dX) < epsilon &&
167 fabs(dY - rect.dY) < epsilon);
168 }
169
170 RectTmpl& offset(PointType offX, PointType offY)
171 {
172 if (!isEmpty())
173 {
174 x += offX;
175 y += offY;
176 }
177 return *this;
178 }
179
184 RectTmpl& inset(PointType insetX, PointType insetY)
185 {
186 if (!isEmpty())
187 {
188 if (dX < insetX * 2)
189 {
190 x += dX / 2;
191 dX = 0;
192 }
193 else
194 {
195 dX -= insetX * 2;
196 x += insetX;
197 }
198 if (dY < insetY * 2)
199 {
200 y += dY / 2;
201 dY = 0;
202 }
203 else
204 {
205 dY -= insetY * 2;
206 y += insetY;
207 }
208 }
209 return *this;
210 }
211
217 {
218 bool result = false;
219 if (isEmpty())
220 {
221 x = point.x; y = point.y;
222 dX = 0; dY = 0;
223 result = true;
224 }
225 else
226 {
227 if (point.x < x)
228 {
229 dX += (x - point.x);
230 x = point.x;
231 result = true;
232 }
233 if (point.y < y)
234 {
235 dY += (y - point.y);
236 y = point.y;
237 result = true;
238 }
239 if (point.x > x + dX)
240 {
241 dX = point.x - x;
242 result = true;
243 }
244 if (point.y > y + dY)
245 {
246 dY = point.y - y;
247 result = true;
248 }
249 }
250 return result;
251 }
252
257 {
258 if (!isEmpty() && !rect.isEmpty())
259 {
260 PointType llX = std::max<PointType>(x, rect.x);
261 PointType urX = std::min<PointType>(x + dX, rect.x + rect.dX);
262 PointType llY = std::max<PointType>(y, rect.y);
263 PointType urY = std::min<PointType>(y + dY, rect.y + rect.dY);
264 x = llX; y = llY; dX = urX - x; dY = urY - y;
265 }
266 else
267 {
268 setEmpty(); // Empty result
269 }
270 }
271
274 {
275 if (!isEmpty())
276 {
277 if (containsRect(rect))
278 {
279 // We completely contain the input rect; no need to grow
280 }
281 else if (!rect.isEmpty())
282 {
283 PointType llX = std::min<PointType>(x, rect.x);
284 PointType urX = std::max<PointType>(x + dX, rect.x + rect.dX);
285 PointType llY = std::min<PointType>(y, rect.y);
286 PointType urY = std::max<PointType>(y + dY, rect.y + rect.dY);
287 x = llX; y = llY; dX = urX - x; dY = urY - y;
288 }
289 }
290 else
291 {
292 x = rect.x; y = rect.y; dX = rect.dX; dY = rect.dY;
293 }
294 }
295
298 {
299 RectTmpl<PointType> copy = rect;
300 copy.intersectRect(*this);
301 return !copy.isEmpty();
302 }
303
305 bool containsRect(const RectTmpl<PointType>& rect) const
306 {
307 if (rect.isEmpty() || isEmpty())
308 {
309 return false;
310 }
311 if (x <= rect.x && // We start at or to the left of the input rect
312 y <= rect.y && // We start at or above the top of the input rect
313 (x + dX) >= (rect.x + rect.dX) && // We extend to or beyond the rect to the right
314 (y + dY) >= (rect.y + rect.dY)) // We extend to or beyond the rect to the bottom
315 {
316 return true;
317 }
318 else
319 {
320 return false;
321 }
322 }
323
324 bool containsPoint(PointType px, PointType py) const
325 {
326 return x <= px && px <= getRight() && y <= py && py <= getBottom();
327 }
328
329 PointType getRight() const
330 {
331 return x + dX;
332 }
333
334 PointType getBottom() const
335 {
336 return y + dY;
337 }
338};
339
343
350template <typename PointType>
352{
353 public:
354 BoxTmpl() : left(0), bottom(0), right(0), top(0)
355 {}
356
357 BoxTmpl(PointType _left, PointType _bottom, PointType _right, PointType _top) :
358 left(_left), bottom(_bottom), right(_right), top(_top)
359 {}
360
362 left(b.left), bottom(b.bottom), right(b.right), top(b.top)
363 {}
364
366 {
367 if (rect.isEmpty())
368 {
369 left = rect.x;
370 bottom = rect.y;
371 right = rect.x;
372 top = rect.y;
373 }
374 else
375 {
376 left = rect.x;
377 bottom = rect.y;
378 right = rect.x + rect.dX;
379 top = rect.y + rect.dY;
380 }
381 }
382
384
386
388 {
389 RectTmpl<PointType> result;
390 result.x = left < right ? left : right;
391 result.y = top < bottom ? top : bottom;
392 result.dX = left < right ? (right - left) : (left - right);
393 result.dY = top < bottom ? (bottom - top) : (top - bottom);
394 return result;
395 }
396
398 {
399 if (left > right)
400 {
401 PointType tmp = left;
402 left = right;
403 right = tmp;
404 }
405 if (bottom > top)
406 {
407 PointType tmp = bottom;
408 bottom = top;
409 top = tmp;
410 }
411 }
412
413 void offset(PointType x, PointType y)
414 {
415 left += x;
416 right += x;
417 top += y;
418 bottom += y;
419 }
420
421 void scale(PointType s)
422 {
423 left *= s;
424 right *= s;
425 top *= s;
426 bottom *= s;
427 }
428
429 bool equal(const BoxTmpl<PointType>& other) const
430 {
431 return (left == other.left)
432 && (bottom == other.bottom)
433 && (top == other.top)
434 && (right == other.right);
435 }
436
437 PointType left;
438 PointType bottom;
439 PointType top;
440 PointType right;
441};
442
446
448template <typename TItem>
450{
451 public:
456 typedef enum {
462
467 {
468 set();
469 }
470
481 CTransformMatrix(TItem _xx, TItem _xy, TItem _yx, TItem _yy, TItem _dx, TItem _dy)
482 {
483 set(_xx, _xy, _yx, _yy, _dx, _dy);
484 }
485
491 {
492 *this = m;
493 }
494
501 {
502 if (this != &m)
503 {
504 m_xx = m.m_xx;
505 m_xy = m.m_xy;
506 m_yx = m.m_yx;
507 m_yy = m.m_yy;
508 m_dx = m.m_dx;
509 m_dy = m.m_dy;
510 }
511 return *this;
512 }
513
520 CTransformMatrix(const RectTmpl<TItem>& sourceRect, const RectTmpl<TItem>& destRect)
521 {
522 set();
523 if (sourceRect.dX > 0 && destRect.dX > 0 && sourceRect.dY > 0 && destRect.dY > 0)
524 {
525 m_xx = destRect.dX / sourceRect.dX;
526 m_yy = destRect.dY / sourceRect.dY;
527 m_dx = destRect.x - sourceRect.x * m_xx;
528 m_dy = destRect.y - sourceRect.y * m_yy;
529 }
530 }
531
542 void set(TItem _xx = 1, TItem _xy = 0, TItem _yx = 0, TItem _yy = 1, TItem _dx = 0, TItem _dy = 0)
543 {
544 m_xx = _xx; m_xy = _xy; m_yx = _yx; m_yy = _yy; m_dx = _dx; m_dy = _dy;
545 }
546
551 TItem xx() const { return m_xx; }
552
557 TItem xy() const { return m_xy; }
558
563 TItem yx() const { return m_yx; }
564
569 TItem yy() const { return m_yy; }
570
575 TItem dx() const { return m_dx; }
576
581 TItem dy() const { return m_dy; }
582
587 void setXX(TItem x) { m_xx = x; }
588
593 void setXY(TItem x) { m_xy = x; }
594
599 void setYX(TItem x) { m_yx = x; }
600
605 void setYY(TItem x) { m_yy = x; }
606
611 void setDX(TItem x) { m_dx = x; }
612
617 void setDY(TItem x) { m_dy = x; }
618
625 bool equal(const CTransformMatrix<TItem>& matrix, bool ignoreDXDY = false) const
626 {
627 return (m_xx == matrix.xx()) &&
628 (m_xy == matrix.xy()) &&
629 (m_yx == matrix.yx()) &&
630 (m_yy == matrix.yy()) &&
631 (ignoreDXDY || (
632 (m_dx == matrix.dx()) &&
633 (m_dy == matrix.dy())));
634 }
635
641 bool identity(bool ignoreDXDY = false) const
642 {
643 return (m_xx == 1.0) &&
644 (m_xy == 0.0) &&
645 (m_yx == 0.0) &&
646 (m_yy == 1.0) &&
647 (ignoreDXDY || (
648 (m_dx == 0.0) &&
649 (m_dy == 0.0)));
650 }
651
661 bool ortho(bool &rotated) const
662 {
663 rotated = false; // Until proven otherwise
664 if (m_xy == 0 && m_yx == 0)
665 {
666 return true;
667 }
668 else if (m_xx == 0 && m_yy == 0)
669 {
670 rotated = true;
671 return true;
672 }
673 else
674 {
675 return false;
676 }
677 }
678
685 {
686 TItem a = matrix.xx() * m_xx + matrix.xy() * m_yx;
687 TItem b = matrix.xx() * m_xy + matrix.xy() * m_yy;
688 TItem c = matrix.yx() * m_xx + matrix.yy() * m_yx;
689 TItem d = matrix.yx() * m_xy + matrix.yy() * m_yy;
690 TItem e = matrix.dx() * m_xx + matrix.dy() * m_yx + m_dx;
691 TItem f = matrix.dx() * m_xy + matrix.dy() * m_yy + m_dy;
692 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
693 return *this;
694 }
695
702 TItem a = m_xx * matrix.xx() + m_xy * matrix.yx();
703 TItem b = m_xx * matrix.xy() + m_xy * matrix.yy();
704 TItem c = m_yx * matrix.xx() + m_yy * matrix.yx();
705 TItem d = m_yx * matrix.xy() + m_yy * matrix.yy();
706 TItem e = m_dx * matrix.xx() + m_dy * matrix.yx() + matrix.dx();
707 TItem f = m_dx * matrix.xy() + m_dy * matrix.yy() + matrix.dy();
708 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
709 return *this;
710 }
711
716 bool degenerate () const
717 {
718 // Find the determinant
719 TItem det = m_xx * m_yy - m_yx * m_xy;
720
721 // A zero determinant indicates a degenerate matrix.
722 return (det == 0.0);
723 }
724
729 bool invert()
730 {
731 TItem det;
732
733 // Find the determinant
734 det = m_xx * m_yy - m_yx * m_xy;
735 if (det == 0.0)
736 {
737 // This matrix cannot be inverted
738 return false;
739 }
740
741 TItem a = m_yy / det;
742 TItem b = -m_xy / det;
743 TItem c = -m_yx / det;
744 TItem d = m_xx / det;
745 TItem e = -(m_dx * m_yy - m_dy * m_yx) / det;
746 TItem f = (m_dx * m_xy - m_dy * m_xx) / det;
747 m_xx = a; m_xy = b; m_yx = c; m_yy = d; m_dx = e; m_dy = f;
748 return true;
749 }
750
752
758 void transform(PointTmpl<TItem>& result, const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
759 {
760 TItem x = point.x * m_xx + point.y * m_yx;
761 TItem y = point.x * m_xy + point.y * m_yy;
762 if (!ignoreDXDY)
763 {
764 x += m_dx;
765 y += m_dy;
766 }
767 result.x = x;
768 result.y = y;
769 }
770
777 PointTmpl<TItem> transform(const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
778 {
779 PointTmpl<TItem> result;
780
781 TItem x = point.x * m_xx + point.y * m_yx;
782 TItem y = point.x * m_xy + point.y * m_yy;
783 if (!ignoreDXDY)
784 {
785 x += m_dx;
786 y += m_dy;
787 }
788 result.x = x;
789 result.y = y;
790
791 return result;
792 }
793
801 bool iTransform(PointTmpl<TItem>& result, const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
802 {
803 TItem det = m_xx * m_yy - m_yx * m_xy;
804 if (det == 0.0)
805 {
806 // This matrix cannot be inverted
807 return false;
808 }
809 TItem iDet = 1 / det;
810
811 TItem x = point.x;
812 TItem y = point.y;
813 if (!ignoreDXDY)
814 {
815 x -= m_dx;
816 y -= m_dy;
817 }
818
819 result.x = ((x * m_yy - y * m_yx) * iDet);
820 result.y = ((-x * m_xy + y * m_xx) * iDet);
821
822 return true;
823 }
824
832 std::pair<bool, PointTmpl<TItem> > iTransform(const PointTmpl<TItem>& point, bool ignoreDXDY = false) const
833 {
834 PointTmpl<TItem> result;
835
836 TItem det = m_xx * m_yy - m_yx * m_xy;
837 if (det == 0.0)
838 {
839 // This matrix cannot be inverted
840 return std::pair<bool, PointTmpl<TItem> >(false, result);
841 }
842 TItem iDet = 1 / det;
843
844 TItem x = point.x;
845 TItem y = point.y;
846 if (!ignoreDXDY)
847 {
848 x -= m_dx;
849 y -= m_dy;
850 }
851
852 result.x = ((x * m_yy - y * m_yx) * iDet);
853 result.y = ((-x * m_xy + y * m_xx) * iDet);
854
855 return std::pair<bool, PointTmpl<TItem> >(true, result);
856 }
857
862 void rotate(double radians)
863 {
864 constexpr double rad_90 = PI / 2.0;
865 constexpr double rad_180 = PI;
866 constexpr double rad_270 = 3.0 * PI / 2.0;
867 constexpr double rad_360 = 2.0 * PI;
868 constexpr double eps = 1.0e-6;
869
870 // Clamp to between 0 and 2*PI
871 while (radians >= rad_360)
872 radians -= rad_360;
873 while (radians < 0.0)
874 radians += rad_360;
875
877
878 if (fabs(radians) < 1.0e-6); // 0 degrees
879 else if (fabs(radians - rad_90) < eps) // 90 degrees
880 rotate = CTransformMatrix(0.0, 1.0, -1.0, 0.0, 0.0, 0.0);
881 else if (fabs(radians - rad_180) < eps) // 180 degrees
882 rotate = CTransformMatrix(-1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
883 else if (fabs(radians - rad_270) < eps) // 270 degrees
884 rotate = CTransformMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0);
885 else
886 rotate = CTransformMatrix(cos(radians), sin(radians), -sin(radians), cos(radians), 0.0, 0.0);
887
888 preMul(rotate);
889 }
890
896 void scale(TItem xscale, TItem yscale)
897 {
898 CTransformMatrix mat(xscale, 0.0, 0.0, yscale, 0.0, 0.0);
899 preMul(mat);
900 }
901
907 void translate(TItem dx, TItem dy)
908 {
909 CTransformMatrix mat(1.0, 0.0, 0.0, 1.0, dx, dy);
910 preMul(mat);
911 }
912
917 TItem determinant() const
918 {
919 return m_xx * m_yy - m_yx * m_xy;
920 }
921
927 void transformRect(RectTmpl<TItem>& rect, bool ignoreDXDY = false) const
928 {
929 TItem llX, llY, urX, urY;
930 PointTmpl<TItem> point, transformedPoint;
931
932 if (rect.isEmpty())
933 return;
934#define EDLTMIN(a, b) (a) < (b) ? (a) : (b)
935#define EDLTMAX(a, b) (a) < (b) ? (b) : (a)
936 // Transform each of the points that make up the corners,
937 // and find the extremes.
938 point.x = rect.x;
939 point.y = rect.y;
940 transform(transformedPoint, point, ignoreDXDY);
941 llX = urX = transformedPoint.x;
942 llY = urY = transformedPoint.y;
943 point.x = rect.x + rect.dX;
944 transform(transformedPoint, point, ignoreDXDY);
945 llX = EDLTMIN(llX, transformedPoint.x);
946 llY = EDLTMIN(llY, transformedPoint.y);
947 urX = EDLTMAX(urX, transformedPoint.x);
948 urY = EDLTMAX(urY, transformedPoint.y);
949 point.y = rect.y + rect.dY;
950 transform(transformedPoint, point, ignoreDXDY);
951 llX = EDLTMIN(llX, transformedPoint.x);
952 llY = EDLTMIN(llY, transformedPoint.y);
953 urX = EDLTMAX(urX, transformedPoint.x);
954 urY = EDLTMAX(urY, transformedPoint.y);
955 point.x = rect.x;
956 transform(transformedPoint, point, ignoreDXDY);
957 llX = EDLTMIN(llX, transformedPoint.x);
958 llY = EDLTMIN(llY, transformedPoint.y);
959 urX = EDLTMAX(urX, transformedPoint.x);
960 urY = EDLTMAX(urY, transformedPoint.y);
961#undef EDLTMIN
962#undef EDLTMAX
963 rect.x = llX; rect.y = llY; rect.dX = urX - llX; rect.dY = urY - llY;
964 }
965
971 {
972 uint32 operationFlags = 0;
973
974 if ((m_dx != 0.0) || (m_dy != 0))
975 operationFlags |= eDoesTranslate;
976
977 if ((m_xy == 0) && (m_yx == 0))
978 operationFlags |= eDoesScale;
979
980 if ((m_xx == m_yy) && (m_xy == -m_yx)) {
981 operationFlags |= eDoesRotate;
982
983 double det = m_xx * m_yy - m_yx * m_xy;
984 double eps = 1.0e-06;
985
986 if (fabs(det - 1.0) > eps)
987 operationFlags |= eDoesScale;
988
989 }
990 else {
991
992 operationFlags |= eIsComplex;
993
994 }
995
996 return operationFlags;
997 }
998
999
1009 void decompose(PointTmpl<TItem>& translate, FPoint& scale, FPoint& shear, double& rotationAngle, double eps = 1.0e-06) const
1010 {
1011 // unit square decomposition of matrix ...
1012 // A={a,c}, B={b,d}, Q=angle between vectors (ie PI/2-shear angle)!
1013 // |A|=sqrt(aa+cc)
1014 // |B|=sqrt(bb+dd)
1015 // AxB=|A||B|sinQ=ad-bc=(new area of unit square)
1016 // A.B=|A||B|cosQ=ab+cd
1017
1018 // ScaleX = |A|
1019 // ScaleY = |B|
1020 // Scale = ScaleY*cos(PI/2-Q) = ScaleY*sinQ = AxB/|A|
1021 // AbsScale = abs(Scale) // effectively remove any mirror
1022 // Aspect = ScaleX/abs(Scale)
1023 // Shear = PI/2-Q = PI/2-acos((A.B)/(|A||B|))
1024 // Rotate = atan2(c,a)
1025
1026 double a = m_xx;
1027 double b = m_xy;
1028 double c = m_yx;
1029 double d = m_yy;
1030
1031 // Determine the cross product (determinant), modulus (length) of A and scale
1032 double AdotB = a * b + c * d;
1033 double ModA = ::sqrt(a * a + c * c);
1034 double ModB = ::sqrt(b * b + d * d);
1035 double pi = PI;
1036 double Shear = (pi / 2 - ::acos(AdotB / (ModB * ModA)));
1037
1038 // Set the translate
1039 translate.x = m_dx;
1040 translate.y = m_dy;
1041
1042 // Set the rotation angle
1043 if ((b == 0) || (c == 0))
1044 rotationAngle = 0;
1045 else {
1046 rotationAngle = ::atan2(c, a);
1047 if (fabs(rotationAngle) < eps)
1048 rotationAngle = 0.0;
1049 }
1050
1051 //Set the scale
1052 scale.x = ((a != 0) && (a > 0)) || ((a == 0) && (c * b <= 0)) ? ModA : -ModA;
1053 scale.y = ((d != 0) && (d > 0)) || ((d == 0) && (c * b <= 0)) ? ModB : -ModB;
1054
1055 // Set shear
1056 if (fabs(Shear) < eps) {
1057
1058 // Case: no shear
1059 shear.x = 0;
1060 shear.y = 0;
1061
1062 }
1063 else {
1064
1065 // Case: shear present.
1066 shear.x = -tan(Shear);
1067 shear.y = 0;
1068
1069 if (a == d) {
1070
1071 // Shear will handle differential x and y scaling
1072 scale.x = a;
1073 scale.y = d;
1074
1075 }
1076 }
1077
1078 }
1079
1087
1095 DecomposeInfo decompose(double eps = 1.0e-06) const
1096 {
1097 DecomposeInfo info;
1098
1099 decompose(info.translate, info.scale, info.shear, info.rotationAngle, eps);
1100
1101 return info;
1102 }
1103
1108 double getScale() const
1109 {
1110 double a = m_xx;
1111 double b = m_xy;
1112 double c = m_yx;
1113 double d = m_yy;
1114
1115 double AxB = a * d - b * c;
1116 double ModA = ::sqrt(a * a + c * c);
1117
1118 return ::fabs(AxB / ModA);
1119 }
1120
1126 bool isSimpleScaled(TItem& scale) const
1127 {
1128 bool isSimple = ((m_xx == m_yy) && (m_xy == 0) && (m_yx == 0));
1129
1130 if (isSimple)
1131 scale = m_xx;
1132
1133 return isSimple;
1134 }
1135
1141 std::pair<bool, TItem> isSimpleScaled() const
1142 {
1143 TItem scale;
1144 bool val = isSimpleScaled(scale);
1145
1146 return std::pair<bool, TItem>(val, scale);
1147 }
1148
1173 void decompose(PointTmpl<TItem>& translate, double& rotationAngle, double& shearAngle, FPoint& scale) const
1174 {
1175 CTransformMatrix<TItem> r = *this;
1176 translate = PointTmpl<TItem>(r.dx(), r.dy());
1177 r.setDX(0);
1178 r.setDY(0);
1179 {
1180 PointTmpl<TItem> point(1, 0);
1181 r.transform(point, point);
1182 rotationAngle = atan2(point.y, point.x);
1183 {
1185 rotate.rotate(-rotationAngle);
1186 r.postMul(rotate);
1187 }
1188 r.setXY(0);
1189 }
1190 {
1191 PointTmpl<TItem> point(0, 1);
1192 r.transform(point, point);
1193 shearAngle = (PI / 2.0) - atan2(point.y, point.x);
1194 if (shearAngle < -(PI / 2.0))
1195 {
1196 shearAngle += PI;
1197 }
1198 else if (shearAngle > (PI / 2.0))
1199 {
1200 shearAngle -= PI;
1201 }
1202 r.setYX(0);
1203 }
1204 scale = FPoint(r.xx(), r.yy());
1205 }
1206
1221 void compose(const PointTmpl<TItem>& translateAmount, double rotationAngle, double shearAngle, const FPoint& scaleAmount)
1222 {
1223 // Reset
1224 set();
1225
1226 // First translate
1227 translate(translateAmount.x, translateAmount.y);
1228
1229 // Then rotate
1230 rotate(rotationAngle);
1231
1232 // Then the shear. Must be less than +/- PI/2.
1233 if (shearAngle < -(PI / 2.0) || shearAngle >(PI / 2.0))
1234 {
1236 }
1237 double shearAmount = tan(shearAngle);
1238 CTransformMatrix<TItem> shearMat(1, 0, (TItem)shearAmount, 1, 0, 0);
1239 preMul(shearMat);
1240
1241 // Finally scale
1242 scale((TItem)scaleAmount.x, (TItem)scaleAmount.y);
1243 }
1244
1249 template <typename AType>
1250 void asArray(AType* array) const
1251 {
1252 if (!array)
1253 {
1255 }
1256 array[0] = (AType)m_xx;
1257 array[1] = (AType)m_xy;
1258 array[2] = (AType)m_yx;
1259 array[3] = (AType)m_yy;
1260 array[4] = (AType)m_dx;
1261 array[5] = (AType)m_dy;
1262 }
1263
1264 private:
1265 TItem m_xx, m_xy, m_yx, m_yy, m_dx, m_dy;
1266};
1267
1269
1271
1272#endif /* EDLGEOM_H */
Template for a PDF-style box. Similar to a rectangle but specified using a left, bottom,...
Definition edlgeom.h:352
void scale(PointType s)
Definition edlgeom.h:421
void normalize()
Definition edlgeom.h:397
void offset(PointType x, PointType y)
Definition edlgeom.h:413
bool equal(const BoxTmpl< PointType > &other) const
Definition edlgeom.h:429
double top
Definition edlgeom.h:439
BoxTmpl(const RectTmpl< PointType > &rect)
Definition edlgeom.h:365
BoxTmpl(BoxTmpl< PointType > &&p)=default
RectTmpl< PointType > asRect() const
Definition edlgeom.h:387
BoxTmpl()
Definition edlgeom.h:354
double bottom
Definition edlgeom.h:438
BoxTmpl(PointType _left, PointType _bottom, PointType _right, PointType _top)
Definition edlgeom.h:357
BoxTmpl(const BoxTmpl< PointType > &b)
Definition edlgeom.h:361
double right
Definition edlgeom.h:440
BoxTmpl< PointType > & operator=(const BoxTmpl< PointType > &other)=default
double left
Definition edlgeom.h:437
Definition edlvector.h:30
Matrix class - special 3x2 matrix.
Definition edlgeom.h:450
CTransformMatrix< TItem > & preMul(const CTransformMatrix< TItem > &matrix)
Premultiply by the given matrix.
Definition edlgeom.h:684
CTransformMatrix< TItem > & postMul(const CTransformMatrix< TItem > &matrix)
Postmultiply by the given matrix.
Definition edlgeom.h:701
TItem xy() const
Fetch the xy component.
Definition edlgeom.h:557
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:1173
void transform(PointTmpl< TItem > &result, const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point.
Definition edlgeom.h:758
bool equal(const CTransformMatrix< TItem > &matrix, bool ignoreDXDY=false) const
Compare to another matrix.
Definition edlgeom.h:625
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:1009
CTransformMatrix(const CTransformMatrix< TItem > &m)
Copy constructor.
Definition edlgeom.h:490
bool invert()
Invert the matrix.
Definition edlgeom.h:729
TItem yy() const
Fetch the yy component.
Definition edlgeom.h:569
bool identity(bool ignoreDXDY=false) const
Determine if identity matrix.
Definition edlgeom.h:641
CTransformMatrix()
Initializes the matrix to identity.
Definition edlgeom.h:466
CTransformMatrix(TItem _xx, TItem _xy, TItem _yx, TItem _yy, TItem _dx, TItem _dy)
Initializes the matrix.
Definition edlgeom.h:481
double getScale() const
Determine the average scale of the transform.
Definition edlgeom.h:1108
TItem dy() const
Fetch the dy component.
Definition edlgeom.h:581
void translate(TItem dx, TItem dy)
Translate.
Definition edlgeom.h:907
TItem xx() const
Fetch the xx component.
Definition edlgeom.h:551
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:1221
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:542
bool isSimpleScaled(TItem &scale) const
Determine if the transform is merely a scale, and if so, populate the scale.
Definition edlgeom.h:1126
TItem dx() const
Fetch the dx component.
Definition edlgeom.h:575
PointTmpl< TItem > transform(const PointTmpl< TItem > &point, bool ignoreDXDY=false) const
Transform a point.
Definition edlgeom.h:777
void setDX(TItem x)
Sets the dx component.
Definition edlgeom.h:611
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:1095
void transformRect(RectTmpl< TItem > &rect, bool ignoreDXDY=false) const
Transform a rectangle.
Definition edlgeom.h:927
CTransformMatrix & operator=(const CTransformMatrix< TItem > &m)
Assignment operator.
Definition edlgeom.h:500
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:661
void setYY(TItem x)
Sets the yy component.
Definition edlgeom.h:605
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:832
TItem determinant() const
Find the determinant of the matrix.
Definition edlgeom.h:917
void setXX(TItem x)
Sets the xx component.
Definition edlgeom.h:587
void scale(TItem xscale, TItem yscale)
Scale.
Definition edlgeom.h:896
void setXY(TItem x)
Sets the xy component.
Definition edlgeom.h:593
std::pair< bool, TItem > isSimpleScaled() const
Determine if the transform is merely a scale, and if so, return that scale.
Definition edlgeom.h:1141
void rotate(double radians)
Add a rotation, clockwise, in radians.
Definition edlgeom.h:862
void setDY(TItem x)
Sets the dy component.
Definition edlgeom.h:617
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:801
uint32 classify() const
Classify the transform.
Definition edlgeom.h:970
void asArray(AType *array) const
Retrieve the matrix as an array of the given type.
Definition edlgeom.h:1250
bool degenerate() const
Check to see if the matrix is degenerate (0 scale).
Definition edlgeom.h:716
CTransformMatrix(const RectTmpl< TItem > &sourceRect, const RectTmpl< TItem > &destRect)
Creates a matrix that transforms from one rectangle to another.
Definition edlgeom.h:520
TItem yx() const
Fetch the yx component.
Definition edlgeom.h:563
void setYX(TItem x)
Sets the yx component.
Definition edlgeom.h:599
Geometry primitives including: point, rectangle and matrix types supporting both integer and floating...
Definition edlgeom.h:31
double y
Definition edlgeom.h:90
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:64
double x
Definition edlgeom.h:89
bool operator==(const PointTmpl &point) const
Definition edlgeom.h:59
PointTmpl< PointType > & operator=(const PointTmpl< PointType > &other)=default
bool equal(const PointTmpl &point) const
Definition edlgeom.h:54
PointTmpl< PointType > getMidPoint(const PointTmpl< PointType > &pt) const
Find the mid-point between this and another point.
Definition edlgeom.h:74
PointTmpl(const PointTmpl< PointType > &p)=default
double getDistance(const PointTmpl< PointType > &pt) const
Find the distance to another point.
Definition edlgeom.h:84
PointTmpl(PointTmpl< PointType > &&p)=default
Definition edlgeom.h:113
void setEmpty()
Definition edlgeom.h:134
RectTmpl(RectTmpl< PointType > &&p)=default
double dX
Definition edlgeom.h:131
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:256
double y
Definition edlgeom.h:130
RectTmpl(const RectTmpl< PointType > &r)=default
RectTmpl & offset(PointType offX, PointType offY)
Definition edlgeom.h:170
void unionRect(const RectTmpl< PointType > &rect)
Unite this rect with another rect.
Definition edlgeom.h:273
bool similar(const RectTmpl &rect, float epsilon) const
Definition edlgeom.h:162
RectTmpl< PointType > & operator=(const RectTmpl< PointType > &other)=default
bool isEmpty() const
Definition edlgeom.h:140
bool containsPoint(PointType px, PointType py) const
Definition edlgeom.h:324
PointType getBottom() const
Definition edlgeom.h:334
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:184
double dY
Definition edlgeom.h:132
PointType getRight() const
Definition edlgeom.h:329
bool operator==(const RectTmpl &rect) const
Definition edlgeom.h:151
bool equal(const RectTmpl &rect) const
Definition edlgeom.h:145
RectTmpl()
Definition edlgeom.h:115
RectTmpl(PointType ax, PointType ay, PointType adX, PointType adY)
Definition edlgeom.h:119
bool operator!=(const RectTmpl &rect) const
Definition edlgeom.h:157
bool expandToPoint(const PointTmpl< PointType > &point)
Expand this rect if necessary to include point.
Definition edlgeom.h:216
bool intersectsWithRect(const RectTmpl< PointType > &rect) const
Does this rect intersect with another rect?
Definition edlgeom.h:297
double x
Definition edlgeom.h:129
bool containsRect(const RectTmpl< PointType > &rect) const
Does this rectangle completely contain the given rect?
Definition edlgeom.h:305
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:99
#define EDLTMIN(a, b)
PointTmpl< double > FPoint
Definition edlgeom.h:104
#define EDLTMAX(a, b)
CTransformMatrix< double > FMatrix
Definition edlgeom.h:1268
BoxTmpl< double > FBox
Definition edlgeom.h:443
RectTmpl< double > FRect
Definition edlgeom.h:340
RectTmpl< int64 > Int64Rect
Definition edlgeom.h:342
RectTmpl< int32 > IntRect
Definition edlgeom.h:341
const PointTmpl< PointType > operator+(const PointTmpl< PointType > &lhp, const PointTmpl< PointType > &rhp)
Definition edlgeom.h:94
BoxTmpl< int32 > IntBox
Definition edlgeom.h:444
CEDLVector< FPoint > CFPointVect
Definition edlgeom.h:108
PointTmpl< int32 > IntPoint
Definition edlgeom.h:105
PointTmpl< uint32 > UIntPoint
Definition edlgeom.h:106
PointTmpl< int64 > Int64Point
Definition edlgeom.h:107
BoxTmpl< int64 > Int64Box
Definition edlgeom.h:445
(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:456
@ eIsComplex
Definition edlgeom.h:460
@ eDoesScale
Definition edlgeom.h:458
@ eDoesTranslate
Definition edlgeom.h:457
@ eDoesRotate
Definition edlgeom.h:459
Definition edlgeom.h:1081
double rotationAngle
Definition edlgeom.h:1085
FPoint scale
Definition edlgeom.h:1083
PointTmpl< TItem > translate
Definition edlgeom.h:1082
FPoint shear
Definition edlgeom.h:1084