/////////////////////////////////////////////////////////////////////////////
// Name: cmotioncalibration.h
// Purpose:
// Author: Cesar Mauri Loba (cesar at crea-si dot com)
// Modified by:
// Created: 07/09/2010
// Copyright: (C) 2008 Cesar Mauri Loba - CREA Software Systems
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
/////////////////////////////////////////////////////////////////////////////
#include "cmotioncalibration.h"
#include "viacamcontroller.h"
#include "wmotioncalibrationx.h"
#include "wmotioncalibrationy.h"
#include "wconfirmcalibration.h"
#include "timeutil.h"
#include "pointeraction.h"
#include "eviacamapp.h"
#include
#include
#include
#include
#if defined(_WIN32) || defined(_WIN64)
#define fmax max
#define fmin min
#endif
#define BUTTON_OK 1
#define BUTTON_CANCEL 2
#define BUTTON_REPEAT 3
#define TIME_LIMIT_NO_MOTION_X 5000
#define MOTION_THRESHOLD_X 0.5f
#define TIME_LIMIT_NO_X_RANGE_EXPANDED 3000
#define TIME_LIMIT_NO_MOTION_Y 5000
#define MOTION_THRESHOLD_Y 0.5f
#define TIME_LIMIT_NO_Y_RANGE_EXPANDED 3000
#define MULTIPLIER_X 0.27f
#define MULTIPLIER_Y 0.20f
#define MAX_THRESHOLD_SPEED 30.0f
#define MIN_THRESHOLD_SPEED 1.0f
CMotionCalibration::CMotionCalibration()
{
m_pDialog = NULL;
m_state = BEFORE_WAITING_X;
InitValues();
}
void CMotionCalibration::InitValues()
{
m_posXVirt = 0;
m_posYVirt = 0;
m_posXVirtMax = 0;
m_posYVirtMax = 0;
m_posXVirtMin = 0;
m_posYVirtMin = 0;
m_lastTimestamp = CTimeUtil::GetMiliCount();
}
CMotionCalibration::~CMotionCalibration()
{
}
bool CMotionCalibration::InitMotionCalibration()
{
bool changes = false;
//
// Store previous values
//
unsigned int xSpeedBackup= wxGetApp().GetController().GetPointerAction().GetXSpeed();
unsigned int ySpeedBackup= wxGetApp().GetController().GetPointerAction().GetYSpeed();
bool isEnabled= wxGetApp().GetController().GetEnabled();
CPointerAction::EClickMode clickMode= wxGetApp().GetController().GetPointerAction().GetClickMode();
m_state = BEFORE_WAITING_X;
do {
//
// Begin calibration process. Initialise values
//
InitValues();
assert (m_state == BEFORE_WAITING_X);
// Externally enable motion calibration process, after this point,
// ComputeMotionRange begins to get called
wxGetApp().GetController().SetMotionCalibrationEnabled(true);
//
// Calibration X dialogue
//
m_pDialog = new WMotionCalibrationX(NULL);
m_state = WAITING_X;
// Show. The dialogue is closed form ComputeMotionRange
m_pDialog->ShowModal();
assert (m_state == ABORTING || m_state == BEFORE_WAITING_Y);
// Close dialogue
m_pDialog->Destroy();
m_pDialog= NULL;
//
// Calibration X dialogue
//
if (m_state == BEFORE_WAITING_Y) {
assert (m_pDialog == NULL);
m_pDialog = new WMotionCalibrationY(NULL);
m_state = WAITING_Y;
// Show. The dialogue is closed form ComputeMotionRange
m_pDialog->ShowModal();
assert (m_state == ABORTING || m_state == CONFIRMATION);
// Close dialogue
m_pDialog->Destroy();
m_pDialog= NULL;
}
// Externally disable motion calibration process, after this point,
// ComputeMotionRange stops being called
wxGetApp().GetController().SetMotionCalibrationEnabled(false);
if (m_state == CONFIRMATION) {
// Compute new speed parameters
// TODO: improve formula taking into account several proves and adjustements
float newSpeedX = 600.0f / (m_posXVirtMax - m_posXVirtMin);
float newSpeedY = 600.0f / (m_posYVirtMax - m_posYVirtMin);
// Set between reasonable limits
#define MAX_CALIBRATION_SPEED 18.0f
#define MIN_CALIBRATION_SPEED 5.0f
if (newSpeedX> MAX_CALIBRATION_SPEED) newSpeedX = MAX_CALIBRATION_SPEED;
else if (newSpeedX< MIN_CALIBRATION_SPEED) newSpeedX = MIN_CALIBRATION_SPEED;
if (newSpeedY> MAX_CALIBRATION_SPEED) newSpeedY = MAX_CALIBRATION_SPEED;
else if (newSpeedY< MIN_CALIBRATION_SPEED) newSpeedY = MIN_CALIBRATION_SPEED;
// Set new parameters
wxGetApp().GetController().GetPointerAction().SetXSpeed((unsigned int) newSpeedX);
wxGetApp().GetController().GetPointerAction().SetYSpeed((unsigned int) newSpeedY);
// Disable click generation & enable motion to test
wxGetApp().GetController().GetPointerAction().SetClickMode(CPointerAction::NONE);
wxGetApp().GetController().SetEnabled(true, true);
// Request user acknowledgment
assert (m_pDialog== NULL);
m_pDialog = new WConfirmCalibration(NULL);
int retvalConfirm = m_pDialog->ShowModal();
if (retvalConfirm== BUTTON_REPEAT) m_state = BEFORE_WAITING_X;
else {
if (retvalConfirm== BUTTON_OK) changes = true;
else if (retvalConfirm== BUTTON_CANCEL) {
wxGetApp().GetController().GetPointerAction().SetXSpeed(xSpeedBackup);
wxGetApp().GetController().GetPointerAction().SetYSpeed(ySpeedBackup);
}
else
assert (false);
m_state = FINISHED;
}
m_pDialog->Destroy();
m_pDialog= NULL;
} else if (m_state == ABORTING) {
wxMessageDialog dlg (NULL, _("No movement was detected.\nDo you want to repeat the calibration?"),
_("eViacam warning"), wxICON_EXCLAMATION | wxYES_NO );
if (dlg.ShowModal() == wxID_YES)
m_state = BEFORE_WAITING_X;
else
m_state = FINISHED;
}
} while (m_state != FINISHED);
assert (m_pDialog== NULL);
// Restore previous settings
wxGetApp().GetController().GetPointerAction().SetClickMode(clickMode);
wxGetApp().GetController().SetEnabled(isEnabled, true);
return changes;
}
void CMotionCalibration::ComputeMotionRange (float vx, float vy, bool warnFaceNotDetected)
{
switch (m_state)
{
case WAITING_X:
((WMotionCalibrationX*)m_pDialog)->SetFaceDetected(warnFaceNotDetected);
m_posXVirt += vx;
if (fabs(vx) > MOTION_THRESHOLD_X) {
m_state = MEASURING_X;
m_lastTimestamp = CTimeUtil::GetMiliCount();
} else {
if (CTimeUtil::GetMiliCount() - m_lastTimestamp > TIME_LIMIT_NO_MOTION_X) {
m_state = ABORTING;
wxCommandEvent event (wxEVT_CLOSE_WINDOW);
wxPostEvent(m_pDialog, event);
}
}
break;
case MEASURING_X:
((WMotionCalibrationX*)m_pDialog)->SetFaceDetected(warnFaceNotDetected);
m_posXVirt += vx;
if (m_posXVirt > m_posXVirtMax) {
m_posXVirtMax = m_posXVirt;
m_lastTimestamp = CTimeUtil::GetMiliCount();
}
if (m_posXVirt < m_posXVirtMin) {
m_posXVirtMin = m_posXVirt;
m_lastTimestamp = CTimeUtil::GetMiliCount();
}
if (CTimeUtil::GetMiliCount() - m_lastTimestamp > TIME_LIMIT_NO_X_RANGE_EXPANDED) {
m_state = BEFORE_WAITING_Y;
m_lastTimestamp = CTimeUtil::GetMiliCount();
wxCommandEvent event (wxEVT_CLOSE_WINDOW);
wxPostEvent(m_pDialog, event);
}
break;
case WAITING_Y:
((WMotionCalibrationY*)m_pDialog)->SetFaceDetected(warnFaceNotDetected);
m_posYVirt += vy;
if (fabs(vy) > MOTION_THRESHOLD_Y) {
m_state = MEASURING_Y;
m_lastTimestamp = CTimeUtil::GetMiliCount();
} else {
if (CTimeUtil::GetMiliCount() - m_lastTimestamp > TIME_LIMIT_NO_MOTION_Y) {
m_state = ABORTING;
wxCommandEvent event (wxEVT_CLOSE_WINDOW);
wxPostEvent(m_pDialog, event);
}
}
break;
case MEASURING_Y:
((WMotionCalibrationY*)m_pDialog)->SetFaceDetected(warnFaceNotDetected);
m_posYVirt += vy;
if (m_posYVirt > m_posYVirtMax) {
m_posYVirtMax = m_posYVirt;
m_lastTimestamp = CTimeUtil::GetMiliCount();
}
if (m_posYVirt < m_posYVirtMin) {
m_posYVirtMin = m_posYVirt;
m_lastTimestamp = CTimeUtil::GetMiliCount();
}
if (CTimeUtil::GetMiliCount() - m_lastTimestamp > TIME_LIMIT_NO_Y_RANGE_EXPANDED) {
m_state = CONFIRMATION;
m_lastTimestamp = CTimeUtil::GetMiliCount();
wxCommandEvent event (wxEVT_CLOSE_WINDOW);
wxPostEvent(m_pDialog, event);
}
break;
case BEFORE_WAITING_X:
case BEFORE_WAITING_Y:
case CONFIRMATION:
case ABORTING:
case FINISHED:
// Do nothing
break;
default:
assert (false);
break;
}
}