2 #include "../Common/Common.h"
4 #include "UserLogTrial.h"
6 // Track memory leaks on Windows to the line that new'd the memory
9 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
12 static char THIS_FILE
[] = __FILE__
;
16 CUserLogTrial::CUserLogTrial(const string
& strCurrentTrialFilename
)
18 //CFunctionLogger f1("CUserLogTrial::CUserLogTrial", g_pLogger);
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
];
40 for (unsigned int i
= 0; i
< m_vpNavCycles
.size(); i
++)
42 NavCycle
* pCycle
= (NavCycle
*) m_vpNavCycles
[i
];
46 if (pCycle
->pSpan
!= NULL
)
52 for (unsigned int i
= 0; i
< pCycle
->vectorButtons
.size(); i
++)
54 CUserButton
* pButton
= (CUserButton
*) pCycle
->vectorButtons
[i
];
63 for (unsigned int i
= 0; i
< pCycle
->vectorMouseLocations
.size(); i
++)
65 CUserLocation
* pLocation
= (CUserLocation
*) pCycle
->vectorMouseLocations
[i
];
67 if (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
;
87 Dasher::VECTOR_SYMBOL_PROB_DISPLAY
* pVectorAdded
= pLocation
->pVectorAdded
;
88 if (pVectorAdded
!= 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";
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)
162 void CUserLogTrial::StartWriting()
164 //CFunctionLogger f1("CUserLogTrial::StartWriting", g_pLogger);
168 g_pLogger
->Log("CUserLogTrial::StartWriting, nav already marked as started!", logNORMAL
);
172 // Make sure our trial time span is running
176 // Start the task timer if we haven't already done so
178 m_pSpan
= new CTimeSpan("Time", false);
182 g_pLogger
->Log("CUserLogTrial::StartWriting, m_pSpan was NULL!", logNORMAL
);
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();
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
);
212 if (m_vpNavCycles
.size() <= 0)
214 g_pLogger
->Log("CUserLogTrial::StopWriting, vector was empty!", logNORMAL
);
218 NavCycle
* pCycle
= GetCurrentNavCycle();
221 g_pLogger
->Log("CUserLogTrial::StopWriting, current cycle was NULL!", logNORMAL
);
225 CTimeSpan
* pSpan
= (CTimeSpan
*) pCycle
->pSpan
;
228 g_pLogger
->Log("CUserLogTrial::StopWriting, span was NULL!", logNORMAL
);
232 pCycle
->dBits
= dBits
;
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
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.
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
);
265 if (vpNewSymbolProbs
== NULL
)
267 g_pLogger
->Log("CUserLogTrial::AddSymbols, vectorNewSymbolProbs was NULL!", logNORMAL
);
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
);
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
);
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
);
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();
322 pCycle
->vectorNavLocations
.push_back(pLocation
);
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)
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
343 m_vHistory
.pop_back();
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
);
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();
367 pCycle
->vectorNavLocations
.push_back(pLocation
);
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);
382 // Stop the time span that tracks the total trial time (if not already stopped)
383 if ((m_pSpan
!= NULL
) && (!m_pSpan
->IsStopped()))
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();
404 pCycle
->vectorMouseLocations
.push_back(pLocation
);
406 g_pLogger
->Log("CUserLogTrial::AddLocation, cycle was NULL!", logNORMAL
);
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
,
429 m_sCanvasCoordinates
.top
,
430 m_sCanvasCoordinates
.left
,
431 m_sCanvasCoordinates
.bottom
,
432 m_sCanvasCoordinates
.right
,
436 if (pLocation
!= NULL
)
438 // m_vectorMouseLocations.push_back(location);
439 NavCycle
* pCycle
= GetCurrentNavCycle();
442 pCycle
->vectorMouseLocations
.push_back(pLocation
);
444 g_pLogger
->Log("CUserLogTrial::AddMouseLocationNormalized, cycle was NULL!", logNORMAL
);
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
);
454 NavCycle
* pCycle
= GetCurrentNavCycle();
457 pCycle
->vectorButtons
.push_back(pButton
);
459 g_pLogger
->Log("CUserLogTrial::AddLocation, cycle was NULL!", logNORMAL
);
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;
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
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";
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
;
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();
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
);
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";
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
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";
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
= "";
742 g_pLogger
->Log("CUserLogTrial::GetStatsXML, pSpan = NULL!", logNORMAL
);
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";
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";
814 strResult
+= m_pSpan
->GetXML(strPrefixTabTab
);
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";
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";
906 int CUserLogTrial::GetButtonCount() {
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();
916 double CUserLogTrial::GetTotalBits() {
919 for(VECTOR_NAV_CYCLE_PTR::iterator
it(m_vpNavCycles
.begin()); it
!= m_vpNavCycles
.end(); ++it
)
920 dBits
+= (*it
)->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
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.
941 for (unsigned int i
= 0; i
< m_vpParams
.size(); i
++)
943 CUserLogParam
* pParam
= (CUserLogParam
*) m_vpParams
[i
];
947 if (pParam
->strName
.compare(strName
) == 0)
949 pParam
->strValue
= strValue
;
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
);
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
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
= "";
985 strResult
+= strPrefix
;
987 strResult
+= pParam
->strName
;
990 if (pParam
->strTimeStamp
.length() > 0)
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
;
1007 strResult
+= pParam
->strValue
;
1011 strResult
+= pParam
->strName
;
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)
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)
1039 // if (pCycle->vectorNavLocations.size() <= 0)
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];
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
);
1066 pNewCycle
->pSpan
= new CTimeSpan("Time", false);
1068 m_vpNavCycles
.push_back(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
];
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
];
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";
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);
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
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
++)
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();
1228 g_pLogger
->Log("CUserLogTrial::CUserLogTrial, failed to create NavCycle!", logNORMAL
);
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
);
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>
1322 // <Value>7.0100</Value>
1323 // <Time>15:48:53.140</Time>
1325 for (VECTOR_NAME_VALUE_PAIR_ITER iter
= vParams
.begin(); iter
< vParams
.end(); iter
++)
1327 CUserLogParam
* pParam
= new CUserLogParam();
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
;
1343 pParam
->strValue
= iter
->strValue
;
1345 pParam
->options
= 0;
1347 vResult
.push_back(pParam
);
1354 // Parse our window or canvas coorindates from XML
1355 WindowSize
CUserLogTrial::ParseWindowXML(const string
& strXML
)
1357 //CFunctionLogger f1("CUserLogTrial::ParseWindowXML", g_pLogger);
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
);
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
= "";
1382 for (VECTOR_USER_LOCATION_PTR_ITER iter2
= (*iter
)->vectorMouseLocations
.begin();
1383 iter2
< (*iter
)->vectorMouseLocations
.end();
1387 strResult
+= (*iter2
)->GetTabMouseXY(bReturnNormalized
);
1391 vResult
.push_back(strResult
);
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
++)
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
++)
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();
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;
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
);
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
))
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
];
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
)
1529 if (ppGridB
!= NULL
)
1531 for (int i
= 0; i
< iGridSize
; i
++)
1533 if (ppGridB
[i
] != NULL
)