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.

1444 lines
29 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Implementation of XBezier class and its DDA.
  8. *
  9. * History:
  10. *
  11. * 11/05/1999 ikkof
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. //==========================================================================
  17. // GpXBezier class
  18. //==========================================================================
  19. GpXBezier::~GpXBezier()
  20. {
  21. if(Data)
  22. GpFree(Data);
  23. }
  24. GpStatus
  25. GpXBezier::SetBeziers(INT order, const GpPointF* points, INT count)
  26. {
  27. ASSERT(points && order > 1 && count > order && count % order == 1);
  28. if(!points || order <= 1 || count <= order || count % order != 1)
  29. return InvalidParameter;
  30. GpStatus status = Ok;
  31. INT totalSize = 2*count*sizeof(REALD);
  32. REALD* data = (REALD*) GpRealloc(Data, totalSize);
  33. if(data)
  34. {
  35. REALD* dataPtr = data;
  36. GpPointF* ptr = (GpPointF*) points;
  37. for(INT i = 0; i < count; i++)
  38. {
  39. *dataPtr++ = ptr->X;
  40. *dataPtr++ = ptr->Y;
  41. ptr++;
  42. }
  43. NthOrder = order;
  44. Dimension = 2;
  45. Count = count;
  46. Data = data;
  47. status = Ok;
  48. }
  49. else
  50. status = OutOfMemory;
  51. return status;
  52. }
  53. GpStatus
  54. GpXBezier::SetBeziers(INT order, const GpXPoints& xpoints)
  55. {
  56. ASSERT(xpoints.Count % order == 1);
  57. if(xpoints.Count % order != 1)
  58. return InvalidParameter;
  59. INT totalSize = xpoints.Dimension*xpoints.Count*sizeof(REALD);
  60. REALD* data = (REALD*) GpRealloc(Data, totalSize);
  61. if(data)
  62. {
  63. NthOrder = order;
  64. Dimension = xpoints.Dimension;
  65. Count = xpoints.Count;
  66. GpMemcpy(data, xpoints.Data, totalSize);
  67. Data = data;
  68. }
  69. return Ok;
  70. }
  71. /**************************************************************************\
  72. *
  73. * Function Description:
  74. *
  75. * Flattens the series of Bezier control points and stores
  76. * the results to the arrays of the flatten points.
  77. *
  78. * Arguments:
  79. *
  80. * [OUT] flattenPts - the returned flattend points.
  81. * [IN] matrix - Specifies the transform
  82. *
  83. * Return Value:
  84. *
  85. * NONE
  86. *
  87. * Created:
  88. *
  89. * 11/05/1999 ikkof
  90. * Created it.
  91. *
  92. \**************************************************************************/
  93. GpStatus
  94. GpXBezier::Flatten(
  95. DynPointFArray* flattenPts,
  96. const GpMatrix *matrix
  97. )
  98. {
  99. if(flattenPts == NULL)
  100. return InvalidParameter;
  101. GpXBezierDDA dda;
  102. REALD* bezierData = Data;
  103. INT bezierDataStep = Dimension*NthOrder;
  104. BOOL isFirstBezier = TRUE;
  105. INT count = Count;
  106. flattenPts->Reset(FALSE);
  107. while(count > 1)
  108. {
  109. FlattenEachBezier(
  110. flattenPts,
  111. dda,
  112. isFirstBezier,
  113. matrix,
  114. bezierData);
  115. count -= NthOrder;
  116. bezierData += bezierDataStep;
  117. isFirstBezier = FALSE;
  118. }
  119. return Ok;
  120. }
  121. /**************************************************************************\
  122. *
  123. * Function Description:
  124. *
  125. * Transforms the control points.
  126. *
  127. * Arguments:
  128. *
  129. * [IN] matrix - Specifies the transform
  130. *
  131. * Return Value:
  132. *
  133. * NONE
  134. *
  135. * Created:
  136. *
  137. * 11/05/1999 ikkof
  138. * Created it.
  139. *
  140. \**************************************************************************/
  141. VOID
  142. GpXBezier::Transform(
  143. GpMatrix *matrix
  144. )
  145. {
  146. FPUStateSaver fpuState;
  147. if(matrix == NULL || !Data || Count <= 0)
  148. return;
  149. // Since this is the 2D transform, we transform only
  150. // the first two component.
  151. GpPointF pt;
  152. INT j = 0;
  153. for(INT i = 0; i < Count; i++)
  154. {
  155. pt.X = TOREAL(Data[j]);
  156. pt.Y = TOREAL(Data[j+1]);
  157. matrix->Transform(&pt, 1);
  158. Data[j] = pt.X;
  159. Data[j + 1] = pt.Y;
  160. j += Dimension;
  161. }
  162. return;
  163. }
  164. /**************************************************************************\
  165. *
  166. * Function Description:
  167. *
  168. * Returns the bounds in the specified transform.
  169. * This first calculates the bounds of the control points
  170. * in the world coordinates.
  171. * Then it converts the bounds in the given transform.
  172. * Therefore, this is bigger than the real bounds.
  173. *
  174. * Arguments:
  175. *
  176. * [IN] matrix - Specifies the transform
  177. * [OUT] bounds - Returns the bounding rectangle
  178. *
  179. * Return Value:
  180. *
  181. * NONE
  182. *
  183. * Created:
  184. *
  185. * 12/16/1998 ikkof
  186. * Created it.
  187. *
  188. \**************************************************************************/
  189. VOID
  190. GpXBezier::GetBounds(
  191. GpMatrix* matrix,
  192. GpRect* bounds
  193. )
  194. {
  195. ASSERT(IsValid());
  196. // Currently only Dimension = 2 case is implemented.
  197. if(Dimension != 2)
  198. return;
  199. INT count = Count;
  200. if (count == 0)
  201. {
  202. bounds->X = 0;
  203. bounds->Y = 0;
  204. bounds->Width = 0;
  205. bounds->Height = 0;
  206. }
  207. else
  208. {
  209. FPUStateSaver fpuState;
  210. REALD* data = Data;
  211. REALD left = *data;
  212. REALD right = left;
  213. REALD top = *data++;
  214. REALD bottom = top;
  215. count--;
  216. REALD x, y;
  217. while(count > 0)
  218. {
  219. x = *data++;
  220. y = *data++;
  221. if (x < left)
  222. left = x;
  223. if (y < top)
  224. top = y;
  225. if (x > right)
  226. right = x;
  227. if (y > bottom)
  228. bottom = y;
  229. count--;
  230. }
  231. GpRectF boundsF;
  232. TransformBounds(
  233. matrix,
  234. TOREAL(left),
  235. TOREAL(top),
  236. TOREAL(right),
  237. TOREAL(bottom), &boundsF);
  238. BoundsFToRect(&boundsF, bounds);
  239. }
  240. }
  241. GpStatus
  242. GpXBezier::Get2DPoints(
  243. GpPointF* points,
  244. INT count,
  245. const REALD* dataPoints,
  246. const GpMatrix* matrix)
  247. {
  248. ASSERT(points && dataPoints && count > 0);
  249. if(points && dataPoints && count > 0)
  250. {
  251. FPUStateSaver fpuState;
  252. GpPointF* ptr = points;
  253. const REALD* dataPtr = dataPoints;
  254. INT i, j = 0;
  255. GpMatrix identityMatrix;
  256. const GpMatrix* mat = matrix;
  257. if(!mat)
  258. mat = &identityMatrix;
  259. switch(Dimension)
  260. {
  261. case 2:
  262. for(i = 0; i < count; i++)
  263. {
  264. ptr->X = TOREAL(*dataPtr++);
  265. ptr->Y = TOREAL(*dataPtr++);
  266. ptr++;
  267. }
  268. mat->Transform(points, count);
  269. break;
  270. case 3:
  271. for(i = 0; i < count; i++)
  272. {
  273. REALD x, y, w;
  274. x = *dataPtr++;
  275. y = *dataPtr++;
  276. w = *dataPtr++;
  277. // Do the perspective projection.
  278. ptr->X = TOREAL(x/w);
  279. ptr->Y = TOREAL(y/w);
  280. ptr++;
  281. }
  282. mat->Transform(points, count);
  283. default:
  284. // Not implemented yet.
  285. break;
  286. }
  287. return Ok;
  288. }
  289. return InvalidParameter;
  290. }
  291. /**************************************************************************\
  292. *
  293. * Function Description:
  294. *
  295. * Flattens a given cubic Bezier curve.
  296. *
  297. * Arguments:
  298. *
  299. * [OUT] flattenPts - the returned flattend points.
  300. * [IN] points - the four control points for a Cubic Bezier
  301. *
  302. * Return Value:
  303. *
  304. * NONE
  305. *
  306. * Created:
  307. *
  308. * 02/10/1999 ikkof
  309. * Created it.
  310. *
  311. \**************************************************************************/
  312. GpStatus
  313. GpXBezier::FlattenEachBezier(
  314. DynPointFArray* flattenPts,
  315. GpXBezierDDA& dda,
  316. BOOL isFirstBezier,
  317. const GpMatrix *matrix,
  318. const REALD* bezierData
  319. )
  320. {
  321. GpPointF pts[7];
  322. if(Get2DPoints(&pts[0], NthOrder + 1, bezierData, matrix) != Ok)
  323. return GenericError;
  324. // Use DDA to flatten a Bezier.
  325. GpPointF nextPt;
  326. GpXPoints xpoints(&pts[0], NthOrder + 1);
  327. if(xpoints.Data == NULL)
  328. return OutOfMemory;
  329. dda.SetBezier(xpoints, FlatnessLimit, DistanceLimit);
  330. dda.InitDDA(&nextPt);
  331. GpPointF buffer[BZ_BUFF_SIZE];
  332. INT count = 0;
  333. // If this is the first Bezier curve, add the first point.
  334. if(isFirstBezier)
  335. {
  336. buffer[count++] = nextPt;
  337. }
  338. while(dda.GetNextPoint(&nextPt))
  339. {
  340. if(count < BZ_BUFF_SIZE)
  341. buffer[count++] = nextPt;
  342. else
  343. {
  344. flattenPts->AddMultiple(&buffer[0], count);
  345. buffer[0] = nextPt;
  346. count = 1;
  347. }
  348. dda.MoveForward();
  349. }
  350. // Add the last point.
  351. if(count < BZ_BUFF_SIZE)
  352. buffer[count++] = nextPt;
  353. else
  354. {
  355. flattenPts->AddMultiple(&buffer[0], count);
  356. buffer[0] = nextPt;
  357. count = 1;
  358. }
  359. flattenPts->AddMultiple(&buffer[0], count);
  360. return Ok;
  361. }
  362. /**************************************************************************\
  363. *
  364. * Function Description:
  365. *
  366. * Initialized constants needed for DDA of General Bezier.
  367. *
  368. * Arguments:
  369. *
  370. * NONE
  371. *
  372. * Return Value:
  373. *
  374. * NONE
  375. *
  376. * Created:
  377. *
  378. * 02/10/1999 ikkof
  379. * Created it.
  380. *
  381. \**************************************************************************/
  382. GpXBezierConstants::GpXBezierConstants()
  383. {
  384. INT i, j;
  385. for(i = 0; i <= 6; i++)
  386. {
  387. GpMemset(&H[i][0], 0, 7*sizeof(REAL));
  388. GpMemset(&D[i][0], 0, 7*sizeof(REAL));
  389. GpMemset(&S[i][0], 0, 7*sizeof(REAL));
  390. }
  391. // Matrix for half step
  392. H[0][0] = 1;
  393. H[1][0] = 0.5; // = 1/2
  394. H[1][1] = 0.5; // = 1/2
  395. H[2][0] = 0.25; // = 1/4
  396. H[2][1] = 0.5; // = 1/2
  397. H[2][2] = 0.25; // = 1/4
  398. H[3][0] = 0.125; // = 1/8
  399. H[3][1] = 0.375; // = 3/8
  400. H[3][2] = 0.375; // = 3/8
  401. H[3][3] = 0.125; // = 1/8
  402. H[4][0] = 0.0625; // = 1/16
  403. H[4][1] = 0.25; // = 1/4
  404. H[4][2] = 0.375; // = 3/8
  405. H[4][3] = 0.25; // = 1/4
  406. H[4][4] = 0.0625; // = 1/16
  407. H[5][0] = 0.03125; // = 1/32
  408. H[5][1] = 0.15625; // = 5/32
  409. H[5][2] = 0.3125; // = 5/16
  410. H[5][3] = 0.3125; // = 5/16
  411. H[5][4] = 0.15625; // = 5/32
  412. H[5][5] = 0.03125; // = 1/32
  413. H[6][0] = 0.015625; // = 1/64
  414. H[6][1] = 0.09375; // = 3/32
  415. H[6][2] = 0.234375; // = 15/64
  416. H[6][3] = 0.3125; // = 5/16
  417. H[6][4] = 0.234375; // = 15/64
  418. H[6][5] = 0.09375; // = 3/32
  419. H[6][6] = 0.015625; // = 1/64
  420. // Matrix for double step
  421. D[0][0] = 1;
  422. D[1][0] = -1;
  423. D[1][1] = 2;
  424. D[2][0] = 1;
  425. D[2][1] = -4;
  426. D[2][2] = 4;
  427. D[3][0] = -1;
  428. D[3][1] = 6;
  429. D[3][2] = -12;
  430. D[3][3] = 8;
  431. D[4][0] = 1;
  432. D[4][1] = -8;
  433. D[4][2] = 24;
  434. D[4][3] = -32;
  435. D[4][4] = 16;
  436. D[5][0] = -1;
  437. D[5][1] = 10;
  438. D[5][2] = -40;
  439. D[5][3] = 80;
  440. D[5][4] = -80;
  441. D[5][5] = 32;
  442. D[6][0] = 1;
  443. D[6][1] = -12;
  444. D[6][2] = 60;
  445. D[6][3] = -160;
  446. D[6][4] = 240;
  447. D[6][5] = -192;
  448. D[6][6] = 64;
  449. // Matrix for one step
  450. S[0][0] = 1;
  451. S[1][0] = 2;
  452. S[1][1] = -1;
  453. S[2][0] = 4;
  454. S[2][1] = -4;
  455. S[2][2] = 1;
  456. S[3][0] = 8;
  457. S[3][1] = -12;
  458. S[3][2] = 6;
  459. S[3][3] = -1;
  460. S[4][0] = 16;
  461. S[4][1] = -32;
  462. S[4][2] = 24;
  463. S[4][3] = -8;
  464. S[4][4] = 1;
  465. S[5][0] = 32;
  466. S[5][1] = -80;
  467. S[5][2] = 80;
  468. S[5][3] = -40;
  469. S[5][4] = 10;
  470. S[5][5] = -1;
  471. S[6][0] = 64;
  472. S[6][1] = -192;
  473. S[6][2] = 240;
  474. S[6][3] = -160;
  475. S[6][4] = 60;
  476. S[6][5] = -12;
  477. S[6][6] = 1;
  478. F[0][0] = 1;
  479. F[0][1] = 1;
  480. F[0][2] = 1;
  481. F[0][3] = 1;
  482. F[0][4] = 1;
  483. F[0][5] = 1;
  484. F[0][6] = 1;
  485. F[1][1] = 1;
  486. F[1][2] = 2;
  487. F[1][3] = 3;
  488. F[1][4] = 4;
  489. F[1][5] = 5;
  490. F[1][6] = 6;
  491. F[2][2] = 1;
  492. F[2][3] = 3;
  493. F[2][4] = 6;
  494. F[2][5] = 10;
  495. F[2][6] = 15;
  496. F[3][3] = 1;
  497. F[3][4] = 4;
  498. F[3][5] = 10;
  499. F[3][6] = 20;
  500. F[4][4] = 1;
  501. F[4][5] = 5;
  502. F[4][6] = 15;
  503. F[5][5] = 1;
  504. F[5][6] = 6;
  505. F[6][6] = 1;
  506. H6[0][0] = 1;
  507. H6[1][0] = 1;
  508. H6[1][1] = 1.0/6;
  509. H6[2][0] = 1;
  510. H6[2][1] = 1.0/3;
  511. H6[2][2] = 1.0/15;
  512. H6[3][0] = 1;
  513. H6[3][1] = 1.0/2;
  514. H6[3][2] = 1.0/5;
  515. H6[3][3] = 1.0/20;
  516. H6[4][0] = 1;
  517. H6[4][1] = 2.0/3;
  518. H6[4][2] = 2.0/5;
  519. H6[4][3] = 1.0/5;
  520. H6[4][4] = 1.0/15;
  521. H6[5][0] = 1;
  522. H6[5][1] = 5.0/6;
  523. H6[5][2] = 2.0/3;
  524. H6[5][3] = 1.0/2;
  525. H6[5][4] = 1.0/3;
  526. H6[5][5] = 1.0/6;
  527. H6[6][0] = 1;
  528. H6[6][1] = 1;
  529. H6[6][2] = 1;
  530. H6[6][3] = 1;
  531. H6[6][4] = 1;
  532. H6[6][5] = 1;
  533. H6[6][6] = 1;
  534. G6[0][0] = 1;
  535. G6[1][0] = -6;
  536. G6[1][1] = 6;
  537. G6[2][0] = 15;
  538. G6[2][1] = -30;
  539. G6[2][2] = 15;
  540. G6[3][0] = -20;
  541. G6[3][1] = 60;
  542. G6[3][2] = -60;
  543. G6[3][3] = 20;
  544. G6[4][0] = 15;
  545. G6[4][1] = -60;
  546. G6[4][2] = 90;
  547. G6[4][3] = -60;
  548. G6[4][4] = 15;
  549. G6[5][0] = -6;
  550. G6[5][1] = 30;
  551. G6[5][2] = -60;
  552. G6[5][3] = 60;
  553. G6[5][4] = -30;
  554. G6[5][5] = 6;
  555. G6[6][0] = 1;
  556. G6[6][1] = -6;
  557. G6[6][2] = 15;
  558. G6[6][3] = -20;
  559. G6[6][4] = 15;
  560. G6[6][5] = -6;
  561. G6[6][6] = 1;
  562. }
  563. GpStatus
  564. GpXPoints::Transform(const GpMatrix* matrix)
  565. {
  566. return TransformPoints(matrix, Data, Dimension, Count);
  567. }
  568. GpStatus
  569. GpXPoints::TransformPoints(
  570. const GpMatrix* matrix,
  571. REALD* data,
  572. INT dimension,
  573. INT count
  574. )
  575. {
  576. if(matrix == NULL || data == NULL
  577. || dimension == 0 || count == 0)
  578. return Ok;
  579. // !! This code should consider using Matrix->Transform.
  580. if(dimension >= 2)
  581. {
  582. FPUStateSaver fpuState;
  583. INT j = 0;
  584. // Transform only the first two axis.
  585. for(INT i = 0; i < count; i++)
  586. {
  587. GpPointF pt;
  588. pt.X = TOREAL(data[j]);
  589. pt.Y = TOREAL(data[j + 1]);
  590. matrix->Transform(&pt);
  591. data[j] = pt.X;
  592. data[j + 1] = pt.Y;
  593. j += dimension;
  594. }
  595. return Ok;
  596. }
  597. else
  598. return GenericError;
  599. }
  600. //==========================================================================
  601. // Cubic Bezier class
  602. //
  603. // GpXBezierDDA class
  604. //
  605. // This is based on GDI's flatten path methods written
  606. // by Paul Butzi and J. Andrew Gossen.
  607. // Ikko Fushiki wrote this with different parameters
  608. // and different flatness tests.
  609. //==========================================================================
  610. VOID
  611. GpXBezierDDA::Initialize(
  612. VOID
  613. )
  614. {
  615. INT i;
  616. T = 0;
  617. Dt = 1;
  618. NthOrder = 0;
  619. GpMemset(&P[0], 0, 16*sizeof(REALD));
  620. GpMemset(&Q[0], 0, 16*sizeof(REALD));
  621. NSteps = 1;
  622. // In order to avoid the later multiplication, we pre-multiply
  623. // the flatness limit by 3.
  624. FlatnessLimit = 3*FLATNESS_LIMIT;
  625. DistanceLimit = DISTANCE_LIMIT;
  626. }
  627. /**************************************************************************\
  628. *
  629. * Function Description:
  630. *
  631. * Set the control points of a CubicBezier.
  632. *
  633. * Arguments:
  634. *
  635. * [IN] points - the four control points for a Cubic Bezier
  636. * [IN] flatnessLimit - used for flattening
  637. * [IN] distanceLimit - used for flattening
  638. *
  639. * Return Value:
  640. *
  641. * NONE
  642. *
  643. * Created:
  644. *
  645. * 02/10/1999 ikkof
  646. * Created it.
  647. *
  648. \**************************************************************************/
  649. VOID
  650. GpXBezierDDA::SetBezier(
  651. const GpXPoints& xpoints,
  652. REAL flatnessLimit,
  653. REAL distanceLimit
  654. )
  655. {
  656. if(xpoints.Data == NULL)
  657. return;
  658. T = 0;
  659. Dt = 1;
  660. NthOrder = 0;
  661. INT totalCount = xpoints.Count*xpoints.Dimension;
  662. // This can handle the two dimensional Bezier of 6-th order
  663. // and the three and four dimensional Bezier of 3rd order.
  664. ASSERT(totalCount < 16);
  665. NthOrder = xpoints.Count - 1;
  666. Dimension = xpoints.Dimension;
  667. GpMemcpy(&Q[0], xpoints.Data, totalCount*sizeof(REALD));
  668. SetPolynomicalCoefficients();
  669. NSteps = 1;
  670. // In order to avoid the later multiplication, we pre-multiply
  671. // the flatness limit by 3.
  672. FlatnessLimit = 3*flatnessLimit;
  673. DistanceLimit = distanceLimit;
  674. }
  675. VOID
  676. GpXBezierDDA::SetPolynomicalCoefficients(
  677. VOID
  678. )
  679. {
  680. if(NthOrder == 6)
  681. {
  682. for(INT i = 0; i <= 6; i++)
  683. {
  684. REALD x[4];
  685. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  686. INT k, k0;
  687. for(INT j = 0; j <= i; j++)
  688. {
  689. k0 = Dimension*j;
  690. k = 0;
  691. while(k < Dimension)
  692. {
  693. x[k] += C.G6[i][j]*Q[k0 + k];
  694. k++;
  695. }
  696. }
  697. k0 = Dimension*i;
  698. GpMemcpy(&P[k0], &x[0], Dimension*sizeof(REALD));
  699. }
  700. }
  701. }
  702. /**************************************************************************\
  703. *
  704. * Function Description:
  705. *
  706. * Initializes DDA for CubicBezier and make one step forward.
  707. * This must be called before GetNextPoint() is called.
  708. *
  709. * Arguments:
  710. *
  711. * [OUT] pt - Returns the start point
  712. *
  713. * Return Value:
  714. *
  715. * NONE
  716. *
  717. * Created:
  718. *
  719. * 02/10/1999 ikkof
  720. * Created it.
  721. *
  722. \**************************************************************************/
  723. VOID
  724. GpXBezierDDA::InitDDA(
  725. GpPointF* pt
  726. )
  727. {
  728. switch(Dimension)
  729. {
  730. case 2:
  731. pt->X = (REAL) Q[0];
  732. pt->Y = (REAL) Q[1];
  733. break;
  734. case 3:
  735. // Do something
  736. break;
  737. default:
  738. // Do something
  739. break;
  740. }
  741. INT shift = 2;
  742. // Subdivide fast until it is flat enough
  743. while(NeedsSubdivide(FlatnessLimit))
  744. {
  745. HalveStepSize();
  746. // FastShrinkStepSize(shift);
  747. }
  748. // If it is subdivided too much, expand it.
  749. if((NSteps & 1) == 0)
  750. {
  751. // If the current subdivide is too small,
  752. // double it up.
  753. while(NSteps > 1 && !NeedsSubdivide(FlatnessLimit/4))
  754. {
  755. DoubleStepSize();
  756. }
  757. }
  758. // Take the first step forward.
  759. TakeStep();
  760. }
  761. /**************************************************************************\
  762. *
  763. * Function Description:
  764. *
  765. * Shrinks the current Bezier segment to half.
  766. * The section of t = 0 -> 1/2 of the current
  767. * Beizer segment becomes the new current segment.
  768. *
  769. * Arguments:
  770. *
  771. * NONE
  772. *
  773. * Return Value:
  774. *
  775. * NONE
  776. *
  777. * Created:
  778. *
  779. * 02/10/1999 ikkof
  780. * Created it.
  781. *
  782. \**************************************************************************/
  783. VOID
  784. GpXBezierDDA::HalveStepSize(
  785. VOID
  786. )
  787. {
  788. INT i, j;
  789. REALD x[4];
  790. i = NthOrder;
  791. while(i >= 0)
  792. {
  793. j = i;
  794. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  795. INT k0, k;
  796. while(j >= 0)
  797. {
  798. k0 = Dimension*j;
  799. k = 0;
  800. while(k < Dimension)
  801. {
  802. x[k] += C.H[i][j]*Q[k0 + k];
  803. k++;
  804. }
  805. j--;
  806. }
  807. k0 = Dimension*i;
  808. GpMemcpy(&Q[k0], &x[0], Dimension*sizeof(REALD));
  809. i--;
  810. }
  811. NSteps <<= 1; // The number of steps needed is doubled.
  812. Dt *= 0.5;
  813. }
  814. /**************************************************************************\
  815. *
  816. * Function Description:
  817. *
  818. * Doubles the current Bezier segment.
  819. * The section of t = 0 -> 2 of the current
  820. * Bezier segment becomes the new current segment.
  821. *
  822. * Arguments:
  823. *
  824. * NONE
  825. *
  826. * Return Value:
  827. *
  828. * NONE
  829. *
  830. * Created:
  831. *
  832. * 02/10/1999 ikkof
  833. * Created it.
  834. *
  835. \**************************************************************************/
  836. VOID
  837. GpXBezierDDA::DoubleStepSize(
  838. VOID
  839. )
  840. {
  841. INT i, j;
  842. REALD x[4];
  843. i = NthOrder;
  844. while(i >= 0)
  845. {
  846. j = i;
  847. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  848. INT k, k0;
  849. while(j >= 0)
  850. {
  851. k0 = Dimension*j;
  852. k = 0;
  853. while(k < Dimension)
  854. {
  855. x[k] += C.D[i][j]*Q[k0 + k];
  856. k++;
  857. }
  858. j--;
  859. }
  860. k0 = Dimension*i;
  861. GpMemcpy(&Q[k0], &x[0], Dimension*sizeof(REALD));
  862. i--;
  863. }
  864. NSteps >>= 1; // The number of steps needed is halved.
  865. Dt *= 2;
  866. }
  867. /**************************************************************************\
  868. *
  869. * Function Description:
  870. *
  871. * Shrinks the current Bezier segment by (2^shift).
  872. * The section of t = 0 -> 1/(2^shift) of the current
  873. * Beizer segment becomes the new current segment.
  874. * If shift > 0, this shrinks the step size.
  875. * If shift < 0, this enlarge the step size.
  876. *
  877. * halfStepSize() is equal to fastShrinkStepSize(1).
  878. * doubleStepSize() is equal to fastShrinkStepSize(-1).
  879. *
  880. * Arguments:
  881. *
  882. * [INT] shift - the bits to shift
  883. *
  884. * Return Value:
  885. *
  886. * NONE
  887. *
  888. * Created:
  889. *
  890. * 02/10/1998 ikkof
  891. * Created it.
  892. *
  893. \**************************************************************************/
  894. VOID
  895. GpXBezierDDA::FastShrinkStepSize(
  896. INT shift
  897. )
  898. {
  899. /*
  900. INT n = 1;
  901. if(shift > 0) {
  902. n <<= shift;
  903. Cx /= n;
  904. Cy /= n;
  905. n <<= shift;
  906. Bx /= n;
  907. By /= n;
  908. n <<= shift;
  909. Ax /= n;
  910. Ay /= n;
  911. NSteps <<= shift; // Increase the number of steps.
  912. }
  913. else if(shift < 0) {
  914. n <<= - shift;
  915. Cx *= n;
  916. Cy *= n;
  917. n <<= - shift;
  918. Bx *= n;
  919. By *= n;
  920. n <<= - shift;
  921. Ax *= n;
  922. Ay *= n;
  923. NSteps >>= - shift; // Reduce the number of steps.
  924. }
  925. // Dx and Dy remain the same.
  926. */
  927. }
  928. /**************************************************************************\
  929. *
  930. * Function Description:
  931. *
  932. * Advances the current Bezeir segment to the next one.
  933. * The section of t = 1 -> 2 of the current Bezier segment
  934. * becoms the new current segment.
  935. *
  936. * Arguments:
  937. *
  938. * NONE
  939. *
  940. * Return Value:
  941. *
  942. * NONE
  943. *
  944. * Created:
  945. *
  946. * 12/16/1998 ikkof
  947. * Created it.
  948. *
  949. \**************************************************************************/
  950. VOID
  951. GpXBezierDDA::TakeStep(
  952. VOID
  953. )
  954. {
  955. REALD p[16];
  956. INT i, j;
  957. REALD x[4];
  958. i = NthOrder;
  959. if(NthOrder != 6)
  960. {
  961. while(i >= 0)
  962. {
  963. j = i;
  964. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  965. INT k0, k;
  966. while(j >= 0)
  967. {
  968. k0 = Dimension*(NthOrder - j);
  969. k = 0;
  970. while(k < Dimension)
  971. {
  972. x[k] += C.S[i][j]*Q[k0 + k];
  973. k++;
  974. }
  975. j--;
  976. }
  977. k0 = Dimension*i;
  978. k = 0;
  979. while(k < Dimension)
  980. {
  981. p[k0 + k] = x[k];
  982. k++;
  983. }
  984. i--;
  985. }
  986. GpMemcpy(&Q[0], &p[0], Dimension*(NthOrder + 1)*sizeof(REALD));
  987. }
  988. else
  989. TakeConvergentStep();
  990. NSteps--; // Reduce one step.
  991. T += Dt;
  992. }
  993. VOID
  994. GpXBezierDDA::TakeConvergentStep(
  995. VOID
  996. )
  997. {
  998. REALD t[7], dt[7];
  999. INT i, j;
  1000. t[0] = dt[0] = 1;
  1001. for(i = 1; i <= 6; i++)
  1002. {
  1003. t[i] = t[i-1]*T;
  1004. dt[i] = dt[i-1]*Dt;
  1005. }
  1006. REALD c[16];
  1007. REALD x[4];
  1008. INT k0, k;
  1009. for(i = 0; i <= 6; i++)
  1010. {
  1011. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  1012. for(j = i; j <= 6; j++)
  1013. {
  1014. k0 = Dimension*j;
  1015. for(k = 0; k < Dimension; k++)
  1016. {
  1017. x[k] += C.F[i][j]*t[j-i]*dt[i]*P[k0 + k];
  1018. }
  1019. }
  1020. k0 = Dimension*i;
  1021. GpMemcpy(&c[k0], &x[0], Dimension*sizeof(REALD));
  1022. }
  1023. for(i = 0; i <= 6; i++)
  1024. {
  1025. GpMemset(&x[0], 0, Dimension*sizeof(REALD));
  1026. for(j = 0; j <= i; j++)
  1027. {
  1028. k0 = Dimension*j;
  1029. for(k = 0; k < Dimension; k++)
  1030. {
  1031. x[k] += C.H6[i][j]*c[k0 + k];
  1032. }
  1033. }
  1034. k0 = Dimension*i;
  1035. GpMemcpy(&Q[k0], &x[0], Dimension*sizeof(REALD));
  1036. }
  1037. }
  1038. BOOL
  1039. GpXBezierDDA::Get2DDistanceVector(
  1040. REALD* dx,
  1041. REALD* dy,
  1042. INT from,
  1043. INT to
  1044. )
  1045. {
  1046. REALD p0[16], p1[16];
  1047. INT k0, k;
  1048. if(from < 0 || from > NthOrder || to < 0 || to > NthOrder)
  1049. return FALSE;
  1050. k0 = from*Dimension;
  1051. GpMemcpy(&p0[0], &Q[k0], Dimension*sizeof(REALD));
  1052. k0 = to*Dimension;
  1053. GpMemcpy(&p1[0], &Q[k0], Dimension*sizeof(REALD));
  1054. *dx = p1[0] - p0[0];
  1055. *dy = p1[1] - p0[1];
  1056. return TRUE;
  1057. }
  1058. /**************************************************************************\
  1059. *
  1060. * Function Description:
  1061. *
  1062. * Reurns true if more subdivision is necessary.
  1063. *
  1064. * Arguments:
  1065. *
  1066. * [IN] flatnessLimit - flatness parameter
  1067. *
  1068. * Return Value:
  1069. *
  1070. * Returns true if subdivision is necessary. Otherwise this returns false.
  1071. *
  1072. * Created:
  1073. *
  1074. * 02/10/1999 ikkof
  1075. * Created it.
  1076. *
  1077. \**************************************************************************/
  1078. BOOL
  1079. GpXBezierDDA::NeedsSubdivide(
  1080. REAL flatnessLimit
  1081. )
  1082. {
  1083. REALD mx, my;
  1084. REALD baseLen;
  1085. REALD dx, dy;
  1086. // Get the base line vector.
  1087. if(!Get2DDistanceVector(&dx, &dy, 0, NthOrder))
  1088. return FALSE;
  1089. // Get the perpendicular vector to the base line
  1090. mx = - dy;
  1091. my = dx;
  1092. // Approximate the distance by absolute values of x and y components.
  1093. baseLen = fabs(mx) + fabs(my);
  1094. BOOL needsSubdivide = FALSE;
  1095. // First check if the base length is larger than the distance limit.
  1096. if(baseLen > DistanceLimit)
  1097. {
  1098. // Pre-multiply baseLen by flatness limit for convenience.
  1099. baseLen *= flatnessLimit;
  1100. INT i = 1;
  1101. while(i < NthOrder && !needsSubdivide)
  1102. {
  1103. Get2DDistanceVector(&dx, &dy, 0, i);
  1104. if(fabs(dx*mx + dy*my) > baseLen)
  1105. needsSubdivide = TRUE;
  1106. i++;
  1107. }
  1108. }
  1109. return needsSubdivide;
  1110. }
  1111. /**************************************************************************\
  1112. *
  1113. * Function Description:
  1114. *
  1115. * Returns the current start point.
  1116. * If this has reached the end point, this returns false.
  1117. *
  1118. * Arguments:
  1119. *
  1120. * [OUT] pt - the current start point.
  1121. *
  1122. * Return Value:
  1123. *
  1124. * Returns true if there is a next point.
  1125. *
  1126. * Created:
  1127. *
  1128. * 02/10/1999 ikkof
  1129. * Created it.
  1130. *
  1131. \**************************************************************************/
  1132. BOOL
  1133. GpXBezierDDA::GetNextPoint(
  1134. GpPointF* pt
  1135. )
  1136. {
  1137. // Copy the current start point;
  1138. FPUStateSaver fpuState;
  1139. switch(Dimension)
  1140. {
  1141. case 2:
  1142. pt->X = TOREAL(Q[0]);
  1143. pt->Y = TOREAL(Q[1]);
  1144. break;
  1145. case 3:
  1146. default:
  1147. // Do something for projection.
  1148. return FALSE;
  1149. }
  1150. if(NSteps != 0)
  1151. return TRUE;
  1152. else
  1153. return FALSE; // Congratulations! You have reached the end.
  1154. }
  1155. /**************************************************************************\
  1156. *
  1157. * Function Description:
  1158. *
  1159. * Moves to the next Bezier segment
  1160. *
  1161. * Arguments:
  1162. *
  1163. * NONE
  1164. *
  1165. * Return Value:
  1166. *
  1167. * NONE
  1168. *
  1169. * Created:
  1170. *
  1171. * 02/10/1999 ikkof
  1172. * Created it.
  1173. *
  1174. \**************************************************************************/
  1175. VOID
  1176. GpXBezierDDA::MoveForward(
  1177. VOID
  1178. )
  1179. {
  1180. // If the current subdivide is too big,
  1181. // subdivide it.
  1182. while(NeedsSubdivide(FlatnessLimit))
  1183. {
  1184. HalveStepSize();
  1185. }
  1186. if((NSteps & 1) == 0)
  1187. {
  1188. // If the current subdivide is too small,
  1189. // double it up.
  1190. while(NSteps > 1 && !NeedsSubdivide(FlatnessLimit/4))
  1191. {
  1192. DoubleStepSize();
  1193. }
  1194. }
  1195. // Move to the next Bezier segment.
  1196. TakeStep();
  1197. }
  1198. /**************************************************************************\
  1199. *
  1200. * Function Description:
  1201. *
  1202. * Returns the control points of the last Bezier segment
  1203. * which ends at the current point.
  1204. * The current point is given by calling getNextPoint().
  1205. * pts[] must have the dimension of 4.
  1206. *
  1207. * Arguments:
  1208. *
  1209. * [OUT] pts - the Bezier control points
  1210. *
  1211. * Return Value:
  1212. *
  1213. * NONE
  1214. *
  1215. * Created:
  1216. *
  1217. * 02/10/1999 ikkof
  1218. * Created it.
  1219. *
  1220. \**************************************************************************/
  1221. INT
  1222. GpXBezierDDA::GetControlPoints(
  1223. GpXPoints* xpoints
  1224. )
  1225. {
  1226. ASSERT(xpoints);
  1227. if(xpoints == NULL)
  1228. return 0;
  1229. INT totalCount = Dimension*(NthOrder + 1);
  1230. REALD* buff = (REALD*) GpRealloc(xpoints->Data, totalCount*sizeof(REALD));
  1231. if(buff)
  1232. {
  1233. GpMemcpy(buff, &Q[0], Dimension*(NthOrder + 1)*sizeof(REALD));
  1234. xpoints->Count = NthOrder + 1;
  1235. xpoints->Dimension = Dimension;
  1236. xpoints->Data = buff;
  1237. return NthOrder + 1;
  1238. }
  1239. else
  1240. return 0;
  1241. }