tagging release
[dasher.git] / Src / DasherCore / UserLogTrial.cpp
blob123292c1e4b33e951972d4af73933e1222ed5856
2 #include "../Common/Common.h"
4 #include "UserLogTrial.h"
6 // Track memory leaks on Windows to the line that new'd the memory
7 #ifdef _WIN32
8 #ifdef _DEBUG
9 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
10 #define new DEBUG_NEW
11 #undef THIS_FILE
12 static char THIS_FILE[] = __FILE__;
13 #endif
14 #endif
16 CUserLogTrial::CUserLogTrial(const string& strCurrentTrialFilename)
18 //CFunctionLogger f1("CUserLogTrial::CUserLogTrial", g_pLogger);
20 InitMemberVars();
22 m_strCurrentTrialFilename = strCurrentTrialFilename;
25 CUserLogTrial::~CUserLogTrial()
27 //CFunctionLogger f1("CUserLogTrial::~CUserLogTrial", g_pLogger);
29 for (unsigned int i = 0; i < m_vpParams.size(); i++)
31 CUserLogParam* pParam = (CUserLogParam*) m_vpParams[i];
33 if (pParam != NULL)
35 delete pParam;
36 pParam = NULL;
40 for (unsigned int i = 0; i < m_vpNavCycles.size(); i++)
42 NavCycle* pCycle = (NavCycle*) m_vpNavCycles[i];
44 if (pCycle != NULL)
46 if (pCycle->pSpan != NULL)
48 delete pCycle->pSpan;
49 pCycle->pSpan = NULL;
52 for (unsigned int i = 0; i < pCycle->vectorButtons.size(); i++)
54 CUserButton* pButton = (CUserButton*) pCycle->vectorButtons[i];
56 if (pButton != NULL)
58 delete pButton;
59 pButton = NULL;
63 for (unsigned int i = 0; i < pCycle->vectorMouseLocations.size(); i++)
65 CUserLocation* pLocation = (CUserLocation*) pCycle->vectorMouseLocations[i];
67 if (pLocation != NULL)
69 delete pLocation;
70 pLocation = NULL;
74 for (unsigned int i = 0; i < pCycle->vectorNavLocations.size(); i++)
76 NavLocation* pLocation = (NavLocation*) pCycle->vectorNavLocations[i];
77 if (pLocation != NULL)
79 CTimeSpan* pSpan = pLocation->span;
81 if (pSpan != NULL)
83 delete pSpan;
84 pSpan = NULL;
87 Dasher::VECTOR_SYMBOL_PROB_DISPLAY* pVectorAdded = pLocation->pVectorAdded;
88 if (pVectorAdded != NULL)
90 delete pVectorAdded;
91 pVectorAdded = NULL;
94 delete pLocation;
95 pLocation = NULL;
99 delete pCycle;
100 pCycle = NULL;
106 if (m_pSpan!= NULL)
108 delete m_pSpan;
109 m_pSpan = NULL;
114 // Returns an XML version of all our information
115 string CUserLogTrial::GetXML(const string& strPrefix)
117 //CFunctionLogger f1("CUserLogTrial::GetXML", g_pLogger);
119 string strResult = "";
121 string strPrefixTab = strPrefix;
122 strPrefixTab += "\t";
124 string strPrefixTabTab = strPrefixTab;
125 strPrefixTabTab += "\t";
127 strResult += strPrefix;
128 strResult += "<Trial>\n";
130 // Summarize what happened at the beginning of the block
131 strResult += GetSummaryXML(strPrefix);
133 // Parameters that we want tracked on a per trial basis
134 strResult += GetParamsXML(strPrefix);
136 // Size of the window and the canvas in screen coordniates
137 strResult += GetWindowCanvasXML(strPrefix);
139 strResult += m_strCurrentTrial;
141 // All the start and stop navigation events
142 strResult += GetNavCyclesXML(strPrefix);
144 strResult += strPrefix;
145 strResult += "</Trial>\n";
147 return strResult;
150 // See if any navigation has occured during this trial yet
151 bool CUserLogTrial::HasWritingOccured()
153 //CFunctionLogger f1("CUserLogTrial::HasWritingOccured", g_pLogger);
155 if (m_vpNavCycles.size() > 0)
156 return true;
157 return false;
162 void CUserLogTrial::StartWriting()
164 //CFunctionLogger f1("CUserLogTrial::StartWriting", g_pLogger);
166 if (m_bWritingStart)
168 g_pLogger->Log("CUserLogTrial::StartWriting, nav already marked as started!", logNORMAL);
169 return;
172 // Make sure our trial time span is running
173 if (m_pSpan != NULL)
174 m_pSpan->Continue();
176 // Start the task timer if we haven't already done so
177 if (m_pSpan == NULL)
178 m_pSpan = new CTimeSpan("Time", false);
180 if (m_pSpan == NULL)
182 g_pLogger->Log("CUserLogTrial::StartWriting, m_pSpan was NULL!", logNORMAL);
183 return;
186 m_bWritingStart = true;
188 // If we have already done some navigation, then the previous NavStop() would have stopped
189 // the timer in the last NavLocation object. We want to tell it to continue since the
190 // trial is not in fact over.
191 if (m_vpNavCycles.size() > 0)
193 NavLocation* pLastLocation = GetCurrentNavLocation();
194 if ((pLastLocation != NULL) && (pLastLocation->span != NULL))
195 pLastLocation->span->Continue();
198 // NavCycle* newCycle = AddNavCycle();
199 AddNavCycle();
202 void CUserLogTrial::StopWriting(double dBits)
204 //CFunctionLogger f1("CUserLogTrial::StopWriting", g_pLogger);
206 if (!m_bWritingStart)
208 g_pLogger->Log("CUserLogTrial::StopWriting, nav already marked as stopped!", logNORMAL);
209 return;
212 if (m_vpNavCycles.size() <= 0)
214 g_pLogger->Log("CUserLogTrial::StopWriting, vector was empty!", logNORMAL);
215 return;
218 NavCycle* pCycle = GetCurrentNavCycle();
219 if (pCycle == NULL)
221 g_pLogger->Log("CUserLogTrial::StopWriting, current cycle was NULL!", logNORMAL);
222 return;
225 CTimeSpan* pSpan = (CTimeSpan*) pCycle->pSpan;
226 if (pSpan == NULL)
228 g_pLogger->Log("CUserLogTrial::StopWriting, span was NULL!", logNORMAL);
229 return;
232 pCycle->dBits = dBits;
233 pSpan->Stop();
235 m_bWritingStart = false;
237 // Make sure the last location timer is stopped since this could be the end of the trial and
238 // we want the timestamps in the location elements to match the total trial time.
239 NavLocation* pLastLocation = GetCurrentNavLocation();
240 if ((pLastLocation != NULL) && (pLastLocation->span != NULL))
241 pLastLocation->span->Continue();
243 // Could be the last event of the trial
244 if (m_pSpan != NULL)
245 m_pSpan->Stop();
247 // We want to use the UserTrial info from the navigation period in Dasher. We'll update
248 // this everytime the user stops, this should make sure we get the right bit.
249 GetUserTrialInfo();
252 // The user has entered one or more new symbols. UserLog object will
253 // pass us the pointer to the current alphabet that is being used.
254 void CUserLogTrial::AddSymbols(Dasher::VECTOR_SYMBOL_PROB* vpNewSymbolProbs,
255 eUserLogEventType iEvent,
256 Dasher::CAlphabet* pCurrentAlphabet)
258 //CFunctionLogger f1("CUserLogTrial::AddSymbols", g_pLogger);
260 if (pCurrentAlphabet == NULL)
262 g_pLogger->Log("CUserLogTrial::AddSymbols, pCurrentAlphabet was NULL!", logNORMAL);
263 return;
265 if (vpNewSymbolProbs == NULL)
267 g_pLogger->Log("CUserLogTrial::AddSymbols, vectorNewSymbolProbs was NULL!", logNORMAL);
268 return;
271 Dasher::VECTOR_SYMBOL_PROB_DISPLAY* pVectorAdded = NULL;
272 pVectorAdded = new Dasher::VECTOR_SYMBOL_PROB_DISPLAY;
274 if (pVectorAdded == NULL)
276 g_pLogger->Log("CUserLogTrial::AddSymbols, failed to create pVectorAdded!", logNORMAL);
277 return;
280 for (unsigned int i = 0; i < vpNewSymbolProbs->size(); i++)
282 Dasher::SymbolProb sNewSymbolProb = (Dasher::SymbolProb) (*vpNewSymbolProbs)[i];
284 Dasher::SymbolProbDisplay sNewSymbolProbDisplay;
286 sNewSymbolProbDisplay.sym = sNewSymbolProb.sym;
287 sNewSymbolProbDisplay.prob = sNewSymbolProb.prob;
288 sNewSymbolProbDisplay.strDisplay = pCurrentAlphabet->GetText(sNewSymbolProb.sym);
290 pVectorAdded->push_back(sNewSymbolProbDisplay);
292 // Add this symbol to our running total of symbols.
293 // We track the symbols and not the display text
294 // since we may need to delete symbols later and
295 // a given symbol might take up multiple chars.
296 // We also keep the probability around so we can
297 // calculate the average bits of the history.
298 m_vHistory.push_back(sNewSymbolProbDisplay);
301 StopPreviousTimer();
303 // Create the new NavLocation struct that record the data about this addition
304 NavLocation* pLocation = NULL;
305 pLocation = new NavLocation;
307 if (pLocation == NULL)
309 g_pLogger->Log("CUserLogTrial::AddSymbols, failed to create location!", logNORMAL);
310 return;
313 pLocation->strHistory = GetHistoryDisplay();
314 pLocation->span = new CTimeSpan("Time", false);
315 pLocation->avgBits = GetHistoryAvgBits();
316 pLocation->event = iEvent;
317 pLocation->numDeleted = 0;
318 pLocation->pVectorAdded = pVectorAdded;
320 NavCycle* pCycle = GetCurrentNavCycle();
321 if (pCycle != NULL)
322 pCycle->vectorNavLocations.push_back(pLocation);
323 else
324 g_pLogger->Log("CUserLogTrial::AddSymbols, cycle was NULL!", logNORMAL);
328 void CUserLogTrial::DeleteSymbols(int iNumToDelete, eUserLogEventType iEvent)
330 //CFunctionLogger f1("CUserLogTrial::DeleteSymbols", g_pLogger);
332 if (iNumToDelete <= 0)
333 return;
335 // Be careful not to pop more things than we have (this will hork the
336 // memory up on linux but not windows).
337 int iActualNumToDelete = min((int) m_vHistory.size(), iNumToDelete);
339 for (int i = 0; i < iActualNumToDelete; i++)
341 // Remove the request number of symbols from our
342 // ongoing list.
343 m_vHistory.pop_back();
346 StopPreviousTimer();
348 // Create the new NavLocation struct that record the data about this addition
349 NavLocation* pLocation = NULL;
350 pLocation = new NavLocation;
352 if (pLocation == NULL)
354 g_pLogger->Log("CUserLogTrial::DeleteSymbols, failed to create location!", logNORMAL);
355 return;
358 pLocation->strHistory = GetHistoryDisplay();
359 pLocation->span = new CTimeSpan("Time", false);
360 pLocation->avgBits = GetHistoryAvgBits();
361 pLocation->event = iEvent;
362 pLocation->numDeleted = iNumToDelete;
363 pLocation->pVectorAdded = NULL;
365 NavCycle* pCycle = GetCurrentNavCycle();
366 if (pCycle != NULL)
367 pCycle->vectorNavLocations.push_back(pLocation);
368 else
369 g_pLogger->Log("CUserLogTrial::DeleteSymbols, cycle was NULL!", logNORMAL);
374 // Called by UserLog object whenever we move on to the next trial. This lets
375 // our trial object finalize any timers.
376 void CUserLogTrial::Done()
378 //CFunctionLogger f1("CUserLogTrial::Done", g_pLogger);
380 StopPreviousTimer();
382 // Stop the time span that tracks the total trial time (if not already stopped)
383 if ((m_pSpan != NULL) && (!m_pSpan->IsStopped()))
384 m_pSpan->Stop();
389 void CUserLogTrial::AddMouseLocation(int iX, int iY, float dNats)
391 //CFunctionLogger f1("CUserLogTrial::AddMouseLocation", g_pLogger);
393 CUserLocation* pLocation = NULL;
395 pLocation = new CUserLocation(iX, iY, dNats);
397 if (pLocation != NULL)
399 // m_vectorMouseLocations.push_back(location);
401 NavCycle* pCycle = GetCurrentNavCycle();
403 if (pCycle != NULL)
404 pCycle->vectorMouseLocations.push_back(pLocation);
405 else
406 g_pLogger->Log("CUserLogTrial::AddLocation, cycle was NULL!", logNORMAL);
408 else
409 g_pLogger->Log("CUserLogTrial::AddLocation, location was NULL!", logNORMAL);
413 // Adds a normalized version of our mouse coordinates based on the size
414 // of the window. Can optionally be told to store both representations.
415 void CUserLogTrial::AddMouseLocationNormalized(int iX, int iY, bool bStoreIntegerRep, float dNats)
417 //CFunctionLogger f1("CUserLogTrial::AddMouseLocationNormalized", g_pLogger);
419 CUserLocation* pLocation = NULL;
421 if ((m_sCanvasCoordinates.bottom == 0) &&
422 (m_sCanvasCoordinates.left == 0) &&
423 (m_sCanvasCoordinates.right == 0) &&
424 (m_sCanvasCoordinates.top == 0))
425 g_pLogger->Log("CUserLogTrial::AddMouseLocationNormalized, called before AddCanvasSize()?", logNORMAL);
427 pLocation = new CUserLocation(iX,
428 iY,
429 m_sCanvasCoordinates.top,
430 m_sCanvasCoordinates.left,
431 m_sCanvasCoordinates.bottom,
432 m_sCanvasCoordinates.right,
433 bStoreIntegerRep,
434 dNats);
436 if (pLocation != NULL)
438 // m_vectorMouseLocations.push_back(location);
439 NavCycle* pCycle = GetCurrentNavCycle();
441 if (pCycle != NULL)
442 pCycle->vectorMouseLocations.push_back(pLocation);
443 else
444 g_pLogger->Log("CUserLogTrial::AddMouseLocationNormalized, cycle was NULL!", logNORMAL);
446 else
447 g_pLogger->Log("CUserLogTrial::AddLocation, location was NULL!", logNORMAL);
450 void CUserLogTrial::AddKeyDown(int iId, int iType, int iEffect) {
451 CUserButton* pButton = new CUserButton(iId, iType, iEffect);
453 if(pButton) {
454 NavCycle* pCycle = GetCurrentNavCycle();
456 if(pCycle)
457 pCycle->vectorButtons.push_back(pButton);
458 else
459 g_pLogger->Log("CUserLogTrial::AddLocation, cycle was NULL!", logNORMAL);
461 else
462 g_pLogger->Log("CUserLogTrial::AddLocation, location was NULL!", logNORMAL);
465 // Sets the current window size, this includes area for the menu bar,
466 // sliders, canvas, etc.
467 void CUserLogTrial::AddWindowSize(int iTop, int iLeft, int iBottom, int iRight)
469 //CFunctionLogger f1("CUserLogTrial::AddWindowSize", g_pLogger);
471 m_sWindowCoordinates.top = iTop;
472 m_sWindowCoordinates.left = iLeft;
473 m_sWindowCoordinates.bottom = iBottom;
474 m_sWindowCoordinates.right = iRight;
477 // Sets the current canvas size
478 void CUserLogTrial::AddCanvasSize(int iTop, int iLeft, int iBottom, int iRight)
480 //CFunctionLogger f1("CUserLogTrial::AddCanvasSize", g_pLogger);
482 m_sCanvasCoordinates.top = iTop;
483 m_sCanvasCoordinates.left = iLeft;
484 m_sCanvasCoordinates.bottom = iBottom;
485 m_sCanvasCoordinates.right = iRight;
488 // Are we currently navigating?
489 bool CUserLogTrial::IsWriting()
491 return m_bWritingStart;
494 ////////////////////////////////////////// private methods ////////////////////////////////////////////////
496 void CUserLogTrial::InitMemberVars()
498 //CFunctionLogger f1("CUserLogTrial::InitMemberVars", g_pLogger);
500 m_bWritingStart = false;
501 m_pSpan = NULL;
502 m_strCurrentTrial = "";
504 m_sWindowCoordinates.bottom = 0;
505 m_sWindowCoordinates.top = 0;
506 m_sWindowCoordinates.left = 0;
507 m_sWindowCoordinates.right = 0;
509 m_sCanvasCoordinates.bottom = 0;
510 m_sCanvasCoordinates.top = 0;
511 m_sCanvasCoordinates.left = 0;
512 m_sCanvasCoordinates.right = 0;
515 // Obtain information that is being passed in from the UserTrial standalone application.
516 // This information tell us what the user is actually trying to enter.
517 void CUserLogTrial::GetUserTrialInfo()
519 //CFunctionLogger f1("CUserLogTrial::GetUserTrialInfo", g_pLogger);
521 m_strCurrentTrial = "";
525 if (m_strCurrentTrialFilename.length() > 0)
527 fstream fin(m_strCurrentTrialFilename.c_str(), ios::in); // We want ios::nocreate, but not available in .NET 2003, arrgh
529 // Make sure we successfully opened before we start reading it
530 if (fin.is_open())
532 while(!fin.eof())
534 fin.getline(m_szTempBuffer, TEMP_BUFFER_SIZE);
535 if (strlen(m_szTempBuffer) > 0)
537 m_strCurrentTrial += "\t\t\t";
538 m_strCurrentTrial += m_szTempBuffer;
539 m_strCurrentTrial += "\n";
542 fin.close();
545 } catch (...)
547 // The application might not be running in which case the read will fail.
551 // Returns the concatenation of all our symbol history using
552 // the display text that the alphabet at the time of the
553 // symbol being added gave us.
554 string CUserLogTrial::GetHistoryDisplay()
556 //CFunctionLogger f1("CUserLogTrial::GetHistoryDisplay", g_pLogger);
558 string strResult = "";
560 for (unsigned int i = 0; i < m_vHistory.size(); i++)
562 Dasher::SymbolProbDisplay sItem = (Dasher::SymbolProbDisplay) m_vHistory[i];
563 strResult += sItem.strDisplay;
566 return strResult;
569 double CUserLogTrial::GetHistoryAvgBits()
571 //CFunctionLogger f1("CUserLogTrial::GetHistoryAvgBits", g_pLogger);
573 double dResult = 0.0;
575 if (m_vHistory.size() > 0)
577 for (unsigned int i = 0; i < m_vHistory.size(); i++)
579 Dasher::SymbolProbDisplay sItem = (Dasher::SymbolProbDisplay) m_vHistory[i];
581 dResult += log(sItem.prob);
583 dResult = dResult * -1.0;
584 dResult = dResult / log(2.0);
585 dResult = dResult / m_vHistory.size();
588 return dResult;
591 void CUserLogTrial::StopPreviousTimer()
593 //CFunctionLogger f1("CUserLogTrial::StopPreviousTimer", g_pLogger);
595 // Make sure the previous time span (if any) has had its timer stopped
596 if (m_vpNavCycles.size() > 0)
598 NavLocation* pLastLocation = GetCurrentNavLocation();
599 if ((pLastLocation != NULL) && (pLastLocation->span != NULL))
600 pLastLocation->span->Stop();
605 // Gets XML string for a given NavLocation struct
606 string CUserLogTrial::GetLocationXML(NavLocation* pLocation, const string& strPrefix)
608 //CFunctionLogger f1("CUserLogTrial::GetLocationXML", g_pLogger);
610 string strResult = "";
611 if (pLocation == NULL)
613 g_pLogger->Log("CUserLogTrial::GetLocationXML, location was NULL!", logNORMAL);
614 return strResult;
617 strResult += strPrefix;
618 strResult += "<Location>\n";
620 strResult += strPrefix;
621 strResult += "\t<History>";
622 strResult += pLocation->strHistory;
623 strResult += "</History>\n";
625 strResult += strPrefix;
626 strResult += "\t<AvgBits>";
627 sprintf(m_szTempBuffer, "%0.6f", pLocation->avgBits);
628 strResult += m_szTempBuffer;
629 strResult += "</AvgBits>\n";
631 // Only output the event if it is interesting type, not normal mouse navigation
632 if (pLocation->event != userLogEventMouse)
634 strResult += strPrefix;
635 strResult += "\t\t<Event>";
636 sprintf(m_szTempBuffer, "%d", (int) pLocation->event);
637 strResult += m_szTempBuffer;
638 strResult += "</Event>\n";
641 if ((pLocation->pVectorAdded != NULL) && (pLocation->pVectorAdded->size() > 0))
643 strResult += strPrefix;
644 strResult += "\t<NumAdded>";
645 sprintf(m_szTempBuffer, "%d", pLocation->pVectorAdded->size());
646 strResult += m_szTempBuffer;
647 strResult += "</NumAdded>\n";
649 Dasher::VECTOR_SYMBOL_PROB_DISPLAY* pVectorAdded = pLocation->pVectorAdded;
651 if (pVectorAdded != NULL)
653 // Output the details of each add
654 for (unsigned int j = 0; j < pVectorAdded->size(); j++)
656 Dasher::SymbolProbDisplay sItem = (Dasher::SymbolProbDisplay) (*pVectorAdded)[j];
658 strResult += strPrefix;
659 strResult += "\t<Add>\n";
661 strResult += strPrefix;
662 strResult += "\t\t<Text>";
663 strResult += sItem.strDisplay;
664 strResult += "</Text>\n";
666 strResult += strPrefix;
667 strResult += "\t\t<Prob>";
668 sprintf(m_szTempBuffer, "%0.6f", sItem.prob);
669 strResult += m_szTempBuffer;
670 strResult += "</Prob>\n";
672 strResult += strPrefix;
673 strResult += "\t</Add>\n";
678 if (pLocation->numDeleted > 0)
680 strResult += strPrefix;
681 strResult += "\t<NumDeleted>";
682 sprintf(m_szTempBuffer, "%d", pLocation->numDeleted);
683 strResult += m_szTempBuffer;
684 strResult += "</NumDeleted>\n";
687 if (pLocation->span != NULL)
689 string strPrefixTabTabTab = strPrefix;
690 strPrefixTabTabTab += "\t";
692 strResult += pLocation->span->GetXML(strPrefixTabTabTab);
695 strResult += strPrefix;
696 strResult += "</Location>\n";
698 return strResult;
701 // Output the XML for the summary section of XML
702 string CUserLogTrial::GetSummaryXML(const string& strPrefix)
704 //CFunctionLogger f1("CUserLogTrial::GetSummaryXML", g_pLogger);
706 string strResult = "";
708 strResult += strPrefix;
709 strResult += "\t<Summary>\n";
711 // Figure out what the user ended up writing and how fast they did it
712 string strText = "";
713 double dAvgBits = 0.0;
715 NavLocation* pLocation = GetCurrentNavLocation();
716 if (pLocation != NULL)
718 strText = GetHistoryDisplay();
719 dAvgBits = pLocation->avgBits;
722 int iButtonCount = GetButtonCount();
723 double dTotalBits = GetTotalBits();
725 strResult += GetStatsXML(strPrefix, strText, m_pSpan, dAvgBits, iButtonCount, dTotalBits);
727 strResult += strPrefix;
728 strResult += "\t</Summary>\n";
730 return strResult;
733 // Calculates the various summary stats we output
734 string CUserLogTrial::GetStatsXML(const string& strPrefix, const string& strText, CTimeSpan* pSpan, double dAvgBits, int iButtonCount, double dTotalBits)
736 //CFunctionLogger f1("CUserLogTrial::GetStatsXML", g_pLogger);
738 string strResult = "";
740 if (pSpan == NULL)
742 g_pLogger->Log("CUserLogTrial::GetStatsXML, pSpan = NULL!", logNORMAL);
743 return strResult;
746 strResult += strPrefix;
747 strResult += "\t\t<Text>";
748 strResult += strText;
749 strResult += "</Text>\n";
751 // Average number of bits along the path to the final string
752 strResult += strPrefix;
753 strResult += "\t\t<AvgBits>";
754 sprintf(m_szTempBuffer, "%0.6f", dAvgBits);
755 strResult += m_szTempBuffer;
756 strResult += "</AvgBits>\n";
758 strResult += strPrefix;
759 strResult += "\t\t<TotalBits>";
760 sprintf(m_szTempBuffer, "%0.6f", dTotalBits);
761 strResult += m_szTempBuffer;
762 strResult += "</TotalBits>\n";
765 strResult += strPrefix;
766 strResult += "\t\t<ButtonCount>";
767 sprintf(m_szTempBuffer, "%d", iButtonCount);
768 strResult += m_szTempBuffer;
769 strResult += "</ButtonCount>\n";
771 // Calculate the number of words and characters
772 strResult += strPrefix;
773 strResult += "\t\t<Chars>";
775 // We want the number of symbols which might differ
776 // from the actual length of the text history.
777 int iNumChars = m_vHistory.size();
778 sprintf(m_szTempBuffer, "%d", iNumChars);
779 strResult += m_szTempBuffer;
780 strResult += "</Chars>\n";
782 strResult += strPrefix;
783 strResult += "\t\t<Words>";
784 double dNumWords = (double) iNumChars / (double) 5;
785 sprintf(m_szTempBuffer, "%0.2f", dNumWords);
786 strResult += m_szTempBuffer;
787 strResult += "</Words>\n";
789 double dWPM = 0.0;
790 double dCPM = 0.0;
792 if (m_pSpan != NULL)
794 dWPM = (double) dNumWords / (m_pSpan->GetElapsed() / 60.0);
795 dCPM = (double) iNumChars / (m_pSpan->GetElapsed() / 60.0);
798 strResult += strPrefix;
799 strResult += "\t\t<WPM>";
800 sprintf(m_szTempBuffer, "%0.3f", dWPM);
801 strResult += m_szTempBuffer;
802 strResult += "</WPM>\n";
804 strResult += strPrefix;
805 strResult += "\t\t<CPM>";
806 sprintf(m_szTempBuffer, "%0.3f", dCPM);
807 strResult += m_szTempBuffer;
808 strResult += "</CPM>\n";
810 string strPrefixTabTab = strPrefix;
811 strPrefixTabTab += "\t\t";
813 if (m_pSpan != NULL)
814 strResult += m_pSpan->GetXML(strPrefixTabTab);
816 return strResult;
819 string CUserLogTrial::GetWindowCanvasXML(const string& strPrefix)
821 //CFunctionLogger f1("CUserLogTrial::GetWindowCanvasXML", g_pLogger);
823 string strResult = "";
825 // Log the window location and size that was last used during this trial
826 strResult += strPrefix;
827 strResult += "\t<WindowCoordinates>\n";
829 strResult += strPrefix;
830 sprintf(m_szTempBuffer, "\t\t<Top>%d</Top>\n", m_sWindowCoordinates.top);
831 strResult += m_szTempBuffer;
833 strResult += strPrefix;
834 sprintf(m_szTempBuffer, "\t\t<Bottom>%d</Bottom>\n", m_sWindowCoordinates.bottom);
835 strResult += m_szTempBuffer;
837 strResult += strPrefix;
838 sprintf(m_szTempBuffer, "\t\t<Left>%d</Left>\n", m_sWindowCoordinates.left);
839 strResult += m_szTempBuffer;
841 strResult += strPrefix;
842 sprintf(m_szTempBuffer, "\t\t<Right>%d</Right>\n", m_sWindowCoordinates.right);
843 strResult += m_szTempBuffer;
845 strResult += strPrefix;
846 strResult += "\t</WindowCoordinates>\n";
848 // Log the canvas location and size that was last used during this trial
849 strResult += strPrefix;
850 strResult += "\t<CanvasCoordinates>\n";
852 strResult += strPrefix;
853 sprintf(m_szTempBuffer, "\t\t<Top>%d</Top>\n", m_sCanvasCoordinates.top);
854 strResult += m_szTempBuffer;
856 strResult += strPrefix;
857 sprintf(m_szTempBuffer, "\t\t<Bottom>%d</Bottom>\n", m_sCanvasCoordinates.bottom);
858 strResult += m_szTempBuffer;
860 strResult += strPrefix;
861 sprintf(m_szTempBuffer, "\t\t<Left>%d</Left>\n", m_sCanvasCoordinates.left);
862 strResult += m_szTempBuffer;
864 strResult += strPrefix;
865 sprintf(m_szTempBuffer, "\t\t<Right>%d</Right>\n", m_sCanvasCoordinates.right);
866 strResult += m_szTempBuffer;
868 strResult += strPrefix;
869 strResult += "\t</CanvasCoordinates>\n";
871 return strResult;
874 string CUserLogTrial::GetParamsXML(const string& strPrefix)
876 //CFunctionLogger f1("CUserLogTrial::GetParamsXML", g_pLogger);
878 string strResult = "";
880 if (m_vpParams.size() > 0)
882 // Make parameters with the same name appear near each other in the results
883 sort(m_vpParams.begin(), m_vpParams.end(), CUserLogParam::ComparePtr);
885 strResult += strPrefix;
886 strResult += "\t<Params>\n";
888 string strPrefixPlusTabTab = strPrefix;
889 strPrefixPlusTabTab += "\t\t";
891 for (unsigned int i = 0; i < m_vpParams.size(); i++)
893 CUserLogParam* pParam = (CUserLogParam*) m_vpParams[i];
895 strResult += GetParamXML(pParam, strPrefixPlusTabTab);
898 strResult += strPrefix;
899 strResult += "\t</Params>\n";
902 return strResult;
906 int CUserLogTrial::GetButtonCount() {
907 int iCount(0);
909 for(VECTOR_NAV_CYCLE_PTR::iterator it(m_vpNavCycles.begin()); it != m_vpNavCycles.end(); ++it)
910 for(VECTOR_USER_BUTTON_PTR::iterator it2((*it)->vectorButtons.begin()); it2 != (*it)->vectorButtons.end(); ++it2)
911 iCount += (*it2)->GetCount();
913 return iCount;
916 double CUserLogTrial::GetTotalBits() {
917 double dBits(0.0);
919 for(VECTOR_NAV_CYCLE_PTR::iterator it(m_vpNavCycles.begin()); it != m_vpNavCycles.end(); ++it)
920 dBits += (*it)->dBits;
922 return dBits;
925 // Parameters can optionally be specified to be added to the Trial objects.
926 // This allows us to easily see what a certain parameter value was used
927 // in a given trial.
928 void CUserLogTrial::AddParam(const string& strName, const string& strValue, int iOptionMask)
930 //CFunctionLogger f1("CUserLogTrial::AddParam", g_pLogger);
932 bool bTrackMultiple = false;
934 if (iOptionMask & userLogParamTrackMultiple)
935 bTrackMultiple = true;
937 // See if this matches an existing parameter value that we may want to
938 // overwrite. But only if we aren't suppose to keep track of multiple changes.
939 if (!bTrackMultiple)
941 for (unsigned int i = 0; i < m_vpParams.size(); i++)
943 CUserLogParam* pParam = (CUserLogParam*) m_vpParams[i];
945 if (pParam != NULL)
947 if (pParam->strName.compare(strName) == 0)
949 pParam->strValue = strValue;
950 return;
955 // We need to add a new param
956 CUserLogParam* pNewParam = new CUserLogParam;
957 if (pNewParam == NULL)
959 g_pLogger->Log("CUserLogTrial::AddParam, newParam was NULL!", logNORMAL);
960 return;
963 pNewParam->strName = strName;
964 pNewParam->strValue = strValue;
965 pNewParam->strTimeStamp = "";
967 // Parameters that can have multiple values logged will also log when they were changed
968 if (bTrackMultiple)
969 pNewParam->strTimeStamp = CTimeSpan::GetTimeStamp();
971 m_vpParams.push_back(pNewParam);
974 // Static method that generates the XML representation of a
975 // single param name value set. Used both to output params
976 // for a trial and for the parent UserLog object.
977 string CUserLogTrial::GetParamXML(CUserLogParam* pParam, const string& strPrefix)
979 //CFunctionLogger f1("CUserLogTrial::GetParamXML", g_pLogger);
981 string strResult = "";
983 if (pParam != NULL)
985 strResult += strPrefix;
986 strResult += "<";
987 strResult += pParam->strName;
988 strResult += ">";
990 if (pParam->strTimeStamp.length() > 0)
992 strResult += "\n";
993 strResult += strPrefix;
994 strResult += "\t<Value>";
995 strResult += pParam->strValue;
996 strResult += "</Value>\n";
998 strResult += strPrefix;
999 strResult += "\t<Time>";
1000 strResult += pParam->strTimeStamp;
1001 strResult += "</Time>\n";
1003 strResult += strPrefix;
1005 else
1007 strResult += pParam->strValue;
1010 strResult += "</";
1011 strResult += pParam->strName;
1012 strResult += ">\n";
1015 return strResult;
1018 // Returns a pointer to the currently active navigation cycle
1019 NavCycle* CUserLogTrial::GetCurrentNavCycle()
1021 //CFunctionLogger f1("CUserLogTrial::GetCurrentNavCycle", g_pLogger);
1023 if (m_vpNavCycles.size() <= 0)
1024 return NULL;
1025 return m_vpNavCycles[m_vpNavCycles.size() - 1];
1028 // Gets a pointer to the last NavLocation object
1029 // in the current navication cycle.
1030 NavLocation* CUserLogTrial::GetCurrentNavLocation()
1032 //CFunctionLogger f1("CUserLogTrial::GetCurrentNavLocation", g_pLogger);
1034 // NavCycle* pCycle = GetCurrentNavCycle();
1036 // if (pCycle == NULL)
1037 // return NULL;
1039 // if (pCycle->vectorNavLocations.size() <= 0)
1040 // return NULL;
1042 // return (NavLocation*) pCycle->vectorNavLocations[pCycle->vectorNavLocations.size() - 1];
1044 // New version - reverse iterate through the list and find the last nav cycle which has any locations
1046 for(VECTOR_NAV_CYCLE_PTR::reverse_iterator it(m_vpNavCycles.rbegin()); it != m_vpNavCycles.rend(); ++it) {
1047 if((*it)->vectorNavLocations.size() > 0)
1048 return (NavLocation*) (*it)->vectorNavLocations[(*it)->vectorNavLocations.size() - 1];
1051 return NULL;
1054 // Adds a new navgiation cycle to our collection
1055 NavCycle* CUserLogTrial::AddNavCycle()
1057 //CFunctionLogger f1("CUserLogTrial::AddNavCycle", g_pLogger);
1059 NavCycle* pNewCycle = new NavCycle;
1060 if (pNewCycle == NULL)
1062 g_pLogger->Log("CUserLogTrial::AddNavCycle, failed to create NavCycle!", logNORMAL);
1063 return NULL;
1066 pNewCycle->pSpan = new CTimeSpan("Time", false);
1068 m_vpNavCycles.push_back(pNewCycle);
1069 return pNewCycle;
1072 string CUserLogTrial::GetNavCyclesXML(const string& strPrefix)
1074 //CFunctionLogger f1("CUserLogTrial::GetNavCyclesXML", g_pLogger);
1076 string strResult = "";
1078 string strPrefixTab = strPrefix;
1079 strPrefixTab += "\t";
1081 string strPrefixTabTab = strPrefixTab;
1082 strPrefixTabTab += "\t";
1084 string strPrefixTabTabTab = strPrefixTabTab;
1085 strPrefixTabTabTab += "\t";
1087 string strPrefixTabTabTabTab = strPrefixTabTabTab;
1088 strPrefixTabTabTabTab += "\t";
1090 strResult += strPrefixTab;
1091 strResult += "<Navs>\n";
1093 for (unsigned int i = 0; i < m_vpNavCycles.size(); i++)
1095 NavCycle* pCycle = (NavCycle*) m_vpNavCycles[i];
1097 if (pCycle != NULL)
1099 strResult += strPrefixTabTab;
1100 strResult += "<Nav>\n";
1102 if (pCycle->pSpan != NULL)
1103 strResult += pCycle->pSpan->GetXML(strPrefixTabTabTab);
1105 if (pCycle->vectorNavLocations.size() > 0)
1107 strResult += strPrefixTabTabTab;
1108 strResult += "<Locations>\n";
1110 for (unsigned int i = 0; i < pCycle->vectorNavLocations.size(); i++)
1112 NavLocation* pLocation = (NavLocation*) pCycle->vectorNavLocations[i];
1114 if (pLocation != NULL)
1115 strResult += GetLocationXML(pLocation, strPrefixTabTabTabTab);
1117 strResult += strPrefixTabTabTab;
1118 strResult += "</Locations>\n";
1121 if (pCycle->vectorMouseLocations.size() > 0)
1123 strResult += strPrefixTabTabTab;
1124 strResult += "<MousePositions>\n";
1126 for (unsigned int i = 0; i < pCycle->vectorMouseLocations.size(); i++)
1128 CUserLocation* pLocation = (CUserLocation*) pCycle->vectorMouseLocations[i];
1130 if (pLocation != NULL)
1132 strResult += pLocation->GetXML(strPrefixTabTabTabTab);
1136 strResult += strPrefixTabTabTab;
1137 strResult += "</MousePositions>\n";
1140 if (pCycle->vectorButtons.size() > 0)
1142 strResult += strPrefixTabTabTab;
1143 strResult += "<Buttons>\n";
1145 for (unsigned int i = 0; i < pCycle->vectorButtons.size(); i++)
1147 CUserButton* pButton = (CUserButton*) pCycle->vectorButtons[i];
1149 if(pButton)
1151 strResult += pButton->GetXML(strPrefixTabTabTabTab);
1155 strResult += strPrefixTabTabTab;
1156 strResult += "</Buttons>\n";
1159 strResult += strPrefixTabTab;
1160 strResult += "</Nav>\n";
1165 strResult += strPrefixTab;
1166 strResult += "</Navs>\n";
1168 return strResult;
1171 // Construct based on some XML, second parameter is just to make signature
1172 // different from the normal constructor.
1173 CUserLogTrial::CUserLogTrial(const string& strXML, int iIgnored)
1175 //CFunctionLogger f1("CUserLogTrial::CUserLogTrial(XML)", g_pLogger);
1177 InitMemberVars();
1178 VECTOR_STRING vNavs;
1180 string strParams = XMLUtil::GetElementString("Params", strXML, true);
1181 string strWindow = XMLUtil::GetElementString("WindowCoordinates", strXML, true);
1182 string strCanvas = XMLUtil::GetElementString("CanvasCoordinates", strXML, true);
1183 string strNavs = XMLUtil::GetElementString("Navs", strXML, true);
1184 string strSummary = XMLUtil::GetElementString("Summary", strXML, true);
1185 string strSummaryTime = XMLUtil::GetElementString("Time", strSummary, true);
1186 vNavs = XMLUtil::GetElementStrings("Nav", strNavs, true);
1188 string strCurrentTrial = XMLUtil::GetElementString("CurrentTrial", strXML, false);
1189 if (strCurrentTrial.length() > 0)
1191 // We copied the XML string directly into the member variable
1192 // including the start/end tag, so we need to reproduce the
1193 // tags ourselves.
1194 m_strCurrentTrial = "\t\t\t<CurrentTrial>\n";
1195 m_strCurrentTrial += strCurrentTrial;
1196 m_strCurrentTrial += "</CurrentTrial>\n";
1199 m_vpParams = ParseParamsXML(strParams);
1200 m_sWindowCoordinates = ParseWindowXML(strWindow);
1201 m_sCanvasCoordinates = ParseWindowXML(strCanvas);
1202 m_pSpan = new CTimeSpan("Time", strSummaryTime);
1204 // Process each <Nav> tag
1205 string strTime = "";
1206 string strLocations = "";
1207 string strMousePositions = "";
1209 VECTOR_STRING vLocations;
1210 VECTOR_STRING vMousePositions;
1211 VECTOR_STRING vAdded;
1213 for (VECTOR_STRING_ITER iter = vNavs.begin(); iter < vNavs.end(); iter++)
1215 strTime = "";
1216 strLocations = "";
1217 strMousePositions = "";
1218 vLocations.erase(vLocations.begin(), vLocations.end());
1219 vMousePositions.erase(vMousePositions.begin(), vMousePositions.end());
1221 strTime = XMLUtil::GetElementString("Time", *iter, true);
1222 strLocations = XMLUtil::GetElementString("Locations", *iter, true);
1223 strMousePositions = XMLUtil::GetElementString("MousePositions", *iter, true);
1225 NavCycle* pCycle = new NavCycle();
1226 if (pCycle == NULL)
1228 g_pLogger->Log("CUserLogTrial::CUserLogTrial, failed to create NavCycle!", logNORMAL);
1229 return;
1232 pCycle->pSpan = NULL;
1234 if (strTime.length() > 0)
1236 pCycle->pSpan = new CTimeSpan("Time", strTime);
1238 if (strLocations.length() > 0)
1240 vLocations = XMLUtil::GetElementStrings("Location", strLocations, true);
1242 for (VECTOR_STRING_ITER iter2 = vLocations.begin(); iter2 < vLocations.end(); iter2++)
1244 vAdded.erase(vAdded.begin(), vAdded.end());
1246 NavLocation* pLocation = new NavLocation();
1247 if (pLocation == NULL)
1249 g_pLogger->Log("CUserLogTrial::CUserLogTrial, failed to create NavLocation!", logNORMAL);
1250 return;
1253 pLocation->strHistory = XMLUtil::GetElementString("History", *iter2);
1254 pLocation->avgBits = (double) XMLUtil::GetElementFloat("AvgBits", *iter2);
1255 pLocation->event = (eUserLogEventType) XMLUtil::GetElementInt("Event", *iter2);
1256 pLocation->numDeleted = XMLUtil::GetElementInt("NumDeleted", *iter2);
1258 pLocation->span = NULL;
1259 string strTime = XMLUtil::GetElementString("Time", *iter2);
1260 pLocation->span = new CTimeSpan("Time", strTime);
1262 // Handle the multiple <Add> tags that might exist
1263 vAdded = XMLUtil::GetElementStrings("Add", *iter2);
1264 pLocation->pVectorAdded = new Dasher::VECTOR_SYMBOL_PROB_DISPLAY;
1266 for (VECTOR_STRING_ITER iter3 = vAdded.begin(); iter3 < vAdded.end(); iter3++)
1268 Dasher::SymbolProbDisplay sAdd;
1270 sAdd.prob = XMLUtil::GetElementFloat("Prob", *iter3);
1271 sAdd.strDisplay = XMLUtil::GetElementString("Text", *iter3);
1272 sAdd.sym = 0; // We don't have the original integer symbol index
1274 if (pLocation->pVectorAdded != NULL)
1275 pLocation->pVectorAdded->push_back(sAdd);
1277 // Also track it in one complete vector of all the adds
1278 m_vHistory.push_back(sAdd);
1281 // If this was a deleted event, then we need to erase some stuff from the running history
1282 // Be careful not to pop more things than we have (this will hork the
1283 // memory up on linux but not windows).
1284 int iActualNumToDelete = min((int) m_vHistory.size(), pLocation->numDeleted);
1285 for (int i = 0; i < iActualNumToDelete; i++)
1286 m_vHistory.pop_back();
1288 pCycle->vectorNavLocations.push_back(pLocation);
1292 if (strMousePositions.length() > 0)
1294 vMousePositions = XMLUtil::GetElementStrings("Pos", strMousePositions, true);
1295 for (VECTOR_STRING_ITER iter2 = vMousePositions.begin(); iter2 < vMousePositions.end(); iter2++)
1297 CUserLocation* pLocation = new CUserLocation(*iter2);
1298 pCycle->vectorMouseLocations.push_back(pLocation);
1303 m_vpNavCycles.push_back(pCycle);
1308 // Helper that parses parameters out of the XML block, used by UserLog
1309 // and by UserLogTrial to do the same thing.
1310 VECTOR_USER_LOG_PARAM_PTR CUserLogTrial::ParseParamsXML(const string& strXML)
1312 //CFunctionLogger f1("CUserLogTrial::ParseParamsXML", g_pLogger);
1314 VECTOR_USER_LOG_PARAM_PTR vResult;
1315 VECTOR_NAME_VALUE_PAIR vParams;
1317 vParams = XMLUtil::GetNameValuePairs(strXML, true);
1319 // Handle adding all the name/value parameter pairs. XML looks like:
1320 // <Eyetracker>0</Eyetracker>
1321 // <MaxBitRate>
1322 // <Value>7.0100</Value>
1323 // <Time>15:48:53.140</Time>
1324 // </MaxBitRate>
1325 for (VECTOR_NAME_VALUE_PAIR_ITER iter = vParams.begin(); iter < vParams.end(); iter++)
1327 CUserLogParam* pParam = new CUserLogParam();
1329 if (pParam != NULL)
1331 pParam->strName = iter->strName;
1333 // See if we have a type that has a timestamp
1334 string strValue = XMLUtil::GetElementString("Value", iter->strValue, true);
1335 string strTime = XMLUtil::GetElementString("Time", iter->strValue, true);
1337 if ((strValue.length() > 0) || (strTime.length() > 0))
1339 pParam->strValue = strValue;
1340 pParam->strTimeStamp = strTime;
1342 else
1343 pParam->strValue = iter->strValue;
1345 pParam->options = 0;
1347 vResult.push_back(pParam);
1351 return vResult;
1354 // Parse our window or canvas coorindates from XML
1355 WindowSize CUserLogTrial::ParseWindowXML(const string& strXML)
1357 //CFunctionLogger f1("CUserLogTrial::ParseWindowXML", g_pLogger);
1359 WindowSize sResult;
1361 sResult.top = XMLUtil::GetElementInt("Top", strXML);
1362 sResult.bottom = XMLUtil::GetElementInt("Bottom", strXML);
1363 sResult.left = XMLUtil::GetElementInt("Left", strXML);
1364 sResult.right = XMLUtil::GetElementInt("Right", strXML);
1366 return sResult;
1369 // Returns a vector that contains the tab delimited mouse
1370 // coordinates for each of our navigation cycles.
1371 VECTOR_STRING CUserLogTrial::GetTabMouseXY(bool bReturnNormalized)
1373 //CFunctionLogger f1("CUserLogTrial::GetTabMouseXY", g_pLogger);
1375 VECTOR_STRING vResult;
1376 for (VECTOR_NAV_CYCLE_PTR_ITER iter = m_vpNavCycles.begin(); iter < m_vpNavCycles.end(); iter++)
1378 string strResult = "";
1380 if (*iter != NULL)
1382 for (VECTOR_USER_LOCATION_PTR_ITER iter2 = (*iter)->vectorMouseLocations.begin();
1383 iter2 < (*iter)->vectorMouseLocations.end();
1384 iter2++)
1386 if (*iter2 != NULL)
1387 strResult += (*iter2)->GetTabMouseXY(bReturnNormalized);
1391 vResult.push_back(strResult);
1394 return vResult;
1397 // Calculates the mouse density with a given grid size number of buckets.
1398 // Each element of the vector is a 2D array of double values from 0.0 - 1.0.
1400 // NOTE: We allocate the memory here for the double**, our caller must
1401 // handle freeing it!
1402 VECTOR_DENSITY_GRIDS CUserLogTrial::GetMouseDensity(int iGridSize)
1404 //CFunctionLogger f1("CUserLogTrial::GetMouseDensity", g_pLogger);
1406 VECTOR_DENSITY_GRIDS vResult;
1408 for (VECTOR_NAV_CYCLE_PTR_ITER iter = m_vpNavCycles.begin(); iter < m_vpNavCycles.end(); iter++)
1410 if (*iter != NULL)
1412 DENSITY_GRID ppGrid;
1414 // Init the grid with all 0.0 values
1415 ppGrid = new double*[iGridSize];
1416 for (int i = 0; i < iGridSize; i++)
1417 ppGrid[i] = new double[iGridSize];
1419 for (int i = 0; i < iGridSize; i++)
1420 for (int j = 0; j < iGridSize; j++)
1421 ppGrid[i][j] = 0.0;
1423 unsigned int iCount = 0;
1425 // Assign each mouse to location to one of the buckets and increment
1426 // the count on that bucket.
1427 for (VECTOR_USER_LOCATION_PTR_ITER iter2 = (*iter)->vectorMouseLocations.begin();
1428 iter2 < (*iter)->vectorMouseLocations.end();
1429 iter2++)
1431 if (*iter2 != NULL)
1433 int i = 0;
1434 int j = 0;
1435 (*iter2)->GetMouseGridLocation(iGridSize, &i, &j);
1436 // Increment the count on this location, we'll throw away points
1437 // that were outside the canvas grid.
1438 if ((i < iGridSize) && (j < iGridSize) && (i >= 0) && (j >= 0))
1440 // We reverse j and i to get x to increase left top right
1441 // and y from top to bottom
1442 ppGrid[j][i] = ppGrid[j][i] + 1.0;
1443 iCount++;
1447 // Now normalize everything so each grid location is a
1448 // percentage of the time we spent in that location.
1449 for (int i = 0; i < iGridSize; i++)
1452 for (int j = 0; j < iGridSize; j++)
1454 ppGrid[i][j] = ppGrid[i][j] / (double) iCount;
1459 vResult.push_back(ppGrid);
1463 return vResult;
1466 // Merge the density of two grids together. This is done but adding their values
1467 // and dividing by two. If either pointer is NULL, then we return the other grid
1468 // values intact. We free the memory in our parameter grids.
1469 DENSITY_GRID CUserLogTrial::MergeGrids(int iGridSize, DENSITY_GRID ppGridA, DENSITY_GRID ppGridB)
1471 //CFunctionLogger f1("CUserLogTrial::MergeGrids", g_pLogger);
1473 DENSITY_GRID ppResult;
1474 ppResult = new double*[iGridSize];
1475 for (int i = 0; i < iGridSize; i++)
1476 ppResult[i] = new double[iGridSize];
1478 for (int i = 0; i < iGridSize; i++)
1479 for (int j = 0; j < iGridSize; j++)
1480 ppResult[i][j] = 0.0;
1482 // Both NULL, then return grid of all 0.0's
1483 if ((ppGridA == NULL) && (ppGridB == NULL))
1484 return ppResult;
1486 if (ppGridA == NULL)
1488 // grid A is NULL, return copy of grid B
1489 for (int i = 0; i < iGridSize; i++)
1491 for (int j = 0; j < iGridSize; j++)
1492 ppResult[i][j] = ppGridB[i][j];
1495 else if (ppGridB == NULL)
1497 // grid B is NULL, return copy of grid A
1498 for (int i = 0; i < iGridSize; i++)
1500 for (int j = 0; j < iGridSize; j++)
1501 ppResult[i][j] = ppGridA[i][j];
1505 else
1507 // Normal case, merge the two density grids
1508 for (int i = 0; i < iGridSize; i++)
1510 for (int j = 0; j < iGridSize; j++)
1511 ppResult[i][j] = (ppGridA[i][j] + ppGridB[i][j]) / 2.0;
1515 if (ppGridA != NULL)
1517 for (int i = 0; i < iGridSize; i++)
1519 if (ppGridA[i] != NULL)
1521 delete ppGridA[i];
1522 ppGridA[i] = NULL;
1525 delete ppGridA;
1526 ppGridA = NULL;
1529 if (ppGridB != NULL)
1531 for (int i = 0; i < iGridSize; i++)
1533 if (ppGridB[i] != NULL)
1535 delete ppGridB[i];
1536 ppGridB[i] = NULL;
1539 delete ppGridB;
1540 ppGridB = NULL;
1543 return ppResult;