Winding2D.cpp 17 KB

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