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.

4574 lines
124 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Path Self Intersection Remover Class.
  8. *
  9. * Abstract:
  10. *
  11. * Classes and functions used to remove self intersections in paths.
  12. * Given a path, it produces one or more polygons which can be used to
  13. * draw a widened path that is safe to use alternate fill mode with.
  14. *
  15. * Notes:
  16. *
  17. * Modified from Office code frOm John Bowler (at least that is what
  18. * ericvan told me). Apparently owned by some 'KasiaK', but no idea
  19. * who that is. (He is apparently retired)
  20. * CAUTION: Not thoroughly tested yet for arbitrary paths.
  21. *
  22. * API:
  23. * Init(EstimatedNumPts);
  24. * AddPolygon(pathPts, numPts);
  25. * RemoveSelfIntersects();
  26. * GetNewPoints(newPts, polyCounts, numPolys, numTotalPts);
  27. *
  28. * Created:
  29. *
  30. * 06/06/1999 t-wehunt
  31. *
  32. \**************************************************************************/
  33. #include "precomp.hpp"
  34. // Return values for IntersectEdge
  35. #define DONOT_INTERS 0
  36. #define COMMON_POINT 1
  37. #define INTERSECT 2
  38. #define COLINEAR 3
  39. // Used to produce the IEEE floating-point representation of infinity.
  40. // Note that a few compile warnings have to be turned off to stop
  41. // warnings about constant arithmetic overflow.
  42. #pragma warning (disable : 4056 4756)
  43. #define FP_INF (FLT_MAX+FLT_MAX)
  44. /**************************************************************************\
  45. *
  46. * Function Description:
  47. *
  48. * Insert a new item into a sorted dynamic array, keeping it sorted.
  49. *
  50. * Arguments:
  51. *
  52. * newItem - new item to be inserted
  53. * compareFunc - comparison function to be used for insertion.
  54. * userData - User-specified data for use by the compare func.
  55. *
  56. * Return Value:
  57. *
  58. * GpStatus - Ok or failure status
  59. *
  60. * Created:
  61. *
  62. * 6/15/1999 t-wehunt
  63. *
  64. \**************************************************************************/
  65. template <class T>
  66. GpStatus
  67. DynSortArray<T>::InsertSorted(
  68. T &newItem,
  69. DynSortArrayCompareFunc compareFunc,
  70. VOID *userData
  71. )
  72. {
  73. // insert item into sorted position of list.
  74. T *cur;
  75. INT pos = 0;
  76. GpStatus status;
  77. cur = GetDataBuffer();
  78. {
  79. INT sgn = 1;
  80. unsigned iMin = 0;
  81. unsigned iMid = 0;
  82. unsigned iEnd = GetCount();
  83. while (iMin != iEnd)
  84. {
  85. iMid = iMin + (iEnd-iMin)/2;
  86. //Assert(iMid != iMac);
  87. sgn = compareFunc(
  88. (PathSelfIntersectRemover*)userData,
  89. &GetDataBuffer()[iMid],
  90. &newItem
  91. );
  92. if (sgn == 0)
  93. {
  94. // newItem already in sorted list, return index.
  95. return Ok;
  96. }
  97. if (sgn < 0) // x(iMid) < x(p)
  98. iMin = iMid+1;
  99. else
  100. iEnd = iMid;
  101. }
  102. pos = iMin;
  103. }
  104. status = InsertAt(pos,newItem);
  105. if (status != Ok)
  106. {
  107. return status;
  108. }
  109. cur = &GetDataBuffer()[pos];
  110. return Ok;
  111. }
  112. /****************************************************************************\
  113. Private helper functions
  114. \****************************************************************************/
  115. /**************************************************************************\
  116. *
  117. * Function Description:
  118. *
  119. * Return the sign of an INT
  120. *
  121. * Arguments:
  122. *
  123. * newItem - new item to be inserted
  124. * compareFunc - comparison function to be used for insertion.
  125. * userData - User-specified data for use by the compare func.
  126. *
  127. * Return Value:
  128. *
  129. * 1 if greater than zero
  130. * 0 if equal to zero
  131. * -1 if less than zero
  132. *
  133. * Created:
  134. *
  135. * 6/15/1999 t-wehunt
  136. *
  137. \**************************************************************************/
  138. inline INT SignReal(const REAL i) { return (i > 0) - (i < 0); }
  139. /**************************************************************************\
  140. *
  141. * Function Description:
  142. *
  143. * Insert an edge into a linked list. This assumes the edge is an
  144. * orphaned edge (not connected in a current list). Use DeleteEdgeFromList
  145. * to orphan an edge if it's already in a list.
  146. *
  147. * This uses a double indirection pointer to track the address of the
  148. * Next pointer that points to the current element rather than actually
  149. * tracking the current element. This simplifies the code significantly.
  150. *
  151. * Created:
  152. *
  153. * 12/23/2000 asecchia
  154. *
  155. \**************************************************************************/
  156. void PathSelfIntersectRemover::InsertEdgeIntoList(
  157. INT *pListHead,
  158. INT index,
  159. DynSortArrayCompareFunc compare
  160. )
  161. {
  162. ASSERT(EdgeList[index].Next == LIST_END);
  163. ASSERT(index >= 0);
  164. ASSERT(pListHead);
  165. INT *pIndex = pListHead;
  166. Edge *newEdge = &EdgeList[index];
  167. // Calculate the YCur for this edge.
  168. newEdge->YCur = PathPts[newEdge->SortBegin].Y;
  169. newEdge->SortBegin = newEdge->Begin;
  170. newEdge->SortEnd = newEdge->End;
  171. newEdge->Normalize();
  172. while(*pIndex != LIST_END)
  173. {
  174. if(compare(this, &EdgeList[*pIndex], newEdge) != -1)
  175. {
  176. // if we find the right spot, exit the search loop.
  177. break;
  178. }
  179. // keep looking...
  180. pIndex = &EdgeList[*pIndex].Next;
  181. }
  182. // Do the insertion
  183. newEdge->Next = *pIndex;
  184. *pIndex = index;
  185. }
  186. /**************************************************************************\
  187. *
  188. * Function Description:
  189. *
  190. * Delete an edge from a linked list.
  191. * This uses a double indirection pointer to track the address of the
  192. * Next pointer that points to the current element rather than actually
  193. * tracking the current element. This simplifies the code significantly.
  194. *
  195. * Returns true if it found and deleted the edge, false otherwise.
  196. *
  197. * Created:
  198. *
  199. * 12/23/2000 asecchia
  200. *
  201. \**************************************************************************/
  202. bool PathSelfIntersectRemover::DeleteEdgeFromList(
  203. INT *pListHead,
  204. INT index
  205. )
  206. {
  207. ASSERT(index >= 0);
  208. ASSERT(pListHead);
  209. INT *pIndex = pListHead;
  210. while(*pIndex != LIST_END)
  211. {
  212. if(*pIndex == index)
  213. {
  214. // found it.
  215. *pIndex = EdgeList[index].Next; // point past the deleted item.
  216. EdgeList[index].Next = LIST_END; // disconnect the deleted item.
  217. return true;
  218. }
  219. // keep looking...
  220. pIndex = &EdgeList[*pIndex].Next;
  221. }
  222. return false;
  223. }
  224. /**************************************************************************\
  225. *
  226. * Function Description:
  227. *
  228. * Insert edges into the active edge list.
  229. * This function takes a sorted block of edges from the pInactiveIndex list
  230. * and inserts them sorted into the pActiveIndex list in linear time.
  231. * The block from the pInactiveIndex list is known to be contiguous.
  232. *
  233. * Actually the source list and destination list are not sorted with the
  234. * same sorting comparison function and therefore we can't optimize based
  235. * on the known sort order of the destination. This is inefficient. Making
  236. * them use the same sort order and fixing the active edge traversal code
  237. * to compute the winding numbers would probably work better - it would
  238. * allow us an O(n) merge sort here.
  239. *
  240. * Created:
  241. *
  242. * 03/25/2000 andrewgo
  243. * 12/17/2000 asecchia - copied from aarasterizer.cpp and modified for the
  244. * PathSelfIntersectRemover. When we have the time
  245. * we should really merge these two pieces of code.
  246. *
  247. \**************************************************************************/
  248. void PathSelfIntersectRemover::InsertNewEdges(
  249. INT *pActiveIndex, // IN/OUT
  250. INT *pInactiveIndex, // IN/OUT
  251. REAL xCurrent,
  252. DynSortArrayCompareFunc compare
  253. )
  254. {
  255. ASSERT(pInactiveIndex);
  256. while(
  257. (*pInactiveIndex != LIST_END) &&
  258. ((PathPts[EdgeList[*pInactiveIndex].SortBegin].X < xCurrent) ||
  259. (CloseReal(xCurrent, PathPts[EdgeList[*pInactiveIndex].SortBegin].X))
  260. ))
  261. {
  262. // this is an edge we should move.
  263. INT index = *pInactiveIndex;
  264. // delete this element from the inactive list.
  265. // this updates pInactiveIndex for the next iteration of the loop.
  266. *pInactiveIndex = EdgeList[*pInactiveIndex].Next;
  267. EdgeList[index].Next = LIST_END;
  268. // Insert into the active list from the current active position.
  269. InsertEdgeIntoList(pActiveIndex, index, compare);
  270. // Update the active list pointer.
  271. // Can't do this currently - our source and dest have different
  272. // sort order. Were we sure that our source and destination were
  273. // sorted with the same comparison function, we could remember the
  274. // current position here and continue where we left off next time
  275. // round - this would change the complexity from O(n^2) to O(n).
  276. // Currently this is not critical path because it's used on the
  277. // active edge list (small relative to the inactive list).
  278. //pActiveIndex = &EdgeList[index].Next;
  279. }
  280. }
  281. /**************************************************************************\
  282. *
  283. * Function Description:
  284. *
  285. * Normalize the edge - ie. update SortBegin and SortEnd.
  286. *
  287. * All lines have sorted begin and end. Begin.X is always X <= than End.X.
  288. * If they are equal, Begin.Y <= End.Y
  289. *
  290. * Arguments:
  291. *
  292. * None
  293. *
  294. * Return Value:
  295. *
  296. * None
  297. *
  298. * Created:
  299. *
  300. * 6/15/1999 t-wehunt
  301. *
  302. \**************************************************************************/
  303. VOID Edge::Normalize()
  304. {
  305. if (Parent->PathPts[Begin].X < Parent->PathPts[End].X)
  306. {
  307. return;
  308. }
  309. if ((Parent->PathPts[Begin].X == Parent->PathPts[End].X) &&
  310. (Parent->PathPts[Begin].Y <= Parent->PathPts[End].Y))
  311. {
  312. return;
  313. }
  314. // swap the points;
  315. SortBegin = End;
  316. SortEnd = Begin;
  317. return;
  318. }
  319. /**************************************************************************\
  320. *
  321. * Function Description:
  322. *
  323. * Return TRUE if the real numbers are close. This uses the parent's
  324. * comparison criteria.
  325. *
  326. * Arguments:
  327. *
  328. * [IN] val1, val2 - REAL numbers to be compared for closeness
  329. *
  330. * Return Value:
  331. *
  332. * TRUE or FALSE
  333. *
  334. * Created:
  335. *
  336. * 9/11/2000 peterost
  337. *
  338. \**************************************************************************/
  339. inline BOOL Edge::CloseReal(const REAL val1, const REAL val2)
  340. {
  341. return Parent->CloseReal(val1, val2);
  342. }
  343. /**************************************************************************\
  344. *
  345. * Function Description:
  346. *
  347. * Return TRUE if the edge is vertical.
  348. *
  349. * Arguments:
  350. *
  351. * None
  352. *
  353. * Return Value:
  354. *
  355. * TRUE or FALSE
  356. *
  357. * Created:
  358. *
  359. * 6/15/1999 t-wehunt
  360. *
  361. \**************************************************************************/
  362. BOOL Edge::IsVertical()
  363. {
  364. return (CloseReal(Parent->PathPts[Begin].X,
  365. Parent->PathPts[End].X));
  366. }
  367. /**************************************************************************\
  368. *
  369. * Function Description:
  370. *
  371. * Mark the edge as outside
  372. *
  373. * Arguments:
  374. *
  375. * None
  376. *
  377. * Return Value:
  378. *
  379. *
  380. * Created:
  381. *
  382. * 6/15/1999 t-wehunt
  383. *
  384. \**************************************************************************/
  385. VOID Edge::MarkOutside()
  386. {
  387. PointListNode *ptNode = NULL;
  388. ptNode = &Parent->PtList[Begin];
  389. ptNode->Inside = FALSE;
  390. }
  391. /**************************************************************************\
  392. *
  393. * Function Description:
  394. *
  395. * Initialize PathSelfIntersectRemover with for the given number of path points. The
  396. * number of points doesn't have to be exact, it just initializes arrays
  397. * to avoid reallocation later.
  398. *
  399. * Arguments:
  400. *
  401. * numPts - number of points that will be added to the path.
  402. *
  403. * Return Value:
  404. *
  405. * GpStatus.
  406. *
  407. * Created:
  408. *
  409. * 6/15/1999 t-wehunt
  410. *
  411. \**************************************************************************/
  412. GpStatus PathSelfIntersectRemover::Init(INT numPts)
  413. {
  414. BOOL failed=FALSE;
  415. GpStatus status;
  416. // !!!: Decide what the initial number of elements should be.
  417. // In general, we usually will have one extra intersection
  418. // per vertex in the inset path. - KasiaK
  419. // Initialize array with points
  420. failed |= PathPts.ReserveSpace(numPts+1) != Ok;
  421. // Initialize array with order information
  422. failed |= PtList.ReserveSpace(2*numPts) != Ok;
  423. failed |= EdgeList.ReserveSpace(2*numPts) != Ok;
  424. ActiveEdgeList = LIST_END;
  425. InactiveEdgeList = LIST_END;
  426. if (failed)
  427. {
  428. return OutOfMemory;
  429. }
  430. return Ok;
  431. }
  432. /**************************************************************************\
  433. *
  434. * Function Description:
  435. *
  436. * Add a single polygon to the PathSelfIntersectRemover class.
  437. * You cannot AddPolygon() after calling RemoveSelfIntersects().
  438. *
  439. * Arguments:
  440. *
  441. * ptrPts - points to add.
  442. * numPtsToAdd - number of points to add.
  443. *
  444. * Return Value:
  445. *
  446. * GpStatus.
  447. *
  448. * Created:
  449. *
  450. * 6/15/1999 t-wehunt
  451. *
  452. \**************************************************************************/
  453. GpStatus
  454. PathSelfIntersectRemover::AddPolygon(
  455. const GpPointF *ptrPts,
  456. INT numPtsToAdd
  457. )
  458. {
  459. // Cannot add points after fixing path.
  460. ASSERT(CanAddPts);
  461. ASSERT(ptrPts != NULL);
  462. if (numPtsToAdd < 2)
  463. {
  464. return Ok;
  465. }
  466. GpStatus status;
  467. // Make sure there is enough room in the arrays:
  468. status = PathPts.ReserveSpace(numPtsToAdd+1);
  469. if (status != Ok)
  470. {
  471. return status;
  472. }
  473. INT oldNumPts = NumPts;
  474. if (InsertPoints(ptrPts, numPtsToAdd) != Ok ||
  475. InsertEdges(oldNumPts, NumPts-oldNumPts-1) != Ok)
  476. {
  477. return GenericError;
  478. }
  479. return Ok;
  480. }
  481. /**************************************************************************\
  482. *
  483. * Function Description:
  484. *
  485. * Insert points information to relevant arrays.
  486. *
  487. * Arguments:
  488. *
  489. * pts - points to add to the class.
  490. * numPts - number of points we want to add.
  491. *
  492. * Return Value:
  493. *
  494. * GpStatus.
  495. *
  496. * Created:
  497. *
  498. * 6/15/1999 t-wehunt
  499. *
  500. \**************************************************************************/
  501. GpStatus
  502. PathSelfIntersectRemover::InsertPoints(
  503. const GpPointF *pts,
  504. INT numPts
  505. )
  506. {
  507. INT FirstIndex = NumPts;
  508. PointListNode ptNode;
  509. GpPointF pt(0,0);
  510. GpStatus status;
  511. // We don't want to add 0-length edges
  512. // Also, we don't want to add very thin spikes, for example
  513. // when pts[n] == pts[n+2] (or almost the same. We will just
  514. // skip pts[n+1] and pts[n+2].
  515. pt = pts[0];
  516. if ((status = PathPts.Add(pt)) != Ok)
  517. {
  518. return status;
  519. }
  520. NumPts++;
  521. for (INT i = 1; i < numPts; i++)
  522. {
  523. if (!IsClosePointF(pts[i], pts[i-1]))
  524. {
  525. if ((status = PathPts.Add(pts[i])) != Ok)
  526. {
  527. return status;
  528. }
  529. NumPts++;
  530. }
  531. }
  532. // Add the first point to close the path
  533. if (!IsClosePointF(pts[0], pts[numPts-1]))
  534. {
  535. pt = pts[0];
  536. if ((status = PathPts.Add(pt)) != Ok)
  537. {
  538. return status;
  539. }
  540. NumPts++;
  541. }
  542. // If all the points were equal we hit this point with NumPts set to 1
  543. // which is a degenerate polygon.
  544. // Make sure we handle this correctly.
  545. if(NumPts < 2)
  546. {
  547. ONCE(WARNING(("Degenerate polygon in InsertPoints")));
  548. PathPts.SetCount(0);
  549. NumPts = 0;
  550. return Ok;
  551. }
  552. // Initialize the linked list;
  553. // If this is not the first set of points to be added, update
  554. // the next ptr in the last element of the existing list
  555. if (FirstIndex != 0 && PtList.GetCount() > 0)
  556. {
  557. PtList.Last().Next = FirstIndex;
  558. }
  559. // index 0:
  560. ptNode.Prev = FirstIndex-1; // -1 means NULL;
  561. if (NumPts == FirstIndex+1) // only one point is being added
  562. {
  563. ptNode.Next = -1;
  564. ptNode.Dup = -1; // if we added one point, there is no dup
  565. }
  566. else
  567. {
  568. ptNode.Next = FirstIndex+1;
  569. ptNode.Dup = NumPts-1; // the first point is same as closing point
  570. }
  571. ptNode.Inside = TRUE;
  572. ptNode.Used = FALSE;
  573. if ((status = PtList.Add(ptNode)) != Ok)
  574. {
  575. return status;
  576. }
  577. //indecies 1..NumPts-1
  578. INT ptIndex;
  579. for (ptIndex = FirstIndex+1; ptIndex < NumPts-1; ptIndex++)
  580. {
  581. ptNode.Prev = ptIndex-1; // -1 means NULL;
  582. ptNode.Next = ptIndex+1;
  583. ptNode.Dup = -1;
  584. ptNode.Inside = TRUE;
  585. ptNode.Used = FALSE;
  586. if ((status = PtList.Add(ptNode)) != Ok)
  587. {
  588. return status;
  589. }
  590. }
  591. //index NumPts
  592. ptNode.Prev = ptIndex-1;
  593. ptNode.Next = -1; // -1 means NULL;
  594. ptNode.Dup = FirstIndex; // the first point is same as closing point
  595. ptNode.Inside = TRUE;
  596. ptNode.Used = FALSE;
  597. if ((status = PtList.Add(ptNode)) != Ok)
  598. {
  599. return status;
  600. }
  601. return Ok;
  602. }
  603. /**************************************************************************\
  604. *
  605. * Function Description:
  606. *
  607. * Perform a simple partition sort on a list indexing into the vector list.
  608. * The result is a sorted index array keyed on the vertex array Y1 coordinate.
  609. * The index array is sorted in place and in ascending order.
  610. *
  611. * Arguments:
  612. *
  613. * v is the vertex list.
  614. * F, L - First and Last pointer in the index array.
  615. *
  616. * Created:
  617. *
  618. * 09/16/2000 asecchia
  619. *
  620. \**************************************************************************/
  621. void PathSelfIntersectRemover::QuickSortEdges(
  622. Edge *F,
  623. Edge *L
  624. )
  625. {
  626. if(F < L)
  627. {
  628. // Find the median position.
  629. Edge median = *(F + (L-F)/2);
  630. Edge *i = F;
  631. Edge *j = L;
  632. while(i<j)
  633. {
  634. // seek for elements in the wrong partition.
  635. // compare edges:
  636. while(CompareLine(this, i, &median) == -1) { i++; }
  637. while(CompareLine(this, j, &median) == 1) { j--; }
  638. if(i>=j) { break; }
  639. // Swap.
  640. Edge temp = *i;
  641. *i = *j;
  642. *j = temp;
  643. // tie breaker - handle the case where *i == *j == *median, but
  644. // i != j. Only possible with multiple copies of the same entry.
  645. if(CompareLine(this, i, j) == 0) { i++; }
  646. }
  647. // Call recursively for the two sub-partitions. The partitions don't
  648. // include position i because it is correctly positioned.
  649. QuickSortEdges(F, i-1);
  650. QuickSortEdges(i+1, L);
  651. }
  652. }
  653. /**************************************************************************\
  654. *
  655. * Function Description:
  656. *
  657. * Insert numEdges edges joining points stored in array PathPts. First point
  658. * has index firstIndex. There must be numEdges+1 points to create numEdges
  659. * edges.
  660. *
  661. * NOTE: NumEdges CAN be negative! The function will then just return.
  662. * This can potentially happen when called from AddPolygon().
  663. *
  664. * Arguments:
  665. *
  666. * firstIndex - index of first point in PathPts array.
  667. * numEdges - number of edges to add.
  668. *
  669. * Return Value:
  670. *
  671. * GpStatus.
  672. *
  673. * Created:
  674. *
  675. * 6/15/1999 t-wehunt
  676. * 10/19/2000 asecchia rewrote it to support quicksort instead of insert sort.
  677. *
  678. \**************************************************************************/
  679. GpStatus PathSelfIntersectRemover::InsertEdges(INT firstIndex, INT numEdges)
  680. {
  681. // Handle the empty polygon up front.
  682. if(numEdges == 0)
  683. {
  684. return Ok;
  685. }
  686. // Alloc space for all the edges up front.
  687. Edge *edges = EdgeList.AddMultiple(numEdges);
  688. if (edges == NULL)
  689. {
  690. return OutOfMemory;
  691. }
  692. // Create an edge with it's parent pointer.
  693. Edge newEdge(this);
  694. for (INT i = 0; i < numEdges; i++)
  695. {
  696. newEdge.Begin = i+firstIndex;
  697. newEdge.End = i+1+firstIndex;
  698. newEdge.SortBegin = i+firstIndex;
  699. newEdge.SortEnd = i+1+firstIndex;
  700. newEdge.Normalize();
  701. newEdge.YCur = 0; // make debugging easier
  702. newEdge.OrigBegin = newEdge.SortBegin;
  703. newEdge.OrigEnd = newEdge.SortEnd;
  704. //Edge insertion
  705. edges[i] = newEdge;
  706. }
  707. return Ok;
  708. }
  709. /**************************************************************************\
  710. *
  711. * Function Description:
  712. *
  713. * Check if two lines intersect.
  714. * NOTE: Lines also intersect if an end point of one line is anywhere in the
  715. * middle (between the end points) of the other line.
  716. *
  717. * This algorithm was stolen from the NT path code with some modifications
  718. * based on an algorithm presented in Graphics Gems III.
  719. * We can try to speed it up by comparing bounding boxes of the two lines,
  720. * however, according to GG III, this may or may not speed up the
  721. * calculations.
  722. *
  723. * Arguments:
  724. *
  725. * ptrEdge1, ptrEdge2 - edges to intersect.
  726. * [OUT] intersectPt - the intersection point if lines INTERSECT
  727. * or have a COMMON_POINT,
  728. *
  729. * Return Value:
  730. *
  731. * DONOT_INTERS - lines don't intersect
  732. * COMMON_POINT - they share a common end point
  733. * INTERSECT - they intersect
  734. * COLINEAR - they arecolinear.
  735. *
  736. * Created:
  737. *
  738. * 6/15/1999 t-wehunt
  739. *
  740. \**************************************************************************/
  741. INT
  742. PathSelfIntersectRemover::IntersectEdge(
  743. Edge *ptrEdge1,
  744. Edge *ptrEdge2,
  745. GpPointF *intersectPt
  746. )
  747. {
  748. GpPointF *pfpvBegin1; // Start point of first line segment
  749. GpPointF *pfpvEnd1; // End point of the first line segment
  750. GpPointF *pfpvBegin2; // Start point of second line segment
  751. GpPointF *pfpvEnd2; // End point of the second line segment
  752. GpPointF fpvVec1(0,0); // Direction of first line segment
  753. GpPointF fpvVec2(0,0); // Direction of second line segment
  754. GpPointF fpvVec3(0,0);
  755. // Get the actual coordinates of the points.
  756. pfpvBegin1 = &PathPts[ptrEdge1->Begin];
  757. pfpvEnd1 = &PathPts[ptrEdge1->End];
  758. fpvVec1 = SubtractPoint(*pfpvEnd1,*pfpvBegin1);
  759. // Nothing intersects with an empty line.
  760. if( REALABS(fpvVec1.X) < REAL_EPSILON &&
  761. REALABS(fpvVec1.Y) < REAL_EPSILON )
  762. {
  763. return(DONOT_INTERS);
  764. }
  765. pfpvBegin2 = &PathPts[ptrEdge2->Begin];
  766. pfpvEnd2 = &PathPts[ptrEdge2->End];
  767. fpvVec2 = SubtractPoint(*pfpvEnd2,*pfpvBegin2);
  768. // Nothing intersects with an empty line.
  769. if( REALABS(fpvVec2.X) < REAL_EPSILON &&
  770. REALABS(fpvVec2.Y) < REAL_EPSILON )
  771. {
  772. return(DONOT_INTERS);
  773. }
  774. fpvVec3 = SubtractPoint(*pfpvBegin2,*pfpvBegin1);
  775. //
  776. // A -direction 1
  777. // D -direction 2
  778. // C -vec3 ->
  779. // The intersection is computed by:
  780. //
  781. // intersect = pptBegin1 + lambda * A
  782. // intersect = pptBegin2 + beta * D
  783. //
  784. // Cx(-Dy) + Cy(Dx)
  785. // lambda = ------------------------------
  786. // (Ax)(-Dy) + (Ay)(Dx)
  787. //
  788. // Cx(Dy) + Cy(-Dx)
  789. // beta = ---------------------
  790. // (Ax)(Dy) + (-Ay)(Dx)
  791. //
  792. REAL efTerm1;
  793. REAL efTerm2;
  794. REAL efNum1;
  795. REAL efDenom;
  796. REAL efColinX;
  797. REAL efColinY;
  798. REAL efTemp;
  799. // Cx (-Dy)
  800. efNum1 = fpvVec3.X;
  801. efColinX = efNum1;
  802. efTerm2 = -fpvVec2.Y;
  803. efNum1 *= efTerm2;
  804. // Cy (Dx)
  805. efTerm1 = fpvVec3.Y;
  806. efColinY = efTerm1;
  807. efTerm2 = fpvVec2.X;
  808. efTerm1 *= efTerm2;
  809. efNum1 += efTerm1;
  810. // (Ax)(-Dy)
  811. efDenom = fpvVec1.X;
  812. efTerm2 = -fpvVec2.Y;
  813. efDenom *= efTerm2;
  814. // (Ay)(Dx)
  815. efTerm1 = fpvVec1.Y;
  816. efTerm2 = fpvVec2.X;
  817. efTerm1 *= efTerm2;
  818. efDenom += efTerm1;
  819. if (CloseReal(efDenom, 0))
  820. //if (efDenom == 0)
  821. {
  822. // they are colinear, but are they on the same line?
  823. efTemp = -fpvVec1.Y;
  824. efColinX *= efTemp;
  825. efTemp = fpvVec1.X;
  826. efColinY *= efTemp;
  827. efColinX += efColinY;
  828. // if (efColinX == 0)
  829. if (CloseReal(efColinX, 0))
  830. {
  831. return(COLINEAR);
  832. }
  833. else
  834. {
  835. return(DONOT_INTERS);
  836. }
  837. }
  838. // Check if they share a common end point
  839. if (ptrEdge2->End == ptrEdge1->Begin ||
  840. ptrEdge2->End == ptrEdge1->End ||
  841. ptrEdge2->Begin == ptrEdge1->Begin ||
  842. ptrEdge2->Begin == ptrEdge1->End)
  843. {
  844. return COMMON_POINT;
  845. }
  846. if (ClosePt(*pfpvBegin1, *pfpvBegin2))
  847. {
  848. UpdateDups(ptrEdge1->Begin, ptrEdge2->Begin);
  849. return COMMON_POINT;
  850. }
  851. if (ClosePt(*pfpvBegin1, *pfpvEnd2))
  852. {
  853. UpdateDups(ptrEdge1->Begin, ptrEdge2->End);
  854. return COMMON_POINT;
  855. }
  856. if (ClosePt(*pfpvEnd1, *pfpvEnd2))
  857. {
  858. UpdateDups(ptrEdge1->End, ptrEdge2->End);
  859. return COMMON_POINT;
  860. }
  861. if (ClosePt(*pfpvEnd1, *pfpvBegin2))
  862. {
  863. UpdateDups(ptrEdge1->End, ptrEdge2->Begin);
  864. return COMMON_POINT;
  865. }
  866. // lambda
  867. efNum1 /= efDenom;
  868. if (efNum1 < 0.0)
  869. {
  870. return(DONOT_INTERS);
  871. }
  872. else if (efNum1 > 1.0)
  873. {
  874. return (DONOT_INTERS);
  875. }
  876. else
  877. {
  878. REAL efNum2;
  879. REAL efBetaPart1;
  880. REAL efBetaPart2;
  881. // find beta
  882. efNum2 = -fpvVec3.X;
  883. efBetaPart2 = fpvVec1.Y;
  884. efNum2 *= efBetaPart2;
  885. efBetaPart1 = -fpvVec3.Y;
  886. efBetaPart2 = -fpvVec1.X;
  887. efBetaPart1 *= efBetaPart2;
  888. efNum2 += efBetaPart1;
  889. efNum2 /= efDenom;
  890. if (efNum2 < 0.0)
  891. {
  892. return(DONOT_INTERS);
  893. }
  894. else if (efNum2 > 1.0)
  895. {
  896. return (DONOT_INTERS);
  897. }
  898. }
  899. // pptBegin1 + lambda * A
  900. // Following should be nice to the REAL unit - multiply-add instructions
  901. // can be used.
  902. efTerm1 = fpvVec1.X * efNum1 + pfpvBegin1->X;
  903. efTerm2 = fpvVec1.Y * efNum1 + pfpvBegin1->Y;
  904. intersectPt->X = efTerm1;
  905. intersectPt->Y = efTerm2;
  906. // Because of errors, we may still end up with the intersection
  907. // point as a common point:
  908. if (IsCommonPt(ptrEdge1, ptrEdge2, intersectPt))
  909. {
  910. return COMMON_POINT;
  911. }
  912. return(INTERSECT);
  913. }
  914. /**************************************************************************\
  915. *
  916. * Function Description:
  917. *
  918. * Find all self intersections of the paths and break up the edges.
  919. *
  920. * This is considered 'Phase 1' of the algorithm.
  921. *
  922. * Arguments:
  923. *
  924. * None.
  925. *
  926. * Return Value:
  927. *
  928. * FALSE if out of memory.
  929. *
  930. * Created:
  931. *
  932. * 6/15/1999 t-wehunt
  933. *
  934. \**************************************************************************/
  935. BOOL PathSelfIntersectRemover::FindIntersects()
  936. {
  937. // Initialize the array of active edges.
  938. // Take the first edge from the edge array InactiveEdgeList and add it to
  939. // the active edgs. Add all other edges, which start at the same x.
  940. INT numRemoved = 0;
  941. if (EdgeList.GetCount() <= 0)
  942. {
  943. return FALSE;
  944. }
  945. XCur = PathPts[EdgeList[InactiveEdgeList].SortBegin].X;
  946. // "move" all edges starting at XCur to the active edge array
  947. // PathPts in the active edge array will be sorted by y for the
  948. // given XCur.
  949. AddActiveForX(&InactiveEdgeList);
  950. while (TRUE)
  951. {
  952. // Find all intersections among the current edges
  953. if (!FindIntersectsForX())
  954. {
  955. return FALSE;
  956. }
  957. // if there are no edges left, we have found all intersections
  958. // we can stop even if active edges array is not empty, or maybe
  959. // it must be empty then? TODO: Kasiak
  960. if (InactiveEdgeList == LIST_END)
  961. {
  962. break;
  963. }
  964. if (!ClosestActive(InactiveEdgeList))
  965. {
  966. break;
  967. }
  968. // Remove all edges which end before (or on) XCur
  969. ClearActiveListInclusiveX();
  970. AddActiveForX(&InactiveEdgeList);
  971. }
  972. // remove everything else from the ActiveEdgeList
  973. XCur = FP_INF;
  974. ClearActiveListInclusiveX();
  975. return TRUE;
  976. }
  977. /**************************************************************************\
  978. *
  979. * Function Description:
  980. *
  981. * IsTIntersection returns TRUE if the intersection point intersectPt is
  982. * the same as an end point of one of the edges ptrEdge1 and ptrEdge2. If
  983. * it is, pfFirst will be TRUE if the first edge needs to be broken (intersectPt
  984. * is an end point of ptrEdge2), FALSE if the second one needs to be broken
  985. * up. intersectIndex contains the index of the end point which is the same
  986. * as the intersection point.
  987. *
  988. * Arguments:
  989. *
  990. * ptrEdge1,
  991. * ptrEdge2 - the two edges to check for T-intersections
  992. * intersectPt - the intersection point previously found for the edges.
  993. * [OUT] splitFirst - TRUE if the first edge needs to be split. FALSE if
  994. * the second edge.
  995. * [OUT] intersectIndex - index of endpoint which is the same as intersectPt if it
  996. * is a T-intersection.
  997. *
  998. * Return Value:
  999. *
  1000. * TRUE or FALSE
  1001. *
  1002. * Created:
  1003. *
  1004. * 6/15/1999 t-wehunt
  1005. *
  1006. \**************************************************************************/
  1007. BOOL PathSelfIntersectRemover::IsTIntersection(
  1008. Edge *ptrEdge1,
  1009. Edge *ptrEdge2,
  1010. GpPointF *intersectPt,
  1011. BOOL *splitFirst,
  1012. INT *intersectIndex
  1013. )
  1014. {
  1015. GpPointF &begin1 = PathPts[ptrEdge1->SortBegin];
  1016. GpPointF &begin2 = PathPts[ptrEdge2->SortBegin];
  1017. GpPointF &end1 = PathPts[ptrEdge1->SortEnd];
  1018. GpPointF &end2 = PathPts[ptrEdge2->SortEnd];
  1019. if (ClosePt(end1, *intersectPt))
  1020. {
  1021. // only ptrEdge2 needs to be broken up
  1022. *splitFirst = FALSE;
  1023. *intersectIndex = ptrEdge1->SortEnd;
  1024. return TRUE;
  1025. }
  1026. else if(ClosePt(end2, *intersectPt))
  1027. {
  1028. // only ptrEdge1
  1029. *splitFirst = TRUE;
  1030. *intersectIndex = ptrEdge2->SortEnd;
  1031. return TRUE;
  1032. }
  1033. else if(ClosePt(begin1, *intersectPt))
  1034. {
  1035. // only ptrEdge2
  1036. *splitFirst = FALSE;
  1037. *intersectIndex = ptrEdge1->SortBegin;
  1038. return TRUE;
  1039. }
  1040. else if(ClosePt(begin2, *intersectPt))
  1041. {
  1042. // only ptrEdge1
  1043. *splitFirst = TRUE;
  1044. *intersectIndex = ptrEdge2->SortBegin;
  1045. return TRUE;
  1046. }
  1047. return FALSE;
  1048. }
  1049. /**************************************************************************\
  1050. *
  1051. * Function Description:
  1052. *
  1053. * Returns TRUE if the two lines ptrEdge1 and ptrEdge2 share a common
  1054. * end point. If they do, pptInter will contain this point.
  1055. *
  1056. * Arguments:
  1057. *
  1058. *
  1059. * Return Value:
  1060. *
  1061. *
  1062. * Created:
  1063. *
  1064. * 6/15/1999 t-wehunt
  1065. *
  1066. \**************************************************************************/
  1067. BOOL
  1068. PathSelfIntersectRemover::IsCommonPt(
  1069. Edge *ptrEdge1,
  1070. Edge *ptrEdge2,
  1071. GpPointF *commonPt
  1072. )
  1073. {
  1074. GpPointF &begin1 = PathPts[ptrEdge1->SortBegin];
  1075. GpPointF &begin2 = PathPts[ptrEdge2->SortBegin];
  1076. GpPointF &end1 = PathPts[ptrEdge1->SortEnd];
  1077. GpPointF &end2 = PathPts[ptrEdge2->SortEnd];
  1078. if (ClosePt(end1, *commonPt) && ClosePt(end2, *commonPt))
  1079. {
  1080. UpdateDups(ptrEdge1->End, ptrEdge2->End);
  1081. return TRUE;
  1082. }
  1083. else if(ClosePt(end1, *commonPt) && ClosePt(begin2, *commonPt))
  1084. {
  1085. UpdateDups(ptrEdge1->End, ptrEdge2->Begin);
  1086. return TRUE;
  1087. }
  1088. else if(ClosePt(begin1, *commonPt) && ClosePt(begin2, *commonPt))
  1089. {
  1090. UpdateDups(ptrEdge1->Begin, ptrEdge2->Begin);
  1091. return TRUE;
  1092. }
  1093. else if(ClosePt(begin1, *commonPt) && ClosePt(end2, *commonPt))
  1094. {
  1095. UpdateDups(ptrEdge1->Begin, ptrEdge2->End);
  1096. return TRUE;
  1097. }
  1098. return FALSE;
  1099. }
  1100. /**************************************************************************\
  1101. *
  1102. * Function Description:
  1103. *
  1104. * Returns TRUE if point with index inew is already in the "list" of dups
  1105. * for point with index loop.
  1106. *
  1107. * Arguments:
  1108. *
  1109. *
  1110. * Return Value:
  1111. *
  1112. *
  1113. * Created:
  1114. *
  1115. * 6/15/1999 t-wehunt
  1116. *
  1117. \**************************************************************************/
  1118. BOOL PathSelfIntersectRemover::IsLinked(INT loop, INT inew)
  1119. {
  1120. PointListNode *ptNode;
  1121. ptNode = &PtList[loop];
  1122. BOOL isLinked = FALSE;
  1123. INT i = ptNode->Dup;
  1124. INT prev_i = -1; // Added to prevent an infinite loop.
  1125. while(!isLinked && i != -1 && i != prev_i && i != loop)
  1126. {
  1127. if(i == inew)
  1128. {
  1129. isLinked = TRUE;
  1130. break;
  1131. }
  1132. ptNode = &PtList[i];
  1133. prev_i = i;
  1134. i = ptNode->Dup;
  1135. }
  1136. return isLinked;
  1137. }
  1138. /**************************************************************************\
  1139. *
  1140. * Function Description:
  1141. *
  1142. * Joins the list of duplicate points for points pt1 and pt2.
  1143. *
  1144. * Arguments:
  1145. *
  1146. *
  1147. * Return Value:
  1148. *
  1149. *
  1150. * Created:
  1151. *
  1152. * 6/15/1999 t-wehunt
  1153. *
  1154. \**************************************************************************/
  1155. VOID PathSelfIntersectRemover::UpdateDups(INT pt1, INT pt2)
  1156. {
  1157. PointListNode *ptNode1;
  1158. PointListNode *ptNode2;
  1159. if (pt1 == pt2)
  1160. {
  1161. WARNING(("NOT REACHED"));
  1162. return;
  1163. }
  1164. ptNode1 = &PtList[pt1];
  1165. ptNode2 = &PtList[pt2];
  1166. if ((ptNode1->Dup == -1) && (ptNode2->Dup == -1))
  1167. {
  1168. ptNode1->Dup = pt2;
  1169. ptNode2->Dup = pt1;
  1170. return;
  1171. }
  1172. if ((ptNode1->Dup == -1) && (ptNode2->Dup != -1))
  1173. {
  1174. ptNode1->Dup = ptNode2->Dup;
  1175. ptNode2->Dup = pt1;
  1176. return;
  1177. }
  1178. if ((ptNode1->Dup != -1) && (ptNode2->Dup == -1))
  1179. {
  1180. ptNode2->Dup = ptNode1->Dup;
  1181. ptNode1->Dup = pt2;
  1182. return;
  1183. }
  1184. if ((ptNode1->Dup != -1) && (ptNode2->Dup != -1))
  1185. {
  1186. if (!IsLinked(pt1, pt2))
  1187. {
  1188. INT dupTemp;
  1189. dupTemp = ptNode2->Dup;
  1190. ptNode2->Dup = ptNode1->Dup;
  1191. ptNode1->Dup = dupTemp;
  1192. }
  1193. return;
  1194. }
  1195. }
  1196. /**************************************************************************\
  1197. *
  1198. * Function Description:
  1199. *
  1200. * Delete edges from the active edge table; Indices of edges to delete
  1201. * are stored in EdgesToDelete1..3. Deletes the highest index edge first.
  1202. * Returns NULL if fails due to out of memory error.
  1203. *
  1204. * Arguments:
  1205. *
  1206. *
  1207. * Return Value:
  1208. *
  1209. *
  1210. * Created:
  1211. *
  1212. * 6/15/1999 t-wehunt
  1213. *
  1214. \**************************************************************************/
  1215. BOOL PathSelfIntersectRemover::DeleteEdges()
  1216. {
  1217. INT minIndex;
  1218. INT midIndex;
  1219. INT maxIndex;
  1220. if (EdgesToDelete1 > EdgesToDelete2)
  1221. {
  1222. if (EdgesToDelete1 > EdgesToDelete3)
  1223. {
  1224. minIndex = EdgesToDelete1;
  1225. if (EdgesToDelete2 > EdgesToDelete3)
  1226. {
  1227. midIndex = EdgesToDelete2;
  1228. maxIndex = EdgesToDelete3;
  1229. }
  1230. else
  1231. {
  1232. midIndex = EdgesToDelete3;
  1233. maxIndex = EdgesToDelete2;
  1234. }
  1235. }
  1236. else
  1237. {
  1238. minIndex = EdgesToDelete3;
  1239. midIndex = EdgesToDelete1;
  1240. maxIndex = EdgesToDelete2;
  1241. }
  1242. }
  1243. else
  1244. {
  1245. if (EdgesToDelete2 > EdgesToDelete3)
  1246. {
  1247. minIndex = EdgesToDelete2;
  1248. if (EdgesToDelete1 > EdgesToDelete3)
  1249. {
  1250. midIndex = EdgesToDelete1;
  1251. maxIndex = EdgesToDelete3;
  1252. }
  1253. else
  1254. {
  1255. midIndex = EdgesToDelete3;
  1256. maxIndex = EdgesToDelete1;
  1257. }
  1258. }
  1259. else
  1260. {
  1261. minIndex = EdgesToDelete3;
  1262. midIndex = EdgesToDelete2;
  1263. maxIndex = EdgesToDelete1;
  1264. }
  1265. }
  1266. if (minIndex == -1)
  1267. {
  1268. return TRUE;
  1269. }
  1270. // delete the first one
  1271. if (!DeleteEdgeFromList(&ActiveEdgeList, minIndex))
  1272. {
  1273. return FALSE;
  1274. }
  1275. if (midIndex == -1)
  1276. {
  1277. return TRUE;
  1278. }
  1279. // delete the second one
  1280. if (!DeleteEdgeFromList(&ActiveEdgeList, midIndex))
  1281. {
  1282. return FALSE;
  1283. }
  1284. if (maxIndex == -1)
  1285. {
  1286. return TRUE;
  1287. }
  1288. // delete the third one
  1289. if (!DeleteEdgeFromList(&ActiveEdgeList, maxIndex))
  1290. {
  1291. return FALSE;
  1292. }
  1293. return TRUE;
  1294. }
  1295. /**************************************************************************\
  1296. *
  1297. * Function Description:
  1298. *
  1299. * Edge with index index into the array of Active edges needs to be deleted.
  1300. * Store its index for deletion.
  1301. *
  1302. * Arguments:
  1303. *
  1304. *
  1305. * Return Value:
  1306. *
  1307. *
  1308. * Created:
  1309. *
  1310. * 6/15/1999 t-wehunt
  1311. *
  1312. \**************************************************************************/
  1313. VOID PathSelfIntersectRemover::MarkToDelete(INT index)
  1314. {
  1315. ASSERT((EdgesToDelete1 == -1) ||
  1316. (EdgesToDelete2 == -1) ||
  1317. (EdgesToDelete3 == -1));
  1318. if (EdgesToDelete1 == -1 )
  1319. {
  1320. EdgesToDelete1 = index;
  1321. return;
  1322. }
  1323. if (EdgesToDelete2 == -1 )
  1324. {
  1325. EdgesToDelete2 = index;
  1326. return;
  1327. }
  1328. if (EdgesToDelete3 == -1 )
  1329. {
  1330. EdgesToDelete3 = index;
  1331. return;
  1332. }
  1333. return; // error
  1334. }
  1335. /**************************************************************************\
  1336. *
  1337. * Function Description:
  1338. *
  1339. * Edge ptrEdge needs to be added to the array with Active edges. Make a
  1340. * copy of the edge and store it, so that it can be later added.
  1341. * We have to add new edges after the edges marked for deletion are deleted.
  1342. *
  1343. * Arguments:
  1344. *
  1345. *
  1346. * Return Value:
  1347. *
  1348. *
  1349. * Created:
  1350. *
  1351. * 6/15/1999 t-wehunt
  1352. *
  1353. \**************************************************************************/
  1354. VOID PathSelfIntersectRemover::MarkToAdd(Edge *ptrEdge)
  1355. {
  1356. ASSERT(!(FlgAdd1 && FlgAdd2 && FlgAdd3));
  1357. if (!FlgAdd1)
  1358. {
  1359. AddToActive1 = *ptrEdge;
  1360. FlgAdd1 = TRUE;
  1361. return;
  1362. }
  1363. if (!FlgAdd2)
  1364. {
  1365. AddToActive2 = *ptrEdge;
  1366. FlgAdd2 = TRUE;
  1367. return;
  1368. }
  1369. if (!FlgAdd3)
  1370. {
  1371. AddToActive3 = *ptrEdge;
  1372. FlgAdd3 = TRUE;
  1373. return;
  1374. }
  1375. return; // this the error condition, which should never happen.
  1376. }
  1377. /**************************************************************************\
  1378. *
  1379. * Function Description:
  1380. *
  1381. * Add new edges to the active edge table. The edges are stored in
  1382. * AddToActive1..3. flag FlgAdd1..3 specify if the given edge needs to
  1383. * be added or not. Returns if fails due to out of memory.
  1384. *
  1385. * Arguments:
  1386. *
  1387. *
  1388. * Return Value:
  1389. *
  1390. *
  1391. * Created:
  1392. *
  1393. * 6/15/1999 t-wehunt
  1394. *
  1395. \**************************************************************************/
  1396. BOOL PathSelfIntersectRemover::AddNewEdges()
  1397. {
  1398. if (FlgAdd1)
  1399. {
  1400. AddToActive1.SortBegin = AddToActive1.Begin;
  1401. AddToActive1.SortEnd = AddToActive1.End;
  1402. AddToActive1.Normalize();
  1403. AddToActive1.YCur = PathPts[AddToActive1.SortBegin].Y;
  1404. AddToActive1.Next = LIST_END;
  1405. //Edge Insertion
  1406. if(Ok != EdgeList.Add(AddToActive1))
  1407. {
  1408. return FALSE; // out of memory.
  1409. }
  1410. InsertEdgeIntoList(
  1411. &ActiveEdgeList,
  1412. EdgeList.GetCount()-1,
  1413. CompareYCurLine
  1414. );
  1415. }
  1416. if (FlgAdd2)
  1417. {
  1418. AddToActive2.SortBegin = AddToActive2.Begin;
  1419. AddToActive2.SortEnd = AddToActive2.End;
  1420. AddToActive2.Normalize();
  1421. AddToActive2.YCur = PathPts[AddToActive2.SortBegin].Y;
  1422. AddToActive2.Next = LIST_END;
  1423. //Edge Insertion
  1424. if(Ok != EdgeList.Add(AddToActive2))
  1425. {
  1426. return FALSE; // out of memory.
  1427. }
  1428. InsertEdgeIntoList(
  1429. &ActiveEdgeList,
  1430. EdgeList.GetCount()-1,
  1431. CompareYCurLine
  1432. );
  1433. }
  1434. if (FlgAdd3)
  1435. {
  1436. AddToActive3.SortBegin = AddToActive3.Begin;
  1437. AddToActive3.SortEnd = AddToActive3.End;
  1438. AddToActive3.Normalize();
  1439. AddToActive3.YCur = PathPts[AddToActive3.SortBegin].Y;
  1440. AddToActive3.Next = LIST_END;
  1441. //Edge Insertion
  1442. if(Ok != EdgeList.Add(AddToActive3))
  1443. {
  1444. return FALSE; // out of memory.
  1445. }
  1446. InsertEdgeIntoList(
  1447. &ActiveEdgeList,
  1448. EdgeList.GetCount()-1,
  1449. CompareYCurLine
  1450. );
  1451. }
  1452. return TRUE;
  1453. }
  1454. /**************************************************************************\
  1455. *
  1456. * Function Description:
  1457. *
  1458. * Find all intersections for the current X value. Intersection points
  1459. * will be inserted into the Edges array and information about their
  1460. * order into PtList. Returns FALSE on out of memory.
  1461. *
  1462. * Arguments:
  1463. *
  1464. *
  1465. * Return Value:
  1466. *
  1467. *
  1468. * Created:
  1469. *
  1470. * 6/15/1999 t-wehunt
  1471. *
  1472. \**************************************************************************/
  1473. BOOL PathSelfIntersectRemover::FindIntersectsForX()
  1474. {
  1475. Edge *ptrEdge1 = NULL;
  1476. Edge *ptrEdge2 = NULL;
  1477. Edge *ptrEdge3 = NULL;
  1478. // If we find an intersection, we will be breaking up edges - need two more
  1479. // line variables for the new edges.
  1480. Edge newEdge1(this);
  1481. Edge newEdge2(this);
  1482. GpPointF intersectPt(0,0);
  1483. INT result = DONOT_INTERS;
  1484. BOOL breakFirst = TRUE;
  1485. INT dup1 = -1;
  1486. INT dup2 = -1;
  1487. INT ptIndex1 = -1;
  1488. INT ptIndex2 = -1;
  1489. PointListNode *ptNode = NULL;
  1490. INT edgeIndex1, edgeIndex2, edgeIndexOld;
  1491. REAL yCur2;
  1492. BOOL deleteEdge1;
  1493. BOOL deleteEdge2;
  1494. BOOL edge1Deleted;
  1495. BOOL edge2Deleted;
  1496. // Go through all active edges but consider only consecutive pairs of egdes
  1497. // because they are sorted in y. There is no need to check every edge with
  1498. // every other edge in general case. However, when we have multiple edges
  1499. // with the same current y value and end points, we have to consider all of
  1500. // them.
  1501. edgeIndexOld = LIST_END;
  1502. edgeIndex1 = ActiveEdgeList;
  1503. if(edgeIndex1 == LIST_END)
  1504. {
  1505. return TRUE;
  1506. }
  1507. edgeIndex2 = EdgeList[ActiveEdgeList].Next;
  1508. while (edgeIndex1 != LIST_END && edgeIndex2 != LIST_END)
  1509. {
  1510. edge1Deleted = FALSE;
  1511. edge2Deleted = FALSE;
  1512. // Get the next two edges
  1513. ptrEdge1 = &EdgeList[edgeIndex1];
  1514. ptrEdge2 = &EdgeList[edgeIndex2];
  1515. yCur2 = ptrEdge2->YCur;
  1516. FlgAdd1 = FALSE;
  1517. FlgAdd2 = FALSE;
  1518. FlgAdd3 = FALSE;
  1519. EdgesToDelete1 = -1;
  1520. EdgesToDelete2 = -1;
  1521. EdgesToDelete3 = -1;
  1522. // Do they intersect?
  1523. result = IntersectEdge(ptrEdge1, ptrEdge2, &intersectPt);
  1524. if (result == INTERSECT)
  1525. {
  1526. // check if both edges need to be broken up, we may have
  1527. // a "T" intersection
  1528. if (IsTIntersection(ptrEdge1, ptrEdge2, &intersectPt,
  1529. &breakFirst, &dup1))
  1530. {
  1531. // only one edge needs to be broken up
  1532. // The index of the new point will be:
  1533. ptIndex1 = PathPts.GetCount();
  1534. // Update the dup field
  1535. // we have idup from IsTIntersection - it returned the index of
  1536. // the end point which is the same as the point of intersection
  1537. // It is a duplicate of the new point
  1538. ptNode = &PtList[dup1];
  1539. if (ptNode->Dup == -1)
  1540. {
  1541. ptNode->Dup = ptIndex1;
  1542. }
  1543. else
  1544. {
  1545. dup1 = ptNode->Dup;
  1546. ptNode->Dup = ptIndex1;
  1547. }
  1548. if (breakFirst)
  1549. {
  1550. // we need to break up the first edge
  1551. if (!BreakEdge(ptrEdge1, &intersectPt, &newEdge2, dup1))
  1552. {
  1553. return FALSE;
  1554. }
  1555. // BreakEdge can cause a realloc, thus invalidating
  1556. // ptrEdge1 and ptrEdge2
  1557. ptrEdge1 = &EdgeList[edgeIndex1];
  1558. ptrEdge2 = &EdgeList[edgeIndex2];
  1559. // Check if the left side of ptIntersect shouldn't be
  1560. // removed. This is the case when
  1561. // ptrEdge1->yCur == intersectPt.y && intersectPt.x == xCur;
  1562. if (ptrEdge1->YCur >= intersectPt.Y && intersectPt.X <= XCur)
  1563. {
  1564. MarkToDelete(edgeIndex1);
  1565. edge1Deleted = TRUE;
  1566. }
  1567. }
  1568. else
  1569. {
  1570. // we need to break up the first edge
  1571. if (!BreakEdge(ptrEdge2, &intersectPt, &newEdge1, dup1))
  1572. {
  1573. return FALSE;
  1574. }
  1575. // BreakEdge can cause a realloc, thus invalidating
  1576. // ptrEdge1 and ptrEdge2
  1577. ptrEdge1 = &EdgeList[edgeIndex1];
  1578. ptrEdge2 = &EdgeList[edgeIndex2];
  1579. // Check if the left side of ptIntersect shouldn't be
  1580. // removed. This is the case when
  1581. // ptrEdge2->yCur == intersectPt.y && intersectPt.x == xCur;
  1582. if (ptrEdge2->YCur >= intersectPt.Y && intersectPt.X <= XCur)
  1583. {
  1584. MarkToDelete(edgeIndex2);
  1585. edge2Deleted = TRUE;
  1586. }
  1587. }
  1588. }
  1589. else
  1590. {
  1591. // both need to be broken up
  1592. // We need to add two new points. They are identical and
  1593. // will be duplicates. Let's get thei indecies.
  1594. ptIndex1 = PathPts.GetCount();
  1595. ptIndex2 = ptIndex1+1;
  1596. if (!BreakEdge(ptrEdge1, &intersectPt, &newEdge2, ptIndex2))
  1597. return FALSE;
  1598. // BreakEdge can cause a realloc, thus invalidating
  1599. // ptrEdge1 and ptrEdge2
  1600. ptrEdge1 = &EdgeList[edgeIndex1];
  1601. ptrEdge2 = &EdgeList[edgeIndex2];
  1602. if (!BreakEdge(ptrEdge2, &intersectPt, &newEdge1, ptIndex1))
  1603. return FALSE;
  1604. // BreakEdge can cause a realloc, thus invalidating
  1605. // ptrEdge1 and ptrEdge2
  1606. ptrEdge1 = &EdgeList[edgeIndex1];
  1607. ptrEdge2 = &EdgeList[edgeIndex2];
  1608. // Let's delete what we will not need any more - the left hand
  1609. // sides of the old edges only if the intersection point is on
  1610. // the scanline
  1611. deleteEdge2 = (ptrEdge2->YCur >= intersectPt.Y &&
  1612. intersectPt.X <= XCur);
  1613. deleteEdge1 = (ptrEdge1->YCur >= intersectPt.Y &&
  1614. intersectPt.X <= XCur);
  1615. if (deleteEdge2)
  1616. {
  1617. MarkToDelete(edgeIndex2);
  1618. edge2Deleted = TRUE;
  1619. }
  1620. if (deleteEdge1)
  1621. {
  1622. MarkToDelete(edgeIndex1);
  1623. edge1Deleted = TRUE;
  1624. }
  1625. }
  1626. }
  1627. else if (result == COLINEAR)
  1628. {
  1629. BOOL three;
  1630. GpPointF intersectPt2(0,0);
  1631. BOOL breakSecond;
  1632. // The line segments must overlap or both are vertical...
  1633. // Find out if they overlap and if this is the case,
  1634. // Let's pick the begin point with the greater x.
  1635. // Overlap will check if the two edges overlap and return
  1636. // a point of intersection as well as information of which edge
  1637. // to break up.
  1638. if (Overlap(ptrEdge1, ptrEdge2, &intersectPt, &intersectPt2, &breakFirst,
  1639. &breakSecond, &three, &dup1, &dup2))
  1640. {
  1641. if (breakFirst)
  1642. {
  1643. if (!three)
  1644. {
  1645. // As before, get the index, so we can set up
  1646. // the duplicates
  1647. ptIndex1 = PathPts.GetCount();
  1648. // Update the dup field
  1649. ptNode = &PtList[dup1];
  1650. if (ptNode->Dup == -1)
  1651. {
  1652. ptNode->Dup = ptIndex1;
  1653. }
  1654. else
  1655. {
  1656. dup1 = ptNode->Dup;
  1657. ptNode->Dup = ptIndex1;
  1658. }
  1659. if (!BreakEdge(ptrEdge1, &intersectPt, &newEdge2, dup1))
  1660. {
  1661. return FALSE;
  1662. }
  1663. // BreakEdge can cause a realloc, thus invalidating
  1664. // ptrEdge1 and ptrEdge2
  1665. ptrEdge1 = &EdgeList[edgeIndex1];
  1666. ptrEdge2 = &EdgeList[edgeIndex2];
  1667. }
  1668. else
  1669. {
  1670. ptIndex1 = PathPts.GetCount();
  1671. ptIndex2 = ptIndex1+1;
  1672. // we need to break this edge into 3 pieces
  1673. // Update the dup field
  1674. ptNode = &PtList[dup1];
  1675. if (ptNode->Dup == -1)
  1676. {
  1677. ptNode->Dup = ptIndex1;
  1678. }
  1679. else
  1680. {
  1681. dup1 = ptNode->Dup;
  1682. ptNode->Dup = ptIndex1;
  1683. }
  1684. // Update the dup field
  1685. ptNode = &PtList[dup2];
  1686. if (ptNode->Dup == -1)
  1687. {
  1688. ptNode->Dup = ptIndex2;
  1689. }
  1690. else
  1691. {
  1692. dup2 = ptNode->Dup;
  1693. ptNode->Dup = ptIndex2;
  1694. }
  1695. if (!BreakEdgeIn3(ptrEdge1, &intersectPt, &intersectPt2,
  1696. &newEdge1, &newEdge2, dup1, dup2))
  1697. {
  1698. return FALSE;
  1699. }
  1700. // BreakEdge can cause a realloc, thus invalidating
  1701. // ptrEdge1 and ptrEdge2
  1702. ptrEdge1 = &EdgeList[edgeIndex1];
  1703. ptrEdge2 = &EdgeList[edgeIndex2];
  1704. }
  1705. deleteEdge1 = (ptrEdge1->YCur >= intersectPt.Y &&
  1706. intersectPt.X <= XCur);
  1707. if (deleteEdge1)
  1708. {
  1709. MarkToDelete(edgeIndex1);
  1710. edge1Deleted = TRUE;
  1711. }
  1712. }
  1713. if (breakSecond)
  1714. {
  1715. if (!three)
  1716. {
  1717. // break ptrEdge2
  1718. // Update the dup field
  1719. ptIndex1 = PathPts.GetCount();
  1720. ptNode = &PtList[dup2];
  1721. if (ptNode->Dup == -1)
  1722. {
  1723. ptNode->Dup = ptIndex1;
  1724. }
  1725. else
  1726. {
  1727. dup2 = ptNode->Dup;
  1728. ptNode->Dup = ptIndex1;
  1729. }
  1730. if (!BreakEdge(ptrEdge2, &intersectPt2, &newEdge1, dup2))
  1731. {
  1732. return FALSE;
  1733. }
  1734. // BreakEdge can cause a realloc, thus invalidating
  1735. // ptrEdge1 and ptrEdge2
  1736. ptrEdge1 = &EdgeList[edgeIndex1];
  1737. ptrEdge2 = &EdgeList[edgeIndex2];
  1738. deleteEdge2 = ptrEdge2->YCur >= intersectPt2.Y &&
  1739. intersectPt2.X <= XCur;
  1740. if (deleteEdge2)
  1741. {
  1742. MarkToDelete(edgeIndex2);
  1743. edge2Deleted = TRUE;
  1744. }
  1745. }
  1746. else
  1747. {
  1748. ptIndex1 = PathPts.GetCount();
  1749. ptIndex2 = ptIndex1+1;
  1750. // we need to break this edge into 3 pieces
  1751. // Update the dup field
  1752. ptNode = &PtList[dup1];
  1753. if (ptNode->Dup == -1)
  1754. {
  1755. ptNode->Dup = ptIndex1;
  1756. }
  1757. else
  1758. {
  1759. dup1 = ptNode->Dup;
  1760. ptNode->Dup = ptIndex1;
  1761. }
  1762. // Update the dup field
  1763. ptNode = &PtList[dup2];
  1764. if (ptNode->Dup == -1)
  1765. {
  1766. ptNode->Dup = ptIndex2;
  1767. }
  1768. else
  1769. {
  1770. dup2 = ptNode->Dup;
  1771. ptNode->Dup = ptIndex2;
  1772. }
  1773. if (!BreakEdgeIn3(ptrEdge2, &intersectPt, &intersectPt2,
  1774. &newEdge1, &newEdge2, dup1, dup2))
  1775. {
  1776. return FALSE;
  1777. }
  1778. // BreakEdge can cause a realloc, thus invalidating
  1779. // ptrEdge1 and ptrEdge2
  1780. ptrEdge1 = &EdgeList[edgeIndex1];
  1781. ptrEdge2 = &EdgeList[edgeIndex2];
  1782. deleteEdge2 = ptrEdge2->YCur >= intersectPt.Y &&
  1783. intersectPt.X <= XCur;
  1784. if (deleteEdge2)
  1785. {
  1786. MarkToDelete(edgeIndex2);
  1787. edge2Deleted = TRUE;
  1788. }
  1789. }
  1790. }
  1791. }
  1792. }
  1793. bool modifiedList = false;
  1794. // If we're deleting any edges, we've modified the list.
  1795. if((EdgesToDelete1 != -1) ||
  1796. (EdgesToDelete2 != -1) ||
  1797. (EdgesToDelete3 != -1))
  1798. {
  1799. modifiedList = true;
  1800. }
  1801. if (!DeleteEdges())
  1802. {
  1803. return FALSE;
  1804. }
  1805. // If we're adding any edges, we've modified the list.
  1806. if(FlgAdd1 || FlgAdd2 || FlgAdd3)
  1807. {
  1808. modifiedList = true;
  1809. }
  1810. if (!AddNewEdges())
  1811. {
  1812. return FALSE;
  1813. }
  1814. // Note: We check all vertically adjacent pairs of edges. Because
  1815. // the AET is sorted vertically and we're only looking for the
  1816. // intersection with the x coordinate closest to XCur, this is
  1817. // sufficient (and O(n) instead of O(n^2)).
  1818. if(modifiedList)
  1819. {
  1820. // back up to a stable position if we invalidate our list.
  1821. // this makes assumptions on where in the list we add or
  1822. // delete elements based on the sort order for the ActiveEdgeList.
  1823. edgeIndex1 = edgeIndexOld;
  1824. if(edgeIndexOld == LIST_END)
  1825. {
  1826. edgeIndex1 = ActiveEdgeList;
  1827. }
  1828. if(edgeIndex1 != LIST_END)
  1829. {
  1830. edgeIndex2 = EdgeList[edgeIndex1].Next;
  1831. }
  1832. }
  1833. else
  1834. {
  1835. edgeIndexOld = edgeIndex1;
  1836. edgeIndex2 = EdgeList[edgeIndex2].Next;
  1837. edgeIndex1 = EdgeList[edgeIndex1].Next;
  1838. }
  1839. }
  1840. return TRUE;
  1841. }
  1842. /**************************************************************************\
  1843. *
  1844. * Function Description:
  1845. *
  1846. * Returns TRUE if two collinear edges ptrEdge1 and ptrEdge2 overlap.
  1847. * There are 4 ways in which edges can overlap and depending on the
  1848. * case, either none, one or both edges need to be broken up. In some
  1849. * cases one edge may need to broken into 3 pieces.
  1850. * Return values:
  1851. * split1 - set to TRUE if ptrEdge1 needs to be split
  1852. * split2 - set to TRUE if ptrEdge2 needs to be split
  1853. * split3 - set to TRUE if an edge needs to be broken into 3 pieces
  1854. * intersect1 - intersection point (where edge needs to be split)
  1855. * intersect2 - second point (if the edge needs to be broken into 3
  1856. * pieces or for the second edge if both edges need to
  1857. * be broken up)
  1858. * dupIndex1 - index of the duplicate point to intersect1,
  1859. * dupIndex2 - index of the duplicate point to intersect2,
  1860. *
  1861. * Arguments:
  1862. *
  1863. *
  1864. * Return Value:
  1865. *
  1866. *
  1867. * Created:
  1868. *
  1869. * 6/15/1999 t-wehunt
  1870. *
  1871. \**************************************************************************/
  1872. BOOL PathSelfIntersectRemover::Overlap(
  1873. Edge *ptrEdge1,
  1874. Edge *ptrEdge2,
  1875. GpPointF *intersect1,
  1876. GpPointF *intersect2,
  1877. BOOL *split1,
  1878. BOOL *split2,
  1879. BOOL *split3,
  1880. INT *dupIndex1,
  1881. INT *dupIndex2
  1882. )
  1883. {
  1884. // We are assuming that the lines are colinear and they both belong
  1885. // to the active edges table which means that their x ranges overlap
  1886. // We need to check if they are vertical and if yes, find out if their
  1887. // y ranges overlap. If they are not vertical, they must overlap or
  1888. // they share a common end point.
  1889. *split3 = FALSE;
  1890. GpPointF &begin1 = PathPts[ptrEdge1->SortBegin];
  1891. GpPointF &begin2 = PathPts[ptrEdge2->SortBegin];
  1892. GpPointF &end1 = PathPts[ptrEdge1->SortEnd];
  1893. GpPointF &end2 = PathPts[ptrEdge2->SortEnd];
  1894. // Calculate bounding box for each edge:
  1895. GpPointF min1(
  1896. min(begin1.X, end1.X),
  1897. min(begin1.Y, end1.Y));
  1898. GpPointF max1(
  1899. max(begin1.X, end1.X),
  1900. max(begin1.Y, end1.Y));
  1901. GpPointF min2(
  1902. min(begin2.X, end2.X),
  1903. min(begin2.Y, end2.Y));
  1904. GpPointF max2(
  1905. max(begin2.X, end2.X),
  1906. max(begin2.Y, end2.Y));
  1907. // Abort if the bounding box of either edge is empty.
  1908. if(IsClosePointF(min1, max1) ||
  1909. IsClosePointF(min2, max2) )
  1910. {
  1911. return FALSE;
  1912. }
  1913. // If the edges are not vertical, they must overlap, because both of them
  1914. // are in the active edge array. We only need to chose a point, which will
  1915. // be used as an intersection point.
  1916. if (!ptrEdge1->IsVertical())
  1917. {
  1918. // Let's check first if they share a common end point
  1919. // if they share just a common point, return FALSE
  1920. if (CloseReal(min1.X,max2.X))
  1921. {
  1922. // We have to update the dups of the shared point
  1923. if (ptrEdge1->SortBegin != ptrEdge2->SortEnd)
  1924. {
  1925. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortEnd);
  1926. return FALSE;
  1927. }
  1928. }
  1929. if (CloseReal(min2.X,max1.X))
  1930. {
  1931. // We have to update the dups of the shared point
  1932. if (ptrEdge1->SortEnd != ptrEdge2->SortBegin)
  1933. {
  1934. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortBegin);
  1935. return FALSE;
  1936. }
  1937. }
  1938. // the edges must overlap, we need to break both of them
  1939. // There are 4 different ways in which edges may overlap
  1940. // case4: edges are identical
  1941. // ----------------
  1942. // ----------------
  1943. // No edges need to be broken up, but do we need to update some
  1944. // dup values?
  1945. if (CloseReal(max1.X, max2.X) && CloseReal(min1.X, min2.X))
  1946. {
  1947. // for now, we will return FALSE
  1948. // I think, that it should be OK.
  1949. // TODO: - Review
  1950. // !!! Is this still ok? - t-wehunt
  1951. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  1952. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  1953. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  1954. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  1955. return FALSE;
  1956. }
  1957. // case2: the edges overlap and share one end point
  1958. // --------------
  1959. // ----------------------
  1960. // The longer edge needs to be broken into 2 pieces
  1961. if (CloseReal(min1.X, min2.X) && max1.X < max2.X)
  1962. {
  1963. // --------------
  1964. // ----------------------
  1965. // We have to update the dups of the shared point
  1966. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  1967. {
  1968. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  1969. }
  1970. *split1 = FALSE;
  1971. *split2 = TRUE;
  1972. *dupIndex2 = ptrEdge1->SortEnd;
  1973. *intersect2 = PathPts[*dupIndex2];
  1974. return TRUE;
  1975. }
  1976. else if (CloseReal(min1.X, min2.X) && max1.X > max2.X)
  1977. {
  1978. // ----------------------
  1979. // --------------
  1980. // We have to update the dups of the shared point
  1981. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  1982. {
  1983. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  1984. }
  1985. *split1 = TRUE;
  1986. *split2 = FALSE;
  1987. *dupIndex1 = ptrEdge2->SortEnd;
  1988. *intersect1 = PathPts[*dupIndex1];
  1989. return TRUE;
  1990. }
  1991. else if (CloseReal(max1.X, max2.X) && min1.X > min2.X)
  1992. {
  1993. // ----------------------
  1994. // --------------
  1995. // We have to update the dups of the shared point
  1996. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  1997. {
  1998. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  1999. }
  2000. *split1 = FALSE;
  2001. *split2 = TRUE;
  2002. *dupIndex2 = ptrEdge1->SortBegin;
  2003. *intersect2 = PathPts[*dupIndex2];
  2004. return TRUE;
  2005. }
  2006. else if (CloseReal(max1.X, max2.X) && min1.X < min2.X)
  2007. {
  2008. // --------------
  2009. // ----------------------
  2010. // We have to update the dups of the shared point
  2011. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  2012. {
  2013. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  2014. }
  2015. *split1 = TRUE;
  2016. *split2 = FALSE;
  2017. *dupIndex1 = ptrEdge2->SortBegin;
  2018. *intersect1 = PathPts[*dupIndex1];
  2019. return TRUE;
  2020. }
  2021. // case1: one is "inside" of another
  2022. // ---------
  2023. // -----------------
  2024. // In this case, the longer edge has to be broken into 3 pieces
  2025. if (min1.X < min2.X && max1.X > max2.X)
  2026. {
  2027. // intersection points are the end points of the second edge
  2028. // we are breaking up the first edge
  2029. *split1 = TRUE;
  2030. *split2 = FALSE;
  2031. *split3 = TRUE;
  2032. *dupIndex1 = ptrEdge2->SortBegin;
  2033. *dupIndex2 = ptrEdge2->SortEnd;
  2034. *intersect1 = PathPts[*dupIndex1];
  2035. *intersect2 = PathPts[*dupIndex2];
  2036. return TRUE;
  2037. }
  2038. else if (min1.X > min2.X && max1.X < max2.X)
  2039. {
  2040. // intersection points are the end points of the first edge
  2041. // we are breaking up the second edge
  2042. *split1 = FALSE;
  2043. *split2 = TRUE;
  2044. *split3 = TRUE;
  2045. *dupIndex1 = ptrEdge1->SortBegin;
  2046. *dupIndex2 = ptrEdge1->SortEnd;
  2047. *intersect1 = PathPts[*dupIndex1];
  2048. *intersect2 = PathPts[*dupIndex2];
  2049. return TRUE;
  2050. }
  2051. // case3: edges overlap
  2052. // ---------------
  2053. // -----------------
  2054. // Each edge has to be broken up INT 2 pieces
  2055. else if (max1.X < max2.X && min1.X < min2.X)
  2056. {
  2057. *split1 = TRUE;
  2058. *split2 = TRUE;
  2059. *dupIndex1 = ptrEdge2->SortBegin;
  2060. *dupIndex2 = ptrEdge1->SortEnd;
  2061. *intersect1 = PathPts[*dupIndex1];
  2062. *intersect2 = PathPts[*dupIndex2];
  2063. return TRUE;
  2064. }
  2065. else if (max2.X < max1.X && min2.X < min1.X)
  2066. {
  2067. // -----------------
  2068. // ---------------
  2069. *split1 = TRUE;
  2070. *split2 = TRUE;
  2071. *dupIndex1 = ptrEdge2->SortEnd;
  2072. *dupIndex2 = ptrEdge1->SortBegin;
  2073. *intersect1 = PathPts[*dupIndex1];
  2074. *intersect2 = PathPts[*dupIndex2];
  2075. return TRUE;
  2076. }
  2077. }
  2078. // The edges are vertical.
  2079. // We have to test for the same cases using y intervals
  2080. // if they share just a common point, return FALSE
  2081. if (CloseReal(min1.Y, max2.Y))
  2082. {
  2083. // We have to update the dups of the shared point
  2084. if (ptrEdge1->SortBegin != ptrEdge2->SortEnd)
  2085. {
  2086. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortEnd);
  2087. }
  2088. return FALSE;
  2089. }
  2090. if (CloseReal(min2.Y, max1.Y))
  2091. {
  2092. // We have to update the dups of the shared point
  2093. if (ptrEdge1->SortEnd != ptrEdge2->SortBegin)
  2094. {
  2095. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortBegin);
  2096. }
  2097. return FALSE;
  2098. }
  2099. // These edges may not overlap at all
  2100. if (min1.Y > max2.Y)
  2101. {
  2102. return FALSE;
  2103. }
  2104. if (min2.Y > max1.Y)
  2105. {
  2106. return FALSE;
  2107. }
  2108. // case4: edges are identical
  2109. // ----------------
  2110. // ----------------
  2111. // No edges need to be broken up, but do we need to update some
  2112. // dup values?
  2113. if (CloseReal(max1.Y, max2.Y) && CloseReal(min1.Y, min2.Y))
  2114. {
  2115. // for now, we will return FALSE
  2116. // I think, that it should be OK.
  2117. // TODO: - Review
  2118. // !!! IS this still ok? - t-wehunt
  2119. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  2120. {
  2121. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  2122. }
  2123. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  2124. {
  2125. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  2126. }
  2127. return FALSE;
  2128. }
  2129. // case2: the edges overlap and share one end point
  2130. // --------------
  2131. // ----------------------
  2132. // The longer edge needs to be broken into 2 pieces
  2133. if (CloseReal(min1.Y, min2.Y) && max1.Y < max2.Y)
  2134. {
  2135. // --------------
  2136. // ----------------------
  2137. // We have to update the dups of the shared point
  2138. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  2139. {
  2140. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  2141. }
  2142. *split1 = FALSE;
  2143. *split2 = TRUE;
  2144. *dupIndex2 = ptrEdge1->SortEnd;
  2145. *intersect2 = PathPts[*dupIndex2];
  2146. return TRUE;
  2147. }
  2148. else if (CloseReal(min1.Y, min2.Y) && max1.Y > max2.Y)
  2149. {
  2150. // ----------------------
  2151. // --------------
  2152. // We have to update the dups of the shared point
  2153. if (ptrEdge1->SortBegin != ptrEdge2->SortBegin)
  2154. {
  2155. UpdateDups(ptrEdge1->SortBegin, ptrEdge2->SortBegin);
  2156. }
  2157. *split1 = TRUE;
  2158. *split2 = FALSE;
  2159. *dupIndex1 = ptrEdge2->SortEnd;
  2160. *intersect1 = PathPts[*dupIndex1];
  2161. return TRUE;
  2162. }
  2163. else if (CloseReal(max1.Y, max2.Y) && min1.Y > min2.Y)
  2164. {
  2165. // ----------------------
  2166. // --------------
  2167. // We have to update the dups of the shared point
  2168. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  2169. {
  2170. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  2171. }
  2172. *split1 = FALSE;
  2173. *split2 = TRUE;
  2174. *dupIndex2 = ptrEdge1->SortBegin;
  2175. *intersect2 = PathPts[*dupIndex2];
  2176. return TRUE;
  2177. }
  2178. else if (CloseReal(max1.Y, max2.Y) && min1.Y < min2.Y)
  2179. {
  2180. // --------------
  2181. // ----------------------
  2182. // We have to update the dups of the shared point
  2183. if (ptrEdge1->SortEnd != ptrEdge2->SortEnd)
  2184. {
  2185. UpdateDups(ptrEdge1->SortEnd, ptrEdge2->SortEnd);
  2186. }
  2187. *split1 = TRUE;
  2188. *split2 = FALSE;
  2189. *dupIndex1 = ptrEdge2->SortBegin;
  2190. *intersect1 = PathPts[*dupIndex1];
  2191. return TRUE;
  2192. }
  2193. // case1: one is "inside" of another
  2194. // ---------
  2195. // -----------------
  2196. // In this case, the longer edge has to be broken into 3 pieces
  2197. if (min1.Y < min2.Y && max1.Y > max2.Y)
  2198. {
  2199. // intersection points are the end points of the second edge
  2200. // we are breaking up the first edge
  2201. *split1 = TRUE;
  2202. *split2 = FALSE;
  2203. *split3 = TRUE;
  2204. *dupIndex1 = ptrEdge2->SortBegin;
  2205. *dupIndex2 = ptrEdge2->SortEnd;
  2206. *intersect1 = PathPts[*dupIndex1];
  2207. *intersect2 = PathPts[*dupIndex2];
  2208. return TRUE;
  2209. }
  2210. else if(min1.Y > min2.Y && max1.Y < max2.Y)
  2211. {
  2212. // intersection points are the end points of the first edge
  2213. // we are breaking up the second edge
  2214. *split1 = FALSE;
  2215. *split2 = TRUE;
  2216. *split3 = TRUE;
  2217. *dupIndex1 = ptrEdge1->SortBegin;
  2218. *dupIndex2 = ptrEdge1->SortEnd;
  2219. *intersect1 = PathPts[*dupIndex1];
  2220. *intersect2 = PathPts[*dupIndex2];
  2221. return TRUE;
  2222. }
  2223. // case3: edges overlap
  2224. // ---------------
  2225. // -----------------
  2226. // Each edge has to be broken up INT 2 pieces
  2227. else if (max1.Y < max2.Y && min1.Y < min2.Y)
  2228. {
  2229. *split1 = TRUE;
  2230. *split2 = TRUE;
  2231. *dupIndex1 = ptrEdge2->SortBegin;
  2232. *dupIndex2 = ptrEdge1->SortEnd;
  2233. *intersect1 = PathPts[*dupIndex1];
  2234. *intersect2 = PathPts[*dupIndex2];
  2235. return TRUE;
  2236. }
  2237. else if (max2.Y < max1.Y && min2.Y < min1.Y)
  2238. {
  2239. // -----------------
  2240. // ---------------
  2241. *split1 = TRUE;
  2242. *split2 = TRUE;
  2243. *dupIndex1 = ptrEdge2->SortEnd;
  2244. *dupIndex2 = ptrEdge1->SortBegin;
  2245. *intersect1 = PathPts[*dupIndex1];
  2246. *intersect2 = PathPts[*dupIndex2];
  2247. return TRUE;
  2248. }
  2249. WARNING(("Couldn't resolve overlapping edges"));
  2250. return FALSE; // Shouldn't get here
  2251. }
  2252. /**************************************************************************\
  2253. *
  2254. * Function Description:
  2255. *
  2256. * Break edge in 3 pieces.
  2257. *
  2258. * Arguments:
  2259. *
  2260. *
  2261. * Return Value:
  2262. *
  2263. *
  2264. * Created:
  2265. *
  2266. * 6/15/1999 t-wehunt
  2267. *
  2268. \**************************************************************************/
  2269. BOOL PathSelfIntersectRemover::BreakEdgeIn3(
  2270. Edge *ptrEdge,
  2271. GpPointF *ptrPt1,
  2272. GpPointF *ptrPt2,
  2273. Edge *ptrNew1,
  2274. Edge *ptrNew2,
  2275. INT dupIndex1,
  2276. INT dupIndex2
  2277. )
  2278. {
  2279. INT iptt1, ipto1; // Indecies to the point arrays
  2280. INT iptt2, ipto2;
  2281. PointListNode ptord1; // Pointers to the linked list and point information
  2282. PointListNode ptord2;
  2283. PointListNode *pptordBeg = NULL;
  2284. PointListNode *pptordEnd = NULL;
  2285. // Let's first add the intersection points to the array of points.
  2286. // Don't add identical points to the last point in the path.
  2287. // iptt is the index of this point
  2288. GpPointF &lastPt = PathPts.Last();
  2289. if (ClosePt(*ptrPt1, lastPt))
  2290. {
  2291. return FALSE;
  2292. }
  2293. if (PathPts.Add(*ptrPt1) != Ok)
  2294. {
  2295. return FALSE;
  2296. }
  2297. else
  2298. {
  2299. iptt1 = (PathPts.GetCount())-1;
  2300. }
  2301. if (PathPts.Add(*ptrPt2) != Ok)
  2302. {
  2303. return FALSE;
  2304. }
  2305. else
  2306. {
  2307. iptt2 = (PathPts.GetCount())-1;
  2308. }
  2309. // we have to figure out how to link in the new points, it depends on
  2310. // the direction of the new edge; iptt1 has the x coordinate <= than
  2311. // iptt2.
  2312. if (ptrEdge->Begin == ptrEdge->SortBegin)
  2313. {
  2314. // PointListNode record for the new point.
  2315. ptord1.Prev = ptrEdge->Begin;
  2316. ptord1.Next = iptt2;
  2317. ptord2.Prev = iptt1;
  2318. ptord2.Next = ptrEdge->End;
  2319. }
  2320. else
  2321. {
  2322. // PointListNode record for the new point.
  2323. ptord1.Prev = iptt2;
  2324. ptord1.Next = ptrEdge->End;
  2325. ptord2.Prev = ptrEdge->Begin;
  2326. ptord2.Next = iptt1;
  2327. }
  2328. // Update the duplicate field with the iptDup value passed in
  2329. ptord1.Dup = dupIndex1;
  2330. ptord2.Dup = dupIndex2;
  2331. // Inside set to TRUE is the default
  2332. ptord1.Inside = TRUE;
  2333. ptord1.Used = FALSE;
  2334. ptord2.Inside = TRUE;
  2335. ptord2.Used = FALSE;
  2336. // And now add it to the array.
  2337. if (PtList.Add(ptord1) != Ok)
  2338. {
  2339. return FALSE;
  2340. }
  2341. else
  2342. {
  2343. ipto1 = (PtList.GetCount()-1);
  2344. }
  2345. if (PtList.Add(ptord2) != Ok)
  2346. {
  2347. return FALSE;
  2348. }
  2349. else
  2350. {
  2351. ipto2 = (PtList.GetCount()-1);
  2352. }
  2353. // Update ptord records for next and prev
  2354. pptordBeg = &PtList[ptrEdge->Begin];
  2355. pptordEnd = &PtList[ptrEdge->End];
  2356. if (ptrEdge->Begin == ptrEdge->SortBegin)
  2357. {
  2358. pptordBeg->Next = ipto1;
  2359. pptordEnd->Prev = ipto2;
  2360. }
  2361. else
  2362. {
  2363. pptordBeg->Next = ipto2;
  2364. pptordEnd->Prev = ipto1;
  2365. }
  2366. // Both arrays - ptt and pto must have exactly the same # of elements
  2367. ASSERTMSG((iptt2 == ipto2),("Assert failed."));
  2368. //GpPointF pfpvBegin = *(PathPts.PGet(ptrEdge->SortBegin));
  2369. //GpPointF pfpvEnd = *(PathPts.PGet(ptrEdge->SortEnd));
  2370. // Lets create the new line segments. The sorted order of
  2371. // end points is easy - intersection point must be before the SortEnd.
  2372. ptrNew1->SortBegin = iptt1;
  2373. ptrNew1->SortEnd = iptt2;
  2374. // remember the original end point of the edge
  2375. ptrNew1->OrigBegin = ptrEdge->OrigBegin;
  2376. ptrNew1->OrigEnd = ptrEdge->OrigEnd;
  2377. ptrNew2->SortBegin = iptt2;
  2378. ptrNew2->SortEnd = ptrEdge->SortEnd;
  2379. // remember the original end point of the edge
  2380. ptrNew2->OrigBegin = ptrEdge->OrigBegin;
  2381. ptrNew2->OrigEnd = ptrEdge->OrigEnd;
  2382. // Also iptt (new point) becomes the new SortEnd of the old edge
  2383. ptrEdge->SortEnd = iptt1;
  2384. // Now, depending on whether the edge being broken up was swapped or not,
  2385. // the new edges need to be swapped
  2386. if (ptrEdge->Begin == ptrEdge->SortBegin)
  2387. {
  2388. // not swapped
  2389. ptrEdge->End = iptt1;
  2390. ptrNew1->Begin = ptrNew1->SortBegin;
  2391. ptrNew1->End = ptrNew1->SortEnd;
  2392. ptrNew2->Begin = ptrNew2->SortBegin;
  2393. ptrNew2->End = ptrNew2->SortEnd;
  2394. }
  2395. else
  2396. {
  2397. // swapped
  2398. ptrEdge->Begin = iptt1;
  2399. ptrNew1->Begin = ptrNew1->SortEnd;
  2400. ptrNew1->End = ptrNew1->SortBegin;
  2401. ptrNew2->Begin = ptrNew2->SortEnd;
  2402. ptrNew2->End = ptrNew2->SortBegin;
  2403. }
  2404. ptrNew1->Next = LIST_END;
  2405. ptrNew2->Next = LIST_END;
  2406. // If the point of intersection is on the scan line, we need to insert
  2407. // the new edge to the Active table, otherwise to the table with edges
  2408. // to process.
  2409. if (CloseReal(XCur, ptrPt1->X))
  2410. {
  2411. MarkToAdd(ptrNew1);
  2412. }
  2413. else
  2414. {
  2415. if(Ok != EdgeList.Add(*ptrNew1))
  2416. {
  2417. return FALSE; // out of memory
  2418. }
  2419. InsertEdgeIntoList(
  2420. &InactiveEdgeList,
  2421. EdgeList.GetCount()-1,
  2422. CompareLine
  2423. );
  2424. }
  2425. if (CloseReal(XCur, ptrPt2->X))
  2426. {
  2427. MarkToAdd(ptrNew2);
  2428. }
  2429. else
  2430. {
  2431. if(Ok != EdgeList.Add(*ptrNew2))
  2432. {
  2433. return FALSE; // out of memory
  2434. }
  2435. InsertEdgeIntoList(
  2436. &InactiveEdgeList,
  2437. EdgeList.GetCount()-1,
  2438. CompareLine
  2439. );
  2440. }
  2441. return TRUE;
  2442. }
  2443. /**************************************************************************\
  2444. *
  2445. * Function Description:
  2446. *
  2447. * Breaks edge ptrEdge. We have found intersection point intersectPt, which is
  2448. * guranteed to be somewhere on the line segment (not an end point).
  2449. * The 'left' part of the edge will either remain in the active edges
  2450. * or will be removed (only if the intersection point has the current
  2451. * x value. In the latter case, the right edge segment will need to be
  2452. * inserted to active edges, otherwise (the former case) it will go
  2453. * to InactiveEdgeList. If it needs to go to active edges, Breakedge cannot
  2454. * insert it because it would disrupt the order of edges there before
  2455. * both edges broken up are handled. The caller would have to handle
  2456. * the insertion in such case. Therefore, we return the new line
  2457. * segment newEdge and a BOOL value specifying if the caller has to insert
  2458. * the newEdge edge.
  2459. * dupIndex is the index of the duplicate point created by this intersection:
  2460. * When two edges intersect, we have to insert two points (identical)
  2461. * to maintain the same shape of the polygon. These two points are
  2462. * called duplicates.
  2463. * Return FALSE on out of memory.
  2464. *
  2465. * Arguments:
  2466. *
  2467. *
  2468. * Return Value:
  2469. *
  2470. *
  2471. * Created:
  2472. *
  2473. * 6/15/1999 t-wehunt
  2474. *
  2475. \**************************************************************************/
  2476. BOOL PathSelfIntersectRemover::BreakEdge(
  2477. Edge *ptrEdge,
  2478. GpPointF *intersectPt,
  2479. Edge *newEdge,
  2480. INT dupIndex
  2481. )
  2482. {
  2483. INT iptt, ipto; // Indecies to the point arrays
  2484. PointListNode ptNode; // Pointers to the linked list and point information
  2485. PointListNode *ptNodeBeg = NULL;
  2486. PointListNode *ptNodeEnd = NULL;
  2487. // Let's first add the intersection point to the array of points.
  2488. if (PathPts.Add(*intersectPt) != Ok)
  2489. {
  2490. return FALSE;
  2491. }
  2492. else
  2493. {
  2494. iptt = (PathPts.GetCount())-1;
  2495. }
  2496. // PointListNode record for the new point. It is in the middle of the
  2497. // edge, so Begin and End point of the edge will be its previous and next
  2498. ptNode.Prev = ptrEdge->Begin;
  2499. ptNode.Next = ptrEdge->End;
  2500. // Update the duplicate field with the dupIndex value passed in
  2501. ptNode.Dup = dupIndex;
  2502. // Inside set to TRUE is the default
  2503. ptNode.Inside = TRUE;
  2504. ptNode.Used = FALSE;
  2505. // And now add it to the array.
  2506. if (PtList.Add(ptNode) != Ok)
  2507. {
  2508. return FALSE;
  2509. }
  2510. else
  2511. {
  2512. ipto = (PtList.GetCount()-1);
  2513. }
  2514. // Update ptNode records for next and prev
  2515. ptNodeBeg = &PtList[ptrEdge->Begin];
  2516. ptNodeEnd = &PtList[ptrEdge->End];
  2517. ptNodeBeg->Next = ipto;
  2518. ptNodeEnd->Prev = ipto;
  2519. // Both arrays - ptt and pto must have exactly the same # of elements
  2520. ASSERTMSG((iptt == ipto),("Assert failed."));
  2521. // remember the original end point of the edge
  2522. newEdge->OrigBegin = ptrEdge->OrigBegin;
  2523. newEdge->OrigEnd = ptrEdge->OrigEnd;
  2524. // Lets create the new line segment. The sorted order of end points
  2525. // is easy - intersection point must be before the SortEnd.
  2526. newEdge->SortBegin = iptt;
  2527. newEdge->SortEnd = ptrEdge->SortEnd;
  2528. // Also iptt (new point) becomes the new SortEnd of the old edge
  2529. ptrEdge->SortEnd = iptt;
  2530. // Now, depending on whether the edge being broken up was swapped or not,
  2531. // the new edges need to be swapped
  2532. if (ptrEdge->Begin == ptrEdge->SortBegin)
  2533. {
  2534. // not swapped
  2535. ptrEdge->End = iptt;
  2536. newEdge->Begin = newEdge->SortBegin;
  2537. newEdge->End = newEdge->SortEnd;
  2538. }
  2539. else
  2540. {
  2541. // swapped
  2542. ptrEdge->Begin = iptt;
  2543. newEdge->Begin = newEdge->SortEnd;
  2544. newEdge->End = newEdge->SortBegin;
  2545. }
  2546. newEdge->Next = LIST_END;
  2547. // If the point of intersection is on the scan line, we need to insert
  2548. // the new edge to the Active table, otherwise to the table with edges
  2549. // to process.
  2550. if (CloseReal(XCur, intersectPt->X))
  2551. {
  2552. MarkToAdd(newEdge);
  2553. }
  2554. else
  2555. {
  2556. if(Ok != EdgeList.Add(*newEdge))
  2557. {
  2558. return FALSE; // out of memory
  2559. }
  2560. InsertEdgeIntoList(
  2561. &InactiveEdgeList,
  2562. EdgeList.GetCount()-1,
  2563. CompareLine
  2564. );
  2565. }
  2566. return TRUE;
  2567. }
  2568. /**************************************************************************\
  2569. *
  2570. * Function Description:
  2571. *
  2572. * Eliminate Self Intersections in a widened path
  2573. *
  2574. * Arguments:
  2575. *
  2576. *
  2577. * Return Value:
  2578. *
  2579. *
  2580. * Created:
  2581. *
  2582. * 6/15/1999 t-wehunt
  2583. *
  2584. \**************************************************************************/
  2585. GpStatus PathSelfIntersectRemover::RemoveSelfIntersects()
  2586. {
  2587. CanAddPts = FALSE;
  2588. // ------ Phase 1:
  2589. INT count = EdgeList.GetCount();
  2590. if (count <= 0)
  2591. {
  2592. return Ok; //nothing to correct
  2593. }
  2594. // Sort all the edges in EdgeList array.
  2595. Edge *edges = EdgeList.GetDataBuffer();
  2596. QuickSortEdges(edges, edges+count-1);
  2597. InactiveEdgeList = 0; // Point to the first element in the inactive list.
  2598. // Initialize the linked list Next pointers:
  2599. for(int i = 0; i < count-1; i++)
  2600. {
  2601. EdgeList[i].Next = i+1;
  2602. }
  2603. EdgeList[i].Next = LIST_END;
  2604. if (!FindIntersects())
  2605. {
  2606. return GenericError;
  2607. }
  2608. // ------ Phase 2:
  2609. // FindIntersects orphans all the edges from the list. Reconstruct and
  2610. // re-sort using QuickSort. This works out faster because the incremental
  2611. // sort during FindIntersects would have been at least O(n^2).
  2612. count = EdgeList.GetCount();
  2613. // we never actually delete anything from the array - only from the
  2614. // linked list, so if we had count > 0 above, we must have a larger or
  2615. // the same count now.
  2616. ASSERT(count > 0);
  2617. // Sort all the edges in the EdgeList array.
  2618. edges = EdgeList.GetDataBuffer();
  2619. QuickSortEdges(edges, edges+count-1);
  2620. InactiveEdgeList = 0; // Point to the first element in the inactive list.
  2621. // Initialize the linked list Next pointers:
  2622. for(int i = 0; i < count-1; i++)
  2623. {
  2624. EdgeList[i].Next = i+1;
  2625. }
  2626. EdgeList[i].Next = LIST_END;
  2627. if(!EliminatePoints())
  2628. {
  2629. return GenericError;
  2630. }
  2631. // ... move on to phase 3 - collection.
  2632. return Ok;
  2633. }
  2634. /**************************************************************************\
  2635. *
  2636. * Function Description:
  2637. *
  2638. * Eliminate Self Intersections.
  2639. *
  2640. * This is considered 'Phase 2' of the algorithm.
  2641. *
  2642. * Arguments:
  2643. *
  2644. *
  2645. * Return Value:
  2646. *
  2647. *
  2648. * Created:
  2649. *
  2650. * 6/15/1999 t-wehunt
  2651. *
  2652. \**************************************************************************/
  2653. BOOL PathSelfIntersectRemover::EliminatePoints()
  2654. {
  2655. // Initialize the array of active edges.
  2656. // Take the first edge from the edge array and add it to the active edgs.
  2657. // Add all other edges, which start at the same x.
  2658. if (InactiveEdgeList == LIST_END)
  2659. {
  2660. return FALSE;
  2661. }
  2662. XCur = PathPts[EdgeList[InactiveEdgeList].SortBegin].X;
  2663. // "move" all edges starting at xCur to the active edge array
  2664. // PathPts in the active edge array will be sorted by y for the
  2665. // given xCur.
  2666. AddActiveForXScan(&InactiveEdgeList);
  2667. // As long as the Active edge array is not empty, keep scanning
  2668. while (TRUE)
  2669. {
  2670. // Scan the active edge array for the current XCur;
  2671. if (!ScanActive())
  2672. {
  2673. return FALSE;
  2674. }
  2675. RemoveVertAll();
  2676. // Update the XCur using edges from InactiveEdgeList
  2677. if (!ClosestActive(InactiveEdgeList))
  2678. {
  2679. break;
  2680. }
  2681. // Remove all edges which end BEFORE XCur;
  2682. ClearActiveListExclusiveX();
  2683. // Add new edges, which begin at XCur
  2684. AddActiveForXScan(&InactiveEdgeList);
  2685. }
  2686. return TRUE;
  2687. }
  2688. /**************************************************************************\
  2689. *
  2690. * Function Description:
  2691. *
  2692. * Scan through all active edges during the phase of edge elimination.
  2693. * Calculates winding number to the left and to the right of the current
  2694. * x value - XCur. Whenever finds an edge which has 0 winding number
  2695. * on one side, marks it as an outside edge.
  2696. *
  2697. * Arguments:
  2698. *
  2699. *
  2700. * Return Value:
  2701. *
  2702. *
  2703. * Created:
  2704. *
  2705. * 6/15/1999 t-wehunt
  2706. *
  2707. \**************************************************************************/
  2708. BOOL PathSelfIntersectRemover::ScanActive()
  2709. {
  2710. Edge *ptrEdge = NULL;
  2711. Edge *plnNext = NULL;
  2712. GpPointF *pfpvBegin = NULL;
  2713. GpPointF *pfpvEnd = NULL;
  2714. // We are starting from the outside.
  2715. INT lwindLeft = 0;
  2716. INT lwindRight = 0;
  2717. // Look at all edges in the ective edge array.
  2718. INT index = ActiveEdgeList;
  2719. while (index != LIST_END)
  2720. {
  2721. ptrEdge = &EdgeList[index];
  2722. index = ptrEdge->Next;
  2723. // Get the end points
  2724. ASSERTMSG((ptrEdge->SortBegin < PathPts.GetCount()), ("FATAL ERROR."));
  2725. pfpvBegin = &PathPts[ptrEdge->SortBegin];
  2726. ASSERTMSG((ptrEdge->SortEnd < PathPts.GetCount()), ("FATAL ERROR."));
  2727. pfpvEnd = &PathPts[ptrEdge->SortEnd];
  2728. // Is it vertical?
  2729. if (ptrEdge->IsVertical())
  2730. {
  2731. if (NewInterval(ptrEdge))
  2732. {
  2733. if (lwindLeft == 0 || lwindRight == 0)
  2734. {
  2735. MarkVertOutside();
  2736. }
  2737. }
  2738. RemoveVert(ptrEdge->YCur, TRUE /*inclusive*/);
  2739. //add it to the active vertical edges
  2740. //Edge insertion
  2741. if (ActiveVertEdges.InsertSorted(*ptrEdge,
  2742. (DynSortArrayCompareFunc)&(CompareVertLine),
  2743. this) != Ok)
  2744. {
  2745. return FALSE;
  2746. }
  2747. }
  2748. else
  2749. {
  2750. if (lwindLeft == 0 || lwindRight == 0)
  2751. {
  2752. MarkVertOutside();
  2753. }
  2754. RemoveVert(ptrEdge->YCur, TRUE /*inclusive*/);
  2755. // Edge is not vertical, does it have an end point
  2756. // on this scan line
  2757. if ((!CloseReal(pfpvBegin->X, XCur)) &&
  2758. (!CloseReal(pfpvEnd->X, XCur)))
  2759. {
  2760. // we are crossing edge in the middle, so both winding numbers
  2761. // need to be updated
  2762. if (lwindLeft == 0 || lwindRight == 0)
  2763. {
  2764. ptrEdge->MarkOutside();
  2765. }
  2766. if (ptrEdge->SortBegin == ptrEdge->Begin)
  2767. {
  2768. lwindLeft++;
  2769. lwindRight++;
  2770. }
  2771. else
  2772. {
  2773. lwindLeft--;
  2774. lwindRight--;
  2775. }
  2776. if (lwindLeft == 0 || lwindRight == 0)
  2777. {
  2778. ptrEdge->MarkOutside();
  2779. }
  2780. }
  2781. else if ((CloseReal(pfpvBegin->X, XCur)) &&
  2782. (!CloseReal(pfpvEnd->X, XCur)))
  2783. {
  2784. //right edge
  2785. if (lwindRight == 0)
  2786. {
  2787. ptrEdge->MarkOutside();
  2788. }
  2789. if (ptrEdge->SortBegin == ptrEdge->Begin)
  2790. {
  2791. lwindRight++;
  2792. }
  2793. else
  2794. {
  2795. lwindRight--;
  2796. }
  2797. if (lwindRight == 0)
  2798. {
  2799. ptrEdge->MarkOutside();
  2800. }
  2801. }
  2802. else if ((!CloseReal(pfpvBegin->X, XCur)) &&
  2803. (CloseReal(pfpvEnd->X, XCur)))
  2804. {
  2805. //left edge
  2806. if (lwindLeft == 0)
  2807. {
  2808. ptrEdge->MarkOutside();
  2809. }
  2810. if (ptrEdge->SortBegin == ptrEdge->Begin)
  2811. {
  2812. lwindLeft++;
  2813. }
  2814. else
  2815. {
  2816. lwindLeft--;
  2817. }
  2818. if (lwindLeft == 0)
  2819. {
  2820. ptrEdge->MarkOutside();
  2821. }
  2822. }
  2823. else
  2824. {
  2825. WARNING(("Edge is not vertical, but not in XCur"));
  2826. }
  2827. // if we crossed to te outside, all current vertical edges need
  2828. // to be marked
  2829. if (lwindLeft == 0 || lwindRight == 0)
  2830. {
  2831. MarkVertOutside();
  2832. }
  2833. RemoveVert(ptrEdge->YCur, TRUE /*inclusive*/);
  2834. }
  2835. }
  2836. return TRUE;
  2837. }
  2838. /**************************************************************************\
  2839. *
  2840. * Function Description:
  2841. *
  2842. * Mark the one or two of the current vertical edges as outside.
  2843. * If there is an even number of edge going in both directions, it means that
  2844. * the winding number is the same on both sides. Since we are being called,
  2845. * it must be 0. In this case, we pick one edge going up and one edge going
  2846. * down and mark both of them as outside.
  2847. * If there is more edges going in one direction than another, then the winding
  2848. * numbers are different, but one of them is 0. We pick one of the edges from
  2849. * that set edges (up or down) which is larger. So if more edges go down, we
  2850. * pick one of those edges and mark them as outside.
  2851. *
  2852. * Arguments:
  2853. *
  2854. *
  2855. * Return Value:
  2856. *
  2857. *
  2858. * Created:
  2859. *
  2860. * 6/15/1999 t-wehunt
  2861. *
  2862. \**************************************************************************/
  2863. VOID PathSelfIntersectRemover::MarkVertOutside()
  2864. {
  2865. Edge *ptrEdge = NULL;
  2866. INT index = 0;
  2867. INT ndown = 0;
  2868. INT nup = 0;
  2869. INT idown = -1;
  2870. INT iup = -1;
  2871. // we will mark the first one
  2872. while (index < ActiveVertEdges.GetCount() )
  2873. {
  2874. //PGet on edges
  2875. ptrEdge = &ActiveVertEdges[index];
  2876. if (ptrEdge->SortBegin == ptrEdge->Begin)
  2877. {
  2878. //goes down
  2879. ndown++;
  2880. idown = index;
  2881. }
  2882. else
  2883. {
  2884. nup++;
  2885. iup = index;
  2886. }
  2887. index++;
  2888. }
  2889. if (ndown > nup)
  2890. {
  2891. //PGet on edges
  2892. ptrEdge = &ActiveVertEdges[idown];
  2893. ptrEdge->MarkOutside();
  2894. }
  2895. else if (nup > ndown)
  2896. {
  2897. //PGet on edges
  2898. ptrEdge = &ActiveVertEdges[iup];
  2899. ptrEdge->MarkOutside();
  2900. }
  2901. else
  2902. {
  2903. if (nup != 0)
  2904. {
  2905. if (iup > -1)
  2906. {
  2907. //PGet on edges
  2908. ptrEdge = &ActiveVertEdges[iup];
  2909. ptrEdge->MarkOutside();
  2910. }
  2911. }
  2912. if (ndown != 0)
  2913. {
  2914. if (idown > -1)
  2915. {
  2916. //PGet on edges
  2917. ptrEdge = &ActiveVertEdges[idown];
  2918. ptrEdge->MarkOutside();
  2919. }
  2920. }
  2921. }
  2922. }
  2923. /**************************************************************************\
  2924. *
  2925. * Function Description:
  2926. *
  2927. * Returns TRUE if edge ptrEdge belongs to a different interval than the
  2928. * edges currently stored in ActiveVertEdges.
  2929. *
  2930. * Arguments:
  2931. *
  2932. *
  2933. * Return Value:
  2934. *
  2935. *
  2936. * Created:
  2937. *
  2938. * 6/15/1999 t-wehunt
  2939. *
  2940. \**************************************************************************/
  2941. BOOL PathSelfIntersectRemover::NewInterval(Edge *ptrEdge)
  2942. {
  2943. Edge *plnOld;
  2944. if (ActiveVertEdges.GetCount() <= 0)
  2945. {
  2946. return FALSE;
  2947. }
  2948. //PGet on edges
  2949. plnOld = &ActiveVertEdges.First();
  2950. REAL fpY1, fpY2;
  2951. fpY1 = PathPts[plnOld->SortEnd].Y;
  2952. fpY2 = PathPts[ptrEdge->SortEnd].Y;
  2953. if (CloseReal(fpY1, fpY2))
  2954. {
  2955. return FALSE;
  2956. }
  2957. if (fpY1 < fpY2)
  2958. {
  2959. return TRUE;
  2960. }
  2961. else
  2962. {
  2963. return FALSE;
  2964. }
  2965. }
  2966. /**************************************************************************\
  2967. *
  2968. * Function Description:
  2969. *
  2970. * Remove all the edges from the active edge array.
  2971. *
  2972. * Arguments:
  2973. *
  2974. *
  2975. * Return Value:
  2976. *
  2977. *
  2978. * Created:
  2979. *
  2980. * 6/15/1999 t-wehunt
  2981. *
  2982. \**************************************************************************/
  2983. VOID PathSelfIntersectRemover::RemoveVertAll()
  2984. {
  2985. if( ActiveVertEdges.GetCount() > 0)
  2986. {
  2987. ActiveVertEdges.Reset(FALSE);
  2988. }
  2989. }
  2990. /**************************************************************************\
  2991. *
  2992. * Function Description:
  2993. *
  2994. * Remove vertical edges which have end points below given y value.
  2995. *
  2996. * Arguments:
  2997. *
  2998. *
  2999. * Return Value:
  3000. *
  3001. *
  3002. * Created:
  3003. *
  3004. * 6/15/1999 t-wehunt
  3005. *
  3006. \**************************************************************************/
  3007. VOID PathSelfIntersectRemover::RemoveVert(REAL y, BOOL inclusive)
  3008. {
  3009. Edge *ptrEdge = NULL;
  3010. // edges are sorted, so as soon as we find an end point with y value > y
  3011. // we are done
  3012. while (ActiveVertEdges.GetCount() > 0)
  3013. {
  3014. //PGet on edges
  3015. ptrEdge = &ActiveVertEdges.First();
  3016. REAL fpY;
  3017. fpY = PathPts[ptrEdge->SortEnd].Y;
  3018. if (inclusive)
  3019. {
  3020. if (fpY < y || CloseReal(fpY,y))
  3021. {
  3022. ActiveVertEdges.DeleteAt(0);
  3023. }
  3024. else
  3025. {
  3026. return;
  3027. }
  3028. }
  3029. else
  3030. {
  3031. if (fpY < y && (!CloseReal(fpY,y)))
  3032. {
  3033. ActiveVertEdges.DeleteAt(0);
  3034. }
  3035. else
  3036. {
  3037. return;
  3038. }
  3039. }
  3040. }
  3041. }
  3042. /**************************************************************************\
  3043. *
  3044. * Function Description:
  3045. *
  3046. * Scan the ActiveEdgeList for all edges which end at XCur (inclusive) and
  3047. * simply orphan them. This is used in the first phase of the algorithm
  3048. * (FindIntersects) which passes each edge from the InactiveEdgeList through
  3049. * the ActiveEdgeList. When the edges are no longer needed they're removed
  3050. * from all lists.
  3051. *
  3052. * Created
  3053. *
  3054. * 12/27/2000 asecchia
  3055. *
  3056. \**************************************************************************/
  3057. void PathSelfIntersectRemover::ClearActiveListInclusiveX()
  3058. {
  3059. INT *pIndex = &ActiveEdgeList;
  3060. while(*pIndex != LIST_END)
  3061. {
  3062. Edge *pEdge = &EdgeList[*pIndex];
  3063. GpPointF *pSortEnd = &PathPts[pEdge->SortEnd];
  3064. // inclusive check.
  3065. if((pSortEnd->X < XCur) || CloseReal(pSortEnd->X, XCur))
  3066. {
  3067. // delete the item and advance.
  3068. *pIndex = pEdge->Next; // point past the deleted item.
  3069. pEdge->Next = LIST_END; // disconnect the deleted item.
  3070. }
  3071. else
  3072. {
  3073. pIndex = &EdgeList[*pIndex].Next;
  3074. }
  3075. }
  3076. }
  3077. /**************************************************************************\
  3078. *
  3079. * Function Description:
  3080. *
  3081. * Remove from ActiveEdgeList all edges which end at XCur. This uses
  3082. * an exclusive check. This code is used for the second phase of the algorithm
  3083. * (EliminatePoints). Each edge removed is orphaned from the list because
  3084. * the linked list representation will not be used after this phase.
  3085. *
  3086. * Created:
  3087. *
  3088. * 12/23/2000 asecchia
  3089. *
  3090. \**************************************************************************/
  3091. void PathSelfIntersectRemover::ClearActiveListExclusiveX()
  3092. {
  3093. INT *pIndex = &ActiveEdgeList;
  3094. while(*pIndex != LIST_END)
  3095. {
  3096. Edge *pEdge = &EdgeList[*pIndex];
  3097. GpPointF *pSortEnd = &PathPts[pEdge->SortEnd];
  3098. // exclusive check.
  3099. if((pSortEnd->X < XCur) && !CloseReal(pSortEnd->X, XCur))
  3100. {
  3101. // delete the item and advance.
  3102. *pIndex = pEdge->Next; // point past the deleted item.
  3103. pEdge->Next = LIST_END; // disconnect the deleted item.
  3104. }
  3105. else
  3106. {
  3107. pIndex = &EdgeList[*pIndex].Next;
  3108. }
  3109. }
  3110. }
  3111. /**************************************************************************\
  3112. *
  3113. * Function Description:
  3114. *
  3115. * Add all edges with begin point at xCur to the active edge table.
  3116. * Update the index piLn to the edge array to point to the next edge, which
  3117. * will have to be considered.
  3118. *
  3119. * Arguments:
  3120. *
  3121. *
  3122. * Return Value:
  3123. *
  3124. *
  3125. * Created:
  3126. *
  3127. * 6/15/1999 t-wehunt
  3128. *
  3129. \**************************************************************************/
  3130. void PathSelfIntersectRemover::AddActiveForX(INT *inactiveHead)
  3131. {
  3132. // We have a new current x, let's calculate new curent Y's for each edge
  3133. // They are needed to insert the new active edges in the right order
  3134. RecalcActiveYCur();
  3135. InsertNewEdges(
  3136. &ActiveEdgeList, // insert
  3137. inactiveHead, // remove
  3138. XCur,
  3139. CompareYCurLine
  3140. );
  3141. }
  3142. /**************************************************************************\
  3143. *
  3144. * Function Description:
  3145. *
  3146. * Add all edges with begin point at xCur to the active edge table.
  3147. * Update the index piLn to the edge array to point to the next edge, which
  3148. * will have to be considered.
  3149. *
  3150. * Arguments:
  3151. *
  3152. *
  3153. * Return Value:
  3154. *
  3155. *
  3156. * Created:
  3157. *
  3158. * 6/15/1999 t-wehunt
  3159. *
  3160. \**************************************************************************/
  3161. void PathSelfIntersectRemover::AddActiveForXScan(INT *inactiveHead)
  3162. {
  3163. // We have a new current x, let's calculate new curent Y's for each edge
  3164. // They are needed to insert the new active edges in the right order
  3165. RecalcActiveYCur();
  3166. InsertNewEdges(
  3167. &ActiveEdgeList, // insert
  3168. inactiveHead, // remove
  3169. XCur,
  3170. CompareYScanCurLine
  3171. );
  3172. }
  3173. /**************************************************************************\
  3174. *
  3175. * Function Description:
  3176. *
  3177. * Calculate the yCur position for each edge in the active edge table.
  3178. *
  3179. * Arguments:
  3180. *
  3181. *
  3182. * Return Value:
  3183. *
  3184. *
  3185. * Created:
  3186. *
  3187. * 6/15/1999 t-wehunt
  3188. *
  3189. \**************************************************************************/
  3190. VOID PathSelfIntersectRemover::RecalcActiveYCur(VOID)
  3191. {
  3192. REAL dx = 0;
  3193. REAL dy = 0;
  3194. REAL dxCur = 0;
  3195. GpPointF fpvBegin(0,0);
  3196. GpPointF fpvEnd(0,0);
  3197. GpPointF fpvOrigBegin(0,0);
  3198. GpPointF fpvOrigEnd(0,0);
  3199. Edge *ptrEdge = NULL;
  3200. INT active = ActiveEdgeList;
  3201. // Go through all active egdes
  3202. while(active != LIST_END)
  3203. {
  3204. ptrEdge = &EdgeList[active];
  3205. // If the edge will have an end point at XCur,
  3206. // use this end point's y value.
  3207. fpvBegin = PathPts[ptrEdge->SortBegin];
  3208. fpvEnd = PathPts[ptrEdge->SortEnd];
  3209. fpvOrigBegin = PathPts[ptrEdge->OrigBegin];
  3210. fpvOrigEnd = PathPts[ptrEdge->OrigEnd];
  3211. if ((XCur == fpvEnd.X) || (fpvEnd.X == fpvBegin.X))
  3212. {
  3213. ptrEdge->YCur = fpvEnd.Y;
  3214. }
  3215. else
  3216. {
  3217. // Calculate the slope numerator and denominator
  3218. dx = fpvOrigEnd.X - fpvOrigBegin.X;
  3219. dy = fpvOrigEnd.Y - fpvOrigBegin.Y;
  3220. dxCur = XCur - fpvOrigBegin.X;
  3221. ptrEdge->YCur = dy * dxCur / dx + fpvOrigBegin.Y;
  3222. }
  3223. active = EdgeList[active].Next;
  3224. }
  3225. }
  3226. /**************************************************************************\
  3227. *
  3228. * Function Description:
  3229. *
  3230. * Compare two lines. Lines are sorted based on the yCur value.
  3231. * If yCur's are identical, lines are sorted based on the begin point.
  3232. *
  3233. * Arguments:
  3234. *
  3235. *
  3236. * Return Value:
  3237. *
  3238. * -1 if ptrEdge1 < ptrEdge2
  3239. * 0 if ther are equal
  3240. * 1 if ptrEdge1 > ptrEdge2
  3241. *
  3242. * Created:
  3243. *
  3244. * 6/15/1999 t-wehunt
  3245. *
  3246. \**************************************************************************/
  3247. INT
  3248. CompareYScanCurLine(
  3249. PathSelfIntersectRemover *ptrCorrector,
  3250. Edge *ptrEdge1,
  3251. Edge *ptrEdge2
  3252. )
  3253. {
  3254. if (!ptrEdge1->CloseReal(ptrEdge1->YCur, ptrEdge2->YCur))
  3255. {
  3256. if(ptrEdge1->YCur < ptrEdge2->YCur)
  3257. {
  3258. return -1;
  3259. }
  3260. if(ptrEdge1->YCur > ptrEdge2->YCur)
  3261. {
  3262. return 1;
  3263. }
  3264. }
  3265. // All left and vertical edges need to go before right edges if they have
  3266. // the same yCur;
  3267. // A left edge has a begin point < xCur, right edge x = xCur
  3268. BOOL fLeft1 = TRUE;
  3269. BOOL fLeft2 = TRUE;
  3270. fLeft1 = ((ptrCorrector->PathPts[ptrEdge1->SortBegin].X <
  3271. ptrCorrector->XCur &&
  3272. ptrEdge1->CloseReal(ptrCorrector->PathPts[ptrEdge1->SortEnd].X,
  3273. ptrCorrector->XCur)) ||
  3274. ptrEdge1->IsVertical());
  3275. fLeft2 = ((ptrCorrector->PathPts[ptrEdge2->SortBegin].X <
  3276. ptrCorrector->XCur &&
  3277. ptrEdge2->CloseReal(ptrCorrector->PathPts[ptrEdge2->SortEnd].X,
  3278. ptrCorrector->XCur)) ||
  3279. ptrEdge2->IsVertical());
  3280. if (fLeft1 && (!fLeft2))
  3281. return 1;
  3282. if ((!fLeft1) && fLeft2)
  3283. return -1;
  3284. REAL slope1(0.0);
  3285. REAL slope2(0.0);
  3286. // For vertical edges, we actually store them as +/-INF, and
  3287. // can use the sign to determine the direction.
  3288. if (ptrEdge1->IsVertical())
  3289. {
  3290. // Avoid (inf x 0) which causes a real indefinite.
  3291. if( REALABS(
  3292. ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y -
  3293. ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y
  3294. ) > REAL_EPSILON
  3295. )
  3296. {
  3297. slope1 = SignReal( ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y
  3298. - ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y)
  3299. * FP_INF;
  3300. }
  3301. }
  3302. else
  3303. {
  3304. // Avoid divide by zero.
  3305. if( REALABS(
  3306. ptrCorrector->PathPts[ptrEdge1->OrigEnd].X -
  3307. ptrCorrector->PathPts[ptrEdge1->OrigBegin].X
  3308. ) > REAL_EPSILON
  3309. )
  3310. {
  3311. slope1 = ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y
  3312. - ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y;
  3313. slope1 = slope1 /
  3314. (ptrCorrector->PathPts[ptrEdge1->OrigEnd].X
  3315. - ptrCorrector->PathPts[ptrEdge1->OrigBegin].X);
  3316. }
  3317. }
  3318. if (ptrEdge2->IsVertical())
  3319. {
  3320. // Avoid (inf x 0) which causes a real indefinite.
  3321. if( REALABS(
  3322. ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y -
  3323. ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y
  3324. ) > REAL_EPSILON
  3325. )
  3326. {
  3327. slope2 = SignReal(ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y
  3328. - ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y)
  3329. * FP_INF;
  3330. }
  3331. }
  3332. else
  3333. {
  3334. // Avoid divide by zero.
  3335. if( REALABS(
  3336. ptrCorrector->PathPts[ptrEdge2->OrigEnd].X -
  3337. ptrCorrector->PathPts[ptrEdge2->OrigBegin].X
  3338. ) > REAL_EPSILON
  3339. )
  3340. {
  3341. slope2 = ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y
  3342. - ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y;
  3343. slope2 = slope2 /
  3344. (ptrCorrector->PathPts[ptrEdge2->OrigEnd].X
  3345. - ptrCorrector->PathPts[ptrEdge2->OrigBegin].X);
  3346. }
  3347. }
  3348. if (slope1 < slope2)
  3349. return -1;
  3350. if (slope1 > slope2)
  3351. return 1;
  3352. // slopes are equal
  3353. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y <
  3354. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3355. return -1;
  3356. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y >
  3357. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3358. return 1;
  3359. // (ptrCorrector->PathPts.PGet(ptrEdge1->SortEnd))->Y ==
  3360. // (ptrCorrector->PathPts.PGet(ptrEdge2->SortEnd))->Y
  3361. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X <
  3362. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3363. return -1;
  3364. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X >
  3365. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3366. return 1;
  3367. // Now, all point coordinates are exactly the same, but in some cases,
  3368. // we may have two identical edges with the coordinates, these edges
  3369. // may have different points (actual indecies into points array, not
  3370. // coordinate values). We want to consider them as identical only if
  3371. // the indecies are the same.
  3372. if (ptrEdge1->SortBegin < ptrEdge2->SortBegin)
  3373. return -1;
  3374. if (ptrEdge1->SortBegin > ptrEdge2->SortBegin)
  3375. return 1;
  3376. if (ptrEdge1->SortEnd < ptrEdge2->SortEnd)
  3377. return -1;
  3378. if (ptrEdge1->SortEnd > ptrEdge2->SortEnd)
  3379. return 1;
  3380. return 0;
  3381. }
  3382. /**************************************************************************\
  3383. *
  3384. * Function Description:
  3385. *
  3386. * Compare two lines. Lines are sorted based on the yCur value.
  3387. * If yCur's are identical, lines are sorted based on the begin point.
  3388. *
  3389. * Arguments:
  3390. *
  3391. *
  3392. * Return Value:
  3393. *
  3394. * -1 if ptrEdge1 < ptrEdge2
  3395. * 0 if ther are equal
  3396. * 1 if ptrEdge1 > ptrEdge2
  3397. *
  3398. * Created:
  3399. *
  3400. * 6/15/1999 t-wehunt
  3401. *
  3402. \**************************************************************************/
  3403. INT
  3404. CompareYCurLine(
  3405. PathSelfIntersectRemover *ptrCorrector,
  3406. Edge *ptrEdge1,
  3407. Edge *ptrEdge2
  3408. )
  3409. {
  3410. if (!ptrEdge1->CloseReal(ptrEdge1->YCur, ptrEdge2->YCur))
  3411. {
  3412. if(ptrEdge1->YCur < ptrEdge2->YCur)
  3413. return -1;
  3414. if(ptrEdge1->YCur > ptrEdge2->YCur)
  3415. return 1;
  3416. }
  3417. // We have to sort based on slope.
  3418. REAL slope1(0.0);
  3419. REAL slope2(0.0);
  3420. // For vertical edges, we actually store them as +/-INF, and
  3421. // can use the sign to determine the direction.
  3422. if (ptrEdge1->IsVertical())
  3423. {
  3424. // Avoid INF * 0.
  3425. if( REALABS(
  3426. ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y -
  3427. ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y
  3428. ) > REAL_EPSILON
  3429. )
  3430. {
  3431. slope1 = SignReal(
  3432. ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y -
  3433. ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y ) * FP_INF;
  3434. }
  3435. }
  3436. else
  3437. {
  3438. // Avoid divide by zero.
  3439. if( REALABS(
  3440. ptrCorrector->PathPts[ptrEdge1->OrigEnd].X -
  3441. ptrCorrector->PathPts[ptrEdge1->OrigBegin].X
  3442. ) > REAL_EPSILON
  3443. )
  3444. {
  3445. slope1 = ptrCorrector->PathPts[ptrEdge1->OrigEnd].Y
  3446. - ptrCorrector->PathPts[ptrEdge1->OrigBegin].Y;
  3447. slope1 = slope1 /
  3448. (ptrCorrector->PathPts[ptrEdge1->OrigEnd].X
  3449. - ptrCorrector->PathPts[ptrEdge1->OrigBegin].X);
  3450. }
  3451. }
  3452. if (ptrEdge2->IsVertical())
  3453. {
  3454. // Avoid INF * 0.
  3455. if( REALABS(
  3456. ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y -
  3457. ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y
  3458. ) > REAL_EPSILON
  3459. )
  3460. {
  3461. slope2 = SignReal(
  3462. ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y -
  3463. ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y) * FP_INF;
  3464. }
  3465. }
  3466. else
  3467. {
  3468. // Avoid divide by zero.
  3469. if( REALABS(
  3470. ptrCorrector->PathPts[ptrEdge2->OrigEnd].X -
  3471. ptrCorrector->PathPts[ptrEdge2->OrigBegin].X
  3472. ) > REAL_EPSILON
  3473. )
  3474. {
  3475. slope2 = ptrCorrector->PathPts[ptrEdge2->OrigEnd].Y -
  3476. ptrCorrector->PathPts[ptrEdge2->OrigBegin].Y;
  3477. slope2 = slope2 /
  3478. (ptrCorrector->PathPts[ptrEdge2->OrigEnd].X
  3479. - ptrCorrector->PathPts[ptrEdge2->OrigBegin].X);
  3480. }
  3481. }
  3482. if (slope1 < slope2)
  3483. return -1;
  3484. if (slope1 > slope2)
  3485. return 1;
  3486. // slopes are equal
  3487. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y <
  3488. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3489. return -1;
  3490. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y >
  3491. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3492. return 1;
  3493. // (ptrCorrector->PathPts.PGet(ptrEdge1->SortEnd))->Y ==
  3494. // (ptrCorrector->PathPts.PGet(ptrEdge2->SortEnd))->Y
  3495. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X <
  3496. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3497. return -1;
  3498. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X >
  3499. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3500. return 1;
  3501. // Now, all point coordinates are exactly the same, but in some cases,
  3502. // we may have two identical edges with the coordinates, these edges
  3503. // may have different points (actual indecies into points array, not
  3504. // coordinate values). We want to consider them as identical only if the
  3505. // indecies are the same.
  3506. if (ptrEdge1->SortBegin < ptrEdge2->SortBegin)
  3507. return -1;
  3508. if (ptrEdge1->SortBegin > ptrEdge2->SortBegin)
  3509. return 1;
  3510. if (ptrEdge1->SortEnd < ptrEdge2->SortEnd)
  3511. return -1;
  3512. if (ptrEdge1->SortEnd > ptrEdge2->SortEnd)
  3513. return 1;
  3514. return 0;
  3515. }
  3516. /**************************************************************************\
  3517. *
  3518. * Function Description:
  3519. *
  3520. * Compares lines based on the y coordinate of the end point.
  3521. *
  3522. * Arguments:
  3523. *
  3524. *
  3525. * Return Value:
  3526. *
  3527. *
  3528. * Created:
  3529. *
  3530. * 6/15/1999 t-wehunt
  3531. *
  3532. \**************************************************************************/
  3533. INT
  3534. CompareVertLine(
  3535. PathSelfIntersectRemover *ptrCorrector,
  3536. Edge *ptrEdge1,
  3537. Edge *ptrEdge2
  3538. )
  3539. {
  3540. if(ptrCorrector->PathPts[ptrEdge1->SortEnd].Y <
  3541. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3542. return -1;
  3543. if(ptrCorrector->PathPts[ptrEdge1->SortEnd].Y >
  3544. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3545. return 1;
  3546. if(ptrCorrector->PathPts[ptrEdge1->SortBegin].Y <
  3547. ptrCorrector->PathPts[ptrEdge2->SortBegin].Y)
  3548. return -1;
  3549. if(ptrCorrector->PathPts[ptrEdge1->SortBegin].Y >
  3550. ptrCorrector->PathPts[ptrEdge2->SortBegin].Y)
  3551. return 1;
  3552. // Now, all point coordinates are exactly the same, but in some cases,
  3553. // we may have two identical edges with the coordinates, these edges may
  3554. // have different points (actual indecies into points array, not
  3555. // coordinate values). We want to consider them as identical only if the
  3556. // indecies are the same.
  3557. if (ptrEdge1->SortBegin < ptrEdge2->SortBegin)
  3558. return -1;
  3559. if (ptrEdge1->SortBegin > ptrEdge2->SortBegin)
  3560. return 1;
  3561. if (ptrEdge1->SortEnd < ptrEdge2->SortEnd)
  3562. return -1;
  3563. if (ptrEdge1->SortEnd > ptrEdge2->SortEnd)
  3564. return 1;
  3565. return 0;
  3566. }
  3567. /**************************************************************************\
  3568. *
  3569. * Function Description:
  3570. *
  3571. * Finds the x value of the closest end point (in x) - the next scan line.
  3572. * Depending on the phase of the algorithm, it needs to look at edges in
  3573. * different arrays. The new value is stored in XCur.
  3574. * Returns FALSE if there are no more points to look at - we are done.
  3575. * In this case, XCur is set to longLast.
  3576. *
  3577. * Arguments:
  3578. *
  3579. *
  3580. * Return Value:
  3581. *
  3582. *
  3583. * Created:
  3584. *
  3585. * 6/15/1999 t-wehunt
  3586. *
  3587. \**************************************************************************/
  3588. BOOL PathSelfIntersectRemover::ClosestActive(INT arrayIndex)
  3589. {
  3590. REAL xClosest = 0;
  3591. // We need to find the next X value for the scan line:
  3592. // take the minimum of any end point of active edges and the begin point
  3593. // of the first edge which will be inserted to active edges.
  3594. // Let's first look at the possible new edge
  3595. if (arrayIndex == LIST_END) // no more edges to add
  3596. {
  3597. xClosest = FP_INF;
  3598. }
  3599. else
  3600. {
  3601. xClosest = PathPts[EdgeList[arrayIndex].SortBegin].X;
  3602. }
  3603. INT active = ActiveEdgeList;
  3604. // Now, look at all active edges
  3605. while (active != LIST_END)
  3606. {
  3607. REAL xActive = PathPts[EdgeList[active].SortEnd].X;
  3608. if((xClosest > xActive) &&
  3609. (xActive > XCur) &&
  3610. (!CloseReal(xActive, XCur)))
  3611. {
  3612. xClosest = xActive;
  3613. }
  3614. active = EdgeList[active].Next;
  3615. }
  3616. if (xClosest != FP_INF)
  3617. {
  3618. XCur = xClosest;
  3619. return TRUE;
  3620. }
  3621. else
  3622. {
  3623. return FALSE;
  3624. }
  3625. }
  3626. /**************************************************************************\
  3627. *
  3628. * Function Description:
  3629. *
  3630. * Returns the new path. New path contains of 1 or more subpaths.
  3631. * The subpaths are stored as a list of points and a list of points
  3632. * per polygon.
  3633. *
  3634. * Arguments:
  3635. *
  3636. *
  3637. * Return Value:
  3638. *
  3639. *
  3640. * Created:
  3641. *
  3642. * 6/15/1999 t-wehunt
  3643. *
  3644. \**************************************************************************/
  3645. GpStatus PathSelfIntersectRemover::GetNewPoints(
  3646. DynPointFArray *pts,
  3647. DynIntArray *polyCounts
  3648. )
  3649. {
  3650. GpPointF *pptToCopy = NULL;
  3651. INT iptFirst = 0;
  3652. GpStatus status;
  3653. if (PathPts.GetCount() <= 0)
  3654. {
  3655. return Ok;
  3656. }
  3657. if (PtList.GetCount() <= 0)
  3658. {
  3659. return Ok;
  3660. }
  3661. // Initialize the array which will contain the resulting paths
  3662. // We don't know haw many points we are going to have
  3663. // Guess? TODO!
  3664. if ((status = pts->ReserveSpace(2*PathPts.GetCount()/3)) != Ok)
  3665. {
  3666. return status;
  3667. }
  3668. if ((status = polyCounts->ReserveSpace(2*PathPts.GetCount())) != Ok)
  3669. {
  3670. return status;
  3671. }
  3672. // Collect paths as long as there are unused (outside) points
  3673. INT cptOld = 0;
  3674. INT npt = 0;
  3675. while (!AllPointsUsed(&iptFirst))
  3676. {
  3677. if (!CollectPath(iptFirst))
  3678. {
  3679. return GenericError;
  3680. }
  3681. // How many points do we have in the last path?
  3682. npt = ResultPts.GetCount() - cptOld;
  3683. // Add the point count to the poly array
  3684. if ((status = polyCounts->Add(npt)) != Ok)
  3685. {
  3686. return status;
  3687. }
  3688. // Save the count of points
  3689. cptOld = ResultPts.GetCount();
  3690. }
  3691. pts->ReplaceWith(&ResultPts);
  3692. return Ok;
  3693. }
  3694. /**************************************************************************\
  3695. *
  3696. * Function Description:
  3697. *
  3698. * Return TRUE if all points have been used (added to the resulting paths)
  3699. * or are inside. If returns FALSE, returns the index to the next unused
  3700. * point.
  3701. *
  3702. * Arguments:
  3703. *
  3704. *
  3705. * Return Value:
  3706. *
  3707. *
  3708. * Created:
  3709. *
  3710. * 6/15/1999 t-wehunt
  3711. *
  3712. \**************************************************************************/
  3713. BOOL PathSelfIntersectRemover::AllPointsUsed(INT *piptUnUsed)
  3714. {
  3715. PointListNode *ptNode = NULL;
  3716. INT iptord = 0;
  3717. // TODO: Create a static or a member which would remember the last
  3718. // point returned here, so we don't have to start from the beginning each
  3719. // time
  3720. IntersectsWereRemoved = FALSE;
  3721. while (iptord != -1)
  3722. {
  3723. if (iptord >= PtList.GetCount())
  3724. {
  3725. break;
  3726. }
  3727. ptNode = &PtList[iptord];
  3728. if (!ptNode->Used)
  3729. {
  3730. if (ptNode->Inside)
  3731. {
  3732. IntersectsWereRemoved = TRUE;
  3733. iptord = ptNode->Next;
  3734. }
  3735. else
  3736. {
  3737. *piptUnUsed = iptord;
  3738. return FALSE;
  3739. }
  3740. }
  3741. else
  3742. {
  3743. iptord = ptNode->Next;
  3744. }
  3745. }
  3746. *piptUnUsed = -1;
  3747. return TRUE;
  3748. }
  3749. /**************************************************************************\
  3750. *
  3751. * Function Description:
  3752. *
  3753. * After the process of eliminating edges and marking points as inside
  3754. * and outside, we need to go through the linked list of points and
  3755. * build paths from the edges which are outside. CollectPath will
  3756. * collect one path starting from point with index iptFirst. It
  3757. * returns the actual value of this point in pptFirst.
  3758. * CollectPath doesn't check if iptFirst is marked as Inside or Outside.
  3759. * CollectPath returns FALSE on out of memory.
  3760. *
  3761. * Arguments:
  3762. *
  3763. *
  3764. * Return Value:
  3765. *
  3766. *
  3767. * Created:
  3768. *
  3769. * 6/15/1999 t-wehunt
  3770. *
  3771. \**************************************************************************/
  3772. BOOL PathSelfIntersectRemover::CollectPath(INT iptFirst)
  3773. {
  3774. PointListNode *ptNode = NULL;
  3775. GpPointF *pfpvThis = NULL;
  3776. INT iptord = iptFirst;
  3777. GpPointF fpvFirst(0,0);
  3778. // Copy the first point, it always belongs to the path, we don't check
  3779. // here if it is outside. AllPointsUsed did that.
  3780. if (ResultPts.Add(PathPts[iptFirst]) != Ok)
  3781. {
  3782. return FALSE;
  3783. }
  3784. // Store the point, so we can compare with it
  3785. fpvFirst = PathPts[iptFirst];
  3786. // Get the index of the next point and update the fUsed field for the
  3787. // copied point.
  3788. ptNode = &PtList[iptord];
  3789. ptNode->Used = TRUE;
  3790. iptord = ptNode->Next;
  3791. BOOL fhavePptord = FALSE;
  3792. // The end of a subpath will have the next iptord == -1
  3793. while(iptord != -1)
  3794. {
  3795. if (!fhavePptord)
  3796. {
  3797. ptNode = &PtList[iptord];
  3798. }
  3799. fhavePptord = FALSE;
  3800. if (ptNode->Inside)
  3801. {
  3802. // The edge starting in this point is inside, but the
  3803. // point itself isn't.
  3804. // If it is the closing point (the same as the first one)
  3805. // return the collected subpath.
  3806. pfpvThis = &PathPts[iptord];
  3807. if (ClosePt(*pfpvThis, fpvFirst))
  3808. {
  3809. ptNode->Used = TRUE;
  3810. return TRUE;
  3811. }
  3812. // If the point is not the same as the first one and we have
  3813. // already been here, something is wrong
  3814. if (ptNode->Used)
  3815. {
  3816. WARNING(("We have an infinite loop"));
  3817. iptord = -1;
  3818. return FALSE;
  3819. }
  3820. else
  3821. {
  3822. //This is the beginning of an inside edge, our path changes.
  3823. //Let's get the duplicate point
  3824. INT oldiptord = iptord;
  3825. ptNode->Used = TRUE;
  3826. iptord = ptNode->Dup;
  3827. if (iptord >= 0)
  3828. {
  3829. ptNode = &PtList[iptord];
  3830. }
  3831. else
  3832. {
  3833. WARNING(("Dup is negative (1)"));
  3834. return FALSE;
  3835. }
  3836. while (ptNode->Inside || ptNode->Used)
  3837. {
  3838. iptord = ptNode->Dup;
  3839. if (iptord == oldiptord)
  3840. {
  3841. WARNING(("Loop, cannot find a duplicate"));
  3842. return FALSE;
  3843. }
  3844. else if (iptord >= 0)
  3845. {
  3846. ptNode = &PtList[iptord];
  3847. }
  3848. else
  3849. {
  3850. WARNING(("Dup is negative (2)"));
  3851. return FALSE;
  3852. }
  3853. }
  3854. fhavePptord = TRUE;
  3855. }
  3856. }
  3857. else
  3858. {
  3859. // The point is outside
  3860. if (ptNode->Used)
  3861. {
  3862. //This may be a longer list of dups, keep looking
  3863. INT oldiptord2 = iptord;
  3864. ptNode->Used = TRUE;
  3865. iptord = ptNode->Dup;
  3866. if (iptord >= 0)
  3867. {
  3868. ptNode = &PtList[iptord];
  3869. }
  3870. else
  3871. {
  3872. WARNING(("Dup is negative (3)"));
  3873. return FALSE;
  3874. }
  3875. while (ptNode->Inside || ptNode->Used)
  3876. {
  3877. iptord = ptNode->Dup;
  3878. if (iptord == oldiptord2)
  3879. {
  3880. WARNING(("Loop, cannot find a duplicate (2)"));
  3881. return FALSE;
  3882. }
  3883. else if (iptord >= 0)
  3884. {
  3885. ptNode = &PtList[iptord];
  3886. }
  3887. else
  3888. {
  3889. WARNING(("Dup is negative (4)"));
  3890. return FALSE;
  3891. }
  3892. }
  3893. fhavePptord = TRUE;
  3894. }
  3895. else
  3896. {
  3897. //New point, everything is OK
  3898. if (ResultPts.Add(PathPts[iptord]) != Ok)
  3899. {
  3900. WARNING(("Could not append to array"));
  3901. return FALSE;
  3902. }
  3903. ptNode->Used = TRUE;
  3904. iptord = ptNode->Next;
  3905. }
  3906. }
  3907. }
  3908. return TRUE;
  3909. }
  3910. /**************************************************************************\
  3911. *
  3912. * Function Description:
  3913. *
  3914. * Function used to compare lines when we sort them by x coordinate of the
  3915. * Begin point (SortBegin - smaller x).
  3916. *
  3917. * Arguments:
  3918. *
  3919. *
  3920. * Return Value:
  3921. *
  3922. *
  3923. * Created:
  3924. *
  3925. * 6/15/1999 t-wehunt
  3926. *
  3927. \**************************************************************************/
  3928. INT CompareLine(
  3929. PathSelfIntersectRemover *ptrCorrector,
  3930. Edge *ptrEdge1,
  3931. Edge *ptrEdge2
  3932. )
  3933. {
  3934. //PGet on edges
  3935. if (ptrCorrector->PathPts[ptrEdge1->SortBegin].X <
  3936. ptrCorrector->PathPts[ptrEdge2->SortBegin].X)
  3937. return -1;
  3938. if (ptrCorrector->PathPts[ptrEdge1->SortBegin].X >
  3939. ptrCorrector->PathPts[ptrEdge2->SortBegin].X)
  3940. return 1;
  3941. if (ptrCorrector->PathPts[ptrEdge1->SortBegin].Y <
  3942. ptrCorrector->PathPts[ptrEdge2->SortBegin].Y)
  3943. return -1;
  3944. if (ptrCorrector->PathPts[ptrEdge1->SortBegin].Y >
  3945. ptrCorrector->PathPts[ptrEdge2->SortBegin].Y)
  3946. return 1;
  3947. // Begin points must be exactly the same
  3948. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X <
  3949. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3950. return -1;
  3951. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].X >
  3952. ptrCorrector->PathPts[ptrEdge2->SortEnd].X)
  3953. return 1;
  3954. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y <
  3955. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3956. return -1;
  3957. if (ptrCorrector->PathPts[ptrEdge1->SortEnd].Y >
  3958. ptrCorrector->PathPts[ptrEdge2->SortEnd].Y)
  3959. return 1;
  3960. // Now, all point coordinates are exactly the same, but in some cases,
  3961. // we may have two identical edges with the coordinates, these edges
  3962. // may have different points (actual indecies into points array, not
  3963. // coordinate values). We want to consider them as identical only if the
  3964. // indecies are the same.
  3965. if (ptrEdge1->SortBegin < ptrEdge2->SortBegin)
  3966. return -1;
  3967. if (ptrEdge1->SortBegin > ptrEdge2->SortBegin)
  3968. return 1;
  3969. if (ptrEdge1->SortEnd < ptrEdge2->SortEnd)
  3970. return -1;
  3971. if (ptrEdge1->SortEnd > ptrEdge2->SortEnd)
  3972. return 1;
  3973. return 0;
  3974. }