Quad.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. Remember that 'Quad.n' in many cases may be inaccurate,
  6. that is for cases when quad is built from 2 non co-planar triangles.
  7. /******************************************************************************/
  8. Quad ::Quad (C QuadD &quad) {p[0]=quad.p[0]; p[1]=quad.p[1]; p[2]=quad.p[2]; p[3]=quad.p[3]; n=quad.n ;}
  9. QuadD::QuadD(C Quad &quad) {p[0]=quad.p[0]; p[1]=quad.p[1]; p[2]=quad.p[2]; p[3]=quad.p[3]; setNormal();}
  10. Quad2 & Quad2 ::operator+=(C Vec2 &v) {p[0]+=v; p[1]+=v; p[2]+=v; p[3]+=v; return T;}
  11. Quad2 & Quad2 ::operator-=(C Vec2 &v) {p[0]-=v; p[1]-=v; p[2]-=v; p[3]-=v; return T;}
  12. QuadD2& QuadD2::operator+=(C VecD2 &v) {p[0]+=v; p[1]+=v; p[2]+=v; p[3]+=v; return T;}
  13. QuadD2& QuadD2::operator-=(C VecD2 &v) {p[0]-=v; p[1]-=v; p[2]-=v; p[3]-=v; return T;}
  14. Quad & Quad ::operator+=(C Vec &v) {p[0]+=v; p[1]+=v; p[2]+=v; p[3]+=v; return T;}
  15. Quad & Quad ::operator-=(C Vec &v) {p[0]-=v; p[1]-=v; p[2]-=v; p[3]-=v; return T;}
  16. QuadD & QuadD ::operator+=(C VecD &v) {p[0]+=v; p[1]+=v; p[2]+=v; p[3]+=v; return T;}
  17. QuadD & QuadD ::operator-=(C VecD &v) {p[0]-=v; p[1]-=v; p[2]-=v; p[3]-=v; return T;}
  18. Quad2 & Quad2 ::operator*=( Flt r) {p[0]*=r; p[1]*=r; p[2]*=r; p[3]*=r; return T;}
  19. Quad2 & Quad2 ::operator/=( Flt r) {p[0]/=r; p[1]/=r; p[2]/=r; p[3]/=r; return T;}
  20. QuadD2& QuadD2::operator*=( Dbl r) {p[0]*=r; p[1]*=r; p[2]*=r; p[3]*=r; return T;}
  21. QuadD2& QuadD2::operator/=( Dbl r) {p[0]/=r; p[1]/=r; p[2]/=r; p[3]/=r; return T;}
  22. Quad & Quad ::operator*=( Flt r) {p[0]*=r; p[1]*=r; p[2]*=r; p[3]*=r; return T;}
  23. Quad & Quad ::operator/=( Flt r) {p[0]/=r; p[1]/=r; p[2]/=r; p[3]/=r; return T;}
  24. QuadD & QuadD ::operator*=( Dbl r) {p[0]*=r; p[1]*=r; p[2]*=r; p[3]*=r; return T;}
  25. QuadD & QuadD ::operator/=( Dbl r) {p[0]/=r; p[1]/=r; p[2]/=r; p[3]/=r; return T;}
  26. /******************************************************************************/
  27. Quad& Quad::set(C Vec &p0, C Vec &p1, C Vec &p2, C Vec &p3, C Vec *normal)
  28. {
  29. p[0]=p0;
  30. p[1]=p1;
  31. p[2]=p2;
  32. p[3]=p3;
  33. if(normal)n=*normal;else setNormal();
  34. return T;
  35. }
  36. QuadD& QuadD::set(C VecD &p0, C VecD &p1, C VecD &p2, C VecD &p3, C VecD *normal)
  37. {
  38. p[0]=p0;
  39. p[1]=p1;
  40. p[2]=p2;
  41. p[3]=p3;
  42. if(normal)n=*normal;else setNormal();
  43. return T;
  44. }
  45. /******************************************************************************/
  46. Flt Quad2 ::area()C {return 0.5f*Abs(Cross(p[1]-p[0], p[3]-p[0]) +Cross(p[2]-p[1], p[3]-p[1]));}
  47. Dbl QuadD2::area()C {return 0.5 *Abs(Cross(p[1]-p[0], p[3]-p[0]) +Cross(p[2]-p[1], p[3]-p[1]));}
  48. Flt Quad ::area()C {return 0.5f* (Cross(p[1]-p[0], p[3]-p[0]).length()+Cross(p[2]-p[1], p[3]-p[1]).length());}
  49. Dbl QuadD ::area()C {return 0.5 * (Cross(p[1]-p[0], p[3]-p[0]).length()+Cross(p[2]-p[1], p[3]-p[1]).length());}
  50. /******************************************************************************/
  51. static inline Bool SameSide( Int a, Int b ) {return a==b || !a || !b;} // both are on same side or one is zero, the same as "a*b>=0"
  52. static Bool SameSide(C Int *x, Int elms) {Int last=0; REP(elms)if(Int v=*x++)if(!last)last=v;else if(last!=v)return false; return true;}
  53. Bool Quad2::convex()C // this method supports non-clockwise ordering (in such case it will treat the quad as if it's in clockwise ordering)
  54. {
  55. Int s[]={Sign(Cross(p[1]-p[0], p[3]-p[0])),
  56. Sign(Cross(p[2]-p[1], p[0]-p[1])),
  57. Sign(Cross(p[3]-p[2], p[1]-p[2])),
  58. Sign(Cross(p[0]-p[3], p[2]-p[3]))};
  59. return SameSide(s, Elms(s));
  60. }
  61. Bool Quad::convex()C // this method supports non-clockwise ordering (in such case it will treat the quad as if it's in clockwise ordering)
  62. {
  63. Int s[]={Sign(Dot(n, Cross(p[1]-p[0], p[3]-p[0]))),
  64. Sign(Dot(n, Cross(p[2]-p[1], p[0]-p[1]))),
  65. Sign(Dot(n, Cross(p[3]-p[2], p[1]-p[2]))),
  66. Sign(Dot(n, Cross(p[0]-p[3], p[2]-p[3])))};
  67. return SameSide(s, Elms(s));
  68. }
  69. Bool Quad2::valid(Flt eps)C
  70. {
  71. return DistPointStr(p[0], p[1], !(p[3]-p[1]))>eps
  72. && DistPointStr(p[1], p[2], !(p[0]-p[2]))>eps
  73. && DistPointStr(p[2], p[3], !(p[1]-p[3]))>eps
  74. && DistPointStr(p[3], p[0], !(p[2]-p[0]))>eps;
  75. }
  76. Bool Quad::valid(Flt eps)C
  77. {
  78. return DistPointStr(p[0], p[1], !(p[3]-p[1]))>eps
  79. && DistPointStr(p[1], p[2], !(p[0]-p[2]))>eps
  80. && DistPointStr(p[2], p[3], !(p[1]-p[3]))>eps
  81. && DistPointStr(p[3], p[0], !(p[2]-p[0]))>eps;
  82. }
  83. /******************************************************************************/
  84. Bool Quad2 ::clockwise()C {return Cross(p[1]-p[0], p[3]-p[0])<0;}
  85. Bool QuadD2::clockwise()C {return Cross(p[1]-p[0], p[3]-p[0])<0;}
  86. /******************************************************************************/
  87. Bool Quad::coplanar(C Quad &quad)C
  88. {
  89. return Abs(DistPointPlane(p[0], quad))<=EPS
  90. && Abs(DistPointPlane(p[1], quad))<=EPS
  91. && Abs(DistPointPlane(p[2], quad))<=EPS
  92. && Abs(DistPointPlane(p[3], quad))<=EPS;
  93. }
  94. /******************************************************************************/
  95. void Quad2::draw(C Color &color, Bool fill)C
  96. {
  97. VI.color (color);
  98. VI.setType(VI_2D_FLAT, fill ? VI_STRIP : VI_LINE|VI_STRIP);
  99. if(Vtx2DFlat *v=(Vtx2DFlat*)VI.addVtx(fill ? 4 : 5))
  100. {
  101. if(fill)
  102. {
  103. v[0].pos=p[0];
  104. v[1].pos=p[1];
  105. v[2].pos=p[3];
  106. v[3].pos=p[2];
  107. }else
  108. {
  109. v[0].pos=p[0];
  110. v[1].pos=p[1];
  111. v[2].pos=p[2];
  112. v[3].pos=p[3];
  113. v[4].pos=p[0];
  114. }
  115. }
  116. VI.end();
  117. }
  118. void Quad::draw(C Color &color, Bool fill)C
  119. {
  120. VI.color (color);
  121. VI.setType(VI_3D_FLAT, fill ? VI_STRIP : VI_LINE|VI_STRIP);
  122. if(Vtx3DFlat *v=(Vtx3DFlat*)VI.addVtx(fill ? 4 : 5))
  123. {
  124. if(fill)
  125. {
  126. v[0].pos=p[0];
  127. v[1].pos=p[1];
  128. v[2].pos=p[3];
  129. v[3].pos=p[2];
  130. }else
  131. {
  132. v[0].pos=p[0];
  133. v[1].pos=p[1];
  134. v[2].pos=p[2];
  135. v[3].pos=p[3];
  136. v[4].pos=p[0];
  137. }
  138. }
  139. VI.end();
  140. }
  141. /******************************************************************************/
  142. static inline DIST_TYPE UpdateTypeQ(DIST_TYPE type, DIST_TYPE p0, DIST_TYPE p1, DIST_TYPE edge)
  143. {
  144. switch(type)
  145. {
  146. case DIST_POINT0: return p0 ;
  147. case DIST_POINT1: return p1 ;
  148. case DIST_EDGE : return edge;
  149. default : return type;
  150. }
  151. }
  152. Flt Dist(C Vec2 &point, C Quad2 &quad, DIST_TYPE *_type)
  153. {
  154. DIST_TYPE t, type=DIST_NONE;
  155. Flt d, dist=0;
  156. UInt sign=(quad.clockwise() ? 0 : SIGN_BIT); // counter-clockwise tris require changing sign
  157. Vec2 p=point-quad.p[1]; if(Xor(DistPointPlane(p, Perp(quad.p[0]-quad.p[1])), sign)>0){d=DistPointEdge(point, quad.p[0], quad.p[1], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT0, DIST_POINT1, DIST_EDGE0);}}
  158. if(Xor(DistPointPlane(p, Perp(quad.p[1]-quad.p[2])), sign)>0){d=DistPointEdge(point, quad.p[1], quad.p[2], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT1, DIST_POINT2, DIST_EDGE1);}}
  159. p=point-quad.p[3]; if(Xor(DistPointPlane(p, Perp(quad.p[2]-quad.p[3])), sign)>0){d=DistPointEdge(point, quad.p[2], quad.p[3], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT2, DIST_POINT3, DIST_EDGE2);}}
  160. if(Xor(DistPointPlane(p, Perp(quad.p[3]-quad.p[0])), sign)>0){d=DistPointEdge(point, quad.p[3], quad.p[0], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT3, DIST_POINT0, DIST_EDGE3);}}
  161. if(!type)
  162. {
  163. type=DIST_PLANE;
  164. dist=0;
  165. }
  166. if(_type)*_type=type; return dist;
  167. }
  168. Flt Dist(C Vec &point, C Quad &quad, DIST_TYPE *_type, Bool test_quads_as_2_tris)
  169. {
  170. DIST_TYPE t, type=DIST_NONE;
  171. Flt d, dist=0;
  172. if(test_quads_as_2_tris)
  173. {
  174. dist=Dist(point, quad.tri013(), &type);
  175. switch(type)
  176. {
  177. case DIST_POINT2: type=DIST_POINT3; break;
  178. case DIST_EDGE1 : type=DIST_PLANE ; break;
  179. case DIST_EDGE2 : type=DIST_EDGE3 ; break;
  180. }
  181. d=Dist(point, quad.tri123(), &t);
  182. if(d<dist)
  183. {
  184. dist=d;
  185. switch(type=t)
  186. {
  187. case DIST_POINT0: type=DIST_POINT1; break;
  188. case DIST_POINT1: type=DIST_POINT2; break;
  189. case DIST_POINT2: type=DIST_POINT3; break;
  190. case DIST_EDGE0 : type=DIST_EDGE1 ; break;
  191. case DIST_EDGE1 : type=DIST_EDGE2 ; break;
  192. case DIST_EDGE2 : type=DIST_PLANE ; break;
  193. }
  194. }
  195. }else
  196. {
  197. Vec p=point-quad.p[1]; if(DistPointPlane(p, Cross(quad.n, quad.p[0]-quad.p[1]))>0){d=DistPointEdge(point, quad.p[0], quad.p[1], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT0, DIST_POINT1, DIST_EDGE0);}}
  198. if(DistPointPlane(p, Cross(quad.n, quad.p[1]-quad.p[2]))>0){d=DistPointEdge(point, quad.p[1], quad.p[2], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT1, DIST_POINT2, DIST_EDGE1);}}
  199. p=point-quad.p[3]; if(DistPointPlane(p, Cross(quad.n, quad.p[2]-quad.p[3]))>0){d=DistPointEdge(point, quad.p[2], quad.p[3], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT2, DIST_POINT3, DIST_EDGE2);}}
  200. if(DistPointPlane(p, Cross(quad.n, quad.p[3]-quad.p[0]))>0){d=DistPointEdge(point, quad.p[3], quad.p[0], &t); if(!type || d<dist){dist=d; type=UpdateTypeQ(t, DIST_POINT3, DIST_POINT0, DIST_EDGE3);}}
  201. if(!type)
  202. {
  203. type=DIST_PLANE;
  204. dist=Abs(DistPointPlane(point, quad));
  205. }
  206. }
  207. if(_type)*_type=type; return dist;
  208. }
  209. /******************************************************************************/
  210. Bool Cuts(C Vec2 &point, C Quad2 &quad)
  211. {
  212. UInt sign=(quad.clockwise() ? 0 : SIGN_BIT); // counter-clockwise tris require changing sign
  213. Vec2 p=point-quad.p[1]; if(Xor(DistPointPlane(p, Perp(quad.p[0]-quad.p[1])), sign)>0)return false;
  214. if(Xor(DistPointPlane(p, Perp(quad.p[1]-quad.p[2])), sign)>0)return false;
  215. p=point-quad.p[3]; if(Xor(DistPointPlane(p, Perp(quad.p[2]-quad.p[3])), sign)>0)return false;
  216. if(Xor(DistPointPlane(p, Perp(quad.p[3]-quad.p[0])), sign)>0)return false;
  217. return true;
  218. }
  219. Bool Cuts(C Vec &point, C Quad &quad, Bool test_quads_as_2_tris)
  220. {
  221. if(test_quads_as_2_tris)
  222. {
  223. return Cuts(point, quad.tri013()) || Cuts(point, quad.tri123());
  224. }else
  225. {
  226. Vec p=point-quad.p[1]; if(DistPointPlane(p, Cross(quad.n, quad.p[0]-quad.p[1]))>0)return false;
  227. if(DistPointPlane(p, Cross(quad.n, quad.p[1]-quad.p[2]))>0)return false;
  228. p=point-quad.p[3]; if(DistPointPlane(p, Cross(quad.n, quad.p[2]-quad.p[3]))>0)return false;
  229. if(DistPointPlane(p, Cross(quad.n, quad.p[3]-quad.p[0]))>0)return false;
  230. }
  231. return true;
  232. }
  233. Bool CutsEps(C Vec2 &point, C Quad2 &quad)
  234. {
  235. UInt sign=(quad.clockwise() ? 0 : SIGN_BIT); // counter-clockwise tris require changing sign
  236. Vec2 d10=!(quad.p[0]-quad.p[1]), p0=point-quad.p[0]; if(Xor(DistPointPlane(p0, Perp(d10)), sign)>EPS)return false;
  237. Vec2 d21=!(quad.p[1]-quad.p[2]), p1=point-quad.p[1]; if(Xor(DistPointPlane(p1, Perp(d21)), sign)>EPS)return false;
  238. Vec2 d32=!(quad.p[2]-quad.p[3]), p2=point-quad.p[2]; if(Xor(DistPointPlane(p2, Perp(d32)), sign)>EPS)return false;
  239. Vec2 d03=!(quad.p[3]-quad.p[0]), p3=point-quad.p[3]; if(Xor(DistPointPlane(p3, Perp(d03)), sign)>EPS)return false;
  240. if( DistPointPlane(p0, !(d10-d03)) >EPS)return false;
  241. if( DistPointPlane(p1, !(d21-d10)) >EPS)return false;
  242. if( DistPointPlane(p2, !(d32-d21)) >EPS)return false;
  243. if( DistPointPlane(p3, !(d03-d32)) >EPS)return false;
  244. return true;
  245. }
  246. Bool CutsEps(C Vec &point, C Quad &quad, Bool test_quads_as_2_tris)
  247. {
  248. if(test_quads_as_2_tris)
  249. {
  250. return Cuts(point, quad.tri013()) || Cuts(point, quad.tri123());
  251. }else
  252. {
  253. Vec d10=!(quad.p[0]-quad.p[1]); if(DistPointPlane(point, quad.p[0], Cross(quad.n, d10))>EPS)return false;
  254. Vec d21=!(quad.p[1]-quad.p[2]); if(DistPointPlane(point, quad.p[1], Cross(quad.n, d21))>EPS)return false;
  255. Vec d32=!(quad.p[2]-quad.p[3]); if(DistPointPlane(point, quad.p[2], Cross(quad.n, d32))>EPS)return false;
  256. Vec d03=!(quad.p[3]-quad.p[0]); if(DistPointPlane(point, quad.p[3], Cross(quad.n, d03))>EPS)return false;
  257. if(DistPointPlane(point, quad.p[0], !(d10-d03))>EPS)return false;
  258. if(DistPointPlane(point, quad.p[1], !(d21-d10))>EPS)return false;
  259. if(DistPointPlane(point, quad.p[2], !(d32-d21))>EPS)return false;
  260. if(DistPointPlane(point, quad.p[3], !(d03-d32))>EPS)return false;
  261. }
  262. return true;
  263. }
  264. /******************************************************************************/
  265. Bool SweepPointQuad(C Vec &point, C Vec &move, C Quad &quad, Flt *hit_frac, Vec *hit_pos, Bool test_quads_as_2_tris, Bool two_sided)
  266. {
  267. Vec hitp;
  268. if(test_quads_as_2_tris)
  269. {
  270. return SweepPointTri(point, move, quad.tri013(), hit_frac, hit_pos, two_sided)
  271. || SweepPointTri(point, move, quad.tri123(), hit_frac, hit_pos, two_sided);
  272. }else
  273. {
  274. if(SweepPointPlane(point, move, Plane(quad.p[0], quad.n), hit_frac, null, &hitp, two_sided) && Cuts(hitp, quad))
  275. {
  276. if(hit_pos)*hit_pos=hitp;
  277. return true;
  278. }
  279. }
  280. return false;
  281. }
  282. Bool SweepPointQuadEps(C Vec &point, C Vec &move, C Quad &quad, Flt *hit_frac, Vec *hit_pos, Bool test_quads_as_2_tris, Bool two_sided)
  283. {
  284. Vec hitp;
  285. if(test_quads_as_2_tris)
  286. {
  287. return SweepPointTriEps(point, move, quad.tri013(), hit_frac, hit_pos, two_sided)
  288. || SweepPointTriEps(point, move, quad.tri123(), hit_frac, hit_pos, two_sided);
  289. }else
  290. {
  291. if(SweepPointPlane(point, move, Plane(quad.p[0], quad.n), hit_frac, null, &hitp, two_sided) && CutsEps(hitp, quad))
  292. {
  293. if(hit_pos)*hit_pos=hitp;
  294. return true;
  295. }
  296. }
  297. return false;
  298. }
  299. /******************************************************************************/
  300. }
  301. /******************************************************************************/