[dasher] Force Dasher to pick a new root rather than stop (except when reversing too far)



commit 64f3748f25b0ec84414bbf707a4d88e2d73cab1f
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Fri Feb 12 13:15:56 2010 +0000

    Force Dasher to pick a new root rather than stop (except when reversing too far)
    
    Remove parameters from Reparent_root; simplify due to no NF_SUBNODES; fix
    abort code (when reparenting impossible). Also GC DasherNode::GetProb().

 Src/DasherCore/AlphabetManager.cpp |    2 +-
 Src/DasherCore/DasherModel.cpp     |  126 ++++++++++++++++++++----------------
 Src/DasherCore/DasherModel.h       |    2 +-
 Src/DasherCore/DasherNode.cpp      |    5 --
 Src/DasherCore/DasherNode.h        |   11 ---
 5 files changed, 71 insertions(+), 75 deletions(-)
---
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index ed52a2f..9ee0c98 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -403,7 +403,7 @@ void CAlphabetManager::CSymbolNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, i
   if (pAdded != NULL) {
     Dasher::SymbolProb sItem;
     sItem.sym    = iSymbol;
-    sItem.prob   = GetProb(iNormalization);
+    sItem.prob   = Range() / (double)iNormalization;
 
     pAdded->push_back(sItem);
   }
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index ab34ea9..383ce8b 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -168,14 +168,14 @@ void CDasherModel::Make_root(CDasherNode *pNewRoot) {
   m_Root = pNewRoot;
 
   // Update the root coordinates, as well as any currently scheduled locations
-  myint range = m_Rootmax - m_Rootmin;
-  m_Rootmax = m_Rootmin + (range * m_Root->Hbnd()) / (int)GetLongParameter(LP_NORMALIZATION);
-  m_Rootmin = m_Rootmin + (range * m_Root->Lbnd()) / (int)GetLongParameter(LP_NORMALIZATION);
+  const myint range = m_Rootmax - m_Rootmin;
+  m_Rootmax = m_Rootmin + (range * m_Root->Hbnd()) / GetLongParameter(LP_NORMALIZATION);
+  m_Rootmin = m_Rootmin + (range * m_Root->Lbnd()) / GetLongParameter(LP_NORMALIZATION);
   
   for(std::deque<SGotoItem>::iterator it(m_deGotoQueue.begin()); it != m_deGotoQueue.end(); ++it) {
-    myint r = it->iN2 - it->iN1;
-    it->iN2 = it->iN1 + (r * m_Root->Hbnd()) / (int)GetLongParameter(LP_NORMALIZATION);
-    it->iN1 = it->iN1 + (r * m_Root->Lbnd()) / (int)GetLongParameter(LP_NORMALIZATION);
+    const myint r = it->iN2 - it->iN1;
+    it->iN2 = it->iN1 + (r * m_Root->Hbnd()) / GetLongParameter(LP_NORMALIZATION);
+    it->iN1 = it->iN1 + (r * m_Root->Lbnd()) / GetLongParameter(LP_NORMALIZATION);
   }
 }
 
@@ -209,7 +209,7 @@ void CDasherModel::RebuildAroundCrosshair() {
   m_Root->PopulateChildren();
 }
 
-void CDasherModel::Reparent_root(int lower, int upper) {
+void CDasherModel::Reparent_root() {
   DASHER_ASSERT(m_Root != NULL);
 
   // Change the root node to the parent of the existing node. We need
@@ -219,52 +219,42 @@ void CDasherModel::Reparent_root(int lower, int upper) {
 
   if(oldroots.size() == 0) {
     pNewRoot = m_Root->RebuildParent();
+    // Return if there's no existing parent and no way of recreating one
+    if(pNewRoot == NULL) return;
   }
   else {
     pNewRoot = oldroots.back();
     oldroots.pop_back();
   }
 
-  // Return if there's no existing parent and no way of recreating one
-  if(pNewRoot == NULL)
-    return;
-
   pNewRoot->SetFlag(NF_COMMITTED, false);
 
-  CDasherNode *pCurrent = m_Root;
-
-  // Need to iterate through group pseudo-nodes
-  while(pCurrent != pNewRoot) {
+  DASHER_ASSERT(m_Root->Parent() == pNewRoot);
 
-    lower = pCurrent->Lbnd();
-    upper = pCurrent->Hbnd();
-
-    pCurrent = pCurrent->Parent();
-        
-    myint iWidth = upper - lower;
-    myint iRootWidth = m_Rootmax - m_Rootmin;
+  const myint lower(m_Root->Lbnd()), upper(m_Root->Hbnd());
+  const myint iRange(upper-lower);
+  myint iRootWidth(m_Rootmax - m_Rootmin);
     
-    // Fail and undo root creation if the new root is bigger than allowed by normalisation
-    if(((myint((GetLongParameter(LP_NORMALIZATION) - upper)) / static_cast<double>(iWidth)) >
-	 (m_Rootmax_max - m_Rootmax)/static_cast<double>(iRootWidth)) || 
-	((myint(lower) / static_cast<double>(iWidth)) > 
-	 (m_Rootmin - m_Rootmin_min) / static_cast<double>(iRootWidth))) {
-      pNewRoot->OrphanChild(m_Root);
-      delete pNewRoot;
-      return;
-    }
+  // Fail if the new root is bigger than allowed by normalisation
+  if(((myint((GetLongParameter(LP_NORMALIZATION) - upper)) / static_cast<double>(iRange)) >
+           (m_Rootmax_max - m_Rootmax)/static_cast<double>(iRootWidth)) || 
+      ((myint(lower) / static_cast<double>(iRange)) > 
+           (m_Rootmin - m_Rootmin_min) / static_cast<double>(iRootWidth))) {
+    //but cache the (currently-unusable) root node - else we'll keep recreating (and deleting) it on every frame... 
+    oldroots.push_back(pNewRoot);
+    return;
+  }
     
-    //Update the root coordinates to reflect the new root
-    m_Root = pNewRoot;
+  //Update the root coordinates to reflect the new root
+  m_Root = pNewRoot;
     
-    m_Rootmax = m_Rootmax + (myint((GetLongParameter(LP_NORMALIZATION) - upper)) * iRootWidth / iWidth);
-    m_Rootmin = m_Rootmin - (myint(lower) * iRootWidth / iWidth);
+  m_Rootmax = m_Rootmax + ((GetLongParameter(LP_NORMALIZATION) - upper) * iRootWidth) / iRange;
+  m_Rootmin = m_Rootmin - (lower * iRootWidth) / iRange;
     
-    for(std::deque<SGotoItem>::iterator it(m_deGotoQueue.begin()); it != m_deGotoQueue.end(); ++it) {
-      iRootWidth = it->iN2 - it->iN1;
-      it->iN2 = it->iN2 + (myint((GetLongParameter(LP_NORMALIZATION) - upper)) * iRootWidth / iWidth);
-      it->iN1 = it->iN1 - (myint(lower) * iRootWidth / iWidth);
-    }
+  for(std::deque<SGotoItem>::iterator it(m_deGotoQueue.begin()); it != m_deGotoQueue.end(); ++it) {
+    iRootWidth = it->iN2 - it->iN1;
+    it->iN2 = it->iN2 + (myint((GetLongParameter(LP_NORMALIZATION) - upper)) * iRootWidth / iRange);
+    it->iN1 = it->iN1 - (myint(lower) * iRootWidth / iRange);
   }
 }
 
@@ -324,7 +314,7 @@ void CDasherModel::InitialiseAtOffset(int iOffset, CDasherView *pView) {
   if(pView) {
     while(pView->IsNodeVisible(m_Rootmin,m_Rootmax)) {
       CDasherNode *pOldRoot = m_Root;
-      Reparent_root(m_Root->Lbnd(), m_Root->Hbnd());
+      Reparent_root();
       if(m_Root == pOldRoot)
 	break;
     }
@@ -507,23 +497,45 @@ void CDasherModel::NewGoTo(myint newRootmin, myint newRootmax, Dasher::VECTOR_SY
   // allowed to let the root max and min cross the midpoint of the
   // screen.
 
-  if(newRootmax < m_Rootmax_max && newRootmin > m_Rootmin_min && (newRootmax - newRootmin) > (myint)GetLongParameter(LP_MAX_Y) / 4) {
+  if(newRootmax < m_Rootmax_max && newRootmin > m_Rootmin_min) {
     // Only update if we're not making things big enough to risk
-    // overflow. In theory we should have reparented the root well
-    // before getting this far.
-    //
-    // Also don't allow the update if it will result in making the
-    // root too small. Again, we should have re-generated a deeper
-    // root in most cases, but the original root is an exception.
-
-    m_Rootmax = newRootmax;
-    m_Rootmin = newRootmin;
-
+    // overflow. (Otherwise, forcibly choose a new root node, below)
+    
+    if ((newRootmax - newRootmin) > (myint)GetLongParameter(LP_MAX_Y) / 4) {
+      // Also don't allow the update if it will result in making the
+      // root too small. We should have re-generated a deeper root
+      // before now already, but the original root is an exception.
+      m_Rootmax = newRootmax;
+      m_Rootmin = newRootmin;
+    } //else, we just stop - this prevents the user from zooming too far back
+      //outside the root node (when we can't generate an older root).
     m_iDisplayOffset = (m_iDisplayOffset * 90) / 100;
-  }
-  else {
-    // TODO - force a new root to be chosen, so that we get better
-    // behaviour than just having Dasher stop at this point.
+  } else {
+    // can't make existing root any bigger because of overflow. So force a new root
+    // to be chosen (so that Dasher doesn't just stop!)...
+    
+    //pick _child_ covering crosshair...
+    const myint iWidth(m_Rootmax-m_Rootmin);
+    for (CDasherNode::ChildMap::const_iterator it = m_Root->GetChildren().begin(), E = m_Root->GetChildren().end(); it!=E; it++) {
+      CDasherNode *pChild(*it);
+      DASHER_ASSERT(m_Rootmin + ((pChild->Lbnd() * iWidth) / GetLongParameter(LP_NORMALIZATION)) <= GetLongParameter(LP_OY));
+      if (m_Rootmin + ((pChild->Hbnd() * iWidth) / GetLongParameter(LP_NORMALIZATION)) > GetLongParameter(LP_OY)) {
+        //proceed only if new root is on the game path. If the user's strayed
+        // that far off the game path, having Dasher stop seems reasonable!
+        if (!m_bGameMode || !pChild->GetFlag(NF_GAME)) {
+          //make pChild the root node...but put (newRootmin,newRootmax) somewhere there'll be converted:
+          SGotoItem temp; temp.iN1 = newRootmin; temp.iN2 = newRootmax;
+          m_deGotoQueue.push_back(temp);
+          m_Root->DeleteNephews(pChild);
+          RecursiveMakeRoot(pChild);
+          temp=m_deGotoQueue.back(); m_deGotoQueue.pop_back();
+          std::cout << "NewGoto Recursing - was (" << newRootmin << "," << newRootmax << "), now (" << temp.iN1 << "," << temp.iN2 << ")" << std::endl;
+          NewGoTo(temp.iN1, temp.iN2, pAdded,pNumDeleted);
+        }
+        return;
+      }
+    }
+    DASHER_ASSERT(false); //did not find a child covering crosshair...?!
   }
 }
 
@@ -648,7 +660,7 @@ bool CDasherModel::CheckForNewRoot(CDasherView *pView) {
   CDasherNode *root(m_Root);
 
   if(!(m_Root->GetFlag(NF_SUPER))) {
-    Reparent_root(root->Lbnd(), root->Hbnd());
+    Reparent_root();
     return(m_Root != root);
   }
 
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index f716e3d..b23b2d4 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -337,7 +337,7 @@ class Dasher::CDasherModel:public Dasher::CFrameRate, private NoClones
   /// Rebuild the parent of the current root - used during backing off
   ///
 
-  void Reparent_root(int lower, int upper); 
+  void Reparent_root(); 
 
   ///
   /// Return a pointer to the Dasher node which is currently under the
diff --git a/Src/DasherCore/DasherNode.cpp b/Src/DasherCore/DasherNode.cpp
index 88c66d4..229f529 100644
--- a/Src/DasherCore/DasherNode.cpp
+++ b/Src/DasherCore/DasherNode.cpp
@@ -176,11 +176,6 @@ void CDasherNode::Delete_children() {
   SetFlag(NF_ALLCHILDREN, false);
 }
 
-// Gets the probability of this node, conditioned on the parent
-double CDasherNode::GetProb(int iNormalization) {    
-  return (double) (m_iHbnd - m_iLbnd) / (double) iNormalization;
-}
-
 void CDasherNode::SetFlag(int iFlag, bool bValue) {
 
  if(bValue)
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index f15beb0..892f060 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -160,17 +160,6 @@ class Dasher::CDasherNode:private NoClones {
   ///
   inline void SetRange(unsigned int iLower, unsigned int iUpper);
 
-  /// @brief Get the probability of a node
-  ///
-  /// @param iNormalization Normalisation constant
-  ///
-  /// @return The probability
-  ///
-  /// @todo Possibly a bit simplistic to make a full member
-  /// @todo Inline
-  ///
-  double GetProb(int iNormalization);
-
   /// @brief Get the size of the most probable child
   ///
   /// @return The size



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]