KDroot.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. ** Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
  3. **
  4. ** File: KDroot.cpp
  5. **
  6. ** Author:
  7. **
  8. ** Description:
  9. **
  10. ** History:
  11. */
  12. #include "pch.h"
  13. KDroot::KDroot(bool bStatic)
  14. :
  15. KDnode(NULL),
  16. m_nAdded(0),
  17. m_nDeleted(0),
  18. m_bStatic(bStatic)
  19. {
  20. //allocate enough space for everything we'll ever want
  21. allocHitTestsEndpoints((c_maxHitTests * 3) >> 1);
  22. }
  23. KDroot::~KDroot(void)
  24. {
  25. //everything should be marked dead before the root destructor is called.
  26. flush();
  27. assert (m_nHitTests == 0);
  28. }
  29. void KDroot::addHitTest(HitTest* pHitTest)
  30. {
  31. assert (m_nHitTests <= m_maxHitTests);
  32. //Not allowed to add a node that was marked dead but not yet pruned.
  33. //Danger: we are performing an operation on another KDRoot which,
  34. //theoretically, could have been freed. The only reason it works is
  35. //that -- if it were freed -- then it would have been flushed and all
  36. //of the hittests that refered back to the it would have had their
  37. //KDRoot's cleared.
  38. if (pHitTest->GetKDRoot() != NULL)
  39. pHitTest->GetKDRoot()->flush();
  40. assert (pHitTest->GetKDRoot() == NULL);
  41. pHitTest->SetKDRoot(this);
  42. pHitTest->SetDeadF(false);
  43. pHitTest->SetDeletedF(false);
  44. if (m_nHitTests == m_maxHitTests)
  45. {
  46. //Need more space but, unlike a KDnode, we can't simply nuke the
  47. //object/endpoint arrays: we need to create, copy and then nuke.
  48. assert (m_ppHitTests);
  49. //Double the existing space
  50. int n = m_maxHitTests << 1;
  51. void** v = new void* [n * (1 + 2 * c_nAxes)];
  52. assert (v);
  53. m_maxHitTests = n;
  54. for (int i = 0; (i < c_nAxes); i++)
  55. {
  56. Endpoint** pOldEndpoints = m_ppEndpoints[i];
  57. m_ppEndpoints[i] = (i == 0)
  58. ? ((Endpoint**)(v + n))
  59. : m_ppEndpoints[i - 1] + (m_maxHitTests << 1);
  60. for (int j = 0; (j < (m_nHitTests << 1)); j++)
  61. m_ppEndpoints[i][j] = pOldEndpoints[j];
  62. }
  63. {
  64. HitTest** ppOldHitTests = m_ppHitTests;
  65. m_ppHitTests = (HitTest**)v;
  66. for (int i = 0; (i < m_nHitTests); i++)
  67. m_ppHitTests[i] = ppOldHitTests[i];
  68. delete ppOldHitTests;
  69. }
  70. }
  71. assert (m_nHitTests < m_maxHitTests);
  72. if (m_bStatic)
  73. pHitTest->UpdateStaticBB();
  74. //Add a reference to the hitTest's data object
  75. pHitTest->AddRef();
  76. //Add the object to the list of
  77. m_ppHitTests[m_nHitTests] = pHitTest;
  78. //create and sort the endpoint lists for each axis.
  79. {
  80. int ht2 = m_nHitTests << 1;
  81. for (int axis = 0; (axis < c_nAxes); axis++)
  82. {
  83. m_ppEndpoints[axis][ht2 ] = &pHitTest->m_endpoints[axis][0];
  84. m_ppEndpoints[axis][ht2 + 1] = &pHitTest->m_endpoints[axis][1];
  85. }
  86. }
  87. m_nHitTests++;
  88. //Increment the changed count (which determines which sort is used in the update).
  89. m_nAdded++;
  90. }
  91. void KDroot::deleteHitTest(HitTest* pHitTest)
  92. {
  93. //Actually defer the delete until the next update
  94. m_nDeleted++;
  95. pHitTest->SetDeadF(true);
  96. pHitTest->SetDeletedF(true);
  97. //If we are deleting a hit test ... it must preserve the pointer to the old hit test
  98. assert (pHitTest->GetKDRoot() == this);
  99. }
  100. void KDroot::flush(void)
  101. {
  102. if (m_nDeleted > 0)
  103. {
  104. //One or more objects were deleted ... scan through the object and endpoint arrays, nuking the dead objects.
  105. //Endpoint arrays first
  106. for (int axis = 0; (axis < c_nAxes); axis++)
  107. {
  108. int dest = 0;
  109. for (int source = 0; (source < (m_nHitTests << 1)); source++)
  110. {
  111. if (!m_ppEndpoints[axis][source]->pHitTest->m_deletedF)
  112. {
  113. m_ppEndpoints[axis][dest++] = m_ppEndpoints[axis][source];
  114. }
  115. }
  116. }
  117. {
  118. //Do the same for the objects ... but also release the object as well
  119. int dest = 0;
  120. for (int source = 0; (source < m_nHitTests); source++)
  121. {
  122. HitTest* pht = m_ppHitTests[source];
  123. if (pht->m_deletedF)
  124. {
  125. pht->SetKDRoot(NULL); //We are not allowed to add this hit test to another KD tree until after this point
  126. //so mark the node as not being dead (and acceptable to add) here.
  127. pht->Release();
  128. }
  129. else
  130. {
  131. m_ppHitTests[dest++] = pht;
  132. }
  133. }
  134. m_nHitTests = dest;
  135. }
  136. m_nDeleted = 0;
  137. }
  138. }
  139. void KDroot::update(void)
  140. {
  141. //Only works from the root
  142. assert (!m_parent);
  143. bool bSort = (!m_bStatic) || (m_nAdded > 0);
  144. if (bSort || ((m_nDeleted << 4) > m_nHitTests))
  145. {
  146. flush();
  147. if (m_nHitTests >= c_minRootSize)
  148. {
  149. if (bSort)
  150. {
  151. //Resort the list of endpoints.
  152. //Use the short or long sort depending on how things have changed
  153. for (int axis = 0; (axis < c_nAxes); axis++)
  154. {
  155. if ((m_nAdded << 2) > m_nHitTests)
  156. {
  157. //Lots of things have changed ... use the long sort.
  158. Endpoint::longSort(&m_ppEndpoints[axis][0],
  159. &m_ppEndpoints[axis][(m_nHitTests << 1) - 1]);
  160. }
  161. else
  162. {
  163. //Only minor changes ... use the short sort.
  164. Endpoint::shortSort(&m_ppEndpoints[axis][0],
  165. &m_ppEndpoints[axis][(m_nHitTests << 1) - 1]);
  166. }
  167. }
  168. m_nAdded = 0;
  169. }
  170. pivot();
  171. }
  172. else
  173. m_pivotAxis = -1;
  174. }
  175. }