home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / programm / 3180 < prev    next >
Encoding:
Internet Message Format  |  1992-11-15  |  41.1 KB

  1. Xref: sparky comp.programming:3180 comp.theory:2462 comp.graphics:12054 sci.math.num-analysis:3348
  2. Nntp-Posting-Host: ull.ifi.uio.no
  3. Newsgroups: comp.programming,comp.theory,comp.graphics,sci.math.num-analysis
  4. Path: sparky!uunet!charon.amdahl.com!pacbell.com!sgiblab!darwin.sura.net!paladin.american.edu!news.univie.ac.at!hp4at!mcsun!sunic!aun.uninett.no!nuug!ifi.uio.no!hkr
  5. From: Hans Kristian Ruud <hkr@ifi.uio.no>
  6. Subject: Point Location Summary - Another go
  7. Message-ID: <CMM.0.90.2.722126791.hkr@ull.ifi.uio.no>
  8. Sender: hkr@ifi.uio.no (Hans Kristian Ruud)
  9. Organization: Dept. of Informatics, University of Oslo, Norway
  10. Date: Wed, 18 Nov 1992 22:46:31 GMT
  11. Lines: 1079
  12. Originator: hkr@ull.ifi.uio.no
  13.  
  14. Hello.
  15.  
  16. I have been a bit slow in editing & reposting the messages I recieved
  17. on point location - I'm sorry about that. 
  18.  
  19. Anyway, here goes:
  20.  
  21.  
  22. -------------------------------------------------------------------------------
  23.  
  24. From pjyamamo@watdragon.uwaterloo.ca
  25.  
  26. I would suppose that a decision might be affected by the particular
  27. application (type of polygons, type of queries, etc).
  28.  
  29. >Preparata & Shamos present several methods:
  30. >
  31. >  i)  The slab method.
  32. > ii)  The chain method.
  33. >iii)  The triangulation refinement method.
  34. > iv)  The bridged chain method.
  35. >
  36. >The general agreement among the students was that method iii) seemed
  37. >the best. I tend to agree, but I would like the opinions from the net
  38. >on the matter.
  39.  
  40. In the same chapter they say that experimentally a bucketing technique
  41. outperformed all others and that of the others, the trapezoid
  42. decomposition performed best.
  43.  
  44. >A thousand thanks in advance (Paa forhaand tusen takk).
  45.  
  46. I would think that it also depends on how large the problem is.
  47. Machine/System dependent problems may only start to show up in larger
  48. problems. Ie because of the accesses to decompositions etc paging
  49. could start to affect performance depending on implementation.
  50.  
  51.  
  52. -------------------------------------------------------------------------------
  53.  
  54. From dougm@cs.rice.edu  (Doug Moore)
  55.  
  56. You might want to look at the article "Planar point location using
  57. persistent search trees" by R. Tarjan and N. Sarnak in the
  58. Communications of the ACM vol. 29 no 6 (1986).  It is theoretically
  59. optimal, and seems rather simpler than triangulation refinement.
  60.  
  61. -------------------------------------------------------------------------------
  62.  
  63. From psu@cs.duke.edu 
  64.  
  65. Having taken a CG class taught from that book, and then worked in CG
  66. for my thesis...
  67.  
  68. I would say that no one uses any of the methods in P&S in real life.  The
  69. algorithms are simply too concerned with worst case asymptotic
  70. optimality, and are thus overly complex, difficult to implement, and
  71. probably slow.
  72.  
  73. I have heard that the trapezoid method is quick, but I've never seen
  74. any code to prove it.
  75.  
  76. Also, one is hardly ever in the position of being able to sit and think
  77. about how to pre-process the subdivision that we are locating
  78. in...it's almost always an on-line process.
  79.  
  80. I have an incremental algorithm for constructing the Delaunay
  81. triangulation (chap 5) that uses a bucketing scheme to do point
  82. location.  This scheme will work much better than the general schemes
  83. in Chap 2, but only on certain kinds of subdivisions (can't have too
  84. many long edges, for example).  I can send you a TR that describes the
  85. algorithm if you want.
  86.  
  87. My feeling is that no one PL scheme is best in general.  What you use
  88. will depend on your application more than anything else.
  89.  
  90.  
  91. -------------------------------------------------------------------------------
  92.  
  93.  
  94. From moret@tiguex.cs.unm.edu (Bernard M.E. Moret)  
  95.  
  96.  
  97. Much better (because much simpler and much faster) is the method of Sarnak
  98. and Tarjan, using persistent data structures.  See their article in Commun. ACM
  99. of 1986 (vol. 29, pp. 669-679).  It also generalizes easily to k-dimensions.
  100. -- 
  101.     Bernard M.E. Moret                       Department of Computer Science
  102.     (505) 277-3112     University of New Mexico, Albuquerque, NM 87131-1386
  103.  
  104. -------------------------------------------------------------------------------
  105.  
  106. Compiled by Eric Haines, 3D/Eye Inc, 2359 Triphammer Rd, Ithaca, NY 14850
  107.     erich@eye.com
  108. All contents are copyright (c) 1992 by the individual authors
  109. Archive locations: anonymous FTP at princeton.edu (128.112.128.1)
  110.     /pub/Graphics/RTNews, wuarchive.wustl.edu:/graphics/graphics/RTNews,
  111.     and many others.
  112. UUCP archive access: write Kory Hamzeh (quad.com!avatar!kory) for info.
  113.  
  114. Contents:
  115.     Introduction
  116.     Intersection Between a Line and a Polygon (UNDECIDABLE??), by Dave Baraff,
  117.     Tom Duff
  118.     Fastest Point in Polygon Test, by Aladdin Nassar, Philip Walden, Eric
  119.     Haines, Tom Dickens, Ron Capelli, Sundar Narasimhan, Christopher Jam,
  120.     and (last but not least) Stuart MacMartin
  121.     Polygon Intersection via Barycentric Coordinates, by Peter Shirley
  122.     Many-Sided Polygon Intersection, by Eric Haines, Benjamin Zhu
  123.     Code for Point in Polygon Intersectors, by Eric Haines
  124.  
  125. -------------------------------------------------------------------------------
  126.  
  127. Introduction
  128.  
  129. This special issue is dedicated to everyone's (well, at least my) favorite
  130. computer graphics FAQ:  how do you find if a given point is inside a polygon?
  131. John Griegg's FAQ posting points at _An Introduction to Ray Tracing_, edited
  132. by Andrew Glassner.  This issue speeds up that algorithm (count the crossings
  133. of a test ray), and hopefully lays to rest the idea of using the "sum the
  134. angles" algorithm.  Plus there's a little discussion of what to do for special
  135. cases such as triangles and complex polygons, and code for four different ways
  136. to do this test at the end of the issue.
  137.  
  138. -------------------------------------------------------------------------------
  139.  
  140. [To begin this issue, here is one of the better pieces of obfuscatory writing
  141. in the field of computer graphics.  Reprinted from RTNews8 - EAH]
  142.  
  143.  
  144. Intersection Between a Line and a Polygon (UNDECIDABLE??),
  145.     by Dave Baraff, Tom Duff
  146.  
  147.     From: deb@charisma.graphics.cornell.edu
  148.     Newsgroups: comp.graphics
  149.     Keywords: P, NP, Jordan curve separation, Ursyhon Metrization Theorem
  150.     Organization: Program of Computer Graphics
  151.  
  152. In article [...] ncsmith@ndsuvax.UUCP (Timothy Lyle Smith) writes:
  153. >
  154. >  I need to find a formula/algorithm to determine if a line intersects
  155. >  a polygon.  I would prefer a method that would do this in as little
  156. >  time as possible.  I need this for use in a forward raytracing
  157. >  program.
  158.  
  159. I think that this is a very difficult problem.  To start with, lines and
  160. polygons are semi-algebraic sets which both contain uncountable number of
  161. points.  Here are a few off-the-cuff ideas.
  162.  
  163. First, we need to check if the line and the polygon are separated.  Now, the
  164. Jordan curve separation theorem says that the polygon divides the plane into
  165. exactly two open (and thus non-compact) regions.  Thus, the line lies
  166. completely inside the polygon, the line lies completely outside the polygon,
  167. or possibly (but this will rarely happen) the line intersects the polyon.
  168.  
  169. Now, the phrasing of this question says "if a line intersects a polygon", so
  170. this is a decision problem.  One possibility (the decision model approach) is
  171. to reduce the question to some other (well known) problem Q, and then try to
  172. solve Q.  An answer to Q gives an answer to the original decision problem.
  173.  
  174. In recent years, many geometric problems have been successfully modeled in a
  175. new language called PostScript.  (See "PostScript Language", by Adobe Systems
  176. Incorporated, ISBN # 0-201-10179-3, co. 1985).
  177.  
  178. So, given a line L and a polygon P, we can write a PostScript program that
  179. draws the line L and the polygon P, and then "outputs" the answer.  By
  180. "output", we mean the program executes a command called "showpage", which
  181. actually prints a page of paper containing the line and the polygon.  A quick
  182. examination of the paper provides an answer to the reduced problem Q, and thus
  183. the original problem.
  184.  
  185. There are two small problems with this approach.
  186.  
  187.     (1) There is an infinite number of ways to encode L and P into the
  188.     reduced problem Q.  So, we will be forced to invoke the Axiom of
  189.     Choice (or equivalently, Zorn's Lemma).  But the use of the Axiom of
  190.     Choice is not regarded in a very serious light these days.
  191.  
  192.     (2) More importantly, the question arises as to whether or not the
  193.     PostScript program Q will actually output a piece of paper; or in
  194.     other words, will it halt?
  195.  
  196.     Now, PostScript is expressive enough to encode everything that a
  197.     Turing Machine might do; thus the halting problem (for PostScript) is
  198.     undecidable.  It is quite possible that the original problem will turn
  199.     out to be undecidable.
  200.  
  201.  
  202. I won't even begin to go into other difficulties, such as aliasing, finite
  203. precision and running out of ink, paper or both.
  204.  
  205. A couple of references might be:
  206.  
  207. 1. Principia Mathematica.  Newton, I.  Cambridge University Press, Cambridge,
  208.    England.  (Sorry, I don't have an ISBN# for this).
  209.  
  210. 2. An Introduction to Automata Theory, Languages, and Computation.  Hopcroft, J
  211.   and Ulman, J.
  212.  
  213. 3. The C Programming Language. Kernighan, B and Ritchie, D.
  214.  
  215. 4. A Tale of Two Cities. Dickens, C.
  216.  
  217. --------
  218.  
  219. From: td@alice.UUCP (Tom Duff)
  220. Summary: Overkill.
  221. Organization: AT&T Bell Laboratories, Murray Hill NJ
  222.  
  223. The situation is not nearly as bleak as Baraff suggests (he should know
  224. better, he's hung around The Labs for long enough).  By the well known
  225. Dobbin-Dullman reduction (see J. Dullman & D. Dobbin, J. Comp. Obfusc.
  226. 37,ii:  pp. 33-947, lemma 17(a)) line-polygon intersection can be reduced to
  227. Hamiltonian Circuit, without(!) the use of Grobner bases, so LPI (to coin an
  228. acronym) is probably only NP-complete.  Besides, Turing-completeness will no
  229. longer be a problem once our Cray-3 is delivered, since it will be able to
  230. complete an infinite loop in 4 milliseconds (with scatter-gather.)
  231.  
  232. --------
  233.  
  234. From: deb@svax.cs.cornell.edu (David Baraff)
  235.  
  236. Well, sure it's no worse than NP-complete, but that's ONLY if you restrict
  237. yourself to the case where the line satisfies a Lipschitz condition on its
  238. second derivative.  (I think there's an '89 SIGGRAPH paper from Caltech that
  239. deals with this).
  240.  
  241. -------------------------------------------------------------------------------
  242.  
  243. Fastest Point in Polygon Test, by Aladdin Nassar, Philip Walden, Eric Haines,
  244.     Tom Dickens, Ron Capelli, Sundar Narasimhan, Christopher Jam, and
  245.     (last but not least) Stuart MacMartin
  246.  
  247.  
  248. Aladdin Nassar asked a variant on the classic question:
  249.  
  250. What is the MOST EFFICIENT way to find if a point lies within a SIMPLE
  251. polygon given a set of vertices (in no particular order) and the point
  252. coordinate ?   Are there anonymous ftp sites with such canned functions
  253. instead of re-inventing the wheel.  Excuse me if that is a trivial question.
  254.  
  255. ----
  256.  
  257. Philip Walden (pwalden@hpcc01.corp.hp.com) replies:
  258.  
  259. Another alternative to using a test ray is to sum the arc angles from
  260. the vertices to the test point. If the sum is 2pi, the point is inside,
  261. if 0 it's outside. i.e.
  262.  
  263.     give a polygon with a set of vertices v[1:n] an test point p
  264.  
  265.     if (SUM i=1 to n (arcangle(v[i]->p->v[i+1])) > pi
  266.     then p is inside
  267.     else it's outside
  268.  
  269. ----
  270.  
  271. Eric Haines replies:
  272.  
  273. This method turns out to be exceedingly slow, about an order of magnitude
  274. slower than the "shoot a ray and count crossings" method.  The problem is that
  275. the "arcangle" routine takes awhile:  you need to normalize your vectors, you
  276. need to compute the dot product (for the angle) and cross product (for the
  277. sign of the angle), and you need the arccosine of the dot product for the
  278. angle itself.  This is done for every vertex of the polygon.  All of this adds
  279. up!
  280.  
  281. In fact, I wrote a program to test the two algorithms head-to-head when I was
  282. deciding which to use:  code attached (for a switch!).  The test program makes
  283. polygons from 3 to 7 (though you can change this) and random scatters the
  284. vertices from [0-1).  It then tests each of these polygons with a series of
  285. random points from [0-1).
  286.  
  287. I won't claim that either implementation of the angle summation or segment
  288. crossing routines below are optimal (though I do try to share intermediate
  289. results between vertices).  But I don't care how much you tune the angle
  290. summation algorithm:  it's still going to be slower than crossing counting.
  291. Please do tell me of any hacks you make to get either algorithm faster,
  292. anyway.
  293.  
  294. Code's at the end of this issue; you should mess with *_TEST_TIMES however you
  295. see fit.  I found you could set them pretty low, but I felt better when they
  296. were relatively high (i.e. the test times were greater than the granularity
  297. of the "time" command).  The crossing counting inside/outside test is the one
  298. I wrote up in _An Introduction to Ray Tracing_, edited by Andrew Glassner,
  299. Academic Press, plus a trick or two not in the book.
  300.  
  301. I should also mention that the tests below assuming that an even winding
  302. number means that the point is outside, as this is how the Jordan Curve test
  303. is used.  Think of the winding number as the number of loops around a point.
  304. As an example, think of a star shape:  the interior pentagon is considered
  305. "outside" since points in it cross two lines.  You can modify the tests as
  306. shown in the comments if you want to test for just a non-zero winding number
  307. (i.e. the star is fully filled).
  308.  
  309. Timings are shown after the next comment.
  310.  
  311. ----
  312.  
  313. Tom Dickens notes in a related article:
  314.  
  315. Additional logic [in the barycentric test] can be added to avoid checking
  316. triangles which are located in a region which has already been determined to
  317. be beyond of a side of a previous triangle which returned a negative check.
  318.  
  319. [I don't know if such an enhancement is possible (one triangle's outside is
  320. another's inside) if the polygon is not convex, but mention it here for
  321. interest's sake; it is certainly not incorporated in my code.  - EAH]
  322.  
  323. ----
  324.  
  325. comments from Ron Capelli (capelli@vnet.ibm.com):
  326.  
  327. >the "arcangle" routine takes awhile:  you need to normalize your vectors, you
  328. >need to compute the dot product (for the angle) and cross product (for the
  329. >sign of the angle), and you need the arccosine of the dot product for the
  330. >angle itself.  This is done for every vertex of the polygon.
  331.  
  332. See "Fast Approximation to the Arctangent" in Graphics Gems II (p.389).  The
  333. maximum error of this approximation allows polygons with up to about 40
  334. vertexes to be handled safely.
  335.  
  336. No need to normalize, take dot products, or cross products either.  From the
  337. vector components (dx, dy) from a test point to a polygon vertex, get an angle
  338. using arctan (or the fast approximation, in which case do not scale to radians
  339. or degrees; use the angle value in the range 0 to 8).  Calculate the signed
  340. angle between two successive vertexes by subtracting the angles for each
  341. vertex.  Add up all the signed angle differences, and compare to the mid-range
  342. value.
  343.  
  344. The case of a test point coincident with a polygon vertex must be explicitly
  345. checked, as the arctangent for a zero-length vector is undefined.  Another
  346. fine point is that angle differences must be wrapped in the range -180 to +180
  347. degrees.
  348.  
  349. As fond as I am :-) of this method, I still won't argue that the "count ray
  350. crossings" method is not better.  For a polygon with N edges, an optimized
  351. "count ray crossings" algorithm requires at most one multiply, one divide, and
  352. about a half-dozen add/subtract/compare operations per edge.  The "add angle
  353. differences" algorithm using the fast approximation to the arctangent requires
  354. only one divide but more than twice as many add/subtract/compare operations
  355. per edge...
  356.  
  357. ----
  358.  
  359. Sundar Narasimhan (sundar@fiber-one.ai.mit.edu) comments on Ron's post:
  360.  
  361. I think it is somewhat misleading to count worst case operations / edge and
  362. then multiply it blindly by N esp.  since the "count ray crossings" algorithm
  363. can be optimized to consider only the subset of N edges that actually have a
  364. chance of intersecting the fired ray, whereas I haven't seen any such
  365. pre-filtering done to the add angle difference algorithm.
  366.  
  367. ----
  368.  
  369. Christopher Jam (phillips@swanee.ee.uwa.oz.au) writes:
  370.  
  371. For the "count ray crossings" method, if your processor has no multiply or
  372. divide instructions, the multiply and divide may be replaced by a binary
  373. search for the point on the edge with the same y coordinate as the point being
  374. tested.  Alternatively, if you are going to draw the polygon at some stage,
  375. generate a list of points on the line for plotting, and keep these in a table
  376. to completely remove any requirements for multiplies, divides or searches.
  377. Just look up a point on the same line ;)
  378.  
  379. ----
  380.  
  381. Stuart MacMartin (sjm@bcrki65.bnr.ca) comments:
  382.  
  383. I know the purpose of your code was for a simple comparison of the two
  384. algorithms, but for production you might want to write optimal code.
  385.  
  386. The loop overhead is actually quite expensive, as I found out when I optimized
  387. someone else's implementation of this algorithm.  Most of the time is spent
  388. looking for the next y that is on/below the ray or the next y that is above
  389. the ray.  You should be able to get at lease a factor of 2 improvement by
  390. optimizing those two loops.  Call a subroutine if necessary for the deleted
  391. stuff.  (Note that subroutines can be MORE efficient because the compiler may
  392. make a better use of registers for the time-consuming part of the loop.)  Use
  393. pointers to the y rather than to the x to avoid the extra adding, and don't
  394. keep track of so many variables in the loop.
  395.  
  396. Finally, is it necessary to use doubles?  With appropriate units, will long
  397. suffice?  Just be careful if you make this switch:  if you have to have
  398. doubles in some places in your code, watch out for conversions from long to
  399. double and back.  On some platforms (definitely Apollo; I don't know about
  400. others) such casts take so long that they totally swamp anything else that is
  401. inefficient in a loop.
  402.  
  403. My code for the loop:
  404.  
  405.     stop = vertices + (numVertices << 1);
  406.  
  407.     for(y = vertices[1], p = vertices+3;  p < stop;  y = *p,p+=2) {
  408.     /* Skip all lines above */
  409.     if      (y > ay) while ((p < stop) && (*p > ay)) p += 2;
  410.     /* Skip all lines below */
  411.     else if (y < ay) while ((p < stop) && (*p < ay)) p += 2;
  412.         /* NOTE! Don't skip horizontal edges at ay! */
  413.     if (p >= stop) break;
  414.  
  415. The routine requires that the first point is duplicated as the last.
  416.  
  417. ----
  418.  
  419. Final (for now) comments, by Eric Haines:
  420.  
  421. Other people noted the barycentric test as being a way to do inside/outside
  422. testing.  The barycentric test is included below in Peter Shirley's article,
  423. and is also written up on page 390-393 of Graphics Gems, Didier Badouel's
  424. article.  You can do better than figuring out all the intermediate differences
  425. (as shown in Badouel's article), instead computing them as needed.  Also, my
  426. code worries about zero area triangles just to be safe, so it could be a bit
  427. faster without these sanity checks.
  428.  
  429. Badouel points out that triangle testing works for convex polygons:  you
  430. simply test all of the triangles, and any intersection ends the test.  Most
  431. people assume that concave triangles must be intersected using a different
  432. test.  Not so!  As Berlin pointed out (Vol 11, SIGGRAPH '85 course notes -
  433. sorry for the obscure reference!), you can test a concave polygon by checking
  434. all its triangles generated from one vertex.  If the number of triangles hit
  435. is odd, the point is inside the (potentially concave) polygon - try it out, it
  436. actually works!  You do have to test all triangles, however; if you knew the
  437. polygon was convex you can stop on the first intersection.  Also, the
  438. barycentric coordinates become somewhat meaningless, since more than one
  439. triangle can be found to overlap your test point.
  440.  
  441.  
  442. So, included in the new code (which is at the end of this issue) are two
  443. flavors of the crossings (segment) test, one which is fairly fast and
  444. readable, the other is "macmartinized" by me and runs a bit faster still.
  445. The barycentric polygon intersector is also included, and it works for all
  446. polygons (concave, self-intersecting, etc).
  447.  
  448. Random polygon testing:
  449.  
  450.              number (or range) of vertices
  451.             3        4        5        3-7        20        100
  452.  
  453. angle           57.21   69.81   86.44   82.98  303.33 1435.78
  454. barycentric        1.80    3.44    5.29    4.90   30.78  164.38
  455. crossings        2.17    2.76    3.32    3.24   12.51   60.13
  456. macmartin        1.86    2.35    2.87    2.64   11.04   52.27
  457.  
  458. inside %        6.00   12.00   13.78    9.33   26.89   41.22
  459.  
  460. Times are in microseconds per intersection test, on an HP 720 workstation.
  461. The "for" loop for repeating each test is counted into these test times
  462. (basically, I repeat each polygon/point test a number of times so that there's
  463. some reasonable amount of time to count) - not counting it just means the
  464. "crossings" tests is all that much faster.  Basically, the macmartinized
  465. crossing test wins on my machine; your mileage may vary.
  466.  
  467. Note that the barycentric intersector could be faster if the polygons are
  468. known to be convex, since then a quick out could be taken (i.e. the first hit
  469. ends testing).  I won't swear at all for the completeness of the barycentric
  470. code:  I suspect you can get into roundoff error problems for intersection
  471. points which lay exactly on some internal, invisible triangle testing edge
  472. (rare, but possible).
  473.  
  474. There are also a few hacks I haven't done on the barycentric intersector:  you
  475. could make the set of if statements into two big if statements, the variable
  476. "v0" is not all that useful, etc.  Also, if the polygon is a triangle the test
  477. could be made a special case and the "for" loop and other baggage could be
  478. eliminated (this I tried, and it resulted in about a 20% reduction in run
  479. time).  However, the code presented is at least readable, and the general
  480. behavior is the same:  this intersector gets more expensive than the crossing
  481. methods as the number of polygon vertices rises.
  482.  
  483. Looking over the branch flow analysis, I find that my test case polygons
  484. (randomly generated points) cause a lot of algebraic tests to occur when using
  485. the crossing algorithms (i.e.  the exact x intersection point has to be
  486. computed when a polygon edge goes from one quadrant to its diagonal opposite).
  487. For real polygons, this case is much less prevalent since vertices tend to be
  488. close to each other, so the polygons I've generated are more pathological than
  489. normally encountered.  For example, if the polygons generated are regular
  490. polygons inscribed in a circle of radius 1.0 and given a random rotation about
  491. the origin, the timings are
  492.  
  493. Regular polygon testing:
  494.  
  495.              number (or range) of vertices
  496.             3        4        5        3-7        20        100
  497.  
  498. angle           54.20   70.80   85.14   87.83  314.53 1522.00
  499. barycentric        2.11    3.98    5.48    5.64   27.63  144.27
  500. crossings        2.50    3.09    3.30    3.42    9.46   42.71
  501. macmartin        2.32    2.81    2.91    2.92    6.29   23.91
  502.  
  503. inside %       33.22   51.00   60.22   55.22   77.44   80.22
  504.  
  505. I'm not sure why there's any noticeable difference in the "angle summation"
  506. tests, since this test should be the same for any test point (I suspect it's
  507. just the "times()" routine's granularity).  The barycentric times change a
  508. little for better and worse, probably due to times() and to different polygon
  509. vs. point tests.  The two crossings test noticeably improve for large polygons
  510. (29% and 54% savings, respectively) - this is due to less "difficult" edges,
  511. and for the macmartin test there are now longer series of edges fully above or
  512. fully below the test point.  These tests show off the real improvement of the
  513. macmartin algorithm when testing many sided polygons.
  514.  
  515. The near-final word is that the crossings tests seems to be the most efficient
  516. overall, the angle test should generally be avoided like the plague, and the
  517. barycentric test is good for the special case of triangles (and you also
  518. get the vertex interpolant weights).  Just to add to the confusion, I talk
  519. about intersecting complex polygons in an article below; if you're using a lot
  520. of these then another intersection algorithm might be a better route to go.
  521.  
  522. -------------------------------------------------------------------------------
  523.  
  524. Polygon Intersection via Barycentric Coordinates, by Peter Shirley
  525.     (shirley@iuvax.cs.indiana.edu)
  526.  
  527. One good way to do ray triangle intersection is to use barycentric
  528. coordinates.  If the triangle has vertices p0, p1, p2, then any point in the
  529. plane containing the triangle can be represented as
  530.  
  531.     p = a*p0 + b*p2 + g*p3
  532.  
  533. and the constraint a + b + g = 1 will also hold.  If you want to interpolate
  534. colors or normals across the triangle, you can use a similar formula.  A
  535. little messing around will convince you that for points inside the triangle,
  536. a, b, and g are all positive, and outside the triangle, at least one is
  537. negative.  We can take this info, and get rid of a:
  538.  
  539.     p = p0 + b*(p1 - p0) + g*(p2-p0)
  540.  
  541. The point p is inside if b and g are positive, and (b+g) < 1.
  542.  
  543. A point on our ray can be represented as p' = o + t*v, where o is the point of
  544. origin on the ray, and v is the direction of propagation.  Plugging this into
  545. the triangle formula, we can find whether any point on the ray is also a point
  546. on the plane:
  547.  
  548.     o + t*v = p0 + b*(p1 - p0) + g*(p2-p0)
  549.  
  550. Note that this is really 3 linear equations (one for x, y and z).  You can
  551. rewrite this as a 3 by 3 linear system and solve for (t, b, g) and there is a
  552. hit if and only if:
  553.  
  554.     t > 0
  555.     b > 0
  556.     g > 0
  557.     b+g < 1
  558.  
  559. Alternatively, you can first find the equation of the plane containing the
  560. triangle and find t.  This will give you an explicit point h on the plane.
  561. You now have:
  562.  
  563.     h = p0 + b*(p1 - p0) + g*(p2-p0)
  564.  
  565. Now you have 3 equations and 2 unknowns.  Choosing any two of the equations is
  566. equivalent to projecting the problem onto one of the cartesian planes.  Watch
  567. out if the triangle is in one of the planes, because the projection might be a
  568. line segment.  You can check the surface normal to see if it is one of those
  569. cases (I just use the dimensions associated with the smallest magnitude
  570. components of the normal).
  571.  
  572. Note-- none of this is new.  GG II and the ray tracing book have other ways to
  573. do it.  Also, if your scenes are large, you are probably better off optimizing
  574. your spatial partitioning code (the part which takes longer for bigger
  575. scenes).
  576.  
  577. [For more info, see Didier Badouel's article in "Graphics Gems", p. 390-393]
  578.  
  579. -------------------------------------------------------------------------------
  580.  
  581. Many-Sided Polygon Intersection, by Eric Haines, Benjamin Zhu
  582.  
  583.  
  584. Jon Bennett (jb7m+@andrew.cmu.edu) writes:
  585.  
  586. >For a project i was working on i needed a very fast 2-D point-in-polygon
  587. >routine for a monte-carlo simulation, and came up with a variation of the
  588. >standard jordan curve theorem algorithm which ran approximately on the
  589. >order of O(n/20) when n > ~100 (for "mostly" round-ish polygons), instead
  590. >of O(n).  What I can't find, and no one here seems to know, is for large
  591. >polygons what is the best 2-D algorithm.  Everything they've heard of runs
  592. >in O(n) (I know that n and n/20 are the same "order" but the you know what
  593. >I mean). I'd like to know if there is something faster.
  594.  
  595.  
  596. You might check Preparata & Shamos's _Computational Geometry_ book, I believe
  597. they talk about faster algorithms.  Unfortunately, much of the stuff in CG
  598. tends to be things like O(K * log n), where K is something pretty large.
  599.  
  600. A simple way to test polygons with a large number of edges in O(n/K) time is
  601. to sort the edges into buckets, then find out which bucket the test point
  602. falls into.  Then you do the usual ray test, but only against those edges in
  603. the bucket.
  604.  
  605. For example, you could take a hundred edge polygon and find the Y extent in the
  606. polygon's plane.  Split this extent into, say, 20 buckets (or whatever number
  607. you like, more ==> more efficient, but also more memory and preprocessing).
  608. Now take each edge and note which buckets it's in.  As an added speed-up, sort
  609. the edges by their leftmost X values in that bucket.
  610.  
  611. Now testing can begin.  When you test a point, use the Y coordinate to find
  612. which bucket to check.  Now test each edge by the normal Jordan test against
  613. the point.  You only need to test edges to the left of the point (i.e. you are
  614. using a test ray in the -X direction), so as soon as you reach an edge whose
  615. leftmost X is greater than the point's X, you can stop testing.
  616.  
  617. The bucket sort immediately gets rid of a lot of edges, and the X test means
  618. often not having to test all edges in the bucket (it's optional icing).
  619.  
  620. If you're really into using memory and like preprocessing, you could use a
  621. grid structure to place buckets on the polygon.  Each grid cell is inside,
  622. outside, or indeterminate.  There are some tricks, but I leave these as an
  623. exercise for the reader...  Anyway, this method can be very fast, since much
  624. of the polygon's area is classified as in or out and much of the time no edges
  625. have to be tested at all.  The only limit is the grid cell resolution.  As the
  626. resolution rises the actual testing approaches constant time ( O(1)!).
  627. There's more preprocessing involved, but if you're making a lot of tests then
  628. this is worth doing.
  629.  
  630. ----
  631.  
  632. Benjamin Zhu (zhu@graphack.asd.sgi.com) comments on a similar question:
  633.  
  634. If your polygon is convex, (more generally, your polygon is star-shaped,) you
  635. can pre-process the polygon into triangle strips by connecting any point in
  636. the kernel of the polygon with each vertex of the polygon.  This takes you
  637. O(n) pre-processing time.  After that, for each point, you do a binary search
  638. in polar coordinates to locate the potential triangle where the point might
  639. lie.  Then you can determine if the point lies within this triangle, which is
  640. trivial.  See Preparata and Shamos' "Computational Geometry" for more details.
  641. Obviously, this algorithm will give you O(log(n)) time per point.  So you
  642. might consider this one if you need to solve the point-inclusion problem many
  643. times.
  644.  
  645. -------------------------------------------------------------------------------
  646.  
  647. Code for Point in Polygon Intersectors, by Eric Haines
  648.  
  649. Here it is, code for the angle test, the barycentric test, and the two
  650. crossings tests, with a main program to test their speeds.  You may need to
  651. use something other than srand()/drand48() for your random number generator,
  652. and the times() command for timing.  You'll also want to change the
  653. *_TEST_TIMES constants if you're using something slower than an HP 720
  654. workstation.  Feel free to complain about the slowness of any of the code -
  655. I'm always interested in new hacks.
  656.  
  657.  
  658. /* Point in polygon inside/outside tester.  Angle summation, barycentric
  659.  * coordinates, and ray along x-axis (crossings testing) compared.
  660.  *
  661.  * copyright 1992 by Eric Haines, 3D/Eye Inc, erich@eye.com
  662.  */
  663.  
  664. #include <math.h>
  665. #include <sys/types.h>
  666. #include <sys/param.h>
  667. #include <sys/times.h>
  668.  
  669. #define    X    0
  670. #define    Y    1
  671.  
  672. double    drand48() ;
  673.  
  674. double    AngleTimeTotal ;
  675. double    BarycentricTimeTotal ;
  676. double    CrossingsTimeTotal ;
  677. double    MacmartinTimeTotal ;
  678.  
  679. /* minimum & maximum number of polygon vertices to generate */
  680. #define    MIN_VERTS    3
  681. #define    MAX_VERTS    7
  682.  
  683. /* number of different polygons to try */
  684. #define    TEST_POLYGONS    30
  685.  
  686. /* number of different intersection points to try */
  687. #define    TEST_POINTS    30
  688.  
  689. /* number of times to try a single point vs. a polygon */
  690. /* this should be > 1 / ( HZ * approx. single test time in seconds ) */
  691. #define    ANGLE_TEST_TIMES    1000
  692. #define    BARYCENTRIC_TEST_TIMES    10000
  693. #define    CROSSINGS_TEST_TIMES    10000
  694. #define    MACMARTIN_TEST_TIMES    10000
  695.  
  696. main(argc,argv)
  697. int argc;  char *argv[];
  698. {
  699. int    i, j, numverts, inside_tot ;
  700. int    angle_flag, barycentric_flag, crossings_flag, macmartin_flag ;
  701. double    pgon[MAX_VERTS][2] ;
  702. double    point[2] ;
  703.  
  704.     srand( 12345 ) ;
  705.  
  706.     AngleTimeTotal = 0.0 ;
  707.     BarycentricTimeTotal = 0.0 ;
  708.     CrossingsTimeTotal = 0.0 ;
  709.     MacmartinTimeTotal = 0.0 ;
  710.     inside_tot = 0 ;
  711.  
  712.     for ( i = 0 ; i < TEST_POLYGONS ; i++ ) {
  713.  
  714. #ifdef CENTERED_SQUARE
  715.     /* for debugging purposes, test against a square */
  716.     numverts = 4 ;
  717.     pgon[0][X] = 0.2 ;
  718.     pgon[0][Y] = 0.2 ;
  719.     pgon[1][X] = 0.8 ;
  720.     pgon[1][Y] = 0.2 ;
  721.     pgon[2][X] = 0.8 ;
  722.     pgon[2][Y] = 0.8 ;
  723.     pgon[3][X] = 0.2 ;
  724.     pgon[3][Y] = 0.8 ;
  725. #else
  726.     /* make an arbitrary polygon fitting 0-1 range in x and y */
  727.     numverts = MIN_VERTS +
  728.         (int)(drand48() * (double)(MAX_VERTS-MIN_VERTS+1)) ;
  729.     for ( j = 0 ; j < numverts ; j++ ) {
  730.         pgon[j][X] = drand48() ;
  731.         pgon[j][Y] = drand48() ;
  732.     }
  733. #endif
  734.  
  735.     /* now try # of points against it */
  736.     for ( j = 0 ; j < TEST_POINTS ; j++ ) {
  737.         point[X] = drand48() ;
  738.         point[Y] = drand48() ;
  739.         angle_flag = angletest( pgon, numverts, point ) ;
  740.         barycentric_flag = barycentrictest( pgon, numverts, point ) ;
  741.         crossings_flag = crossingstest( pgon, numverts, point ) ;
  742.         macmartin_flag = macmartintest( pgon, numverts, point ) ;
  743.  
  744.         /* reality check */
  745.         if ( angle_flag != crossings_flag ) {
  746.         printf( "angle test says %s, crossings test says %s\n",
  747.             angle_flag ? "INSIDE" : "OUTSIDE",
  748.             crossings_flag ? "INSIDE" : "OUTSIDE" ) ;
  749.         printf( "point %g %g\n", (float)point[X], (float)point[Y] ) ;
  750.         printf( "polygon:\n" ) ;
  751.         for ( j = 0 ; j < numverts ; j++ ) {
  752.             printf( "  %g %g\n", (float)pgon[j][X], (float)pgon[j][Y]);
  753.         }
  754.         }
  755.         if ( barycentric_flag != macmartin_flag ) {
  756.         printf( "barycentric test says %s, macmartin test says %s\n",
  757.             barycentric_flag ? "INSIDE" : "OUTSIDE",
  758.             macmartin_flag ? "INSIDE" : "OUTSIDE" ) ;
  759.         printf( "point %g %g\n", (float)point[X], (float)point[Y] ) ;
  760.         printf( "polygon:\n" ) ;
  761.         for ( j = 0 ; j < numverts ; j++ ) {
  762.             printf( "  %g %g\n", (float)pgon[j][X], (float)pgon[j][Y]);
  763.         }
  764.         }
  765.  
  766.         inside_tot += crossings_flag ;
  767.     }
  768.     }
  769.     printf( "angle test time: %g microseconds per test\n",
  770.     (float)( AngleTimeTotal/(double)(TEST_POINTS*TEST_POLYGONS) ) ) ;
  771.     printf( "barycentric test time: %g microseconds per test\n",
  772.     (float)( BarycentricTimeTotal/(double)(TEST_POINTS*TEST_POLYGONS) ) ) ;
  773.     printf( "crossings test time: %g microseconds per test\n",
  774.     (float)( CrossingsTimeTotal/(double)(TEST_POINTS*TEST_POLYGONS) ) ) ;
  775.     printf( "macmartin crossings test time: %g microseconds per test\n",
  776.     (float)( MacmartinTimeTotal/(double)(TEST_POINTS*TEST_POLYGONS) ) ) ;
  777.  
  778.     printf( "%g %% of all points were inside polygons\n",
  779.     (float)inside_tot * 100.0 / (float)(TEST_POINTS*TEST_POLYGONS) ) ;
  780. }
  781.  
  782. /* sum angles of vtxN - point - vtxN+1, check if in PI to 3*PI range */
  783. int
  784. angletest( pgon, numverts, point )
  785. double    pgon[MAX_VERTS][2] ;
  786. int    numverts ;
  787. double    point[2] ;
  788. {
  789. int    i, j, inside_flag ;
  790. struct  tms     timebuf ;
  791. long    timestart ;
  792. long    timestop ;
  793. double    *vtx0, *vtx1, angle, len, vec0[2], vec1[2] ;
  794.  
  795.     /* do the test a bunch of times to get a useful time reading */
  796.     timestart = times( &timebuf ) ;
  797.     for ( i = 0 ; i < ANGLE_TEST_TIMES ; i++ ) {
  798.     /* sum the angles and see if answer mod 2*PI > PI */
  799.     vtx0 = pgon[numverts-1] ;
  800.     vec0[X] = vtx0[X] - point[X] ;
  801.     vec0[Y] = vtx0[Y] - point[Y] ;
  802.     if ( (len = hypot( vec0[X], vec0[Y] )) <= 0.0 ) {
  803.         /* point and vertex coincide */
  804.         return( 1 ) ;
  805.     }
  806.     vec0[X] /= len ;
  807.     vec0[Y] /= len ;
  808.  
  809.     angle = 0.0 ;
  810.     for ( j = 0 ; j < numverts ; j++ ) {
  811.         vtx1 = pgon[j] ;
  812.         vec1[X] = vtx1[X] - point[X] ;
  813.         vec1[Y] = vtx1[Y] - point[Y] ;
  814.         if ( (len = hypot( vec1[X], vec1[Y] )) <= 0.0 ) {
  815.         /* point and vertex coincide */
  816.         return( 1 ) ;
  817.         }
  818.         vec1[X] /= len ;
  819.         vec1[Y] /= len ;
  820.  
  821.         /* check if vec1 is to "left" or "right" of vec0 */
  822.         if ( vec0[X] * vec1[Y] - vec1[X] * vec0[Y] >= 0.0 ) {
  823.         /* add angle due to dot product of vectors */
  824.         angle += acos( vec0[X] * vec1[X] + vec0[Y] * vec1[Y] ) ;
  825.         } else {
  826.         /* subtract angle due to dot product of vectors */
  827.         angle -= acos( vec0[X] * vec1[X] + vec0[Y] * vec1[Y] ) ;
  828.         }
  829.  
  830.         /* get to next point */
  831.         vtx0 = vtx1 ;
  832.         vec0[X] = vec1[X] ;
  833.         vec0[Y] = vec1[Y] ;
  834.     }
  835.     /* test if between PI and 3*PI, 5*PI and 7*PI, etc */
  836.     /* if we care about is winding number > 0, then just:
  837.            inside_flag = fabs(angle) > M_PI ;
  838.      */
  839.     inside_flag = fmod( fabs(angle) + M_PI, 4.0*M_PI ) > 2.0*M_PI ;
  840.     }
  841.     timestop = times( &timebuf ) ;
  842.     /* time in microseconds */
  843.     AngleTimeTotal += 1000000.0 * (double)(timestop - timestart) /
  844.     (double)(HZ * ANGLE_TEST_TIMES) ;
  845.  
  846.     return (inside_flag) ;
  847. }
  848.  
  849. /* barycentric, a la Gems I, with a little efficiency tuning */
  850. int
  851. barycentrictest( pgon, numverts, point )
  852. double    pgon[MAX_VERTS][2] ;
  853. int    numverts ;
  854. double    point[2] ;
  855. {
  856. int    i, tris_hit, inside_flag, p1, p2 ;
  857. struct  tms     timebuf ;
  858. long    timestart ;
  859. long    timestop ;
  860. double    tx, ty, u0, u1, u2, v0, v1, alpha, beta, denom ;
  861.  
  862.     /* do the test a bunch of times to get a useful time reading */
  863.     timestart = times( &timebuf ) ;
  864.     for ( i = 0 ; i < BARYCENTRIC_TEST_TIMES ; i++ ) {
  865.  
  866.     tx = point[X] ;
  867.     ty = point[Y] ;
  868.  
  869.     tris_hit = 0 ;
  870.  
  871.     for ( p1 = 1, p2 = 2 ; p2 < numverts ; p1++, p2++ ) {
  872.  
  873.         if ( ( u1 = pgon[0][X] - pgon[p2][X] ) == 0.0 ) {
  874.  
  875.         /* zero area test - optional */
  876.         if ( ( u2 = pgon[p1][X] - pgon[p2][X] ) == 0.0 ) {
  877.             goto NextTri;
  878.         }
  879.  
  880.         /* Compute intersection point */
  881.         if ( ( ( beta = ( tx - pgon[p2][X] ) / u2 ) < 0.0 ) ||
  882.                ( beta > 1.0 ) ) {
  883.  
  884.             goto NextTri;
  885.         }
  886.  
  887.         if ( ( v1 = pgon[0][Y] - pgon[p2][Y] ) == 0.0 ) {
  888.             goto NextTri;
  889.         }
  890.  
  891.         if ( ( alpha = ( ty - pgon[p2][Y] - beta *
  892.             ( pgon[p1][Y] - pgon[p2][Y] ) ) / v1 ) < 0.0 ) {
  893.             goto NextTri;
  894.         }
  895.  
  896.         } else {
  897.         if ( ( denom = ( pgon[p1][Y] - pgon[p2][Y] ) * u1 -
  898.             ( u2 = pgon[p1][X] - pgon[p2][X] ) *
  899.             ( v1 = pgon[0][Y] - pgon[p2][Y] ) ) == 0.0 ) {
  900.  
  901.             goto NextTri;
  902.         }
  903.  
  904.         /* Compute intersection point & subtract 0 vertex */
  905.         u0 = tx - pgon[p2][X] ;
  906.         v0 = ty - pgon[p2][Y] ;
  907.  
  908.         if ( ( ( ( beta = ( v0 * u1 - u0 * v1 ) / denom ) ) < 0.0 ) ||
  909.                ( beta > 1.0 ) ) {
  910.  
  911.             goto NextTri;
  912.         }
  913.         if ( ( alpha = ( u0 - beta * u2 ) / u1 ) < 0.0 ) {
  914.             goto NextTri;
  915.         }
  916.         }
  917.  
  918.         /* check gamma */
  919.         if ( alpha + beta <= 1.0 ) {
  920.         /* survived */
  921.         tris_hit++ ;
  922.         }
  923.  
  924.         NextTri: ;
  925.     }
  926.     inside_flag = tris_hit & 0x1 ;
  927.     }
  928.     timestop = times( &timebuf ) ;
  929.     /* time in microseconds */
  930.     BarycentricTimeTotal += 1000000.0 * (double)(timestop - timestart) /
  931.     (double)(HZ * BARYCENTRIC_TEST_TIMES) ;
  932.  
  933.     return (inside_flag) ;
  934. }
  935.  
  936. /* shoot a test ray along +X axis - slower version, less messy */
  937. int
  938. crossingstest( pgon, numverts, point )
  939. double    pgon[MAX_VERTS][2] ;
  940. int    numverts ;
  941. double    point[2] ;
  942. {
  943. int    i, j, inside_flag, xflag0 ;
  944. struct  tms     timebuf ;
  945. long    timestart ;
  946. long    timestop ;
  947. double    *vtx0, *vtx1, dv0 ;
  948. int    crossings, yflag0, yflag1 ;
  949.  
  950.     /* do the test a bunch of times to get a useful time reading */
  951.     timestart = times( &timebuf ) ;
  952.     for ( i = 0 ; i < CROSSINGS_TEST_TIMES ; i++ ) {
  953.  
  954.     vtx0 = pgon[numverts-1] ;
  955.     /* get test bit for above/below Y axis */
  956.     yflag0 = ( dv0 = vtx0[Y] - point[Y] ) >= 0.0 ;
  957.  
  958.     crossings = 0 ;
  959.     for ( j = 0 ; j < numverts ; j++ ) {
  960.         /* cleverness:  bobble between filling endpoints of edges, so
  961.          * that the previous edge's shared endpoint is maintained.
  962.          */
  963.         if ( j & 0x1 ) {
  964.         vtx0 = pgon[j] ;
  965.         yflag0 = ( dv0 = vtx0[Y] - point[Y] ) >= 0.0 ;
  966.         } else {
  967.         vtx1 = pgon[j] ;
  968.         yflag1 = ( vtx1[Y] >= point[Y] ) ;
  969.         }
  970.  
  971.         /* check if points not both above/below X axis - can't hit ray */
  972.         if ( yflag0 != yflag1 ) {
  973.         /* check if points on same side of Y axis */
  974.         if ( ( xflag0 = ( vtx0[X] >= point[X] ) ) ==
  975.              ( vtx1[X] >= point[X] ) ) {
  976.  
  977.             if ( xflag0 ) crossings++ ;
  978.         } else {
  979.             /* compute intersection of pgon segment with X ray, note
  980.              * if > point's X.
  981.              */
  982.             crossings += (vtx0[X] -
  983.             dv0*( vtx1[X]-vtx0[X])/(vtx1[Y]-vtx0[Y])) >= point[X] ;
  984.         }
  985.         }
  986.     }
  987.     /* test if crossings is odd */
  988.     /* if we care about is winding number > 0, then just:
  989.            inside_flag = crossings > 0 ;
  990.      */
  991.     inside_flag = crossings & 0x01 ;
  992.     }
  993.     timestop = times( &timebuf ) ;
  994.     /* time in microseconds */
  995.     CrossingsTimeTotal += 1000000.0 * (double)(timestop - timestart) /
  996.     (double)(HZ * CROSSINGS_TEST_TIMES) ;
  997.  
  998.     return (inside_flag) ;
  999. }
  1000.  
  1001. /* shoot a test ray along +X axis - macmartinized by me, a bit messier */
  1002. int
  1003. macmartintest( pgon, numverts, point )
  1004. double    pgon[MAX_VERTS][2] ;
  1005. int    numverts ;
  1006. double    point[2] ;
  1007. {
  1008. int    i, inside_flag, xflag0 ;
  1009. struct  tms     timebuf ;
  1010. long    timestart ;
  1011. long    timestop ;
  1012. double    *p, *stop ;
  1013. int    crossings ;
  1014. double    tx, ty, y ;
  1015.  
  1016.     /* do the test a bunch of times to get a useful time reading */
  1017.     timestart = times( &timebuf ) ;
  1018.     for ( i = 0 ; i < MACMARTIN_TEST_TIMES ; i++ ) {
  1019.  
  1020.     crossings = 0 ;
  1021.  
  1022.     tx = point[X] ;
  1023.     ty = point[Y] ;
  1024.     y = pgon[numverts-1][Y] ;
  1025.  
  1026.     p = (double *)pgon + 1 ;
  1027.     if ( ( y >= ty ) != ( *p >= ty ) ) {
  1028.         /* x crossing */
  1029.         if ( ( xflag0 = ( pgon[numverts-1][X] >= tx ) ) ==
  1030.          ( *(double *)pgon >= tx ) ) {
  1031.  
  1032.         if ( xflag0 ) crossings++ ;
  1033.         } else {
  1034.         /* compute intersection of pgon segment with X ray, note
  1035.          * if > point's X.
  1036.          */
  1037.         crossings += ( pgon[numverts-1][X] -
  1038.         (y-ty)*( *(double *)pgon - pgon[numverts-1][X])/(*p-y)) >= tx ;
  1039.         }
  1040.     }
  1041.  
  1042.     stop = pgon[numverts] ;
  1043.  
  1044.     for ( y=*p,p += 2 ; p < stop ; y=*p,p+=2) {
  1045.  
  1046.         if ( y >= ty ) {
  1047.         while ( (p < stop) && (*p >= ty) ) p+=2 ;
  1048.         if ( p >= stop ) goto Exit ;
  1049.         /* y crosses */
  1050.         if ( ( xflag0 = ( *(p-3) >= tx ) ) ==
  1051.              ( *(p-1) >= tx ) ) {
  1052.  
  1053.             if ( xflag0 ) crossings++ ;
  1054.         } else {
  1055.             /* compute intersection of pgon segment with X ray, note
  1056.              * if > point's X.
  1057.              */
  1058.             crossings += ( *(p-3) -
  1059.             (*(p-2)-ty)*( *(p-1)-*(p-3))/(*p-*(p-2))) >= tx ;
  1060.         }
  1061.         } else {
  1062.         while ( (p < stop) && (*p < ty)) p+=2 ;
  1063.         if ( p >= stop ) goto Exit ;
  1064.         /* y crosses */
  1065.         if ( ( xflag0 = ( *(p-3) >= tx ) ) ==
  1066.              ( *(p-1) >= tx ) ) {
  1067.  
  1068.             if ( xflag0 ) crossings++ ;
  1069.         } else {
  1070.             /* compute intersection of pgon segment with X ray, note
  1071.              * if > point's X.
  1072.              */
  1073.             crossings += ( *(p-3) -
  1074.             (*(p-2)-ty)*( *(p-1)-*(p-3))/(*p-*(p-2))) >= tx ;
  1075.         }
  1076.         }
  1077.     }
  1078.  
  1079.     Exit:
  1080.     /* test if crossings is odd */
  1081.     /* if we care about is winding number > 0, then just:
  1082.            inside_flag = crossings > 0 ;
  1083.      */
  1084.     inside_flag = crossings & 0x01 ;
  1085.     }
  1086.     timestop = times( &timebuf ) ;
  1087.     /* time in microseconds */
  1088.     MacmartinTimeTotal += 1000000.0 * (double)(timestop - timestart) /
  1089.     (double)(HZ * MACMARTIN_TEST_TIMES) ;
  1090.  
  1091.     return (inside_flag) ;
  1092. }
  1093.