Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1170 lines
27 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Matrix.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Implementation of matrix class
  12. *
  13. * Revision History:
  14. *
  15. * 12/02/1998 davidx
  16. * Created it.
  17. *
  18. \**************************************************************************/
  19. #include "precomp.hpp"
  20. /**************************************************************************\
  21. *
  22. * Function Description:
  23. *
  24. * Infer an affine transformation matrix
  25. * from a rectangle-to-rectangle mapping
  26. *
  27. * Arguments:
  28. *
  29. * [IN] destRect - Specifies the destination rectangle
  30. * [IN] srcRect - Specifies the source rectangle
  31. *
  32. * Return Value:
  33. *
  34. * GpStatus - Ok or failure status
  35. *
  36. * Created:
  37. *
  38. * 3/10/1999 DCurtis
  39. *
  40. \**************************************************************************/
  41. GpStatus
  42. GpMatrix::InferAffineMatrix(
  43. const GpRectF & destRect,
  44. const GpRectF & srcRect
  45. )
  46. {
  47. REAL srcLeft = srcRect.X;
  48. REAL srcRight = srcRect.GetRight();
  49. REAL srcTop = srcRect.Y;
  50. REAL srcBottom = srcRect.GetBottom();
  51. REAL destLeft = destRect.X;
  52. REAL destRight = destRect.GetRight();
  53. REAL destTop = destRect.Y;
  54. REAL destBottom = destRect.GetBottom();
  55. if ((srcLeft == srcRight) || (srcTop == srcBottom))
  56. {
  57. return InvalidParameter;
  58. }
  59. M12 = 0;
  60. M21 = 0;
  61. M11 = (destRight - destLeft) / (srcRight - srcLeft);
  62. M22 = (destBottom - destTop) / (srcBottom - srcTop);
  63. Dx = destRight - (M11 * srcRight);
  64. Dy = destBottom - (M22 * srcBottom);
  65. Complexity = ComputeComplexity();
  66. return Ok;
  67. }
  68. /**************************************************************************\
  69. *
  70. * Function Description:
  71. *
  72. * Infer an affine transformation matrix
  73. * from a rectangle-to-parallelogram mapping
  74. *
  75. * Arguments:
  76. *
  77. * [IN] rect - Specifies the source rectangle
  78. * [IN] destPoints - Specifies the destination parallelogram
  79. * The array must contain at least 3 points.
  80. * destPoints[0] <=> top-left corner of the source rectangle
  81. * destPoints[1] <=> top-right corner
  82. * destPoints[2] <=> bottom-left corner
  83. *
  84. * Return Value:
  85. *
  86. * Status code (error when 3 points for the destination
  87. * parallelogram is colinear).
  88. *
  89. * Reference:
  90. *
  91. * Digital Image Warping
  92. * by George Wolberg
  93. * pp. 50-51
  94. *
  95. \**************************************************************************/
  96. GpStatus
  97. GpMatrix::InferAffineMatrix(
  98. const GpPointF* destPoints,
  99. const GpRectF& srcRect
  100. )
  101. {
  102. REAL x0, y0, x1, y1, x2, y2;
  103. REAL u0, v0, u1, v1, u2, v2;
  104. REAL d;
  105. x0 = destPoints[0].X;
  106. y0 = destPoints[0].Y;
  107. x1 = destPoints[1].X;
  108. y1 = destPoints[1].Y;
  109. x2 = destPoints[2].X;
  110. y2 = destPoints[2].Y;
  111. u0 = srcRect.X;
  112. v0 = srcRect.Y;
  113. u1 = u0 + srcRect.Width;
  114. v1 = v0;
  115. u2 = u0;
  116. v2 = v0 + srcRect.Height;
  117. d = u0*(v1-v2) - v0*(u1-u2) + (u1*v2-u2*v1);
  118. if (REALABS(d) < REAL_EPSILON)
  119. {
  120. WARNING(("Colinear points in inferAffineMatrix"));
  121. return InvalidParameter;
  122. }
  123. d = TOREAL(1.0) / d;
  124. REAL t0, t1, t2;
  125. t0 = v1-v2;
  126. t1 = v2-v0;
  127. t2 = v0-v1;
  128. M11 = d * (x0*t0 + x1*t1 + x2*t2);
  129. M12 = d * (y0*t0 + y1*t1 + y2*t2);
  130. t0 = u2-u1;
  131. t1 = u0-u2;
  132. t2 = u1-u0;
  133. M21 = d * (x0*t0 + x1*t1 + x2*t2);
  134. M22 = d * (y0*t0 + y1*t1 + y2*t2);
  135. t0 = u1*v2-u2*v1;
  136. t1 = u2*v0-u0*v2;
  137. t2 = u2*v1-u1*v0;
  138. Dx = d * (x0*t0 + x1*t1 + x2*t2);
  139. Dy = d * (y0*t0 + y1*t1 + y2*t2);
  140. Complexity = ComputeComplexity();
  141. return Ok;
  142. }
  143. GpMatrix::GpMatrix(
  144. const GpPointF* destPoints,
  145. const GpRectF& srcRect
  146. )
  147. {
  148. // !!!
  149. // Should we throw an exception if inferAffineMatrix fails?
  150. SetValid(InferAffineMatrix(destPoints, srcRect) == Ok);
  151. }
  152. /**************************************************************************\
  153. *
  154. * Function Description:
  155. *
  156. * Invert the matrix (in place)
  157. *
  158. * Arguments:
  159. *
  160. * NONE
  161. *
  162. * Return Value:
  163. *
  164. * Status code (error if the matrix is not invertible)
  165. *
  166. * Reference:
  167. *
  168. * Digital Image Warping
  169. * by George Wolberg
  170. * pp. 52-53
  171. *
  172. \**************************************************************************/
  173. GpStatus
  174. GpMatrix::Invert()
  175. {
  176. if(IsIdentity())
  177. {
  178. // Invert the identity matrix - this is easy.
  179. return Ok;
  180. }
  181. if (!IsInvertible())
  182. {
  183. WARNING(("Matrix is non-invertible"));
  184. return InvalidParameter;
  185. }
  186. REAL t11, t12, t21, t22, tx, ty;
  187. REAL d = (M11*M22 - M12*M21);
  188. d = TOREAL(1.0) / d;
  189. t11 = M22;
  190. t12 = -M12;
  191. t21 = -M21;
  192. t22 = M11;
  193. tx = M21*Dy - M22*Dx;
  194. ty = M12*Dx - M11*Dy;
  195. M11 = d*t11;
  196. M12 = d*t12;
  197. M21 = d*t21;
  198. M22 = d*t22;
  199. Dx = d*tx;
  200. Dy = d*ty;
  201. Complexity = ComputeComplexity();
  202. return Ok;
  203. }
  204. /**************************************************************************\
  205. *
  206. * Function Description:
  207. *
  208. * Prepend or append a scale matrix to the current matrix, i.e.
  209. *
  210. * | scaleX 0 0 |
  211. * m = | 0 scaleY 0 |
  212. * | 0 0 1 |
  213. *
  214. * matrix = m * matrix // for prepend
  215. * matrix = matrix * m // for append
  216. *
  217. * Arguments:
  218. *
  219. * scaleX - scale factor along x-axis
  220. * scaleY - scale factor along y-axis
  221. * order - prepend or append.
  222. *
  223. * Return Value:
  224. *
  225. * NONE
  226. *
  227. \**************************************************************************/
  228. VOID
  229. GpMatrix::Scale(
  230. REAL scaleX,
  231. REAL scaleY,
  232. GpMatrixOrder order
  233. )
  234. {
  235. if (order == MatrixOrderPrepend)
  236. {
  237. M11 *= scaleX;
  238. M12 *= scaleX;
  239. M21 *= scaleY;
  240. M22 *= scaleY;
  241. }
  242. else // Append
  243. {
  244. M11 *= scaleX;
  245. M21 *= scaleX;
  246. M12 *= scaleY;
  247. M22 *= scaleY;
  248. Dx *= scaleX;
  249. Dy *= scaleY;
  250. }
  251. // Scaling can magnify the error of other components.
  252. // So it is safest to always recompute the complexity always.
  253. Complexity = ComputeComplexity();
  254. }
  255. /**************************************************************************\
  256. *
  257. * Function Description:
  258. *
  259. * Prepend or append a rotation matrix to the current matrix, i.e.
  260. *
  261. * | cos(angle) sin(angle) 0 |
  262. * m = | -sin(angle) cos(angle) 0 |
  263. * | 0 0 1 |
  264. *
  265. * matrix = m * matrix // for prepend
  266. * matrix = matrix * m // for append
  267. *
  268. * Arguments:
  269. *
  270. * angle - Specify the rotation angle
  271. * order - prepend or append.
  272. *
  273. * Return Value:
  274. *
  275. * NONE
  276. *
  277. \**************************************************************************/
  278. #define PI 3.1415926535897932384626433832795
  279. #define DEGREES_TO_RADIANS (PI / 180.0)
  280. VOID
  281. GpMatrix::Rotate(
  282. REAL angle,
  283. GpMatrixOrder order
  284. )
  285. {
  286. REAL s, c;
  287. REAL t11, t12, t21, t22;
  288. angle *= (REAL)DEGREES_TO_RADIANS;
  289. s = REALSIN(angle);
  290. c = REALCOS(angle);
  291. if (order == MatrixOrderPrepend)
  292. {
  293. t11 = c*M11 + s*M21;
  294. t12 = c*M12 + s*M22;
  295. t21 = c*M21 - s*M11;
  296. t22 = c*M22 - s*M12;
  297. }
  298. else // Append
  299. {
  300. t11 = c*M11 - s*M12;
  301. t12 = s*M11 + c*M12;
  302. t21 = c*M21 - s*M22;
  303. t22 = s*M21 + c*M22;
  304. REAL tx, ty;
  305. tx = c*Dx - s*Dy;
  306. ty = s*Dx + c*Dy;
  307. Dx = tx;
  308. Dy = ty;
  309. }
  310. M11 = t11;
  311. M12 = t12;
  312. M21 = t21;
  313. M22 = t22;
  314. // Rotation is very complex; we choose to simply recalculate the
  315. // complexity:
  316. Complexity = ComputeComplexity();
  317. }
  318. /**************************************************************************\
  319. *
  320. * Function Description:
  321. *
  322. * Prepend or append a translation matrix to the current matrix, i.e.
  323. *
  324. * | 1 0 0 |
  325. * m = | 0 1 0 |
  326. * | offsetX offsetY 1 |
  327. *
  328. * matrix = m * matrix // for prepend
  329. * matrix = matrix * m // for append
  330. *
  331. * Arguments:
  332. *
  333. * offsetX - offset along x-axis
  334. * offsetY - offset along y-axis
  335. * order - prepend or append.
  336. *
  337. * Return Value:
  338. *
  339. * NONE
  340. *
  341. \**************************************************************************/
  342. VOID
  343. GpMatrix::Translate(
  344. REAL offsetX,
  345. REAL offsetY,
  346. GpMatrixOrder order
  347. )
  348. {
  349. if (order == MatrixOrderPrepend)
  350. {
  351. Dx += (offsetX * M11) + (offsetY * M21);
  352. Dy += (offsetX * M12) + (offsetY * M22);
  353. }
  354. else // Append
  355. {
  356. Dx += offsetX;
  357. Dy += offsetY;
  358. }
  359. Complexity |= TranslationMask;
  360. AssertComplexity();
  361. }
  362. /**************************************************************************\
  363. *
  364. * Function Description:
  365. *
  366. * Prepend or append a shear matrix to the current matrix, i.e.
  367. *
  368. * | 1 shearY 0 |
  369. * m = | shearX 1 0 |
  370. * | 0 0 1 |
  371. *
  372. * matrix = m * matrix // for prepend
  373. * matrix = matrix * m // for append
  374. *
  375. * Arguments:
  376. *
  377. * shearX - Amount to shear along x-axis
  378. * shearY - Amount to shear along y-axis
  379. * order - prepend or append.
  380. *
  381. * Return Value:
  382. *
  383. * NONE
  384. *
  385. \**************************************************************************/
  386. VOID
  387. GpMatrix::Shear(
  388. REAL shearX,
  389. REAL shearY,
  390. GpMatrixOrder order
  391. )
  392. {
  393. REAL t;
  394. if (order == MatrixOrderPrepend)
  395. {
  396. t = M11;
  397. M11 += shearY*M21;
  398. M21 += shearX*t;
  399. t = M12;
  400. M12 += shearY*M22;
  401. M22 += shearX*t;
  402. }
  403. else // Append
  404. {
  405. t = M11;
  406. M11 += shearX*M12;
  407. M12 += shearY*t;
  408. t = M21;
  409. M21 += shearX*M22;
  410. M22 += shearY*t;
  411. t= Dx;
  412. Dx += shearX*Dy;
  413. Dy += shearY*t;
  414. }
  415. // Shear is very complex; we choose to simply recalculate the
  416. // complexity:
  417. Complexity = ComputeComplexity();
  418. }
  419. /**************************************************************************\
  420. *
  421. * Function Description:
  422. *
  423. * Multiply two matrices and place the result in the 3rd one:
  424. * m = m1 * m2
  425. *
  426. * Arguments:
  427. *
  428. * m - Destination matrix
  429. * m1, m2 - Source matrices
  430. *
  431. * Return Value:
  432. *
  433. * NONE
  434. *
  435. * Notes:
  436. *
  437. * m can be the same matrix as m1 and/or m2.
  438. *
  439. \**************************************************************************/
  440. VOID
  441. GpMatrix::MultiplyMatrix(
  442. GpMatrix& m,
  443. const GpMatrix& m1,
  444. const GpMatrix& m2
  445. )
  446. {
  447. REAL t11, t12, t21, t22, tx, ty;
  448. t11 = m1.M11 * m2.M11 + m1.M12 * m2.M21;
  449. t12 = m1.M11 * m2.M12 + m1.M12 * m2.M22;
  450. t21 = m1.M21 * m2.M11 + m1.M22 * m2.M21;
  451. t22 = m1.M21 * m2.M12 + m1.M22 * m2.M22;
  452. tx = m1.Dx * m2.M11 + m1.Dy * m2.M21 + m2.Dx;
  453. ty = m1.Dx * m2.M12 + m1.Dy * m2.M22 + m2.Dy;
  454. m.M11 = t11;
  455. m.M12 = t12;
  456. m.M21 = t21;
  457. m.M22 = t22;
  458. m.Dx = tx;
  459. m.Dy = ty;
  460. // Multiply can be very complex; we choose to simply recalculate the
  461. // complexity:
  462. m.Complexity = m.ComputeComplexity();
  463. }
  464. /**************************************************************************\
  465. *
  466. * Function Description:
  467. *
  468. * Scale the entire matrix by the scale value.
  469. *
  470. * +-- --+ +-- --+
  471. * | M11 M12 0 | | Sx 0 0 |
  472. * | M21 M22 0 | x | 0 Sy 0 | => dest matrix
  473. * | Dx Dy 1 | | 0 0 1 |
  474. * +-- --+ +-- --+
  475. *
  476. * Arguments:
  477. *
  478. * [OUT] m - destination matrix
  479. * [IN] m1 - source matrix
  480. * [IN] scaleX - dest = source * scaleValue
  481. * [IN] scaleY - dest = source * scaleValue
  482. *
  483. * Return Value:
  484. *
  485. * NONE
  486. *
  487. * Created:
  488. *
  489. * 3/1/1999 DCurtis
  490. *
  491. \**************************************************************************/
  492. VOID
  493. GpMatrix::ScaleMatrix(
  494. GpMatrix& m,
  495. const GpMatrix& m1,
  496. REAL scaleX,
  497. REAL scaleY
  498. )
  499. {
  500. // !!! some kind of epsilon checking maybe?
  501. if ((scaleX != 1) || (scaleY != 1))
  502. {
  503. m.M11 = scaleX * m1.M11;
  504. m.M12 = scaleY * m1.M12;
  505. m.M21 = scaleX * m1.M21;
  506. m.M22 = scaleY * m1.M22;
  507. m.Dx = scaleX * m1.Dx;
  508. m.Dy = scaleY * m1.Dy;
  509. //!!! Since the scaling can magnify the other component,
  510. // it is safer to recompute the complexity.
  511. m.Complexity = m.ComputeComplexity();
  512. /*
  513. if(m1.IsTranslateScale())
  514. {
  515. m.Complexity = m1.Complexity | ScaleMask;
  516. }
  517. else
  518. {
  519. // Scaling a rotation by different scale factors in x and y
  520. // results in a shear. Instead of working out the correct
  521. // optimized complexity, we just recompute - this is a rotation
  522. // or shear already anyway.
  523. m.Complexity = m.ComputeComplexity();
  524. }
  525. m.AssertComplexity();
  526. */
  527. }
  528. else
  529. {
  530. m = m1;
  531. }
  532. }
  533. /**************************************************************************\
  534. *
  535. * Function Description:
  536. *
  537. * Query for special types of transformation matrices
  538. *
  539. * Arguments:
  540. *
  541. * Return Value:
  542. *
  543. * MatrixRotate enum indicating type of rotation
  544. *
  545. \**************************************************************************/
  546. MatrixRotate
  547. GpMatrix::GetRotation() const
  548. {
  549. // Check for no rotate.
  550. if(IsTranslateScale())
  551. {
  552. return MatrixRotateBy0;
  553. }
  554. // Check for Rotate by 90 degrees
  555. if (REALABS(M12) < REAL_EPSILON &&
  556. REALABS(M21) < REAL_EPSILON &&
  557. (M11 < 0.0f) && (M22 < 0.0f) )
  558. {
  559. return MatrixRotateBy180;
  560. }
  561. else if (REALABS(M11) < REAL_EPSILON &&
  562. REALABS(M22) < REAL_EPSILON)
  563. {
  564. if (M12 > 0.0f)
  565. {
  566. return MatrixRotateBy90;
  567. }
  568. else
  569. {
  570. return MatrixRotateBy270;
  571. }
  572. }
  573. return MatrixRotateByOther;
  574. }
  575. /**************************************************************************\
  576. *
  577. * Function Description:
  578. *
  579. * Query for special types of transformation matrices.
  580. * This will return a RotateFlipType for the rotation. If the rotation
  581. * is Identity or an arbitrary non supported format, return value is
  582. * RotateNoneFlipNone
  583. *
  584. \**************************************************************************/
  585. RotateFlipType GpMatrix::AnalyzeRotateFlip() const
  586. {
  587. // Early out the identity case because we have a flag for it in the matrix.
  588. if(IsIntegerTranslate())
  589. {
  590. return RotateNoneFlipNone;
  591. }
  592. // Main Diagonal is zero.
  593. if( (REALABS(M11) < REAL_EPSILON) && // M11 == 0.0
  594. (REALABS(M22) < REAL_EPSILON) ) // M22 == 0.0
  595. {
  596. // Rotate 270 or Rotate 90 + Flip X
  597. if( REALABS(M21-1) < REAL_EPSILON ) // M21 == 1.0
  598. {
  599. if( REALABS(M12-1) < REAL_EPSILON ) // M12 == 1.0
  600. {
  601. return Rotate90FlipX;
  602. }
  603. if( REALABS(M12+1) < REAL_EPSILON ) // M21 == -1.0
  604. {
  605. return Rotate270FlipNone;
  606. }
  607. }
  608. // Rotate 90 or Rotate 270 + Flip X
  609. if( REALABS(M21+1) < REAL_EPSILON ) // M21 == -1.0
  610. {
  611. if( REALABS(M12-1) < REAL_EPSILON ) // M12 == 1.0
  612. {
  613. return Rotate90FlipNone;
  614. }
  615. if( REALABS(M12+1) < REAL_EPSILON ) // M12 == -1.0
  616. {
  617. return Rotate270FlipX;
  618. }
  619. }
  620. }
  621. // Main Diagonal matrix (non zero).
  622. if( (REALABS(M12) < REAL_EPSILON) && // M12 == 0.0
  623. (REALABS(M21) < REAL_EPSILON) ) // M21 == 0.0
  624. {
  625. // Identity or Flip Y
  626. if( REALABS(M11-1) < REAL_EPSILON ) // M11 == 1.0
  627. {
  628. // Identity is handled already.
  629. // if( REALABS(M22-1) < REAL_EPSILON ) // M22 == 1.0
  630. if( REALABS(M22+1) < REAL_EPSILON ) // M22 == -1.0
  631. {
  632. return RotateNoneFlipY;
  633. }
  634. }
  635. // Flip X or Rotate 180
  636. if( REALABS(M11+1) < REAL_EPSILON ) // M11 == -1.0
  637. {
  638. if( REALABS(M22-1) < REAL_EPSILON ) // M22 == 1.0
  639. {
  640. return RotateNoneFlipX;
  641. }
  642. if( REALABS(M22+1) < REAL_EPSILON ) // M22 == -1.0
  643. {
  644. return Rotate180FlipNone;
  645. }
  646. }
  647. }
  648. // We couldn't find a rotate/flip type.
  649. return RotateNoneFlipNone;
  650. }
  651. /**************************************************************************\
  652. *
  653. * Function Description:
  654. *
  655. * Transform the specified array of points using the current matrix
  656. *
  657. * Arguments:
  658. *
  659. * points - Array of points to be transformed
  660. * The resulting points are stored back into the same array
  661. *
  662. * count - Number of points in the array
  663. *
  664. * Return Value:
  665. *
  666. * NONE
  667. *
  668. \**************************************************************************/
  669. VOID
  670. GpMatrix::Transform(
  671. GpPointF* points,
  672. INT count
  673. ) const
  674. {
  675. if (count <= 0)
  676. return;
  677. ASSERT(points != NULL);
  678. // On checked builds, verify that the Complexity flags are correct:
  679. AssertComplexity();
  680. if(IsIdentity())
  681. {
  682. return;
  683. }
  684. else if(IsTranslate())
  685. {
  686. do {
  687. points->X += Dx;
  688. points->Y += Dy;
  689. } while (points++, --count != 0);
  690. }
  691. else if(IsTranslateScale())
  692. {
  693. do {
  694. points->X = points->X * M11 + Dx;
  695. points->Y = points->Y * M22 + Dy;
  696. } while (points++, --count != 0);
  697. }
  698. else
  699. {
  700. do {
  701. REAL x = points->X;
  702. REAL y = points->Y;
  703. points->X = (M11 * x) + (M21 * y) + Dx;
  704. points->Y = (M12 * x) + (M22 * y) + Dy;
  705. } while (points++, --count != 0);
  706. }
  707. }
  708. /**************************************************************************\
  709. *
  710. * Function Description:
  711. *
  712. * Transform the specified array of points using the current matrix,
  713. * with the destination an array of integer POINTS.
  714. *
  715. * Arguments:
  716. *
  717. * srcPoints - Array of REAL points to be transformed
  718. *
  719. * destPoints - Array of REAL points to store the results
  720. *
  721. * count - Number of points in the array
  722. *
  723. * Return Value:
  724. *
  725. * NONE
  726. *
  727. \**************************************************************************/
  728. VOID
  729. GpMatrix::Transform(
  730. const GpPointF* srcPoints,
  731. GpPointF* destPoints,
  732. INT count
  733. ) const
  734. {
  735. if (count <= 0)
  736. return;
  737. ASSERT((srcPoints != NULL) && (destPoints != NULL));
  738. // On checked builds, verify that the Complexity flags are correct:
  739. AssertComplexity();
  740. if(IsIdentity())
  741. {
  742. GpMemcpy(destPoints, srcPoints, count*sizeof(GpPointF));
  743. }
  744. else if (IsTranslate())
  745. {
  746. do {
  747. destPoints->X = srcPoints->X + Dx;
  748. destPoints->Y = srcPoints->Y + Dy;
  749. } while (destPoints++, srcPoints++, --count != 0);
  750. }
  751. else if (IsTranslateScale())
  752. {
  753. do {
  754. destPoints->X = srcPoints->X * M11 + Dx;
  755. destPoints->Y = srcPoints->Y * M22 + Dy;
  756. } while (destPoints++, srcPoints++, --count != 0);
  757. }
  758. else
  759. {
  760. do {
  761. REAL x = srcPoints->X;
  762. REAL y = srcPoints->Y;
  763. destPoints->X = (M11 * x) + (M21 * y) + Dx;
  764. destPoints->Y = (M12 * x) + (M22 * y) + Dy;
  765. } while (destPoints++, srcPoints++, --count != 0);
  766. }
  767. }
  768. /**************************************************************************\
  769. *
  770. * Function Description:
  771. *
  772. * Transform the specified array of points using the current matrix,
  773. * with the destination an array of integer POINTS.
  774. *
  775. * Arguments:
  776. *
  777. * srcPoints - Array of REAL points to be transformed
  778. *
  779. * destPoints - Array of INT points to store the results
  780. *
  781. * count - Number of points in the array
  782. *
  783. * Return Value:
  784. *
  785. * NONE
  786. *
  787. \**************************************************************************/
  788. VOID
  789. GpMatrix::Transform(
  790. const GpPointF* srcPoints,
  791. POINT * destPoints,
  792. INT count
  793. ) const
  794. {
  795. if (count <= 0)
  796. return;
  797. ASSERT((srcPoints != NULL) && (destPoints != NULL));
  798. // On checked builds, verify that the Complexity flags are correct:
  799. AssertComplexity();
  800. // NOTE: This code should call RasterizeCeiling() to be consistent
  801. // with our aliased line drawing rasterizer.
  802. if (IsTranslate())
  803. {
  804. do {
  805. destPoints->x = RasterizerCeiling(srcPoints->X + Dx);
  806. destPoints->y = RasterizerCeiling(srcPoints->Y + Dy);
  807. } while (destPoints++, srcPoints++, --count != 0);
  808. }
  809. else if (IsTranslateScale())
  810. {
  811. do {
  812. destPoints->x = RasterizerCeiling(srcPoints->X * M11 + Dx);
  813. destPoints->y = RasterizerCeiling(srcPoints->Y * M22 + Dy);
  814. } while (destPoints++, srcPoints++, --count != 0);
  815. }
  816. else
  817. {
  818. do {
  819. REAL x = srcPoints->X;
  820. REAL y = srcPoints->Y;
  821. destPoints->x = RasterizerCeiling((M11 * x) + (M21 * y) + Dx);
  822. destPoints->y = RasterizerCeiling((M12 * x) + (M22 * y) + Dy);
  823. } while (destPoints++, srcPoints++, --count != 0);
  824. }
  825. }
  826. /**************************************************************************\
  827. *
  828. * Function Description:
  829. *
  830. * Transform a rect and return the resulting rect.
  831. * This only works if the matrix is a translate-scale matrix, but we're
  832. * assuming here that you've already checked for that.
  833. *
  834. * Arguments:
  835. *
  836. * [IN/OUT] rect - the rect to transform
  837. *
  838. * Return Value:
  839. *
  840. * NONE
  841. *
  842. * Created:
  843. *
  844. * 3/5/1999 DCurtis
  845. *
  846. \**************************************************************************/
  847. VOID
  848. GpMatrix::TransformRect(
  849. GpRectF & rect
  850. ) const
  851. {
  852. if (IsIdentity())
  853. return;
  854. // NTRAID#NTBUG9-407211-2001-05-31-gillessk "Bad assert triggers when it shouldn't"
  855. // loose the condition to allow rotation by multiple of 90 degrees
  856. ASSERT(IsTranslateScale() || (GetRotation()==MatrixRotateBy90) || (GetRotation()==MatrixRotateBy270));
  857. REAL xMin = rect.X;
  858. REAL yMin = rect.Y;
  859. REAL xMax = xMin + rect.Width;
  860. REAL yMax = yMin + rect.Height;
  861. REAL x;
  862. x = xMin;
  863. xMin = (M11 * x) + (M21 * yMin) + Dx;
  864. yMin = (M12 * x) + (M22 * yMin) + Dy;
  865. x = xMax;
  866. xMax = (M11 * x) + (M21 * yMax) + Dx;
  867. yMax = (M12 * x) + (M22 * yMax) + Dy;
  868. if (xMin > xMax)
  869. {
  870. x = xMin;
  871. xMin = xMax;
  872. xMax = x;
  873. }
  874. if (yMin > yMax)
  875. {
  876. x = yMin;
  877. yMin = yMax;
  878. yMax = x;
  879. }
  880. rect.X = xMin;
  881. rect.Y = yMin;
  882. rect.Width = xMax - xMin;
  883. rect.Height = yMax - yMin;
  884. }
  885. /**************************************************************************\
  886. *
  887. * Function Description:
  888. *
  889. * Transform the specified array of points using the current matrix,
  890. * ignoring translation.
  891. *
  892. * Arguments:
  893. *
  894. * points - Array of points to be transformed
  895. * The resulting points are stored back into the same array
  896. *
  897. * count - Number of points in the array
  898. *
  899. * Return Value:
  900. *
  901. * NONE
  902. *
  903. \**************************************************************************/
  904. VOID
  905. GpMatrix::VectorTransform(
  906. GpPointF* points,
  907. INT count
  908. ) const
  909. {
  910. if (IsIdentity())
  911. return;
  912. REAL x;
  913. for (INT i=0; i < count; i++)
  914. {
  915. x = points[i].X;
  916. points[i].X = M11*x + M21*points[i].Y;
  917. points[i].Y = M12*x + M22*points[i].Y;
  918. }
  919. }
  920. /**************************************************************************\
  921. *
  922. * Function Description:
  923. *
  924. * Determine matrix complexity.
  925. *
  926. * NOTE: This function is fairly expensive. It shouldn't be called
  927. * after every matrix operation. (If it was, I would argue
  928. * that's a good reason to get rid of 'Complexity' entirely,
  929. * which is intended as a short-cut and should not be expensive
  930. * to keep updated.)
  931. *
  932. * Arguments:
  933. *
  934. * NONE
  935. *
  936. * Return Value:
  937. *
  938. * Returns a bitmask representing the matrix complexity.
  939. *
  940. \**************************************************************************/
  941. INT
  942. GpMatrix::ComputeComplexity() const
  943. {
  944. INT complexity = ComplexMask;
  945. REAL maxM = max(
  946. max(REALABS(M11), REALABS(M22)),
  947. max(REALABS(M12), REALABS(M21)));
  948. REAL epsilon = CPLX_EPSILON*maxM;
  949. // M12==0 && M21==0
  950. if ((REALABS(M12) < epsilon) && (REALABS(M21) < epsilon))
  951. {
  952. complexity &= ~(ShearMask | RotationMask);
  953. // M11==1 && M22==1
  954. if ((REALABS(M11 - 1.0f) < CPLX_EPSILON) &&
  955. (REALABS(M22 - 1.0f) < CPLX_EPSILON))
  956. {
  957. complexity &= ~ScaleMask;
  958. }
  959. }
  960. else
  961. {
  962. // Check if this is a pure rotation
  963. // M11==M22 && M12==-M21
  964. if((REALABS(M11 - M22) < epsilon) &&
  965. (REALABS(M12 + M21) < epsilon))
  966. {
  967. complexity &= ~ShearMask;
  968. // M11*M11+M12*M12==1
  969. if (REALABS(M11*M11 + M12*M12 - 1.0f) < CPLX_EPSILON)
  970. {
  971. complexity &= ~ScaleMask;
  972. }
  973. }
  974. }
  975. // Dx==0 && Dy==0
  976. // We don't know the real scaling of the translational part.
  977. // So we use the exact value.
  978. // if ((REALABS(Dx) < CPLX_EPSILON) && (REALABS(Dy) < CPLX_EPSILON))
  979. if(Dx == 0 && Dy == 0)
  980. {
  981. complexity &= ~TranslationMask;
  982. }
  983. return(complexity);
  984. }
  985. /**************************************************************************\
  986. *
  987. * Function Description:
  988. *
  989. * Verify the matrix complexity.
  990. *
  991. \**************************************************************************/
  992. #if DBG
  993. VOID
  994. GpMatrix::AssertComplexity() const
  995. {
  996. INT computed = ComputeComplexity();
  997. // The new complexity can be less complex than the old
  998. // (a sequence or rotations may end up with an identity
  999. // transform, for example), but that's okay - complexity
  1000. // is intended as a short cut, and as such keeping it
  1001. // updated sholud be light weight.
  1002. //
  1003. // But the calculated complexity SHOULD NOT be more complex
  1004. // than the old - if it is, we have a bug someplace -
  1005. // we're updating the matrix but not the complexity...
  1006. //
  1007. // Note: under certain circumstances - such as excessive
  1008. // repeated matrix appending or scaling up by very large
  1009. // factors - we could end up with a more complex computed
  1010. // complexity just due to rounding errors.
  1011. // Under these circumstances, the cause should be determined
  1012. // and most likely the algorithm re-evaluated because when
  1013. // rounding errors are propagated to such large proportions,
  1014. // no operations are going to have predictable results anyway.
  1015. ASSERTMSG((Complexity & computed) == computed,
  1016. (("Matrix more complex than cached Complexity indicates")));
  1017. }
  1018. #endif