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.

594 lines
16 KiB

  1. /**************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Geometry: Some 2D geometry helper routines.
  8. *
  9. * Created:
  10. *
  11. * 08/26/2000 asecchia
  12. * Created it.
  13. *
  14. **************************************************************************/
  15. #include "precomp.hpp"
  16. /**************************************************************************\
  17. *
  18. * Function Description:
  19. *
  20. * intersect_circle_line
  21. *
  22. * Intersection of a circle and a line specified by two points.
  23. *
  24. * This algorithm is adapted from the geometric line-sphere intersection
  25. * algorithm by Eric Haines in "An Introduction to Ray Tracing" pp39 edited
  26. * by Andrew S Glassner.
  27. *
  28. * Note: This routine only returns positive intersections.
  29. *
  30. * Arguments:
  31. *
  32. * const GpPointF &C, // center
  33. * const REAL radius2, // radius * radius (i.e. squared)
  34. * const GpPointF &P0, // line first point (origin)
  35. * const GpPointF &P1, // line last point (end)
  36. * GpPointF &intersection // return intersection point.
  37. *
  38. *
  39. * Return Value:
  40. * 0 - no intersection
  41. * 1 - intersection.
  42. *
  43. * 08/25/2000 [asecchia]
  44. * Created it
  45. *
  46. \**************************************************************************/
  47. INT intersect_circle_line(
  48. IN const GpPointF &C, // center
  49. IN REAL radius2, // radius * radius (i.e. squared)
  50. IN const GpPointF &P0, // line first point (origin)
  51. IN const GpPointF &P1, // line last point (end)
  52. OUT GpPointF *intersection // return intersection point.
  53. )
  54. {
  55. GpPointF vI = P1-P0; // Vector Line equation P0 + t*vI
  56. // Normalize vI
  57. double length = sqrt(dot_product(vI, vI));
  58. if(length < REAL_EPSILON)
  59. {
  60. return 0; // no intersection for degenerate points.
  61. }
  62. double lv = 1.0/length;
  63. vI.X *= (REAL)lv;
  64. vI.Y *= (REAL)lv;
  65. GpPointF vOC = C-P0; // Vector from line origin to circle center
  66. double L2oc = dot_product(vOC, vOC);
  67. // Distance to closest approach to circle center.
  68. double tca = dot_product(vOC, vI);
  69. // Trivial rejection.
  70. if(tca < REAL_EPSILON &&
  71. L2oc >= radius2)
  72. {
  73. return 0; // missed.
  74. }
  75. // Half chord distance squared.
  76. double t2hc = radius2 - L2oc + tca*tca;
  77. // Trivial rejection.
  78. if(t2hc < REAL_EPSILON) {
  79. return 0; // missed.
  80. }
  81. t2hc = sqrt(t2hc);
  82. double t;
  83. if(L2oc >= radius2)
  84. {
  85. t = tca-t2hc;
  86. if(t > REAL_EPSILON)
  87. {
  88. if(t>=0.0)
  89. {
  90. // hit the circle.
  91. *intersection = vI;
  92. intersection->X *= (REAL)t;
  93. intersection->Y *= (REAL)t;
  94. *intersection = *intersection+P0;
  95. return 1;
  96. }
  97. }
  98. }
  99. t = tca+t2hc;
  100. if(t > REAL_EPSILON)
  101. {
  102. if(t>=0.0)
  103. {
  104. // hit the circle.
  105. *intersection = vI;
  106. intersection->X *= (REAL)t;
  107. intersection->Y *= (REAL)t;
  108. *intersection = *intersection+P0;
  109. return 1;
  110. }
  111. }
  112. return 0; // missed.
  113. }
  114. /**************************************************************************\
  115. *
  116. * Function Description:
  117. *
  118. * intersect_line_yaxis
  119. *
  120. * Return the intersection of a line specified by p0-p1 along the
  121. * y axis. Returns FALSE if p0-p1 is parallel to the yaxis.
  122. *
  123. * Intersection is defined as between p0 and p1 (inclusive). Any
  124. * intersection point along the line outside of p0 and p1 is ignored.
  125. *
  126. * Arguments:
  127. *
  128. * IN const GpPointF &p0, first point.
  129. * IN const GpPointF &p1, second point.
  130. * OUT REAL *length Length along the y axis from zero.
  131. *
  132. * Return Value:
  133. * 0 - no intersection
  134. * 1 - intersection.
  135. *
  136. * 08/25/2000 [asecchia]
  137. * Created it
  138. *
  139. \**************************************************************************/
  140. BOOL intersect_line_yaxis(
  141. IN const GpPointF &p0,
  142. IN const GpPointF &p1,
  143. OUT REAL *length
  144. )
  145. {
  146. // using vector notation: Line == p0+t(p1-p0)
  147. GpPointF V = p1-p0;
  148. // Check if the line is parallel to the y-axis.
  149. if( REALABS(V.X) < REAL_EPSILON )
  150. {
  151. return (FALSE);
  152. }
  153. // y-axis intersection: p0.X + t V.X = 0
  154. REAL t = -p0.X/V.X;
  155. // Check to see that t is between 0 and 1
  156. if( (t < -REAL_EPSILON) ||
  157. (t-1.0f > REAL_EPSILON) )
  158. {
  159. return (FALSE);
  160. }
  161. // Compute the actual length along the y-axis.
  162. *length = p0.Y + V.Y * t;
  163. return (TRUE);
  164. }
  165. /**************************************************************************\
  166. *
  167. * Function Description:
  168. *
  169. * IntersectLines
  170. *
  171. * Returns the intersection between two lines specified by their end points.
  172. *
  173. * The intersection point is returned in intersectionPoint and the
  174. * parametric distance along each line is also returned.
  175. *
  176. * line1Length ranges between [0, 1] for the first line
  177. * if line1Length is outside of [0, 1] it means that the intersection
  178. * extended the line.
  179. * line2Length ranges between [0, 1] for the second line
  180. * if r is outside of [0, 1] it means that the intersection extended the line.
  181. *
  182. * Note:
  183. *
  184. * Because we use the vector formulation of the line intersection, there
  185. * is none of that icky mucking about with vertical line infinities, etc.
  186. * The only special case we need to consider is the (almost) zero length
  187. * line - and that's considered to miss everything.
  188. *
  189. * Derivation:
  190. *
  191. * for the derivation below
  192. * p1 == line1End
  193. * p0 == line1Start
  194. * r1 == line2End
  195. * r0 == line2Start
  196. *
  197. * V = p1-p0
  198. * W = r1-r0
  199. *
  200. * The vector formulation of the two line equations
  201. * p0 + tV and r0 + rW
  202. *
  203. * The intersection point is derived as follows:
  204. * Set the two line equations equal to each other
  205. *
  206. * p0 + tV = r0 + rW
  207. *
  208. * Expand by coordinates to reflect the fact that the vector equation is
  209. * actually two simultaneous linear equations.
  210. *
  211. * <=> (1) p0.x + tV.x = r0.x + rW.x
  212. * (2) p0.y + tV.y = r0.y + rW.y
  213. *
  214. * <=> p0.x-r0.x V.x
  215. * (3) --------- + t --- = r
  216. * W.x W.x
  217. *
  218. * p0.y-r0.y V.y
  219. * (4) --------- + t --- = r
  220. * W.y W.y
  221. *
  222. * <=> W.y(p0.x-r0.x) - W.x(p0.y-r0.y) = t(W.x V.y - V.x W.y) [subst 3, 4]
  223. *
  224. * Setting N.x = -W.y and N.y = W.x (N is normal to W)
  225. *
  226. * <=> - N.x(p0.x-r0.x) - N.y(p0.y-r0.y) = t(N.y V.y + N.x V.x)
  227. * <=> - N.(p0-r0) = t(N.V) [rewrite as vectors]
  228. * <=> t = -N.(p0-r0)/(N.V)
  229. *
  230. * r0 + rW = I
  231. * <=> rW = I - r0
  232. * <=> r = (I.x - r0.x)/W.x or (I.y - r0.y)/W.y
  233. *
  234. *
  235. * Arguments:
  236. *
  237. * IN const GpPointF &p0, first line origin
  238. * IN const GpPointF &p1,
  239. * IN const GpPointF &r0, second line origin
  240. * IN const GpPointF &r1,
  241. * OUT REAL *t Length along the first line.
  242. * OUT REAL *r Length along the second line.
  243. * OUT GpPointF *intersect intersection point.
  244. *
  245. * Return Value:
  246. * FALSE - no intersection
  247. * TRUE - intersection.
  248. *
  249. * 10/15/2000 [asecchia]
  250. * Created it
  251. *
  252. \**************************************************************************/
  253. BOOL IntersectLines(
  254. IN const GpPointF &line1Start,
  255. IN const GpPointF &line1End,
  256. IN const GpPointF &line2Start,
  257. IN const GpPointF &line2End,
  258. OUT REAL *line1Length,
  259. OUT REAL *line2Length,
  260. OUT GpPointF *intersectionPoint
  261. )
  262. {
  263. GpVector2D V = line1End-line1Start;
  264. GpVector2D W = line2End-line2Start;
  265. // Fail for zero length lines.
  266. if((REALABS(V.X) < REAL_EPSILON) &&
  267. (REALABS(V.Y) < REAL_EPSILON) )
  268. {
  269. return FALSE;
  270. }
  271. if((REALABS(W.X) < REAL_EPSILON) &&
  272. (REALABS(W.Y) < REAL_EPSILON) )
  273. {
  274. return FALSE;
  275. }
  276. // Normal to W
  277. GpVector2D N;
  278. N.X = -W.Y;
  279. N.Y = W.X;
  280. REAL denom = N*V;
  281. // No intersection or collinear lines.
  282. if(REALABS(denom) < REAL_EPSILON)
  283. {
  284. return FALSE;
  285. }
  286. GpVector2D I = line1Start-line2Start;
  287. *line1Length = -((N*I)/denom);
  288. *intersectionPoint = line1Start + (V * (*line1Length));
  289. // At this point we already know that W.X and W.Y are not both zero because
  290. // of the trivial rejection step at the top.
  291. // Pick the divisor with the largest magnitude to preserve precision.
  292. if(REALABS(W.X) > REALABS(W.Y))
  293. {
  294. *line2Length = (intersectionPoint->X - line2Start.X)/W.X;
  295. }
  296. else
  297. {
  298. *line2Length = (intersectionPoint->Y - line2Start.Y)/W.Y;
  299. }
  300. return TRUE;
  301. }
  302. /**************************************************************************\
  303. *
  304. * Function Description:
  305. *
  306. * PointInPolygonAlternate
  307. *
  308. * This function computes the point in polygon test for an input polygon
  309. * using the fill mode alternate method (even-odd rule).
  310. *
  311. * This algorithm was constructed from an Eric Haines discussion in
  312. * 'An Introduction to Ray Tracing' (Glassner) p.p. 53-59
  313. *
  314. * This algorithm translates the polygon so that the requested point is
  315. * at the origin and then fires a ray along the horizontal positive x axis
  316. * and counts the number of lines in the polygon that cross the axis (NC)
  317. *
  318. * Return Value:
  319. *
  320. * TRUE iff point is inside the polygon.
  321. *
  322. * Input Parameters:
  323. *
  324. * point - the test point.
  325. * count - the number of points in the polygon.
  326. * poly - the polygon points.
  327. *
  328. * 10/11/2000 [asecchia]
  329. * Created it
  330. *
  331. \**************************************************************************/
  332. BOOL PointInPolygonAlternate(
  333. GpPointF point,
  334. INT count,
  335. GpPointF *poly
  336. )
  337. {
  338. UINT crossingCount = 0;
  339. // Sign holder: stores +1 if the point is above the x axis, -1 for below.
  340. // Points on the x axis are considered to be above.
  341. INT signHolder = ((poly[0].Y-point.Y) >=0) ? 1 : -1;
  342. INT nextSignHolder;
  343. // a and b are the indices for the current point and the next point.
  344. for(INT a = 0; a < count; a++)
  345. {
  346. // Get the next vertex with modulo arithmetic.
  347. INT b = a + 1;
  348. if(b >= count)
  349. {
  350. b = 0;
  351. }
  352. // Compute the next sign holder.
  353. ((poly[b].Y - point.Y) >= 0) ? nextSignHolder = 1: nextSignHolder = -1;
  354. // If the sign holder and next sign holder are different, this may
  355. // indicate a crossing of the x axis - determine if it's on the
  356. // positive side.
  357. if(signHolder != nextSignHolder)
  358. {
  359. // Both X coordinates are positive, we have a +xaxis crossing.
  360. if( ((poly[a].X - point.X) >= 0) &&
  361. ((poly[b].X - point.X) >= 0))
  362. {
  363. crossingCount++;
  364. }
  365. else
  366. {
  367. // if at least one of the points is positive, we could intersect
  368. if( ((poly[a].X - point.X) >= 0) ||
  369. ((poly[b].X - point.X) >= 0))
  370. {
  371. // Compute the line intersection with the xaxis.
  372. if( (REALABS(poly[b].Y-poly[a].Y) > REAL_EPSILON ) &&
  373. ((poly[a].X - point.X) -
  374. (poly[a].Y - point.Y) *
  375. (poly[b].X - poly[a].X) /
  376. (poly[b].Y - poly[a].Y)
  377. ) > 0)
  378. {
  379. crossingCount++;
  380. }
  381. }
  382. }
  383. signHolder = nextSignHolder;
  384. }
  385. }
  386. return (BOOL)!(crossingCount & 0x1);
  387. }
  388. /**************************************************************************\
  389. *
  390. * Function Description:
  391. *
  392. * GetFastAngle computes a NON-angle. It is simply a number representing
  393. * a monotonically increasing ordering on angles starting at 0 at 0 radians
  394. * and ending at 8 for 2PI radians. It has a NON-linear relation to the angle.
  395. *
  396. * Starting on the x-axis with the number 0, we increase by one for
  397. * each octant as we traverse around the origin in an anti-clockwise direction.
  398. * This is a very useful (fast) way of comparing angles without working out
  399. * tricky square roots or arctangents.
  400. *
  401. * The 'angle' is based on the gradient of the input vector.
  402. *
  403. * \ | /
  404. * \3|2/
  405. * 4\|/1
  406. * -------
  407. * 5/|\8
  408. * /6|7\
  409. * / | \
  410. *
  411. *
  412. * Arguments:
  413. *
  414. * [OUT] angle - the angle substitute.
  415. * [IN] vector - the input vector.
  416. *
  417. * Return Value:
  418. *
  419. * Status
  420. *
  421. \**************************************************************************/
  422. GpStatus GetFastAngle(REAL* angle, const GpPointF& vector)
  423. {
  424. // 0, 0 is an invalid angle.
  425. if(vector.X == 0 && vector.Y == 0)
  426. {
  427. *angle = 0.0f;
  428. return InvalidParameter;
  429. }
  430. // Perform a binary octant search. 3 comparisons and 1 divide.
  431. // Are we on the right or the left half of the plane.
  432. if(vector.X >= 0)
  433. {
  434. // Right hand half plane.
  435. // Top or bottom half of the right half plane.
  436. if(vector.Y >= 0)
  437. {
  438. // Top right quadrant - check if we're the first or second
  439. // octant.
  440. if(vector.X >= vector.Y)
  441. {
  442. // First octant - our range is from 0 to 1
  443. *angle = vector.Y/vector.X;
  444. }
  445. else
  446. {
  447. // Second octant - our range is from 1 to 2
  448. // reverse the direction to keep the angle increasing
  449. *angle = 2 - vector.X/vector.Y;
  450. }
  451. }
  452. else
  453. {
  454. // Bottom right quadrant
  455. if(vector.X >= - vector.Y)
  456. {
  457. // eighth (last) octant. y is actually negative, so we're
  458. // doing an 8- here. Range 7 to 8
  459. *angle = 8 + vector.Y/vector.X;
  460. }
  461. else
  462. {
  463. // 7th octant. Our range is 6 to 7
  464. *angle = 6 - vector.X/vector.Y;
  465. }
  466. }
  467. }
  468. else
  469. {
  470. // Left halfplane.
  471. if(vector.Y >= 0)
  472. {
  473. // Top left
  474. if(-vector.X >= vector.Y)
  475. {
  476. // 4th octant - our range is 3 to 4
  477. *angle = 4 + vector.Y/vector.X;
  478. }
  479. else
  480. {
  481. // 3rd octant - our range is 2 to 3
  482. *angle = 2 - vector.X/vector.Y;
  483. }
  484. }
  485. else
  486. {
  487. // Bottom left
  488. if(-vector.X >= - vector.Y)
  489. {
  490. // 5th octant - 4 to 5
  491. *angle = 4 + vector.Y/vector.X;
  492. }
  493. else
  494. {
  495. // 6th octant - 5 to 6
  496. *angle = 6 - vector.X/vector.Y;
  497. }
  498. }
  499. }
  500. return Ok;
  501. }