Clone of UAS2 @ https://github.com/drudgedance/uas2

cPhysics.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * This file is part of UAS2.
  3. *
  4. * UAS2 is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * UAS2 is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. * You should have received a copy of the GNU General Public License
  14. * along with UASv1; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. /**
  18. * @file cPhysics.cpp
  19. * Implements functionality for item models.
  20. *
  21. * Item models comprise the generic traits shared among a type of object with a particular model.
  22. *
  23. * Special thanks to Greg Kusnick for his work on the landblock triangulation algorithm.
  24. */
  25. #include "cPhysics.h"
  26. #include "WorldManager.h"
  27. #ifdef _DEBUG
  28. #undef THIS_FILE
  29. static char THIS_FILE[]=__FILE__;
  30. #define new DEBUG_NEW
  31. #endif
  32. /***************
  33. * constructors/destructors
  34. **************/
  35. cPhysics::cPhysics()
  36. {
  37. }
  38. cPhysics::~cPhysics()
  39. {
  40. }
  41. float cPhysics::length(quaternion quat)
  42. {
  43. return sqrt(quat.x*quat.x + quat.y*quat.y + quat.z*quat.z + quat.w*quat.w);
  44. }
  45. quaternion cPhysics::normalize(quaternion quat)
  46. {
  47. float L = length(quat);
  48. quat.x /= L;
  49. quat.y /= L;
  50. quat.z /= L;
  51. quat.w /= L;
  52. return quat;
  53. }
  54. quaternion cPhysics::conjugate(quaternion quat)
  55. {
  56. quat.x = -quat.x;
  57. quat.y = -quat.y;
  58. quat.z = -quat.z;
  59. return quat;
  60. }
  61. quaternion cPhysics::mult(quaternion A, quaternion B)
  62. {
  63. quaternion C;
  64. C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
  65. C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
  66. C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
  67. C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
  68. return C;
  69. }
  70. void cPhysics::Rotate(float Angle, float x, float y, float z, vector& View)
  71. {
  72. quaternion temp, quat_view, result;
  73. temp.x = x * sin(Angle/2);
  74. temp.y = y * sin(Angle/2);
  75. temp.z = z * sin(Angle/2);
  76. temp.w = cos(Angle/2);
  77. quat_view.x = View.x;
  78. quat_view.y = View.y;
  79. quat_view.z = View.z;
  80. quat_view.w = 0;
  81. result = mult(mult(temp, quat_view), conjugate(temp));
  82. View.x = result.x;
  83. View.y = result.y;
  84. View.z = result.z;
  85. }
  86. float cPhysics::GetLineDistance ( cLocation OldLoc, cLocation NewLoc, cLocation TarLoc ) //agentsparrow
  87. {
  88. float nsCoord1,ewCoord1,nsCoord2,ewCoord2;
  89. float nsTarCoord,ewTarCoord,flDistance;
  90. nsCoord1 = (((((OldLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(OldLoc.m_flY / 24) - 1027.5;
  91. ewCoord1 = (((((OldLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(OldLoc.m_flX / 24) - 1027.5;
  92. nsCoord2 = (((((NewLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(NewLoc.m_flY / 24) - 1027.5;
  93. ewCoord2 = (((((NewLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(NewLoc.m_flX / 24) - 1027.5;
  94. nsTarCoord = (((((TarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(TarLoc.m_flY / 24) - 1027.5;
  95. ewTarCoord = (((((TarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(TarLoc.m_flX / 24) - 1027.5;
  96. float flNumerator = (ewTarCoord-ewCoord1)*(ewCoord2-ewCoord1) + (nsTarCoord-nsCoord1)*(nsCoord2-nsCoord1);
  97. float flDenomenator = (ewCoord2-ewCoord1)*(ewCoord2-ewCoord1) + (nsCoord2-nsCoord1)*(nsCoord2-nsCoord1);
  98. float flR = flNumerator / flDenomenator;
  99. if ( (flR >= 0.0f) && (flR <= 1.0f) )
  100. {
  101. float flS = ((nsCoord1-nsTarCoord)*(ewCoord2-ewCoord1)-(ewCoord1-ewTarCoord)*(nsCoord2-nsCoord1)) / flDenomenator;
  102. flDistance = fabs(flS)*sqrt(flDenomenator);
  103. return flDistance;
  104. }
  105. else
  106. {
  107. float flDist1 = (ewTarCoord-ewCoord1)*(ewTarCoord-ewCoord1) + (nsTarCoord-nsCoord1)*(nsTarCoord-nsCoord1);
  108. float flDist2 = (ewTarCoord-ewCoord2)*(ewTarCoord-ewCoord2) + (nsTarCoord-nsCoord2)*(nsTarCoord-nsCoord2);
  109. if (flDist1 < flDist2)
  110. {
  111. flDistance = sqrt(flDist1);
  112. }
  113. else
  114. {
  115. flDistance = sqrt(flDist2);
  116. }
  117. }
  118. return flDistance;
  119. }
  120. float cPhysics::Get3DLineDistance ( cLocation OldLoc, cLocation NewLoc, cLocation TarLoc ) //agentsparrow
  121. {
  122. float nsCoord1,ewCoord1,nsCoord2,ewCoord2;
  123. float nsTarCoord,ewTarCoord,OldZ,NewZ,TarZ,flDistance;
  124. nsCoord1 = (((((OldLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(OldLoc.m_flY / 24) - 1027.5;
  125. ewCoord1 = (((((OldLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(OldLoc.m_flX / 24) - 1027.5;
  126. nsCoord2 = (((((NewLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(NewLoc.m_flY / 24) - 1027.5;
  127. ewCoord2 = (((((NewLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(NewLoc.m_flX / 24) - 1027.5;
  128. nsTarCoord = (((((TarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(TarLoc.m_flY / 24) - 1027.5;
  129. ewTarCoord = (((((TarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(TarLoc.m_flX / 24) - 1027.5;
  130. OldZ = OldLoc.m_flZ/24;
  131. NewZ = NewLoc.m_flZ/24;
  132. TarZ = TarLoc.m_flZ/24;
  133. float flNumerator = (ewTarCoord-ewCoord1)*(ewCoord2-ewCoord1) + (nsTarCoord-nsCoord1)*(nsCoord2-nsCoord1) + (TarZ-OldZ)*(NewZ-OldZ);
  134. float flDenomenator = (ewCoord2-ewCoord1)*(ewCoord2-ewCoord1) + (nsCoord2-nsCoord1)*(nsCoord2-nsCoord1) + (NewZ-OldZ)*(NewZ-OldZ);
  135. float flR = flNumerator / flDenomenator;
  136. if ( (flR >= 0.0f) && (flR <= 1.0f) )
  137. {
  138. float IntX = ewCoord1 + flR * (ewCoord2-ewCoord1);
  139. float IntY = nsCoord1 + flR * (nsCoord2-nsCoord1);
  140. float IntZ = OldZ + flR * (NewZ-OldZ);
  141. flDistance = sqrt((ewTarCoord-IntX)*(ewTarCoord-IntX) + (nsTarCoord-IntY)*(nsTarCoord-IntY) + (TarZ-IntZ)*(TarZ-IntZ));
  142. return flDistance;
  143. }
  144. else
  145. {
  146. float flDist1 = (ewTarCoord-ewCoord1)*(ewTarCoord-ewCoord1) + (nsTarCoord-nsCoord1)*(nsTarCoord-nsCoord1) + (TarZ-OldZ)*(TarZ-OldZ);
  147. float flDist2 = (ewTarCoord-ewCoord2)*(ewTarCoord-ewCoord2) + (nsTarCoord-nsCoord2)*(nsTarCoord-nsCoord2) + (TarZ-NewZ)*(TarZ-NewZ);
  148. if (flDist1 < flDist2)
  149. {
  150. flDistance = sqrt(flDist1);
  151. }
  152. else
  153. {
  154. flDistance = sqrt(flDist2);
  155. }
  156. }
  157. return flDistance;
  158. }
  159. float cPhysics::GetRange ( cLocation usrLoc, cLocation tarLoc )
  160. {
  161. float nsCoord,ewCoord;
  162. float nsTarCoord,ewTarCoord;
  163. float flRange;
  164. nsCoord = (((((usrLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flY / 24) - 1027.5;
  165. ewCoord = (((((usrLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flX / 24) - 1027.5;
  166. nsTarCoord = (((((tarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flY / 24) - 1027.5;
  167. ewTarCoord = (((((tarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flX / 24) - 1027.5;
  168. flRange = sqrt(pow(nsTarCoord - nsCoord,2) + pow(ewTarCoord - ewCoord,2));
  169. return flRange;
  170. }
  171. float cPhysics::Get3DRange ( cLocation usrLoc, cLocation tarLoc ) //agentsparrow
  172. {
  173. float nsCoord,ewCoord;
  174. float nsTarCoord,ewTarCoord;
  175. float flRange;
  176. nsCoord = (((((usrLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flY / 24) - 1027.5;
  177. ewCoord = (((((usrLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flX / 24) - 1027.5;
  178. nsTarCoord = (((((tarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flY / 24) - 1027.5;
  179. ewTarCoord = (((((tarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flX / 24) - 1027.5;
  180. flRange = sqrt(pow(nsTarCoord - nsCoord,2) + pow(ewTarCoord - ewCoord,2) + pow((tarLoc.m_flZ - usrLoc.m_flZ)/24,2));
  181. return flRange;
  182. }
  183. cVelocity cPhysics::GetTargetVelocity ( cLocation usrLoc, cLocation tarLoc ) //agentsparrow
  184. {
  185. float nsCoord,ewCoord;
  186. float nsTarCoord,ewTarCoord;
  187. cVelocity tarVel;
  188. float flRange;
  189. nsCoord = (((((usrLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flY / 24) - 1027.5;
  190. ewCoord = (((((usrLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flX / 24) - 1027.5;
  191. nsTarCoord = (((((tarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flY / 24) - 1027.5;
  192. ewTarCoord = (((((tarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flX / 24) - 1027.5;
  193. flRange = sqrt(pow(nsTarCoord - nsCoord,2) + pow(ewTarCoord - ewCoord,2) + pow((tarLoc.m_flZ - usrLoc.m_flZ)/24,2));
  194. tarVel.m_dx = (ewTarCoord - ewCoord)/flRange;
  195. tarVel.m_dy = (nsTarCoord - nsCoord)/flRange;
  196. tarVel.m_dz = (tarLoc.m_flZ - usrLoc.m_flZ)/24/flRange;
  197. return tarVel;
  198. }
  199. cLocation cPhysics::VelocityMove ( cLocation usrLoc, cVelocity tarVel, float flSpeed ) //agentsparrow
  200. {
  201. float x, y;
  202. cLocation newLoc;
  203. newLoc = usrLoc;
  204. x = (((((usrLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flX / 24) - 1027.5;
  205. y = (((((usrLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flY / 24) - 1027.5;
  206. x += tarVel.m_dx * flSpeed/24;
  207. x += 1027.5;
  208. int iLBx = (int) (x/8);
  209. x -= iLBx*8;
  210. newLoc.m_flX = x*24;
  211. iLBx -= 1;
  212. int squareX = (int) (x+1);
  213. y += tarVel.m_dy * flSpeed/24;
  214. y += 1027.5;
  215. int iLBy = (int) (y/8);
  216. y -= iLBy*8;
  217. newLoc.m_flY = y*24;
  218. iLBy -= 1;
  219. int squareY = (int) (y+1);
  220. int square = ((squareX-1)*8)+squareY;
  221. newLoc.m_dwLandBlock = ((double) iLBx * 0x1000000) + ((double) iLBy * 0x10000) + (double) square;
  222. newLoc.m_flZ += tarVel.m_dz * flSpeed;
  223. return newLoc;
  224. }
  225. float cPhysics::GetHeadingTarget( cLocation usrLoc, cLocation tarLoc )
  226. {
  227. float nsCoord,ewCoord;
  228. float nsTarCoord,ewTarCoord;
  229. float flHeading;
  230. float flRange;
  231. flHeading = 0.0f;
  232. nsCoord = (((((usrLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flY / 24) - 1027.5;
  233. ewCoord = (((((usrLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(usrLoc.m_flX / 24) - 1027.5;
  234. nsTarCoord = (((((tarLoc.m_dwLandBlock & 0x00FF0000) / 0x0010000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flY / 24) - 1027.5;
  235. ewTarCoord = (((((tarLoc.m_dwLandBlock & 0xFF000000) / 0x1000000) & 0xFF) + 1) * 8) + static_cast<float>(tarLoc.m_flX / 24) - 1027.5;
  236. flRange = sqrt(pow(nsTarCoord - nsCoord,2) + pow(ewTarCoord - ewCoord,2));
  237. if(flRange > 0)
  238. {
  239. if(nsTarCoord - nsCoord < 0 )
  240. {
  241. flHeading = acos((ewTarCoord - ewCoord) / flRange) * 57.2957796;
  242. }
  243. else
  244. {
  245. flHeading = acos(-(ewTarCoord - ewCoord) / flRange) * 57.2957796 + 180;
  246. }
  247. }
  248. return flHeading;
  249. }
  250. float cPhysics::GetAvatarHeading( cLocation usrLoc )
  251. {
  252. float pi = 3.14159f;
  253. float flHeading;
  254. if ( (usrLoc.m_flA > 0 && usrLoc.m_flW > 0) || (usrLoc.m_flA < 0 && usrLoc.m_flW > 0) )
  255. usrLoc.m_flA *= -1;
  256. flHeading = (360/pi) * acos(usrLoc.m_flA);
  257. flHeading -= 90;
  258. if (flHeading > 360)
  259. flHeading -= 360;
  260. if (flHeading < 0)
  261. flHeading += 360;
  262. return flHeading;
  263. }
  264. float cPhysics::GetHeadingDifference( float flUserHeading, float flTargetHeading ) //agentsparrow
  265. {
  266. float flDifference = 0.0f;
  267. if ( flUserHeading > flTargetHeading )
  268. {
  269. if ( flUserHeading - flTargetHeading < 180 )
  270. {
  271. flDifference = flUserHeading - flTargetHeading;
  272. }
  273. else
  274. {
  275. flDifference = (360 - flUserHeading) + flTargetHeading;
  276. }
  277. }
  278. else if ( flTargetHeading > flUserHeading )
  279. {
  280. if ( flTargetHeading - flUserHeading < 180 )
  281. {
  282. flDifference = flTargetHeading - flUserHeading;
  283. }
  284. else
  285. {
  286. flDifference = (360 - flTargetHeading) + flUserHeading;
  287. }
  288. }
  289. return flDifference;
  290. }
  291. float cPhysics::GetLandZ( cLocation usrLoc ) //agentsparrow
  292. {
  293. float flLandZ;
  294. float pSW[3], pNW[3], pSE[3], pNE[3];
  295. float flA, flB, flC;
  296. int startX, startY, count;
  297. cLandBlock *pcLB = cLandBlock::Hash_Find( HIWORD( usrLoc.m_dwLandBlock ) );
  298. int square = LOBYTE( LOWORD( usrLoc.m_dwLandBlock ) );
  299. flLandZ = usrLoc.m_flZ;
  300. if (pcLB)
  301. {
  302. count = 1;
  303. startY = square;
  304. while (square > 8)
  305. {
  306. square -= 8;
  307. startY = square;
  308. count++;
  309. }
  310. startX = count;
  311. pSW[2] = pcLB->m_flLandBlockZ[startX-1][startY-1]*2;
  312. pNW[2] = pcLB->m_flLandBlockZ[startX-1][startY]*2;
  313. pSE[2] = pcLB->m_flLandBlockZ[startX][startY-1]*2;
  314. pNE[2] = pcLB->m_flLandBlockZ[startX][startY]*2;
  315. pSW[0] = (startX-1)*24;
  316. pNW[0] = (startX-1)*24;
  317. pSE[0] = startX*24;
  318. pNE[0] = startX*24;
  319. pSW[1] = (startY-1)*24;
  320. pNW[1] = startY*24;
  321. pSE[1] = (startY-1)*24;
  322. pNE[1] = startY*24;
  323. int x = HIBYTE(pcLB->m_wLandBlock) * 8;
  324. int y = LOBYTE(pcLB->m_wLandBlock) * 8;
  325. x += startX - 1;
  326. y += startY - 1;
  327. DWORD dw = x * y * 0x0CCAC033 - x * 0x421BE3BD + y * 0x6C1AC587 - 0x519B8F25;
  328. if ((dw & 0x80000000) != 0) // NE-SW split
  329. {
  330. float pNWRange = sqrt(pow(pNW[0] - usrLoc.m_flX,2) + pow(pNW[1] - usrLoc.m_flY,2));
  331. float pSERange = sqrt(pow(pSE[0] - usrLoc.m_flX,2) + pow(pSE[1] - usrLoc.m_flY,2));
  332. if ( pNWRange > pSERange ) // usrLoc is closer to pSE
  333. {
  334. flA = (pNE[1]-pSE[1])*(pSW[2]-pSE[2])-(pSW[1]-pSE[1])*(pNE[2]-pSE[2]);
  335. flB = (pNE[2]-pSE[2])*(pSW[0]-pSE[0])-(pSW[2]-pSE[2])*(pNE[0]-pSE[0]);
  336. flC = (pNE[0]-pSE[0])*(pSW[1]-pSE[1])-(pSW[0]-pSE[0])*(pNE[1]-pSE[1]);
  337. flLandZ = -flA/flC*(usrLoc.m_flX-pSE[0])-flB/flC*(usrLoc.m_flY-pSE[1])+pSE[2];
  338. }
  339. else // usrLoc is closer to pNW
  340. {
  341. flA = (pNE[1]-pNW[1])*(pSW[2]-pNW[2])-(pSW[1]-pNW[1])*(pNE[2]-pNW[2]);
  342. flB = (pNE[2]-pNW[2])*(pSW[0]-pNW[0])-(pSW[2]-pNW[2])*(pNE[0]-pNW[0]);
  343. flC = (pNE[0]-pNW[0])*(pSW[1]-pNW[1])-(pSW[0]-pNW[0])*(pNE[1]-pNW[1]);
  344. flLandZ = -flA/flC*(usrLoc.m_flX-pNW[0])-flB/flC*(usrLoc.m_flY-pNW[1])+pNW[2];
  345. }
  346. }
  347. else // NW-SE split
  348. {
  349. float pNERange = sqrt(pow(pNE[0] - usrLoc.m_flX,2) + pow(pNE[1] - usrLoc.m_flY,2));
  350. float pSWRange = sqrt(pow(pSW[0] - usrLoc.m_flX,2) + pow(pSW[1] - usrLoc.m_flY,2));
  351. if ( pNERange > pSWRange ) // usrLoc is closer to pSW
  352. {
  353. flA = (pSE[1]-pSW[1])*(pNW[2]-pSW[2])-(pNW[1]-pSW[1])*(pSE[2]-pSW[2]);
  354. flB = (pSE[2]-pSW[2])*(pNW[0]-pSW[0])-(pNW[2]-pSW[2])*(pSE[0]-pSW[0]);
  355. flC = (pSE[0]-pSW[0])*(pNW[1]-pSW[1])-(pNW[0]-pSW[0])*(pSE[1]-pSW[1]);
  356. flLandZ = -flA/flC*(usrLoc.m_flX-pSW[0])-flB/flC*(usrLoc.m_flY-pSW[1])+pSW[2];
  357. }
  358. else // usrLoc is closer to pNE
  359. {
  360. flA = (pNW[1]-pNE[1])*(pSE[2]-pNE[2])-(pSE[1]-pNE[1])*(pNW[2]-pNE[2]);
  361. flB = (pNW[2]-pNE[2])*(pSE[0]-pNE[0])-(pSE[2]-pNE[2])*(pNW[0]-pNE[0]);
  362. flC = (pNW[0]-pNE[0])*(pSE[1]-pNE[1])-(pSE[0]-pNE[0])*(pNW[1]-pNE[1]);
  363. flLandZ = -flA/flC*(usrLoc.m_flX-pNE[0])-flB/flC*(usrLoc.m_flY-pNE[1])+pNE[2];
  364. }
  365. }
  366. }
  367. return flLandZ;
  368. }