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.

665 lines
24 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Path Self Intersection Remover.
  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. #ifndef _PATH_INTERSECT_REMOVER_H
  34. #define _PATH_INTERSECT_REMOVER_H
  35. extern REAL FP_INF;
  36. // Forward declarations
  37. class PathSelfIntersectRemover;
  38. class Edge;
  39. // Comparison function for DynSortArray
  40. typedef INT (*DynSortArrayCompareFunc)(
  41. PathSelfIntersectRemover*,
  42. Edge*,
  43. Edge*
  44. );
  45. /*****************************************************************************
  46. Subtract two points
  47. *****************************************************************************/
  48. inline GpPointF SubtractPoint(const GpPointF &pt1, const GpPointF &pt2)
  49. {
  50. return GpPointF(pt1.X-pt2.X,pt1.Y-pt2.Y);
  51. }
  52. #ifdef USE_OBSOLETE_DYNSORTARRAY
  53. /*****************************************************************************
  54. DynSortArray
  55. Contains a new method that will perform a sorted insertion into the (already
  56. sorted) array.
  57. *****************************************************************************/
  58. //
  59. // NOTE: This class should be avoided by all performance critical code.
  60. // The InsertAt method is O(n) and very easily leads to O(n^3) insert
  61. // sorting algorithms.
  62. //
  63. template <class T>
  64. class DynSortArray : public DynArray<T>
  65. {
  66. public:
  67. // Add a new element to the array at position index.
  68. // index'th element moves index + 1.
  69. // CAUTION! could cause a big performance hit if the array is large!
  70. GpStatus InsertAt(INT index, const T& newItem)
  71. {
  72. return DynArrayImpl::AddMultipleAt(sizeof(T), index, 1, &newItem);
  73. }
  74. // Insert multiple items starting at index'th element.
  75. // index'th element moves index + n, etc...
  76. // CAUTION! could cause a big performance hit if the array is large!
  77. GpStatus AddMultipleAt(INT index, const T* newItems, INT n)
  78. {
  79. return DynArrayImpl::AddMultipleAt(sizeof(T), index, n, newItems);
  80. }
  81. // Another variation of AddMultipleAt above.
  82. //
  83. // In this case, the data for the new elements are
  84. // not available. Instead, we'll do the following:
  85. // (1) shift the old data over just as AddMultipleAt
  86. // (2) reserve the space for additional elements
  87. // (3) increase the Count by the number of additional elements
  88. // (4) return a pointer to the first new elements
  89. // CAUTION! could cause a big performance hit if the array is large!
  90. T *AddMultipleAt(INT index, INT n)
  91. {
  92. return static_cast<T *>(DynArrayImpl::AddMultipleAt(sizeof(T), index, n));
  93. }
  94. // Deletes n items from the array starting at the index'th position.
  95. // CAUTION! could cause a big performance hit if the array is large!
  96. GpStatus DeleteMultipleAt(INT index, INT n)
  97. {
  98. return DynArrayImpl::DeleteMultipleAt(sizeof(T), index, n);
  99. }
  100. // Deletes one item from the array at the index'th position.
  101. // CAUTION! could cause a big performance hit if the array is large!
  102. GpStatus DeleteAt(INT index)
  103. {
  104. return DynArrayImpl::DeleteMultipleAt(sizeof(T), index, 1);
  105. }
  106. GpStatus InsertSorted(
  107. T &newItem,
  108. DynSortArrayCompareFunc compareFunc,
  109. VOID *userData
  110. );
  111. };
  112. #endif
  113. /*****************************************************************************
  114. Edge
  115. Edge represents an edge of a polygon. It stores its end points
  116. as indices to the array of points.
  117. *****************************************************************************/
  118. // represents the terminator of the list.
  119. #define LIST_END -1
  120. class Edge
  121. {
  122. private:
  123. PathSelfIntersectRemover *Parent;
  124. Edge() {}
  125. public:
  126. BOOL CloseReal(const REAL val1, const REAL val2);
  127. VOID SetParent(PathSelfIntersectRemover *aParent)
  128. {
  129. Parent = aParent;
  130. }
  131. Edge(PathSelfIntersectRemover *aParent)
  132. {
  133. SetParent(aParent);
  134. }
  135. // Next pointer. This is an index into the array for the next element
  136. // in the Edge list. -1 indicates NULL.
  137. INT Next;
  138. // Begin and End are the indecies to the array of points. The edge
  139. // has a direction, which is important when we determine winding numbers.
  140. // Edge goes from Begin to End.
  141. INT Begin;
  142. INT End;
  143. // When we look for intersections of edges, we need to sort them based on
  144. // the smallest x, therefore we want to store the edge, so that SortBegin
  145. // refers always to the "smaller" end point of this edge.
  146. INT SortBegin;
  147. INT SortEnd;
  148. // This is the y value at which the edge is currently crossed by a
  149. // scan line
  150. REAL YCur;
  151. // Original slope of the edge. We want to keep it around even if the
  152. // is broken up into small pieces and the end points change.
  153. // We store the slope as the original begin and end points.
  154. INT OrigBegin;
  155. INT OrigEnd;
  156. // Normalize the edge - ie. update SortBegin and SortEnd.
  157. VOID Normalize();
  158. // Return TRUE if the edge is vertical.
  159. BOOL IsVertical();
  160. VOID MarkOutside();
  161. };
  162. /*****************************************************************************
  163. EdgeArray
  164. Array of line segments.
  165. *****************************************************************************/
  166. typedef DynSortArray<Edge> EdgeArray;
  167. /*****************************************************************************
  168. PointListNode
  169. Structure used to maintain the order of points and some additional
  170. information about them. It is used to create a linked list in an array and
  171. then to construct final paths.
  172. Notice the designation List for this structure instead of array.
  173. *****************************************************************************/
  174. struct PointListNode
  175. {
  176. INT Prev; // Previous record
  177. INT Next; // Next record
  178. // Duplicate point - For example, if two edges intersect and they are
  179. // broken up, there are two points needed in order to maintain the
  180. // correct edge directions for the path. These two points are identical,
  181. // so we will call them duplicates. Each of them stores an index to the
  182. // other one. Note that it doesn't mean that allpoints with the same
  183. // x and y values are duplicates. This is only 1-1 correspondence for
  184. // points created from intersections.
  185. INT Dup;
  186. // Is this point inside or outside. Actually, this applies to the edge
  187. // coming out of this point.
  188. BOOL Inside;
  189. // Has this point been consumed during the final creation of resulting
  190. // paths. Initially set to FALSE and changed to TRUE when the point is
  191. // copied to the resulting array.
  192. BOOL Used;
  193. };
  194. /*****************************************************************************
  195. PathSelfIntersectRemover
  196. Path Self Intersection Remover Class.
  197. It is given input polygons and returns polygons with all self intersections
  198. removed. The number of returned polygons can be 1, 2 or more.
  199. See comments for the methods for more details on input and output arguments.
  200. API:
  201. Init(estimatedNumPts);
  202. AddPolygon(pathPts, numPts);
  203. RemoveSelfIntersects();
  204. GetNewPoints(newPts, polyCounts, numPolys, numTotalPts);
  205. *****************************************************************************/
  206. class PathSelfIntersectRemover
  207. {
  208. public:
  209. PathSelfIntersectRemover() :
  210. NumPts(0),
  211. PathPts(),
  212. PtList(),
  213. ActiveVertEdges(),
  214. ResultPts(),
  215. CanAddPts(TRUE),
  216. AddToActive1(NULL),
  217. AddToActive2(NULL),
  218. AddToActive3(NULL)
  219. {
  220. AddToActive1.SetParent(this);
  221. AddToActive2.SetParent(this);
  222. AddToActive3.SetParent(this);
  223. IntersectsWereRemoved = FALSE;
  224. }
  225. ~PathSelfIntersectRemover() {}
  226. // Initialize PathSelfIntersectRemover for the given number of points,
  227. // numPts. numPts can be an approximate number of points that will be
  228. // added to the PathSelfIntersectRemover class for correction. Init
  229. // allocates memory for DynArrays.
  230. GpStatus Init(INT numPts);
  231. // Add one polygon to the class.
  232. GpStatus AddPolygon(const GpPointF *ptrPt, INT numPtsToAdd);
  233. // Correct the path.
  234. GpStatus RemoveSelfIntersects();
  235. // Returns the new path. New path contains of 1 or more subpaths
  236. // The subpaths are stored as a list of points and a list of points
  237. // per polygon.
  238. GpStatus GetNewPoints(DynPointFArray *pts, DynIntArray *polyCounts);
  239. BOOL PathWasModified() {return IntersectsWereRemoved;}
  240. private:
  241. // QuickSort a list of edges from First (F) to Last (L) inclusive.
  242. // This function uses the CompareLine comparison function to determine
  243. // the ordering.
  244. void QuickSortEdges(Edge *F, Edge *L);
  245. // This function moves edges from the list pointed to by pInactiveIndex
  246. // into the list pointed to by pActiveIndex. The sort order for the Active
  247. // list is determined by the 'compare' function. Edges are selected from the
  248. // Inactive list based on xCurrent.
  249. void InsertNewEdges(
  250. INT *pActiveIndex, // IN/OUT
  251. INT *pInactiveIndex, // IN/OUT
  252. REAL xCurrent,
  253. DynSortArrayCompareFunc compare
  254. );
  255. // Delete Edge at index from the list pointed to by pListHead. The edge is
  256. // orphaned (Next points to LIST_END). This function returns false if
  257. // index is not present in the list.
  258. bool DeleteEdgeFromList(INT *pListHead, INT index);
  259. // Insert Edge at index into the list pointed to by pListHead. The sort
  260. // order is determined by the 'compare' function. The index'th element
  261. // must be an orphan (not a member of any list) - this
  262. // function ASSERTs this condition.
  263. void InsertEdgeIntoList(
  264. INT *pListHead,
  265. INT index,
  266. DynSortArrayCompareFunc compare
  267. );
  268. // Remove edges from active edge array.
  269. void ClearActiveListExclusiveX();
  270. void ClearActiveListInclusiveX();
  271. GpPointF *GetInactivePoint(INT *pInactiveIndex, bool begin);
  272. // Return true if two numbers are very close. This depends on the size
  273. // of the largest number to be compared, which is set in InsertPoints().
  274. // If no points are inserted, the comparison defaults to using REAL_EPSILON
  275. inline BOOL CloseReal(const REAL val1, const REAL val2)
  276. {
  277. return (REALABS(val1-val2) < REAL_EPSILON);
  278. }
  279. // Return true if two points are very close
  280. inline BOOL ClosePt(const GpPointF &pt1, const GpPointF &pt2)
  281. {
  282. return (CloseReal(pt1.X, pt2.X) &&
  283. CloseReal(pt1.Y, pt2.Y));
  284. }
  285. // Find all intersections between all line segments. Returns FALSE if
  286. // out of memory
  287. BOOL FindIntersects();
  288. // TODO: Since we have a different function for each phase, we don't need
  289. // plntFrom any more in both of these methods
  290. // Add new edges, which are active for the new scan line (x value stored
  291. // in xCur. ptrFrom - array to get the edges.
  292. // Returns FALSE on out of memory.
  293. void AddActiveForX(INT *inactiveHead);
  294. // Update duplicate points: the two points overlap, connect their lists
  295. // of duplicates.
  296. VOID UpdateDups(INT pt1, INT pt2);
  297. BOOL IsLinked(INT loop, INT inew);
  298. // Add new edges, which are active for the new scan line (x value stored
  299. // in xCur. This one is used in the second phase only.
  300. // Returns FALSE on out of memory.
  301. void AddActiveForXScan(INT *inactiveHead);
  302. // Find all intersections for the current X value. Intersection points
  303. // will be inserted into the Edges array and information about their
  304. // order into PtList.
  305. // Returns FALSE on out of memory.
  306. BOOL FindIntersectsForX();
  307. // Calculate new current y values for edges in the active edge array.
  308. // For vertical edges, it will pick the maximum y.
  309. VOID RecalcActiveYCur();
  310. // Eliminate edges/points which are inside. In other words, performes
  311. // a line sweep algorithm (similar to scan conversion) and calculates
  312. // winding number on both sides of every edge. If the winding is 0
  313. // (outside the path) on any sides of the edge, the edge is marked as
  314. // an outside edge. All other edges are marked as inside. Edges are
  315. // marked through their begin point in array PtList.
  316. // Returns FALSE on out of memory.
  317. BOOL EliminatePoints(VOID);
  318. // Finds the x value of the closest end point (in x) - the next scan line.
  319. // Depending on the phase of the algorithm, it needs to look at edges in
  320. // different arrays. The new value is stored in xCur.
  321. // Returns FALSE if there are no more points to look at - we are done.
  322. BOOL ClosestActive(INT arrayIndex);
  323. // Scan through all active edges during the phase of edge elimination.
  324. // Calculates winding number to the left and to the right of the current
  325. // x value - xCur. Whenever finds an edge wich has 0 on one side, marks
  326. // it as an outside edge.
  327. BOOL ScanActive();
  328. // Breaks edge ptrEdge. We have found intersection point intersectPt, which is
  329. // guranteed to be somewhere on the line segment (not an end point).
  330. // The 'left' part of the edge will either remain in the active edges
  331. // or will be removed (only if the intersection point has the current
  332. // x value. In the latter case, the right edge segment will need to be
  333. // inserted to active edges, otherwise (the former case) it will go
  334. // to Pass1Edges. If it needs to go to active edges, Breakedge cannot
  335. // insert it because it would disrupt the order of edges there before
  336. // both edges broken up are handled. The caller would have to handle
  337. // the insertion in such case. Therefore, we return the new line
  338. // segment newEdge and a BOOL value specifying if the caller has to
  339. // insert the newEdge edge.
  340. // dupIndex is the index of the duplicate point created by this
  341. // intersection:
  342. // When two edges intersect, we have to insert two points (identical)
  343. // to maintain the same shape of the polygon. These two points are
  344. // called duplicates.
  345. // Return FALSE on out of memory.
  346. BOOL BreakEdge(
  347. Edge *ptrEdge,
  348. GpPointF *intersectPt,
  349. Edge *newEdge,
  350. INT dupIndex
  351. );
  352. BOOL BreakEdgeIn3(
  353. Edge *ptrEdge,
  354. GpPointF *ptrPt1,
  355. GpPointF *ptrPt2,
  356. Edge *ptrNew1,
  357. Edge *ptrNew2,
  358. INT dupIndex1,
  359. INT dupIndex2
  360. );
  361. // Insert numEdges edges joining points stored in array Edges. First
  362. // point has index firstIndex. There must be numEdges+1 points to
  363. // create numEdges edges.
  364. GpStatus InsertEdges(INT firstIndex, INT numEdges);
  365. // Insert points information to relevant arrays.
  366. GpStatus InsertPoints(const GpPointF *pts, INT numPts);
  367. // Returns TRUE if lines ptrEdge1 and ptrEdge2 overlap.
  368. // There are 4 ways in which edges can overlap and depending on the
  369. // case, either none, one or both edges need to be broken up. In some
  370. // cases one edge may need to broken into 3 pieces.
  371. // Return values:
  372. // split1 - set to TRUE if ptrEdge1 needs to be split
  373. // split2 - set to TRUE if ptrEdge2 needs to be split
  374. // split3 - set to TRUE if an edge needs to be broken into 3 pieces
  375. // intersect1 - intersection point (where edge needs to be split)
  376. // intersect2 - second point (if edge needs to be broken in 3 pieces or
  377. // for the second edge if both edges need to broken up)
  378. // dupIndex1 - index of the duplicate point to intersect1,
  379. // dupIndex2 - index of the duplicate point to intersect2,
  380. BOOL Overlap(
  381. Edge *ptrEdge1,
  382. Edge *ptrEdge2,
  383. GpPointF *intersect1,
  384. GpPointF *intersect2,
  385. BOOL *split1,
  386. BOOL *split2,
  387. BOOL *split3,
  388. INT *dupIndex1,
  389. INT *dupIndex2
  390. );
  391. // Method to find the intersection point between edges
  392. // ptrEdge1 and ptrEdge2.
  393. // Returns one of the following values:
  394. // DONOT_INTERS
  395. // COMMON_POINT
  396. // INTERSECT
  397. // COLINEAR
  398. // If the return value == INTERSECT, intersectPt contains the point of
  399. // intersection.
  400. INT IntersectEdge(Edge *ptrEdge1, Edge *ptrEdge2, GpPointF *intersectPt);
  401. // IsTIntersection returns TRUE if the intersection point intersectPt is
  402. // the same as an end point of one of the edges ptrEdge1 and ptrEdge2.
  403. // If it is, splitFirst will be TRUE if the first edge needs to be broken
  404. // up (intersectPt is an end point of ptrEdge2), FALSE if the second one
  405. // needs to be broken up. intersectIndex contains the index of the end
  406. // point which is the same as the intersection point.
  407. BOOL IsTIntersection(
  408. Edge *ptrEdge1,
  409. Edge *ptrEdge2,
  410. GpPointF *intersectPt,
  411. BOOL *splitFirst,
  412. INT *intersectIndex
  413. );
  414. // Returns TRUE if the two lines ptrEdge1 and ptrEdge2 share a common
  415. // end point. If they do, commonPt will contain this point.
  416. BOOL IsCommonPt(Edge *ptrEdge1, Edge *ptrEdge2, GpPointF *commonPt);
  417. // After the process of eliminating edges and marking points as inside
  418. // and outside, we need to go through the linked list of points and
  419. // build paths from the edges which are outside. CollectPath will
  420. // collect one path starting from point with index firstIndex.
  421. // CollectPath doesn't check if firstIndex is marked as Inside or Outside.
  422. // CollectPath returns FALSE on out of memory
  423. BOOL CollectPath(INT firstIndex);
  424. // Return TRUE if all points have been used (added to the resulting paths)
  425. // or are inside. If returns FALSE, returns the index to the next unused
  426. // point
  427. BOOL AllPointsUsed(INT *nextUnusedPt);
  428. // Marks vertical edges as oustide.
  429. VOID MarkVertOutside();
  430. // Remove all vertical edges from the vertical edge array, which do not
  431. // overlap with the give y value
  432. VOID RemoveVert(REAL y, BOOL inclusive);
  433. VOID RemoveVertAll();
  434. // Returns TRUE if edge ptrEdge doesn't belong to the y interval of edges
  435. // stored in ActiveVertEdges.
  436. BOOL NewInterval(Edge *ptrEdge);
  437. // Delete edges from the active edge table; Indecies of edges to delete
  438. // are stored in EdgeToDelete1..3. Deletes the highest index edge first.
  439. // Returns NULL if fails due to out of memory error.
  440. BOOL DeleteEdges();
  441. // Add new edges to the active edge table. The edges are stored in
  442. // AddToActive1..3. FlgAdd1..3 specify if the given edge needs to
  443. // be added or not. Returns if fails due to out of memory.
  444. BOOL AddNewEdges();
  445. // Store the edge in PathSelfIntersectRemover for now, so that it can be later added
  446. // to active edges. Copies the edge, so ptrEdge doesn't need to be kept
  447. // after this method returns.
  448. VOID MarkToAdd(Edge *ptrEdge);
  449. // Store the edge index for later deletion
  450. VOID MarkToDelete(INT index);
  451. friend INT CompareYCurLine(
  452. PathSelfIntersectRemover *ptrCorrector,
  453. Edge *ptrEdge1,
  454. Edge *ptrEdge2
  455. );
  456. friend INT
  457. CompareYScanCurLine(
  458. PathSelfIntersectRemover *ptrCorrector,
  459. Edge *ptrEdge1,
  460. Edge *ptrEdge2
  461. );
  462. friend INT CompareLine(
  463. PathSelfIntersectRemover *ptrCorrector,
  464. Edge *ptrEdge1,
  465. Edge *ptrEdge2);
  466. friend INT CompareVertLine(
  467. PathSelfIntersectRemover *ptrCorrector,
  468. Edge *ptrEdge1,
  469. Edge *ptrEdge2
  470. );
  471. friend Edge;
  472. INT NumPts; // Total #of points stored for corrections
  473. REAL XCur; // Current x value for the scan line
  474. DynArray<GpPointF> PathPts; // array of points
  475. DynArray<GpPointF> ResultPts; // array of points for the resulting paths
  476. DynArray<PointListNode> PtList; // array with order information for points
  477. DynArray<Edge> EdgeList; // List holding all the edges.
  478. INT ActiveEdgeList; // Head index for the Active Edges
  479. INT InactiveEdgeList; // Head index for the inactive edges
  480. EdgeArray ActiveVertEdges; //array with active vertical edges
  481. Edge AddToActive1; //lines which will need to be added to Active edges
  482. Edge AddToActive2; //these lines are created when edges are broken up
  483. Edge AddToActive3; //
  484. BOOL FlgAdd1; //flags specifying which of the above three lines
  485. BOOL FlgAdd2; //need to be active
  486. BOOL FlgAdd3; //
  487. INT EdgesToDelete1;//indices of edges, which need to be deleted
  488. INT EdgesToDelete2;//from active, -1 for all three values means
  489. INT EdgesToDelete3;//that there are no edges to delete
  490. BOOL CanAddPts; // Can we still add new points to the class,
  491. // We can't after the correction process has started
  492. BOOL IntersectsWereRemoved;
  493. };
  494. /*****************************************************************************
  495. Comparison functions used for array sorting.
  496. *****************************************************************************/
  497. /*---------------------------------------------------------------------------
  498. Function used to compare lines when we sort them by x coordinate of the
  499. Begin point (SortBegin - smaller x).
  500. -------------------------------------------------------------KasiaK---------*/
  501. INT CompareLine(
  502. PathSelfIntersectRemover *ptrCorrector,
  503. Edge *ptrEdge1,
  504. Edge *ptrEdge2
  505. );
  506. /*---------------------------------------------------------------------------
  507. Function used to compare vertical lines when we scan them.
  508. -------------------------------------------------------------KasiaK---------*/
  509. INT CompareVertLine(
  510. PathSelfIntersectRemover *ptrCorrector,
  511. Edge *ptrEdge1,
  512. Edge *ptrEdge2
  513. );
  514. /*---------------------------------------------------------------------------
  515. Function used to sort edges by current y value when we scan them in order to
  516. find all intersections of line segments. If y's are the same, sorts based
  517. on slopes.
  518. -------------------------------------------------------------KasiaK---------*/
  519. INT CompareYCurLine(
  520. PathSelfIntersectRemover *ptrCorrector,
  521. Edge *ptrEdge1,
  522. Edge *ptrEdge2
  523. );
  524. /*---------------------------------------------------------------------------
  525. Same as CompareYCurLine, but if y-'s are the same, pots left edges before
  526. right ones before looking at slopes.
  527. -------------------------------------------------------------KasiaK---------*/
  528. INT CompareYScanCurLine(
  529. PathSelfIntersectRemover *ptrCorrector,
  530. Edge *ptrEdge1,
  531. Edge *ptrEdge2
  532. );
  533. #endif