/*
============================================================================
Name : MovingBallAppView.cpp
Author : Ole Kirkeby, Markus K�h�ri and Yk� Huhtala
Copyright : Copyright Nokia
Description : Application view implementation
============================================================================
*/
// INCLUDE FILES
#include <coemain.h>
#include <RDAccelerometer.h>
#include "MovingBallAppView.h"
// CONSTANTS
const TInt KScreenWidth = 240;
const TInt KScreenHeight = 234;
const TInt KScreenCenterX = KScreenWidth >> 1;
const TInt KScreenCenterY = KScreenHeight >> 1;
const TInt KBallRadius = 20; // average radius of ball, in pixels
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CMovingBallAppView::NewL()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMovingBallAppView* CMovingBallAppView::NewL( const TRect& aRect)
{
CMovingBallAppView* self = CMovingBallAppView::NewLC ( aRect);
CleanupStack::Pop ( self);
return self;
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMovingBallAppView* CMovingBallAppView::NewLC( const TRect& aRect)
{
CMovingBallAppView* self = new ( ELeave ) CMovingBallAppView;
CleanupStack::PushL ( self);
self->ConstructL ( aRect);
return self;
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::ConstructL()
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::ConstructL( const TRect& aRect)
{
// Create a window for this application view
CreateWindowL ();
// Set the windows size
SetRect ( aRect);
// Activate the window, which makes it ready to be drawn
ActivateL ();
iAudioToneUtility = CMdaAudioToneUtility::NewL (*this);
iAudioToneUtility->PrepareToPlayTone (577, 3000);
iAccelerometer = CRDAccelerometer::NewL (*this);
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::CMovingBallAppView()
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CMovingBallAppView::CMovingBallAppView()
{
// No implementation required
iRefreshCounter = 0;
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::~CMovingBallAppView()
// Destructor.
// -----------------------------------------------------------------------------
//
CMovingBallAppView::~CMovingBallAppView()
{
delete iAccelerometer;
delete iAudioToneUtility;
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::Draw()
// Draws the display.
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::Draw( const TRect& /*aRect*/) const
{
// Get the standard graphics context
CWindowGc& gc = SystemGc ();
// Gets the control's extent
TRect drawRect( Rect ());
// Clears the screen
gc.Clear ( drawRect);
TInt cx = (TInt)( 1000.0 * iX );//x-coordinate of center of ball relative to screen center
TInt cy = (TInt)( 1000.0 * iY );//y-coordinate of center of ball relative to screen center
TInt dr = (TInt)( ( 100.0 * iZ2 ) / ( 0.1 + iX*iX + iY*iY ) );//change in ball radius due to acceleration in z-direction
TInt BallRadius = KBallRadius;//instantaneous ball radius
if ( Abs ( dr)> 4)
{//ignore the influence of small fluctuations in the accelerometer data
BallRadius += dr;
}
//ensure the ball does not go off the edges of the screen
if ( cx < ( BallRadius - KScreenCenterX ))
{
cx = BallRadius - KScreenCenterX;
}
if ( cx > ( KScreenCenterX - BallRadius ))
{
cx = KScreenCenterX - BallRadius;
}
if ( cy < ( BallRadius - KScreenCenterY ))
{
cy = BallRadius - KScreenCenterY;
}
if ( cy > ( KScreenCenterY - BallRadius ))
{
cy = KScreenCenterY - BallRadius;
}
TInt x1 = KScreenCenterX + cx - BallRadius;
TInt x2 = KScreenCenterX + cx + BallRadius;
TInt y1 = KScreenCenterY + cy - BallRadius;
TInt y2 = KScreenCenterY + cy + BallRadius;
gc.Clear ( drawRect);
TRect Rect1( TPoint ( x1, y1), TPoint ( x2, y2));
gc.SetPenColor ( TRgb (0, 0, 0));
gc.SetBrushStyle ( CWindowGc::ESolidBrush);
gc.SetBrushColor ( TRgb (200, 100, 85));
gc.DrawEllipse ( Rect1);
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::SizeChanged()
// Called by framework when the view size is changed.
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::SizeChanged()
{
DrawNow();
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::HandleAccelerationL()
// Takes care of acceleration data.
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::HandleAccelerationL( TInt aX, TInt aY, TInt aZ)
{
SmoothOutRawData (aX, aY, aZ);
DetectHit();
DrawDeferred();
// keep backlight on (reset on every second; consumes battery...)
++iRefreshCounter;
if (iRefreshCounter > 40)
{
iRefreshCounter = 0;
User::ResetInactivityTime();
}
if ( iDetectHit)
{
// Play a hit tune...
TRAPD(error, iAudioToneUtility->Play())
;
}
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::SmoothOutRawData()
// Takes the integer values from the accelerometer and returns lowpass-filtered
// data in iX and iY, and bandpass-filtered data in iZ2.
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::SmoothOutRawData( TInt aX, TInt aY, TInt aZ)
{
const TReal K128 = 0.0078125;// 1/128
const TReal KPole1 = 0.97;//pole of lowpass filter applied to X and Y
const TReal KPole2 = 0.90;//pole of lowpass filter applied to Z
const TReal KPole3 = 0.75;//pole of highpass filter applied to Z
//single-pole lowpass-filtering of X and Y
iX = KPole1 * iX1 + ( 1.0 - KPole1 ) * ( K128 * aX );
iY = KPole1 * iY1 + ( 1.0 - KPole1 ) * ( K128 * aY );
//single-pole lowpass-filtering of Z
iZ0 = KPole2 * iZ1 + ( 1.0 - KPole2 ) * ( K128 * aZ );
//1st order highpass-filtering of Z (zero at 1)
iZ2 = KPole3 * iZ2 + ( 1.0 - KPole3 ) * ( iZ0 - iZ1 );
//update variables for use at next sample
iX1 = iX;
iY1 = iY;
iZ1 = iZ0;
}
// -----------------------------------------------------------------------------
// CMovingBallAppView::DetectHit()
// Detects when the acceleration in the z-direction crosses zero in the negative
// direction after coming from a relatively large positive value
// -----------------------------------------------------------------------------
//
void CMovingBallAppView::DetectHit()
{
const TReal KDetectHitThreshold = 0.01;
iDetectHit = false;
//keep track of the largest positive value since last time iZ2 was negative
if ( iZ2 > iZmax)
{
iZmax = iZ2;
}
//accept hit when zero crossing follows a large positive value
if ( iZ2 < 0)
{
if ( iZmax > KDetectHitThreshold)
{
iDetectHit = true;
iZmax = 0;
}
}
}
void CMovingBallAppView::MatoPrepareComplete(TInt aError)
{
}
void CMovingBallAppView::MatoPlayComplete(TInt aError)
{
}
// End of File