turning OFF simple text-writing code slows down app - c++

I'm programming a simple game in SFML/C++/Code::blocks. I wrote a simple "dev-console" which basically prints out in the corner fps, position, number of logic/ graphics loops etc.
Everything works fine until I hide it, then fps fall down from 60(blocked max) to around 15. Why disabling writing function causes so much fps drop? (shouldn't disabling it speed things up a little?)
Declarations:
sf::Text consoletxt;
sf::Font font;
if (!font.loadFromFile("Times_New_Roman.ttf"))
std::cout<<"Error loading font Times New Roman"<<std::endl;
consoletxt.setFont(font);
consoletxt.setFillColor(sf::Color(255,255,255,255));
consoletxt.setCharacterSize(14);
consoletxt.setOutlineColor(sf::Color(0,0,0,192));
consoletxt.setOutlineThickness(1);
bool console = true;
Code below: upon switching console = false; fps drops from 60 to 15
tm = t.asMilliseconds();
fps += 1000/tm;
if (console == true)
{
consoletxt.setString("Last loop time: " + doubleToString(tm));
consoletxt.setPosition(0,0);
window.draw(consoletxt);
consoletxt.setString("Fps: " + intToString(1000/tm) + " Average fps: " + intToString(fps/logicLoops));
consoletxt.setPosition(0,15);
window.draw(consoletxt);
consoletxt.setString("objects[0].x: " + doubleToString(objects[0].x));
consoletxt.setPosition(0,30);
window.draw(consoletxt);
consoletxt.setString("objects[0].y: " + doubleToString(objects[0].y));
consoletxt.setPosition(0,45);
window.draw(consoletxt);
consoletxt.setString("Angle radians/degrees: " + doubleToString(cam_angle) + " | " + intToString((int)(cam_angle*180/pi)));
consoletxt.setPosition(0,60);
window.draw(consoletxt);
consoletxt.setString("Logical Loops: " + doubleToString(logicLoops) + " Graphics loops: " + doubleToString(graphicsLoops) + " Difference: " + doubleToString(logicLoops - graphicsLoops - 1));
consoletxt.setPosition(0,75);
window.draw(consoletxt);
consoletxt.setString("Variable test: " + doubleToString(cos(cam_angle*180/3.1415)));
consoletxt.setPosition(0,585);
//window.draw(consoletxt);
}

Related

Locating bug triggering runtime error in Rcpp

I am using Rcpp to translate a model written in C++ to R, to take advantage of the visualization and fitting capabilities. I know the C++ code compiles and runs well. However, in Rcpp it triggers a runtime error that manifests as a fatal error and aborts the R session.
To try to locate where the error is triggered, I have written a wait_for_return() function and placed it along the code. This way I found the function that is triggering the error:
init = 0;
gammas[group[id_data_point]]*
(1 - pow(1 -
rel_abund_resid[id_data_point] -
rel_abund_visitors[id_data_point], 2)) / (1 - gammas[group[id_data_point]]);
draw(clientSet, int(sim_param["totRounds"]),
rel_abund_resid[id_data_point],
rel_abund_visitors[id_data_point]);
cout << id_data_point << '\t'<< group[id_data_point] << '\n';
wait_for_returnRcpp();
cleaners[agent[id_data_point]][group[id_data_point]]->rebirth(init);
wait_for_returnRcpp(); # This function is not reached
idClientSet = 0;
VisPref = 0, countRVopt = 0;
cleaners[agent[id_data_point]][group[id_data_point]]->
act(clientSet, idClientSet, prob_Vis_Leav[id_data_point],
double(sim_param["ResProbLeav"]), double(sim_param["VisReward"]),
sim_param["ResReward"], sim_param["inbr"], sim_param["outbr"],
learnScenario(int(sim_param["scenario"])));
wait_for_returnRcpp();
cleaners[agent[id_data_point]][group[id_data_point]]->update();
return 0;
While trying to understand how the function is triggering the error, I commented some parts of the code. Surprisingly, when I commented a function that is executed after the error-triggering function the error is not triggered anymore.
init = 0;
gammas[group[id_data_point]]*
(1 - pow(1 -
rel_abund_resid[id_data_point] -
rel_abund_visitors[id_data_point], 2)) / (1 - gammas[group[id_data_point]]);
draw(clientSet, int(sim_param["totRounds"]),
rel_abund_resid[id_data_point],
rel_abund_visitors[id_data_point]);
cout << id_data_point << '\t'<< group[id_data_point] << '\n';
wait_for_returnRcpp();
cleaners[agent[id_data_point]][group[id_data_point]]->rebirth(init);
wait_for_returnRcpp();
idClientSet = 0;
VisPref = 0, countRVopt = 0;
// cleaners[agent[id_data_point]][group[id_data_point]]->
// act(clientSet, idClientSet, prob_Vis_Leav[id_data_point],
// double(sim_param["ResProbLeav"]), double(sim_param["VisReward"]),
// sim_param["ResReward"], sim_param["inbr"], sim_param["outbr"],
// learnScenario(int(sim_param["scenario"])));
// wait_for_returnRcpp();
// cleaners[agent[id_data_point]][group[id_data_point]]->update();
return 0;
# Code runs until the end
I have a hard time understanding how this is possible. The code is lengthy, so I was not able to provide a reproducible example. Any ideas of what I am missing are very welcome.

Recursive Breath First Search works on first execution but not following executions

The solution presented at CodeReview works fine on CentOS 7.1. I have tried to port it to Windows 7, Visual Studio 2012. With minor edits to allow for the parts of C++11 that VS 2012 doesn't support the code compiles, and the first execution of the loop works correctly. The rest of the execution of test cases fail, growing progressively more incorrect with each execution.
The code for this problem can be found on github.
finished computation at 0 /* problem here not included in question */
elapsed time: 0.202012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
I believe the problem is in one of the files listed below. I've been debugging this for 2 days, I can use some help.
CRKnightMoves_Cpp2.cpp
/*
* KnightMoves.cpp
*
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <iostream>
#include <stdexcept>
#include <chrono>
#include <ctime>
#include <algorithm>
#include <functional>
#include <vector>
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
double Average(std::vector<double> TestTimes)
{
double AverageTestTime = 0.0;
double SumOfTestTimes = 0.0;
int CountOfTestTimes = 0;
for (auto TestTimesIter : TestTimes)
{
SumOfTestTimes += TestTimesIter;
CountOfTestTimes++;
}
if (CountOfTestTimes) { // Prevent division by zero.
AverageTestTime = SumOfTestTimes / static_cast<double>(CountOfTestTimes);
}
return AverageTestTime;
}
void OutputOverAllStatistics(std::vector<double> TestTimes)
{
if (TestTimes.size() < 1) {
std::cout << "No test times to run statistics on!" << std::endl;
return;
}
std::cout << std::endl << "Overall Results" << std::endl;
std::cout << "The average execution time is " << Average(TestTimes) << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin() + TestTimes.size()/2, TestTimes.end());
std::cout << "The median execution time is " << TestTimes[TestTimes.size()/2] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::greater<double>());
std::cout << "The longest execution time is " << TestTimes[0] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::less<double>());
std::cout << "The shortest execution time is " << TestTimes[0] << " seconds" << std::endl;
}
double ExecutionLoop(KMBaseData UserInputData)
{
KnightMovesImplementation *KnightPathFinder = new KnightMovesImplementation(UserInputData);
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
KMOutputData OutputData = KnightPathFinder->CalculatePaths();
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
double ElapsedTimeForOutPut = elapsed_seconds.count();
char ctimebuffer[1024];
std::cout << "finished computation at " << ctime_s(ctimebuffer, 1024, &end_time) << "\n"
<< "elapsed time: " << ElapsedTimeForOutPut << " Seconds\n" << "\n" << "\n";
// Don't include output of results in elapsed time calculation
OutputData.DontShowPathData();
// OutputData.ShowPathData();
OutputData.ShowResults();
delete KnightPathFinder;
return ElapsedTimeForOutPut;
}
int LetUserEnterTestCaseNumber(std::vector<KMBaseData> &TestData)
{
int i = 1;
int Choice = -1;
std::cout << "Select the number of the test case you want to run.\n";
std::cout << "Test Case #" << "\tStart Name" << "\tTarget Name" << "\tBoard Size" << "\tSlicing Method" << "\n";
for (auto TestCase: TestData) {
std::cout << i << "\t" << TestCase.m_StartName << "\t" << TestCase.m_TargetName << "\t" << TestCase.m_DimensionOneSide << "\t";
switch (TestCase.m_LimitationsOnMoves)
{
default :
throw std::runtime_error("LetUserEnterTestCaseNumber : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
std::cout << "Can't return to previous location";
break;
case DenyByPreviousRowOrColumn:
std::cout << "Can't return to previous row or column";
break;
}
std::cout << "\n";
i++;
}
std::cout << i << "\tAll of the above except for 13 and 14\n";
std::cout << ++i <<"\tAll of the above (Go get lunch)\n";
std::cin >> Choice;
if (Choice == 15)
{
std::vector<KMBaseData> TempTests;
for (auto TestCase: TestData)
{
if ((TestCase.m_DimensionOneSide != MaximumBoardDimension) && (TestCase.m_LimitationsOnMoves != DenyByPreviousLocation))
{
TempTests.push_back(TestCase);
}
}
TestData = TempTests;
}
return Choice;
}
void InitTestData(std::vector<KMBaseData> &TestData)
{
KMBaseData TestCases[] = {
{1,3,"A3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,1,"A1",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,8,"A8",8,1,"H1", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"C1",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"A3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn}, // Minimum should be one move
{8,4,"H4",1,3,"A3", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",1,8,"A8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",5,6,"E6", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", 12, DenyByPreviousRowOrColumn}, // Minimum should be one move
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousLocation}, // Minimum should be one move
{1,3,"A3",2,5,"B5", MaximumBoardDimension, DenyByPreviousRowOrColumn} // Minimum should be one move
};
for (int i = 0; i < sizeof(TestCases)/sizeof(KMBaseData); i++) {
TestData.push_back(TestCases[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int status = 0;
std::vector<KMBaseData> TestData;
std::vector<double> TestTimes;
try {
InitTestData(TestData);
int Choice = LetUserEnterTestCaseNumber(TestData);
if (Choice < 0)
{
return status;
}
if (Choice < 15)
{
ExecutionLoop(TestData[Choice-1]);
}
else
{
for (auto TestDataIter: TestData) {
TestTimes.push_back(ExecutionLoop(TestDataIter));
}
}
OutputOverAllStatistics(TestTimes);
return status;
}
catch(std::runtime_error &e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e.what() << std::endl;
status = 1;
}
catch(std::runtime_error *e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e->what() << std::endl;
status = 1;
}
catch(...) {
std::cerr << "An unknown fatal error occurred in KnightMoves." << std::endl;
status = 1;
}
return status;
}
KnightMovesImplementation.h
#pragma once
/*
* KnightMovesImplementation.h
*
* Created on: Mar 18, 2016
* Modified on: June 20, 2016
* Author: pacmaninbw
*
* This class provides the search for all the paths a Knight on a chess
* board can take from the point of origin to the destination. It
* implements a modified Knights Tour. The classic knights tour problem
* is to visit every location on the chess board without returning to a
* previous location. That is a single path for the knight. This
* implementation returns all possible paths from point a to point b.
* The actual implementation is documented in the CPP file because it
* can be changed. This head file provides the public interface which
* should not be changed. The public interface may be moved to a
* super class in the future.
*/
#ifndef KNIGHTMOVESIMPLEMENTATION_H_
#define KNIGHTMOVESIMPLEMENTATION_H_
#include "KMPath.h"
#include "KMOutputData.h"
#include "KMMoveFilters.h"
class KnightMovesImplementation {
private:
KMBoardLocation m_PointOfOrigin;
KMBoardLocation m_Destination;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMOutputData *m_Results;
KMMoveFilters *m_MoveFilters;
KMPath *m_Path;
protected:
bool CalculatePath(KMMove CurrentMove); // Recursive function
void InitPointOfOrigin(KMBaseData UserData);
void InitDestination(KMBaseData UserData);
public:
KnightMovesImplementation(KMBaseData UserData);
virtual ~KnightMovesImplementation(void);
KMOutputData CalculatePaths();
};
#endif /* KNIGHTMOVESIMPLEMENTATION_H_ */
KnightsImplementation.cpp
/*
* KnightMovesImplementation.cpp
*
* Created on: Mar 18, 2016
* Modified on: June 21, 2016
* Commented on: June 24, 2016
* Author: pacmaninbw
*
* This class implements the search for all possible paths for a Knight
* on a chess board from one particular square on the board to another
* particular square on the board.
*
* The current implementation is a Recursive Breadth First Search. Conceptually
* the algorithm implements a B+ tree with a maximum of 8 possible branches
* at each level. The root of the tree is the point of origin. A particular
* path terminates in a leaf. A leaf is the result of either reaching the
* destination, or reaching a point where there are no more branches to
* traverse.
*
* The m_Path variable is used as a stack within the search.
*
* The public interface CalculatePaths establishes the root and creates
* the first level of branching. The protected interface CalculatePath
* performs the recursive depth first search, however, the
* m_MoveFilters.GetPossibleMoves() function it calls performs a breadth
* first search of the current level.
*
*/
#include "stdafx.h"
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
KnightMovesImplementation::~KnightMovesImplementation(void)
{
delete m_MoveFilters;
delete m_Results;
delete m_Path;
}
KnightMovesImplementation::KnightMovesImplementation(KMBaseData UserInputData)
: m_SingleSideBoardDimension(UserInputData.m_DimensionOneSide),
m_PathLimitations(UserInputData.m_LimitationsOnMoves)
{
InitPointOfOrigin(UserInputData);
InitDestination(UserInputData);
m_Path = new KMPath;
m_MoveFilters = new KMMoveFilters(static_cast<unsigned int>(UserInputData.m_DimensionOneSide), UserInputData.m_LimitationsOnMoves);
m_Results = new KMOutputData(m_PointOfOrigin, m_Destination, m_SingleSideBoardDimension, m_PathLimitations);
}
void KnightMovesImplementation::InitPointOfOrigin(KMBaseData UserInputData)
{
m_PointOfOrigin.SetRow(UserInputData.m_StartRow);
m_PointOfOrigin.SetColumn(UserInputData.m_StartColumn);
m_PointOfOrigin.SetName(UserInputData.m_StartName);
m_PointOfOrigin.SetBoardDimension(m_SingleSideBoardDimension);
}
void KnightMovesImplementation::InitDestination(KMBaseData UserInputData)
{
m_Destination.SetRow(UserInputData.m_TargetRow);
m_Destination.SetColumn(UserInputData.m_TargetColumn);
m_Destination.SetName(UserInputData.m_TargetName);
m_Destination.SetBoardDimension(m_SingleSideBoardDimension);
}
KMOutputData KnightMovesImplementation::CalculatePaths()
{
KMRandomAccessMoveCollection PossibleFirstMoves = m_MoveFilters->GetPossibleMoves(m_PointOfOrigin);
if (PossibleFirstMoves.empty())
{
std::cerr << "No Possible Moves in KnightMovesImplementation::CalculatePaths" << std::endl;
}
else
{
for (auto CurrentMoveIter : PossibleFirstMoves)
{
KMMove CurrentMove = CurrentMoveIter;
CurrentMove.SetOriginCalculateDestination(m_PointOfOrigin);
if (CurrentMove.IsValid()) {
CalculatePath(CurrentMove);
}
}
}
return *m_Results;
}
bool KnightMovesImplementation::CalculatePath(KMMove CurrentMove)
{
bool CompletedSearch = false;
KMBoardLocation CurrentLocation = CurrentMove.GetNextLocation();
m_Path->AddMoveToPath(CurrentMove);
m_MoveFilters->PushVisited(CurrentLocation);
if (CurrentLocation == m_Destination)
{
m_Results->AddPath(*m_Path);
CompletedSearch = true;
m_Results->IncrementAttemptedPaths();
}
else
{
if (CurrentMove.IsValid())
{
KMRandomAccessMoveCollection PossibleMoves = m_MoveFilters->GetPossibleMoves(CurrentLocation);
if (!PossibleMoves.empty())
{
for (auto NextMove : PossibleMoves)
{
CalculatePath(NextMove);
}
}
else
{
// No more moves to test, record the attempted path
m_Results->IncrementAttemptedPaths();
}
}
else
{
// There is a logic error if we get here.
std::cerr << "In KnightMovesImplementation::CalculatePath CurrentMove Not Valid" << std::endl;
}
}
m_Path->RemoveLastMove();
m_MoveFilters->PopVisited();
return CompletedSearch;
}
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
static KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); };
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
KMMoveFilters.cpp
/*
* KMMoveFilters.cpp
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <stdexcept>
#include <algorithm>
#include "KMBoardDimensionConstants.h"
#include "KMMoveFilters.h"
KMMoveFilters::~KMMoveFilters(void)
{
}
KMMoveFilters::KMMoveFilters(void)
: m_SingleSideBoardDimension(DefaultBoardDimensionOnOneSide),
m_PathLimitations(DenyByPreviousRowOrColumn)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
KMMoveFilters::KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod)
: m_SingleSideBoardDimension(BoardDimension), m_PathLimitations(SlicingMethod)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
const int Left1 = -1;
const int Left2 = -2;
const int Down1 = -1;
const int Down2 = -2;
const int Right1 = 1;
const int Right2 = 2;
const int Up1 = 1;
const int Up2 = 2;
KMMove KMMoveFilters::Left1Up2(Left1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Up1(Left2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Down1(Left2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left1Down2(Left1, Down2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Up2(Right1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Up1(Right2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Down1(Right2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Down2(Right1, Down2, DefaultBoardDimensionOnOneSide);
KMRandomAccessMoveCollection KMMoveFilters::AllPossibleMoves;
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibeMove : AllPossibleMoves) {
KMMove *TempMove = new KMMove(PossibeMove);
TempMove->SetBoardDimension(m_SingleSideBoardDimension);
TempMove->SetOriginCalculateDestination(CurrentLocation);
if ((TempMove->IsValid()) && (IsNotPreviouslyVisited(*TempMove))) {
PossibleMoves.push_back(*TempMove);
}
}
return PossibleMoves;
}
bool KMMoveFilters::IsNotPreviouslyVisited(KMBoardLocation PossibleDestination) const
{
bool NotPrevioslyVisited = true;
if (!m_VisitedLocations.empty()) { // This is always a test, we can't move backwards
if (std::find(m_VisitedLocations.begin(), m_VisitedLocations.end(), PossibleDestination)
!= m_VisitedLocations.end()) {
NotPrevioslyVisited = false;
}
}
switch (m_PathLimitations) {
default :
throw std::runtime_error("KMPath::CheckMoveAgainstPreviousLocations : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
// Always tested above.
break;
case DenyByPreviousRowOrColumn:
if ((!m_VisitedRows.empty()) && (!m_VisitedColumns.empty())) {
unsigned int PossibleRow = PossibleDestination.GetRow();
if (std::find(m_VisitedRows.begin(), m_VisitedRows.end(), PossibleRow) != m_VisitedRows.end()) {
NotPrevioslyVisited = false;
break;
}
unsigned int PossibleColum = PossibleDestination.GetColumn();
if (std::find(m_VisitedColumns.begin(), m_VisitedColumns.end(), PossibleColum) != m_VisitedColumns.end()) {
NotPrevioslyVisited = false;
}
}
break;
}
return NotPrevioslyVisited;
}
void KMMoveFilters::PushVisited(KMBoardLocation Location)
{
m_VisitedRows.push_back(Location.GetRow());
m_VisitedColumns.push_back(Location.GetColumn());
m_VisitedLocations.push_back(Location);
}
void KMMoveFilters::PopVisited()
{
m_VisitedRows.pop_back();
m_VisitedColumns.pop_back();
m_VisitedLocations.pop_back();
}
The problem was the static declaration of AllPossibleMoves, the memory leak in GetPossibleMoves may have been an additional contributor to the problem. In the CentOS C++11 version AllPossibleMoves was declared as static const, and was not initialized in the constructor, it was initialized outside as each of it's member moves are. This did not compile in Visual Studio 2012 C++. AllPossibleMoves was declared as static const for execution time reasons in the original version.
I am disappointed in the results since this is much slower than the CentOS version using C++11 compiled with g++. The computer I'm running this on is 2 years new than the CentOS computer and has 8GB of memory with an i7 processor.
First I present the working code, then I present the output of the program.
The final code that solves the problem is:
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); }
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
#endif /* KMMOVEFILTERS_H_ */
Only the changes in KMMoveFilters.cpp
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection SafeAllPossibleMoves = AllPossibleMoves;
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibleMove : SafeAllPossibleMoves) {
PossibleMove.SetBoardDimension(m_SingleSideBoardDimension);
PossibleMove.SetOriginCalculateDestination(CurrentLocation);
if ((PossibleMove.IsValid()) && (IsNotPreviouslyVisited(PossibleMove))) {
PossibleMoves.push_back(PossibleMove);
}
}
return PossibleMoves;
}
The resulting output
Select the number of the test case you want to run.
Test Case # Start Name Target Name Board Size Slicing Method
1 A3 H4 8 Can't return to previous row or column
2 A1 H8 8 Can't return to previous row or column
3 A8 H1 8 Can't return to previous row or column
4 B3 H4 8 Can't return to previous row or column
5 B3 H8 8 Can't return to previous row or column
6 C1 H4 8 Can't return to previous row or column
7 A3 H8 8 Can't return to previous row or column
8 A3 B5 8 Can't return to previous row or column
9 H4 A3 8 Can't return to previous row or column
10 D4 A8 8 Can't return to previous row or column
11 D4 E6 8 Can't return to previous row or column
12 A3 B5 12 Can't return to previous row or column
13 A3 B5 8 Can't return to previous location
14 A3 B5 26 Can't return to previous row or column
15 All of the above except for 13 and 14
16 All of the above (Go get lunch)
finished computation at 0
elapsed time: 0.209012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.0930054 Seconds
The point of origin for all path searches was A1
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.0950054 Seconds
The point of origin for all path searches was A8
The destination point for all path searches was H1
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.248014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 8 Resulting Paths
There were 446 attempted paths
The average path length is 5
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.251014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 39 Resulting Paths
There were 447 attempted paths
The average path length is 6.23077
The median path length is 7
The longest path is 7 moves
The shortest path is 5 moves
finished computation at 0
elapsed time: 0.17801 Seconds
The point of origin for all path searches was C1
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 7 Resulting Paths
There were 324 attempted paths
The average path length is 4.85714
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.18201 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 36 Resulting Paths
There were 324 attempted paths
The average path length is 6
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.131008 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 243 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 0.17301 Seconds
The point of origin for all path searches was H4
The destination point for all path searches was A3
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 12 Resulting Paths
There were 318 attempted paths
The average path length is 5.66667
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.332019 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was A8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 24 Resulting Paths
There were 602 attempted paths
The average path length is 5.25
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.266015 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was E6
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 21 Resulting Paths
There were 487 attempted paths
The average path length is 4.14286
The median path length is 5
The longest path is 7 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 1.86411 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 12
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 3440 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
Overall Results
The average execution time is 0.335186 seconds
The median execution time is 0.209012 seconds
The longest execution time is 1.86411 seconds
The shortest execution time is 0.0930054 seconds
Overall Results with optimized version.
Overall Results
The average execution time is 0.00266682 seconds
The median execution time is 0.0020001 seconds
The longest execution time is 0.0140008 seconds
The shortest execution time is 0.001 seconds
CentOS version Overall Results
The average execution time is 0.00195405 seconds
The median execution time is 0.00103346 seconds
The longest execution time is 0.00130368 seconds
The shortest execution time is 0.000716237 seconds

Send data to c++ application to Matlab

Hello I'm working on a Kinect Application and I need to send the data generated by the Kinect to Matlab.
I transfer the data succesfully by pipes but is not as fast as it should be after 10 minutes (don't know why) so I need to use Sockets.
I need to send the coordenates 'xr' and 'yr'.
How can I implement a Socket in my app and in Matlab?
SingleFace* pApp = reinterpret_cast<SingleFace*>(pVoid);
if (pApp)
{
IFTResult* pResult = pApp->m_FTHelper.GetResult();
if (pResult && SUCCEEDED(pResult->GetStatus()))
{
AllocConsole();
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
FLOAT* pAU = NULL;
UINT numAU;
pResult->GetAUCoefficients(&pAU, &numAU);
pApp->m_eggavatar.SetCandideAU(pAU, numAU);
FLOAT scale;
FLOAT rotationXYZ[3];
FLOAT translationXYZ[3];
pResult->Get3DPose(&scale, rotationXYZ, translationXYZ);
pApp->m_eggavatar.SetTranslations(translationXYZ[0], translationXYZ[1], translationXYZ[2]);
pApp->m_eggavatar.SetRotations(rotationXYZ[0], rotationXYZ[1], rotationXYZ[2]);
// OUTPUT WINDOW
std::string resultados = "T = [" + to_string(translationXYZ[0]) + "," + to_string(translationXYZ[1]) + "," + to_string(translationXYZ[2]) + ", ], R=[" + to_string(rotationXYZ[0]) + "," + to_string(rotationXYZ[0]) + "," + to_string(rotationXYZ[1]) + "," + to_string(rotationXYZ[2]) + "], sc=" + to_string(scale) + "/n";
std::wstring stemp = s2ws(resultados);
LPCWSTR results = stemp.c_str();
OutputDebugStringW(results);
/*Matrix to calculate the real coordenates
A1 = 98.1987 4.8642
-6.3882 79.6357
9.9648 20.0521*/
int xr =98.1987*translationXYZ[0] - 6.3882*translationXYZ[2] + 9.9648;
int yr = 4.8642*translationXYZ[0] + 79.6357*translationXYZ[2] + 20.0521;
//Real Tracking Points
cout << "(" << xr << "," << yr << ")\n";
}
}
This isn't a precise solution but I'd start looking here:
http://www.mathworks.com/help/instrument/using-tcpip-server-sockets.html
to start figuring out how to do the matlab server side, then you could leverage some TCP/IP library in windows (I'm not too familiar with programming windows applications).
HTH.

webservice in mobile application as3

i have a problem with an application for mobile devices, when i test the app in my pc the webservice conection is ok, i get an answer. however when i test the application in my mobile devices, the first use of the application takes too long to get an answer from the server and the screen stays in "SENDING..." , after many attemps and resets of the application, the conection is ok and after that, the application works fine. what could be my problem? pd: i dont speak english very well.
the code is:
private function panicStart(e:MouseEvent = null):void
{
trace("han presionado el boton de panico");
//Alert.show(_canvas, "Datos de Usuario :" + "\nNombre: " + _currentName + "\nKey: " + _currentKey + "\nD.N.I. :" + _currentDni + "\nMóvil: " + _currentPhone + "\n\nDatos de Geoposición:\n" + "\Latitud: " + _latitud + "\nLongitud: " + _longitud + "\n ", "Envío de Datos", new Array("ok"), null);
var url:String = "http://appmovil.munijesusmaria.gob.pe/1380panico/ws_panico.asmx?WSDL";
webService = new WebService();
webService.loadWSDL(url);
webService.addEventListener(LoadEvent.LOAD, BuildServiceRequest);
_state = STATE_STARTSEND
}
function BuildServiceRequest(evt:LoadEvent)
{
_state = STATE_SENDING;
serviceOperation = webService.getOperation("Insertar");
trace("esperando respuesta");
serviceOperation.addEventListener(FaultEvent.FAULT, DisplayError);
serviceOperation.addEventListener(ResultEvent.RESULT, DisplayResult);
if (_panicScreen.txtReference.text == _textReference || _panicScreen.txtReference.text == "")
serviceOperation.send(_currentDni, _currentName, _currentPhone, _latitud.toString(), _longitud.toString(), "ninguna", "285DF565H5654CC");
else
serviceOperation.send(_currentDni, _currentName, _currentPhone, _latitud.toString(), _longitud.toString(), _panicScreen.txtReference.text, "285DF565H5654CC");
}
function sentgotoPanic(e:MouseEvent = null):void
{
ScreenManager.gotoScreen("panic");
_state = STATE_SENT;
}
function DisplayError(evt:FaultEvent)
{
_state = STATE_JUSTSENT;
sentgotoPanic();
Alert.show(_canvas, "Error al enviar los datos" + "\n ", "Alerta", new Array("ok"), new Array("ok"), null);
trace("error");
_panicScreen.txtReference.text = "";
_state = STATE_SENT;
}
function DisplayResult(evt:ResultEvent)
{
_state = STATE_JUSTSENT;
trace("EEEEEEEXITO")
var result:String = evt.result as String;
sentgotoPanic();
Alert.show(_canvas, "Datos Enviados" + "\n ", "Alerta", new Array("ok"), null);
trace("error");
_panicScreen.txtReference.text = "";
_state = STATE_SENT;
}

Boost.thread code presents different behaviour in Ubuntu and in Windows

I have a little simple program to test wether I can visualize a point cloud from a different thread and continue working in the main thread until typing 'q' in the terminal.
In Ubuntu 10.04, the code works, letting me visualize the cloud as new points are added to it in each iteration. However, in Windows 7 this dosn't work (I'm compiling it with QtCreator). The cloud is shown and new points are computed in each turn, but this never exits. When typing 'q', the loop stops but the visualization thread keeps running. The only way to stop execution is to explicitly use CTRL+C.
More things:
If I don't uncomment the addPointCloud line before the !viewer->wasStopped() loop in the Visualize function, the point cloud is never shown. It doesn't matter that later in the loop I explicitly add it. It has to be done before the loop (now that line is commented to demonstrate that behaviour).
I also tried to use boost::mutex instead of *tbb::queuing_mutex*, but again, the program won't exit.
Do you have any idea why the thread is never joining?. Also, constructive critics about my thread usage are always welcomed, I want to keep improving.
Here's the code:
#include <boost/thread/thread.hpp>
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include "tbb/queuing_mutex.h"
typedef pcl::PointXYZ PointType;
typedef pcl::PointCloud<PointType> PointCloudType;
typedef tbb::queuing_mutex MutexType;
//typedef boost::mutex MutexType;
MutexType safe_update;
const unsigned int HEIGHT = 100;
const unsigned int WIDTH = 100;
bool has_to_update(true);
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
// viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped()) {
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
int main(int argc, char** argv) {
PointCloudType::Ptr c(new PointCloudType);
c->height=HEIGHT;
c->width=WIDTH;
const unsigned int size( c->height*c->width);
c->points.resize(size);
for(unsigned int i(0);i<size;++i){
c->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
c->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cout << "Filled cloud height: " << c->height << " ** widht = "
<< c->width << " ** size: " << c->points.size()
<< "\n"
;
boost::thread vis_thread( boost::bind( &Visualize, boost::ref(c) ) );
char exit;
std::vector<PointType> new_points;
new_points.resize(10);
PointType new_point;
while(exit!='q') {
for(unsigned int i(0);i<10;++i) {
new_point.x = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.y = 2000 * rand () / (RAND_MAX + 1.0f);
new_point.z = 2000 * rand () / (RAND_MAX + 1.0f);
std::cout << "New point " << i << " with x = " << new_point.x
<< " ; y = " << new_point.y << " ; z = "
<< new_point.z << "\n"
;
new_points.push_back(new_point);
}
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
c->insert( c->points.end(), new_points.begin(), new_points.end() );
has_to_update = true;
} // end scoped_lock
std::cout << "Exit?: ";
std::cin>>exit;
}
vis_thread.join();
return 0;
}
Thanks for your time!.
EDIT: Since I can't use a debugger due to Windows not recognizing the executable format(?) I've put some qDebug() lines over the Visualize function (also, instead of directly calling viewer->wasStopped() now I'm using a volatile intermediate var, stopped):
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
volatile bool stopped( false );
int iterations( -1 );
while(!stopped) {
++iterations;
qDebug() << "Before spinOnce - it: << iteration << "\n";
viewer->spinOnce(100);
{
// boost::lock_guard<MutexType> lock(safe_update);
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
stopped = viewer->wasStopped();
qDebug() << "Before a new loop - it:" << iteration << "\n";
}
delete viewer;
};
Well, Before spinOnce is only displayed once, with iteration=0. The Before a new loop line is never printed.
On the other hand, the main thread keeps calculating and printing those points to the standard output until 'q' is inputted.
It seems that the visualization thread frozens in the viewer->spinOnce(100) call. If instead of spinOnce(100) I use the other visualization method, spin(), nothing changes.
Maybe there's a data race in my code, but for much I keep checking it, I can't find the race myself.
NOTE: According to the PCL library doc, spinOnce(int time) calls the interactor and updates the screen once, whereas spin() calls the interactor and runs an internal loop.
EDIT #2: Today I tried to execute the code again in Ubuntu and resulted in a deadlock with the PCL visualizer. I added some volatile keywords and a new loop check. Now it seems it goes well (at least it worked as expected, no wrong turns...). Here's the new version:
Global vars:
volatile bool has_to_update(true); // as suggested by #daramarak
volatile bool quit(false); // new while loop control var
Visualize method:
void Visualize(PointCloudType::Ptr cloud) {
pcl::visualization::PCLVisualizer* viewer = new pcl::visualization::PCLVisualizer("Vis in thread",true);
viewer->setBackgroundColor(1.0,0.0,0.0);
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->addCoordinateSystem(1.0);
viewer->initCameraParameters();
viewer->resetCamera();
while(!viewer->wasStopped() && !quit ) {
viewer->spinOnce(100);
{
MutexType::scoped_lock lock(safe_update);
if(has_to_update) {
if(!viewer->updatePointCloud<PointType>(cloud, "sample cloud")) {
viewer->addPointCloud<PointType>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
viewer->resetCamera();
}
has_to_update = false;
}
} // end scoped_lock
}
delete viewer;
};
Main function:
// everything the same until...
std::cin>>exit;
quit = (exit=='q');
// no more changes
I dont' like, however, the new control loop var hack. Isn't there a better way to know when to exit?. Right now, I can't realize any other way...
I believe that the wasStopped() function is a const member function thereby not changing the state of the object, so there might be an optimization in play here (It might cache the wasStopped() value as the compiler assumes the answer won't change. I suggest you try to wrap the viewer in another object with a function bool wasStopped() volatile, that might prevent such optimizations.