Winding2D.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../precompiled.h"
  22. #include "Winding2D.h"
  23. /*
  24. ============
  25. GetAxialBevel
  26. ============
  27. */
  28. bool GetAxialBevel( const idVec3 &plane1, const idVec3 &plane2, const idVec2 &point, idVec3 &bevel ) {
  29. if ( IEEE_FLT_SIGNBITSET( plane1.x ) ^ IEEE_FLT_SIGNBITSET( plane2.x ) ) {
  30. if ( idMath::Fabs( plane1.x ) > 0.1f && idMath::Fabs( plane2.x ) > 0.1f ) {
  31. bevel.x = 0.0f;
  32. if ( IEEE_FLT_SIGNBITSET( plane1.y ) ) {
  33. bevel.y = -1.0f;
  34. }
  35. else {
  36. bevel.y = 1.0f;
  37. }
  38. bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
  39. return true;
  40. }
  41. }
  42. if ( IEEE_FLT_SIGNBITSET( plane1.y ) ^ IEEE_FLT_SIGNBITSET( plane2.y ) ) {
  43. if ( idMath::Fabs( plane1.y ) > 0.1f && idMath::Fabs( plane2.y ) > 0.1f ) {
  44. bevel.y = 0.0f;
  45. if ( IEEE_FLT_SIGNBITSET( plane1.x ) ) {
  46. bevel.x = -1.0f;
  47. }
  48. else {
  49. bevel.x = 1.0f;
  50. }
  51. bevel.z = - ( point.x * bevel.x + point.y * bevel.y );
  52. return true;
  53. }
  54. }
  55. return false;
  56. }
  57. /*
  58. ============
  59. idWinding2D::ExpandForAxialBox
  60. ============
  61. */
  62. void idWinding2D::ExpandForAxialBox( const idVec2 bounds[2] ) {
  63. int i, j, numPlanes;
  64. idVec2 v;
  65. idVec3 planes[MAX_POINTS_ON_WINDING_2D], plane, bevel;
  66. // get planes for the edges and add bevels
  67. for ( numPlanes = i = 0; i < numPoints; i++ ) {
  68. j = (i+1) % numPoints;
  69. if ( ( p[j] - p[i] ).LengthSqr() < 0.01f ) {
  70. continue;
  71. }
  72. plane = Plane2DFromPoints( p[i], p[j], true );
  73. if ( i ) {
  74. if ( GetAxialBevel( planes[numPlanes-1], plane, p[i], bevel ) ) {
  75. planes[numPlanes++] = bevel;
  76. }
  77. }
  78. assert( numPlanes < MAX_POINTS_ON_WINDING_2D );
  79. planes[numPlanes++] = plane;
  80. }
  81. assert( numPlanes < MAX_POINTS_ON_WINDING_2D && numPlanes > 0 );
  82. if ( GetAxialBevel( planes[numPlanes-1], planes[0], p[0], bevel ) ) {
  83. planes[numPlanes++] = bevel;
  84. }
  85. // expand the planes
  86. for ( i = 0; i < numPlanes; i++ ) {
  87. v.x = bounds[ IEEE_FLT_SIGNBITSET( planes[i].x ) ].x;
  88. v.y = bounds[ IEEE_FLT_SIGNBITSET( planes[i].y ) ].y;
  89. planes[i].z += v.x * planes[i].x + v.y * planes[i].y;
  90. }
  91. // get intersection points of the planes
  92. for ( numPoints = i = 0; i < numPlanes; i++ ) {
  93. if ( Plane2DIntersection( planes[(i+numPlanes-1) % numPlanes], planes[i], p[numPoints] ) ) {
  94. numPoints++;
  95. }
  96. }
  97. }
  98. /*
  99. ============
  100. idWinding2D::Expand
  101. ============
  102. */
  103. void idWinding2D::Expand( const float d ) {
  104. int i;
  105. idVec2 edgeNormals[MAX_POINTS_ON_WINDING_2D];
  106. for ( i = 0; i < numPoints; i++ ) {
  107. idVec2 &start = p[i];
  108. idVec2 &end = p[(i+1)%numPoints];
  109. edgeNormals[i].x = start.y - end.y;
  110. edgeNormals[i].y = end.x - start.x;
  111. edgeNormals[i].Normalize();
  112. edgeNormals[i] *= d;
  113. }
  114. for ( i = 0; i < numPoints; i++ ) {
  115. p[i] += edgeNormals[i] + edgeNormals[(i+numPoints-1)%numPoints];
  116. }
  117. }
  118. /*
  119. =============
  120. idWinding2D::Split
  121. =============
  122. */
  123. int idWinding2D::Split( const idVec3 &plane, const float epsilon, idWinding2D **front, idWinding2D **back ) const {
  124. float dists[MAX_POINTS_ON_WINDING_2D];
  125. byte sides[MAX_POINTS_ON_WINDING_2D];
  126. int counts[3];
  127. float dot;
  128. int i, j;
  129. const idVec2 * p1, *p2;
  130. idVec2 mid;
  131. idWinding2D * f;
  132. idWinding2D * b;
  133. int maxpts;
  134. counts[0] = counts[1] = counts[2] = 0;
  135. // determine sides for each point
  136. for ( i = 0; i < numPoints; i++ ) {
  137. dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  138. if ( dot > epsilon ) {
  139. sides[i] = SIDE_FRONT;
  140. } else if ( dot < -epsilon ) {
  141. sides[i] = SIDE_BACK;
  142. } else {
  143. sides[i] = SIDE_ON;
  144. }
  145. counts[sides[i]]++;
  146. }
  147. sides[i] = sides[0];
  148. dists[i] = dists[0];
  149. *front = *back = NULL;
  150. // if nothing at the front of the clipping plane
  151. if ( !counts[SIDE_FRONT] ) {
  152. *back = Copy();
  153. return SIDE_BACK;
  154. }
  155. // if nothing at the back of the clipping plane
  156. if ( !counts[SIDE_BACK] ) {
  157. *front = Copy();
  158. return SIDE_FRONT;
  159. }
  160. maxpts = numPoints+4; // cant use counts[0]+2 because of fp grouping errors
  161. *front = f = new (TAG_IDLIB_WINDING) idWinding2D;
  162. *back = b = new (TAG_IDLIB_WINDING) idWinding2D;
  163. for ( i = 0; i < numPoints; i++ ) {
  164. p1 = &p[i];
  165. if ( sides[i] == SIDE_ON ) {
  166. f->p[f->numPoints] = *p1;
  167. f->numPoints++;
  168. b->p[b->numPoints] = *p1;
  169. b->numPoints++;
  170. continue;
  171. }
  172. if ( sides[i] == SIDE_FRONT ) {
  173. f->p[f->numPoints] = *p1;
  174. f->numPoints++;
  175. }
  176. if ( sides[i] == SIDE_BACK ) {
  177. b->p[b->numPoints] = *p1;
  178. b->numPoints++;
  179. }
  180. if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
  181. continue;
  182. }
  183. // generate a split point
  184. p2 = &p[(i+1)%numPoints];
  185. // always calculate the split going from the same side
  186. // or minor epsilon issues can happen
  187. if ( sides[i] == SIDE_FRONT ) {
  188. dot = dists[i] / ( dists[i] - dists[i+1] );
  189. for ( j = 0; j < 2; j++ ) {
  190. // avoid round off error when possible
  191. if ( plane[j] == 1.0f ) {
  192. mid[j] = plane.z;
  193. } else if ( plane[j] == -1.0f ) {
  194. mid[j] = -plane.z;
  195. } else {
  196. mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
  197. }
  198. }
  199. } else {
  200. dot = dists[i+1] / ( dists[i+1] - dists[i] );
  201. for ( j = 0; j < 2; j++ ) {
  202. // avoid round off error when possible
  203. if ( plane[j] == 1.0f ) {
  204. mid[j] = plane.z;
  205. } else if ( plane[j] == -1.0f ) {
  206. mid[j] = -plane.z;
  207. } else {
  208. mid[j] = (*p2)[j] + dot * ( (*p1)[j] - (*p2)[j] );
  209. }
  210. }
  211. }
  212. f->p[f->numPoints] = mid;
  213. f->numPoints++;
  214. b->p[b->numPoints] = mid;
  215. b->numPoints++;
  216. }
  217. return SIDE_CROSS;
  218. }
  219. /*
  220. ============
  221. idWinding2D::ClipInPlace
  222. ============
  223. */
  224. bool idWinding2D::ClipInPlace( const idVec3 &plane, const float epsilon, const bool keepOn ) {
  225. int i, j, maxpts, newNumPoints;
  226. int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
  227. float dot, dists[MAX_POINTS_ON_WINDING_2D+1];
  228. idVec2 *p1, *p2, mid, newPoints[MAX_POINTS_ON_WINDING_2D+4];
  229. counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
  230. for ( i = 0; i < numPoints; i++ ) {
  231. dists[i] = dot = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  232. if ( dot > epsilon ) {
  233. sides[i] = SIDE_FRONT;
  234. } else if ( dot < -epsilon ) {
  235. sides[i] = SIDE_BACK;
  236. } else {
  237. sides[i] = SIDE_ON;
  238. }
  239. counts[sides[i]]++;
  240. }
  241. sides[i] = sides[0];
  242. dists[i] = dists[0];
  243. // if the winding is on the plane and we should keep it
  244. if ( keepOn && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) {
  245. return true;
  246. }
  247. if ( !counts[SIDE_FRONT] ) {
  248. numPoints = 0;
  249. return false;
  250. }
  251. if ( !counts[SIDE_BACK] ) {
  252. return true;
  253. }
  254. maxpts = numPoints + 4; // cant use counts[0]+2 because of fp grouping errors
  255. newNumPoints = 0;
  256. for ( i = 0; i < numPoints; i++ ) {
  257. p1 = &p[i];
  258. if ( newNumPoints+1 > maxpts ) {
  259. return true; // can't split -- fall back to original
  260. }
  261. if ( sides[i] == SIDE_ON ) {
  262. newPoints[newNumPoints] = *p1;
  263. newNumPoints++;
  264. continue;
  265. }
  266. if ( sides[i] == SIDE_FRONT ) {
  267. newPoints[newNumPoints] = *p1;
  268. newNumPoints++;
  269. }
  270. if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
  271. continue;
  272. }
  273. if ( newNumPoints+1 > maxpts ) {
  274. return true; // can't split -- fall back to original
  275. }
  276. // generate a split point
  277. p2 = &p[(i+1)%numPoints];
  278. dot = dists[i] / (dists[i] - dists[i+1]);
  279. for ( j = 0; j < 2; j++ ) {
  280. // avoid round off error when possible
  281. if ( plane[j] == 1.0f ) {
  282. mid[j] = plane.z;
  283. } else if ( plane[j] == -1.0f ) {
  284. mid[j] = -plane.z;
  285. } else {
  286. mid[j] = (*p1)[j] + dot * ((*p2)[j] - (*p1)[j]);
  287. }
  288. }
  289. newPoints[newNumPoints] = mid;
  290. newNumPoints++;
  291. }
  292. if ( newNumPoints >= MAX_POINTS_ON_WINDING_2D ) {
  293. return true;
  294. }
  295. numPoints = newNumPoints;
  296. memcpy( p, newPoints, newNumPoints * sizeof(idVec2) );
  297. return true;
  298. }
  299. /*
  300. =============
  301. idWinding2D::Copy
  302. =============
  303. */
  304. idWinding2D *idWinding2D::Copy() const {
  305. idWinding2D *w;
  306. w = new (TAG_IDLIB_WINDING) idWinding2D;
  307. w->numPoints = numPoints;
  308. memcpy( w->p, p, numPoints * sizeof( p[0] ) );
  309. return w;
  310. }
  311. /*
  312. =============
  313. idWinding2D::Reverse
  314. =============
  315. */
  316. idWinding2D *idWinding2D::Reverse() const {
  317. idWinding2D *w;
  318. int i;
  319. w = new (TAG_IDLIB_WINDING) idWinding2D;
  320. w->numPoints = numPoints;
  321. for ( i = 0; i < numPoints; i++ ) {
  322. w->p[ numPoints - i - 1 ] = p[i];
  323. }
  324. return w;
  325. }
  326. /*
  327. ============
  328. idWinding2D::GetArea
  329. ============
  330. */
  331. float idWinding2D::GetArea() const {
  332. int i;
  333. idVec2 d1, d2;
  334. float total;
  335. total = 0.0f;
  336. for ( i = 2; i < numPoints; i++ ) {
  337. d1 = p[i-1] - p[0];
  338. d2 = p[i] - p[0];
  339. total += d1.x * d2.y - d1.y * d2.x;
  340. }
  341. return total * 0.5f;
  342. }
  343. /*
  344. ============
  345. idWinding2D::GetCenter
  346. ============
  347. */
  348. idVec2 idWinding2D::GetCenter() const {
  349. int i;
  350. idVec2 center;
  351. center.Zero();
  352. for ( i = 0; i < numPoints; i++ ) {
  353. center += p[i];
  354. }
  355. center *= ( 1.0f / numPoints );
  356. return center;
  357. }
  358. /*
  359. ============
  360. idWinding2D::GetRadius
  361. ============
  362. */
  363. float idWinding2D::GetRadius( const idVec2 &center ) const {
  364. int i;
  365. float radius, r;
  366. idVec2 dir;
  367. radius = 0.0f;
  368. for ( i = 0; i < numPoints; i++ ) {
  369. dir = p[i] - center;
  370. r = dir * dir;
  371. if ( r > radius ) {
  372. radius = r;
  373. }
  374. }
  375. return idMath::Sqrt( radius );
  376. }
  377. /*
  378. ============
  379. idWinding2D::GetBounds
  380. ============
  381. */
  382. void idWinding2D::GetBounds( idVec2 bounds[2] ) const {
  383. int i;
  384. if ( !numPoints ) {
  385. bounds[0].x = bounds[0].y = idMath::INFINITY;
  386. bounds[1].x = bounds[1].y = -idMath::INFINITY;
  387. return;
  388. }
  389. bounds[0] = bounds[1] = p[0];
  390. for ( i = 1; i < numPoints; i++ ) {
  391. if ( p[i].x < bounds[0].x ) {
  392. bounds[0].x = p[i].x;
  393. } else if ( p[i].x > bounds[1].x ) {
  394. bounds[1].x = p[i].x;
  395. }
  396. if ( p[i].y < bounds[0].y ) {
  397. bounds[0].y = p[i].y;
  398. } else if ( p[i].y > bounds[1].y ) {
  399. bounds[1].y = p[i].y;
  400. }
  401. }
  402. }
  403. /*
  404. =============
  405. idWinding2D::IsTiny
  406. =============
  407. */
  408. #define EDGE_LENGTH 0.2f
  409. bool idWinding2D::IsTiny() const {
  410. int i;
  411. float len;
  412. idVec2 delta;
  413. int edges;
  414. edges = 0;
  415. for ( i = 0; i < numPoints; i++ ) {
  416. delta = p[(i+1)%numPoints] - p[i];
  417. len = delta.Length();
  418. if ( len > EDGE_LENGTH ) {
  419. if ( ++edges == 3 ) {
  420. return false;
  421. }
  422. }
  423. }
  424. return true;
  425. }
  426. /*
  427. =============
  428. idWinding2D::IsHuge
  429. =============
  430. */
  431. bool idWinding2D::IsHuge() const {
  432. int i, j;
  433. for ( i = 0; i < numPoints; i++ ) {
  434. for ( j = 0; j < 2; j++ ) {
  435. if ( p[i][j] <= MIN_WORLD_COORD || p[i][j] >= MAX_WORLD_COORD ) {
  436. return true;
  437. }
  438. }
  439. }
  440. return false;
  441. }
  442. /*
  443. =============
  444. idWinding2D::Print
  445. =============
  446. */
  447. void idWinding2D::Print() const {
  448. int i;
  449. for ( i = 0; i < numPoints; i++ ) {
  450. idLib::common->Printf( "(%5.1f, %5.1f)\n", p[i][0], p[i][1] );
  451. }
  452. }
  453. /*
  454. =============
  455. idWinding2D::PlaneDistance
  456. =============
  457. */
  458. float idWinding2D::PlaneDistance( const idVec3 &plane ) const {
  459. int i;
  460. float d, min, max;
  461. min = idMath::INFINITY;
  462. max = -min;
  463. for ( i = 0; i < numPoints; i++ ) {
  464. d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  465. if ( d < min ) {
  466. min = d;
  467. if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
  468. return 0.0f;
  469. }
  470. }
  471. if ( d > max ) {
  472. max = d;
  473. if ( IEEE_FLT_SIGNBITSET( min ) & IEEE_FLT_SIGNBITNOTSET( max ) ) {
  474. return 0.0f;
  475. }
  476. }
  477. }
  478. if ( IEEE_FLT_SIGNBITNOTSET( min ) ) {
  479. return min;
  480. }
  481. if ( IEEE_FLT_SIGNBITSET( max ) ) {
  482. return max;
  483. }
  484. return 0.0f;
  485. }
  486. /*
  487. =============
  488. idWinding2D::PlaneSide
  489. =============
  490. */
  491. int idWinding2D::PlaneSide( const idVec3 &plane, const float epsilon ) const {
  492. bool front, back;
  493. int i;
  494. float d;
  495. front = false;
  496. back = false;
  497. for ( i = 0; i < numPoints; i++ ) {
  498. d = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  499. if ( d < -epsilon ) {
  500. if ( front ) {
  501. return SIDE_CROSS;
  502. }
  503. back = true;
  504. continue;
  505. }
  506. else if ( d > epsilon ) {
  507. if ( back ) {
  508. return SIDE_CROSS;
  509. }
  510. front = true;
  511. continue;
  512. }
  513. }
  514. if ( back ) {
  515. return SIDE_BACK;
  516. }
  517. if ( front ) {
  518. return SIDE_FRONT;
  519. }
  520. return SIDE_ON;
  521. }
  522. /*
  523. ============
  524. idWinding2D::PointInside
  525. ============
  526. */
  527. bool idWinding2D::PointInside( const idVec2 &point, const float epsilon ) const {
  528. int i;
  529. float d;
  530. idVec3 plane;
  531. for ( i = 0; i < numPoints; i++ ) {
  532. plane = Plane2DFromPoints( p[i], p[(i+1) % numPoints] );
  533. d = plane.x * point.x + plane.y * point.y + plane.z;
  534. if ( d > epsilon ) {
  535. return false;
  536. }
  537. }
  538. return true;
  539. }
  540. /*
  541. ============
  542. idWinding2D::LineIntersection
  543. ============
  544. */
  545. bool idWinding2D::LineIntersection( const idVec2 &start, const idVec2 &end ) const {
  546. int i, numEdges;
  547. int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
  548. float d1, d2, epsilon = 0.1f;
  549. idVec3 plane, edges[2];
  550. counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
  551. plane = Plane2DFromPoints( start, end );
  552. for ( i = 0; i < numPoints; i++ ) {
  553. d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  554. if ( d1 > epsilon ) {
  555. sides[i] = SIDE_FRONT;
  556. }
  557. else if ( d1 < -epsilon ) {
  558. sides[i] = SIDE_BACK;
  559. }
  560. else {
  561. sides[i] = SIDE_ON;
  562. }
  563. counts[sides[i]]++;
  564. }
  565. sides[i] = sides[0];
  566. if ( !counts[SIDE_FRONT] ) {
  567. return false;
  568. }
  569. if ( !counts[SIDE_BACK] ) {
  570. return false;
  571. }
  572. numEdges = 0;
  573. for ( i = 0; i < numPoints; i++ ) {
  574. if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
  575. edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
  576. if ( numEdges >= 2 ) {
  577. break;
  578. }
  579. }
  580. }
  581. if ( numEdges < 2 ) {
  582. return false;
  583. }
  584. d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
  585. d2 = edges[0].x * end.x + edges[0].y * end.y + edges[0].z;
  586. if ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( d2 ) ) {
  587. return false;
  588. }
  589. d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
  590. d2 = edges[1].x * end.x + edges[1].y * end.y + edges[1].z;
  591. if ( IEEE_FLT_SIGNBITNOTSET( d1 ) & IEEE_FLT_SIGNBITNOTSET( d2 ) ) {
  592. return false;
  593. }
  594. return true;
  595. }
  596. /*
  597. ============
  598. idWinding2D::RayIntersection
  599. ============
  600. */
  601. bool idWinding2D::RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums ) const {
  602. int i, numEdges, localEdgeNums[2];
  603. int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3];
  604. float d1, d2, epsilon = 0.1f;
  605. idVec3 plane, edges[2];
  606. scale1 = scale2 = 0.0f;
  607. counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
  608. plane = Plane2DFromVecs( start, dir );
  609. for ( i = 0; i < numPoints; i++ ) {
  610. d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z;
  611. if ( d1 > epsilon ) {
  612. sides[i] = SIDE_FRONT;
  613. }
  614. else if ( d1 < -epsilon ) {
  615. sides[i] = SIDE_BACK;
  616. }
  617. else {
  618. sides[i] = SIDE_ON;
  619. }
  620. counts[sides[i]]++;
  621. }
  622. sides[i] = sides[0];
  623. if ( !counts[SIDE_FRONT] ) {
  624. return false;
  625. }
  626. if ( !counts[SIDE_BACK] ) {
  627. return false;
  628. }
  629. numEdges = 0;
  630. for ( i = 0; i < numPoints; i++ ) {
  631. if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) {
  632. localEdgeNums[numEdges] = i;
  633. edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] );
  634. if ( numEdges >= 2 ) {
  635. break;
  636. }
  637. }
  638. }
  639. if ( numEdges < 2 ) {
  640. return false;
  641. }
  642. d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z;
  643. d2 = - ( edges[0].x * dir.x + edges[0].y * dir.y );
  644. if ( d2 == 0.0f ) {
  645. return false;
  646. }
  647. scale1 = d1 / d2;
  648. d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z;
  649. d2 = - ( edges[1].x * dir.x + edges[1].y * dir.y );
  650. if ( d2 == 0.0f ) {
  651. return false;
  652. }
  653. scale2 = d1 / d2;
  654. if ( idMath::Fabs( scale1 ) > idMath::Fabs( scale2 ) ) {
  655. SwapValues( scale1, scale2 );
  656. SwapValues( localEdgeNums[0], localEdgeNums[1] );
  657. }
  658. if ( edgeNums ) {
  659. edgeNums[0] = localEdgeNums[0];
  660. edgeNums[1] = localEdgeNums[1];
  661. }
  662. return true;
  663. }