diff -r 1fc85118c3ae -r 870918037e16 mapnavproviderrefapp/src/mnrpmapmodel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapnavproviderrefapp/src/mnrpmapmodel.cpp Wed Sep 01 12:31:27 2010 +0100 @@ -0,0 +1,1251 @@ +/* +* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: CMnrpMapModel class implementation +* +*/ + + + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "debug.h" +#include "mnrpengine.h" +#include "mnrputils.h" +#include "mnrpappserver.h" + +#include "mnrpmapviewservice.h" +#ifdef RD_MAPNAV_BITMAP_ACCESS +#include "mnrpmapimageservice.h" +#endif +#include "mnrpmapmodel.h" + +const TInt KUpdateInterval = 1 * 1000 * 1000; // 1 sec +const TInt KUpdateTimeout = 10 * 1000 * 1000; // 10 sec + +const TInt KMaxX = 180; +const TInt KMinX = -180; +const TInt KMapWidth = KMaxX - KMinX; + +const TInt KMaxY = 90; +const TInt KMinY = -90; +const TInt KMapHeight = KMaxY - KMinY; + +const TReal KDegree = 1.0; +const TReal KMinute = KDegree / 60.0; +const TReal KSecond = KMinute / 60.0; +const TReal KMilliSecond = KSecond / 1000.0; + +const TReal KMaxCell = 60 * KDegree; +const TReal KMinScale = 10 * KMilliSecond; // 0.01 second / 1 px + +const TInt KBigCellsInView = 2; + +const TInt KCellDividers[] = { 6, 2, 5 }; +const TInt KNumCellDividers = 3; + +const TReal KDefaultRadius = 1; // 1 degree +const TReal KRadiusBorderFactor = 1.1; // 110% + +const TReal KEarthEquator = 40075000; +//const TReal KEarthRadius = 6371010; + +const TInt KLmTextOffset = 3; +const TInt KLmTextShadowOffset = 1; + +const TInt KGridPenSize( 1 ); + +// ============================ LOCAL FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TPoint AbsoluteToImage( TRealPoint aAbsolute, TReal aImageToAbsoluteScale ) + { + TInt s = ( KMapWidth / 2 + aAbsolute.iX ) / aImageToAbsoluteScale; + TInt t = ( KMapHeight / 2 - aAbsolute.iY ) / aImageToAbsoluteScale; + + return TPoint( s , t ); + } + +// ============================ MEMBER CLASSES' FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// TRealPoint implementation +// ----------------------------------------------------------------------------- +// + +TRealPoint::TRealPoint() + { + TRealX nan; + nan.SetNaN(); + + iX = nan; + iY = nan; + } + +TRealPoint::TRealPoint( TReal aX, TReal aY ) + : iX( aX ), iY( aY ) + { + } + +TRealPoint::TRealPoint( TCoordinate aCoordinate ) + : iX( aCoordinate.Longitude() ), iY( aCoordinate.Latitude() ) + { + } + +TCoordinate TRealPoint::Coordinate() + { + return TCoordinate( iY, iX ); + } + +TRealPoint TRealPoint::operator+( + const TRealPoint& aRight ) + { + return TRealPoint( this->iX + aRight.iX, this->iY + aRight.iY ); + } + +TRealPoint TRealPoint::operator-( + const TRealPoint& aRight ) + { + return TRealPoint( this->iX - aRight.iX, this->iY - aRight.iY ); + } + +TRealPoint TRealPoint::operator*( const TReal& aRight ) + { + return TRealPoint( this->iX * aRight, this->iY * aRight ); + } + +TRealPoint TRealPoint::operator/( const TReal& aRight ) + { + return TRealPoint( this->iX / aRight, this->iY / aRight ); + } + +void TRealPoint::Set( TReal aX, TReal aY ) + { + iX = aX; + iY = aY; + } + +TBool TRealPoint::IsValid() + { + return ( !Math::IsNaN( iX ) && !Math::IsNaN( iY ) ); + } + +// ----------------------------------------------------------------------------- +// CDrawItem implementation +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::CDrawItem* CMnrpMapModel::CDrawItem::NewLC( + const CPosLandmark& aLm ) + { + CDrawItem* self = new (ELeave) CDrawItem; + CleanupStack::PushL( self ); + + TPtrC name; + aLm.GetLandmarkName( name ); + self->iText = MnrpUtils::PrintableStringLC( name ); + CleanupStack::Pop( self->iText ); + + TLocality loc; + if ( KErrNone == aLm.GetPosition( loc ) ) + { + self->SetAbsolutePosition( loc ); + } + + TPtrC iconFile; + TInt iconIndex, maskIndex; + if ( KErrNone == aLm.GetIcon( iconFile, iconIndex, maskIndex ) ) + { + AknIconUtils::CreateIconL( self->iBitmap, self->iMask, iconFile, iconIndex, maskIndex ); + AknIconUtils::PreserveIconData( self->iBitmap ); + } + + return self; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::CDrawItem* CMnrpMapModel::CDrawItem::NewLC( + const CPosLandmark& aLm, + CPosLmCategoryManager& aCatman ) + { + CDrawItem* self = NewLC( aLm ); + + if ( !self->iBitmap ) + { + // try icon from category + RArray cats; + CleanupClosePushL( cats ); + aLm.GetCategoriesL( cats ); + + if ( cats.Count() == 1 ) + { + CPosLandmarkCategory* cat = aCatman.ReadCategoryLC( cats[0] ); + + TPtrC iconFile; + TInt iconIndex, maskIndex; + if ( KErrNone == cat->GetIcon( iconFile, iconIndex, maskIndex ) ) + { + AknIconUtils::CreateIconL( self->iBitmap, self->iMask, iconFile, iconIndex, maskIndex ); + AknIconUtils::PreserveIconData( self->iBitmap ); + } + + CleanupStack::PopAndDestroy( cat ); + } + CleanupStack::PopAndDestroy( &cats ); + } + + return self; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::CDrawItem::SetAbsolutePosition( const TLocality& aLocality ) + { + iAbsolutePosition = TRealPoint( aLocality.Longitude(), aLocality.Latitude() ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::CDrawItem::~CDrawItem() + { + if ( iBitmap ) + { + AknIconUtils::DestroyIconData( iBitmap ); + } + delete iBitmap; + delete iMask; + delete iText; + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::CMnrpMapModel( + MMapModelObserver& aObserver, + CMnrpEngine& aEngine ) + : + iObserver( &aObserver ), iEngine( aEngine ) + { + iScale = 1; + iViewOrigin.Set( 0, 0 ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::CMnrpMapModel( CMnrpEngine& aEngine ) + : iEngine( aEngine ) + { + iScale = 1; + iViewOrigin.Set( 0, 0 ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::~CMnrpMapModel() + { + delete iPositionRequest; + iDrawItems.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C CMnrpMapModel* CMnrpMapModel::NewL( + MMapModelObserver& aObserver, + CMnrpEngine& aEngine ) + { + CMnrpMapModel* self = new (ELeave) CMnrpMapModel( aObserver, aEngine ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C CMnrpMapModel* CMnrpMapModel::NewL( CMnrpEngine& aEngine ) + { + CMnrpMapModel* self = new (ELeave) CMnrpMapModel( aEngine ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::ConstructL() + { + _LIT( KRequestorName, "MnRefProvider" ); + iPositionRequest = CMnrpPositionRequest::NewL( KRequestorName, *this ); + + TPositionUpdateOptions options; + options.SetUpdateInterval( TTimeIntervalMicroSeconds( KUpdateInterval ) ); + options.SetUpdateTimeOut( TTimeIntervalMicroSeconds( KUpdateTimeout ) ); + iPositionRequest->SetOptionsL( options ); + + AddCitiesL(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TBool CMnrpMapModel::CheckDrawItemHasPositionL( CDrawItem& aItem, const CPosLandmark& aLandmark ) + { + if ( !aItem.AbsolutePosition().IsValid() ) + { + // try to find coordinate by address + CPosLandmark* poi = iEngine.AddressToCoordL( aLandmark ); + if ( poi ) + { + TLocality pos; + poi->GetPosition( pos ); + aItem.SetAbsolutePosition( pos ); + } + delete poi; + } + + return aItem.AbsolutePosition().IsValid(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::UpdateModelL( CMnrpMapViewService& aService ) + { + ASSERT( iObserver ); + + iDrawItems.ResetAndDestroy(); + + iShowCurrentLocation = + aService.CurrentLocationOption() != CMnMapView::ECurrentLocationDisabled; + + if ( iShowCurrentLocation ) + { + iPositionRequest->FetchNewPosition(); + } + + // Add client-defined marks + + iNumIgnoredLandmarks = 0; + TRealPoint min, max; + + // add non-linked landmarks + for ( TInt i = 0; i < aService.LandmarksToShow().Count(); i++) + { + const CPosLandmark* lm = aService.LandmarksToShow()[i]; + + CDrawItem* item = CDrawItem::NewLC( *lm ); + if ( CheckDrawItemHasPositionL( *item, *lm ) ) + { + iDrawItems.AppendL( item ); + CleanupStack::Pop( item ); + AdjustBoundingBox( *item, min, max ); + } + else + { + CleanupStack::PopAndDestroy( item ); + iNumIgnoredLandmarks++; + } + } + + // add linked landmarks + for ( TInt db = 0; db < aService.LandmarksToShowDatabases().Count(); db++ ) + { + const HBufC* uri = aService.LandmarksToShowDatabases()[db]; + + LOG1("MnRefProvider::LinkedLandmarks: database (%S)", uri ); + + CPosLandmarkDatabase* lmdb = CPosLandmarkDatabase::OpenL( *uri ); + CleanupStack::PushL( lmdb ); + + if ( lmdb->IsInitializingNeeded() ) + { + ExecuteAndDeleteLD( lmdb->InitializeL() ); + } + + CPosLmCategoryManager* catman = CPosLmCategoryManager::NewL( *lmdb ); + CleanupStack::PushL( catman ); + + for ( TInt i = 0; i < aService.LinkedLandmarksToShow(db).Count(); i++) + { + TPosLmItemId id = aService.LinkedLandmarksToShow(db)[i]; + LOG1("MnRefProvider::LinkedLandmarks: id (%d)", id ); + + CPosLandmark* lm = lmdb->ReadLandmarkLC( id ); + + CDrawItem* item = CDrawItem::NewLC( *lm, *catman ); + if ( CheckDrawItemHasPositionL( *item, *lm ) ) + { + iDrawItems.AppendL( item ); + CleanupStack::Pop( item ); + AdjustBoundingBox( *item, min, max ); + } + else + { + CleanupStack::PopAndDestroy( item ); + iNumIgnoredLandmarks++; + } + + CleanupStack::PopAndDestroy( lm ); + } + + CleanupStack::PopAndDestroy( catman ); + CleanupStack::PopAndDestroy( lmdb ); + } + + // Add predefined places + AddCitiesL(); + + LOG4("MnRefProvider::BoundingBox: %f, %f, %f, %f", min.iX, min.iY, max.iX, max.iY ); + + // set origin + iUseCurrentLocationAsOrigin = EFalse; + if ( aService.IsAreaCentralPointSet() ) + { + TCoordinate center; + aService.GetAreaCentralPoint( center ); + iViewOrigin.Set( center.Longitude(), center.Latitude() ); + } + else if ( !Math::IsNaN( max.iX ) ) // others are also valid then + { + iViewOrigin.Set( ( max.iX + min.iX ) / 2, ( max.iY + min.iY ) / 2 ); + } + else if ( iShowCurrentLocation ) + { + // get current location and use it as center point + // this implementation defers location acquiring + iUseCurrentLocationAsOrigin = ETrue; + // FetchCurrentLocation(); + iViewOrigin.Set( 0, 0 ); + } + else + { + iViewOrigin.Set( 0, 0 ); + } + + LOG2("MnRefProvider: viewOrigin (%f, %f)", iViewOrigin.iX, iViewOrigin.iY); + + // set scale + TReal desiredScale = 0; + TReal radius = 0; + + if ( !Math::IsNaN( aService.AreaRadius() ) ) + { + // Radius setting is easy in this implementation + // because map is rectangular just convert meters to degrees + radius = Abs( aService.AreaRadius() ) / KEarthEquator * 360; + LOG1("MnRefProvider: user radius (%f)", radius ); + } + else if ( !Math::IsNaN( max.iX ) ) // others are also valid then + { + // get radius from bounding box + radius = Max( Abs( max.iX - min.iX ), Abs( max.iY - min.iY ) ); + LOG2("MnRefProvider: bounding radius (%f), with border (%f)", radius, radius * KRadiusBorderFactor ); + radius *= KRadiusBorderFactor; + } + else + { + // default radius + } + + if ( radius <= 0 ) + { + radius = KDefaultRadius; + LOG1("MnRefProvider: default radius (%f)", radius ); + } + + desiredScale = radius / TReal( Max( iScreenSize.iWidth, iScreenSize.iHeight ) ); + + LOG3("MnRefProvider: desired scale (%f), min (%f), max(%f)", + desiredScale, KMinScale, MaxScale() ); + + iScale = Max( Min( desiredScale, MaxScale() ), KMinScale ); + CheckBorders(); + + LOG1("MnRefProvider: scale (%f)", iScale ); + + iObserver->HandleModelUpdateL(); + } + + +#ifdef RD_MAPNAV_BITMAP_ACCESS +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::UpdateModelL( const CMnrpMapImageService& aService ) + { + iDrawItems.ResetAndDestroy(); + + iShowCurrentLocation = + aService.ShowOptions() & CMnMapImage::EShowOptionCurrentLocation; + + if ( iShowCurrentLocation ) + { + iPositionRequest->FetchNewPosition(); + } + + if ( aService.ShowOptions() & CMnMapImage::EShowOptionLandmarks) + { + + // Add user-defined marks + TRealPoint min, max; + + // add default landmarks + CPosLandmarkDatabase* lmdb = CPosLandmarkDatabase::OpenL(); + CleanupStack::PushL( lmdb ); + + if ( lmdb->IsInitializingNeeded() ) + { + ExecuteAndDeleteLD( lmdb->InitializeL() ); + } + + CPosLmCategoryManager* catman = CPosLmCategoryManager::NewL( *lmdb ); + CleanupStack::PushL( catman ); + + CPosLmItemIterator* iter = lmdb->LandmarkIteratorL(); + CleanupStack::PushL( iter ); + + TInt count = iter->NumOfItemsL(); + for ( TInt i = 0; i < count; i++) + { + TPosLmItemId id = iter->NextL(); + + CPosLandmark* lm = lmdb->ReadLandmarkLC( id ); + + CDrawItem* item = CDrawItem::NewLC( *lm, *catman ); + if ( CheckDrawItemHasPositionL( *item, *lm ) ) + { + iDrawItems.AppendL( item ); + CleanupStack::Pop( item ); + AdjustBoundingBox( *item, min, max ); + } + else + { + CleanupStack::PopAndDestroy( item ); + } + + CleanupStack::PopAndDestroy( lm ); + } + CleanupStack::PopAndDestroy( iter ); + CleanupStack::PopAndDestroy( catman ); + CleanupStack::PopAndDestroy( lmdb ); + + LOG4("MnRefProvider::BoundingBox: %f, %f, %f, %f", min.iX, min.iY, max.iX, max.iY ); + } + + if ( aService.ShowOptions() & CMnMapImage::EShowOptionPois ) + { + // Add predefined places + AddCitiesL(); + } + + TMnMapImageParams params = aService.MapImageParams(); + + UpdateModel( params ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::UpdateModel( const TMnMapImageParams& aParams ) + { + SetScreenSize( aParams.Size() ); + + TCoordinate center; + aParams.GetCenterPoint( center ); + iViewOrigin.Set( center.Longitude(), center.Latitude() ); + + LOG2("MnRefProvider: viewOrigin (%f, %f)", iViewOrigin.iX, iViewOrigin.iY); + + // set scale + TReal desiredScale = 0; + TReal32 width, height; + aParams.GetVisibleArea( width, height ); + TReal radius = Max( width, height ); + + if ( radius <= 0 ) + { + radius = KDefaultRadius; + LOG1("MnRefProvider: default radius (%f)", radius ); + } + + desiredScale = radius / TReal( Max( iScreenSize.iWidth, iScreenSize.iHeight ) ); + + LOG3("MnRefProvider: desired scale (%f), min (%f), max(%f)", + desiredScale, KMinScale, MaxScale() ); + + iScale = Max( Min( desiredScale, MaxScale() ), KMinScale ); + CheckBorders(); + + LOG1("MnRefProvider: scale (%f)", iScale ); + } +#endif + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::AddCitiesL() + { + TArray places = iEngine.KnownPlacesL(); + for ( TInt i = 0; i < places.Count(); i++) + { + CPosLandmark* lm = places[i]; + CDrawItem* item = CDrawItem::NewLC( *lm ); + item->iOwnPoi = ETrue; + iDrawItems.AppendL( item ); + CleanupStack::Pop( item ); + } + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::GetGrid( CMnrpMapModel::TGrid& aGrid ) const + { + TReal angle = Min( Width(), Height() ); + + TReal minAngle = Min( iScreenSize.iWidth, iScreenSize.iHeight ) * KMinScale; + + if ( angle > minAngle ) + { + // 1. Find nice grid scale + + TInt dividerIndex = 0; + TReal cellSize = KMaxCell; + + while ( cellSize * KBigCellsInView > angle ) + { + cellSize /= KCellDividers[dividerIndex]; + + if ( ++dividerIndex == KNumCellDividers ) + { + dividerIndex = 0; + } + } + + aGrid.iAbsoluteGridStep = cellSize; + + // 2. Find closest grid point + + TReal x = TInt( iViewOrigin.iX / cellSize ) * cellSize; + TReal y = TInt( iViewOrigin.iY / cellSize ) * cellSize; + + aGrid.iAbsoluteReference = TRealPoint( x, y ).Coordinate(); + } + else + { + aGrid.iAbsoluteReference = TCoordinate( 0, 0 ); + aGrid.iAbsoluteGridStep = minAngle / KBigCellsInView; + } + + // convert to screen coordinates + aGrid.iReference = AbsoluteToScreen( aGrid.iAbsoluteReference ); + aGrid.iGridStep = AbsoluteToScreen( aGrid.iAbsoluteGridStep ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::Zoom( TReal aZoomRate ) + { + iScale *= aZoomRate; + CheckBorders(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::GoCenter() + { + iViewOrigin.Set( 0, 0 ); + CheckBorders(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::MoveTo( TCoordinate aTarget ) + { + iViewOrigin = aTarget; + CheckBorders(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::CheckBorders() + { + if ( Height() > KMapHeight || Width() > KMapWidth ) + { + iScale = MaxScale(); + } + if ( iScale < KMinScale ) + { + iScale = KMinScale; + } + if ( Left() < KMinX ) + { + iViewOrigin.iX = KMinX + Width() / 2; + } + if ( Right() > KMaxX ) + { + iViewOrigin.iX = KMaxX - Width() / 2; + } + if ( Top() > KMaxY ) + { + iViewOrigin.iY = KMaxY - Height() / 2; + } + if ( Bottom() < KMinY ) + { + iViewOrigin.iY = KMinY + Height() / 2; + } + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Left() const + { + return iViewOrigin.iX - Width() / 2; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Right() const + { + return iViewOrigin.iX + Width() / 2; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Top() const + { + return iViewOrigin.iY + Height() / 2; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Bottom() const + { + return iViewOrigin.iY - Height() / 2; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Width() const + { + return TReal( iScreenSize.iWidth ) * iScale; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::Height() const + { + return TReal( iScreenSize.iHeight ) * iScale; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TCoordinate CMnrpMapModel::Center() const + { + return TCoordinate( iViewOrigin.iY, iViewOrigin.iX ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TArray CMnrpMapModel::Items() const + { + // adjust all items to screen coordinates + for ( TInt i = 0; i < iDrawItems.Count(); i++ ) + { + iDrawItems[i]->iScreenPosition = AbsoluteToScreen( iDrawItems[i]->iAbsolutePosition ); + } + return iDrawItems.Array(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +CMnrpMapModel::TCurrentLocation CMnrpMapModel::CurrentLocation() const + { + TCurrentLocation current; + + TPosition pos; + iPosInfo.GetPosition( pos ); + + current.iAbsoluteLocation = pos; + + if ( !Math::IsNaN( pos.Latitude() ) && !Math::IsNaN( pos.Longitude() ) ) + { + current.iLocation = AbsoluteToScreen( current.iAbsoluteLocation ); + + // calculate error radius in degrees and pixels + if ( !Math::IsNaN( pos.HorizontalAccuracy() ) ) + { + current.iAbsoluteErrorDegrees = ( pos.HorizontalAccuracy() / KEarthEquator ) * 360; + current.iErrorRadius = current.iAbsoluteErrorDegrees / iScale; + } + else + { + current.iErrorRadius = 0; + current.iAbsoluteErrorDegrees = 0; + } + + current.iIsValid = ETrue; + } + else + { + current.iIsValid = EFalse; + } + + return current; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::SetScreenSize( TSize aScreenSize ) + { + __ASSERT_DEBUG( aScreenSize.iWidth >= 1 && aScreenSize.iHeight >= 1, + Panic( KErrGeneral ) ); + iScreenSize = aScreenSize; + CheckBorders(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TReal CMnrpMapModel::MaxScale() const + { + TReal scaleByWidth = KMapWidth / TReal( iScreenSize.iWidth ); + TReal scaleByHeight = KMapHeight / TReal( iScreenSize.iHeight ); + return Min( scaleByWidth, scaleByHeight ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TPoint CMnrpMapModel::AbsoluteToScreen( TRealPoint aAbsolutePoint ) const + { + TRealPoint realScreen = ( aAbsolutePoint - TRealPoint( Left(), Bottom() ) ) / iScale; + return TPoint( realScreen.iX, iScreenSize.iHeight - realScreen.iY ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TPoint CMnrpMapModel::AbsoluteToScreen( TCoordinate aAbsolutePoint ) const + { + TRealPoint real( aAbsolutePoint.Longitude(), aAbsolutePoint.Latitude() ); + return AbsoluteToScreen( real ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +TInt CMnrpMapModel::AbsoluteToScreen( TReal aDistance ) const + { + return aDistance / iScale; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TCoordinate CMnrpMapModel::ScreenToAbsolute( TPoint aScreenPoint ) const + { + TReal xdiff = aScreenPoint.iX * iScale; + TReal ydiff = aScreenPoint.iY * iScale; + return TCoordinate( Top() - ydiff, Left() + xdiff ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TReal CMnrpMapModel::ScreenToAbsolute( TInt aDistance ) const + { + return aDistance * iScale; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::AdjustBoundingBox( + CMnrpMapModel::CDrawItem& aItem, + TRealPoint& aMin, + TRealPoint& aMax ) + { + // X + if ( !Math::IsNaN( aItem.iAbsolutePosition.iX ) ) + { + if ( Math::IsNaN( aMin.iX ) || aItem.iAbsolutePosition.iX < aMin.iX ) + { + aMin.iX = aItem.iAbsolutePosition.iX; + } + if ( Math::IsNaN( aMax.iX ) || aItem.iAbsolutePosition.iX > aMax.iX ) + { + aMax.iX = aItem.iAbsolutePosition.iX; + } + } + + // Y + if ( !Math::IsNaN( aItem.iAbsolutePosition.iY ) ) + { + if ( Math::IsNaN( aMin.iY ) || aItem.iAbsolutePosition.iY < aMin.iY ) + { + aMin.iY = aItem.iAbsolutePosition.iY; + } + if ( Math::IsNaN( aMax.iY ) || aItem.iAbsolutePosition.iY > aMax.iY ) + { + aMax.iY = aItem.iAbsolutePosition.iY; + } + } + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::HandlePositionRequestCompletedL( TInt aError ) + { + if ( !aError ) + { + iPositionRequest->GetPosition( iPosInfo ); + if ( iObserver ) + { + iObserver->HandleModelUpdateL(); + } + } + if ( iShowCurrentLocation ) + { + iPositionRequest->FetchNewPosition(); + } + } + +// ===================================================== +// DRAWING METHODS +// ===================================================== + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMnrpMapModel::RenderL( + CFbsBitmap& aBitmap, + TRect aTargetRect, + CFont* aTextFont, + CFont* aItemFont ) const + { + // create an off-screen device and context + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( &aBitmap ); + CleanupStack::PushL( bitmapDevice ); + + CFbsBitGc* gc = NULL; + User::LeaveIfError( bitmapDevice->CreateContext( gc ) ); + CleanupStack::PushL( gc ); + + gc->UseFont( aTextFont ); + + // get data + TGrid grid; + GetGrid( grid ); + + TBool isBackground = EFalse; + // background + if ( !isBackground ) + { + // no map background, clear map area + gc->Clear( aTargetRect ); + } + + gc->SetClippingRect( aTargetRect ); + gc->SetOrigin( aTargetRect.iTl ); + + DrawGrid( *gc, aTargetRect.Size(), grid ); + + gc->DiscardFont(); // text font + gc->UseFont( aItemFont ); + + // draw items + DrawLandmarks( *gc, *aItemFont, aTargetRect.Size(), isBackground ); // invert shadow and text color + DrawCurrentLocation( *gc, aTargetRect.Size() ); + + // cleanup + + gc->DiscardFont(); // item font + + CleanupStack::PopAndDestroy( gc ); + CleanupStack::PopAndDestroy( bitmapDevice ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CMnrpMapModel::NumIgnoredLandmarks() + { + return iNumIgnoredLandmarks; + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::DrawGrid( + CFbsBitGc& aGc, + const TSize& aBoxSize, + CMnrpMapModel::TGrid& aGrid ) const + { + const TRgb KGridLineColor( 128, 128, 128 ); + + aGc.SetPenSize( TSize( KGridPenSize, KGridPenSize ) ); + aGc.SetPenColor( KGridLineColor ); + + if ( aGrid.iGridStep > 0 ) + { + // 1. Vertical lines + TInt x = aGrid.iReference.iX; + // find leftmost vertical line + while ( x > 0 ) + { + x -= aGrid.iGridStep; + } + x += aGrid.iGridStep; + // draw lines selecting different line colors for major and minor lines + while ( x < aBoxSize.iWidth ) + { + DrawVerticalLine( aGc, x, aBoxSize ); + x += aGrid.iGridStep; + } + + // 2. Horizontal lines + TInt y = aGrid.iReference.iY; + // find topmost vertical line + while ( y > 0 ) + { + y -= aGrid.iGridStep; + } + y += aGrid.iGridStep; + // draw lines selecting different line colors for major and minor lines + while ( y < aBoxSize.iHeight ) + { + DrawHorizontalLine( aGc, y, aBoxSize ); + y += aGrid.iGridStep; + } + } + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::DrawVerticalLine( CFbsBitGc& aGc, TInt aX, TSize aBoxSize ) const + { + aGc.DrawLine( TPoint( aX, 0 ), TPoint( aX, aBoxSize.iHeight ) ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::DrawHorizontalLine( CFbsBitGc& aGc, TInt aY, TSize aBoxSize ) const + { + aGc.DrawLine( TPoint( 0, aY ), TPoint( aBoxSize.iWidth, aY ) ); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::DrawLandmarks( + CFbsBitGc& aGc, + CFont& aFont, + const TSize& aBoxSize, + TBool aSwitchColorAndShadow ) const + { + const TSize KItemMarkSize( 3, 3 ); // pixels + const TSize KItemIconSize( 20, 20 ); // pixels + + const TRgb KPoiColor( 0, 0, 192 ); + const TRgb KPoiTextColor( 0, 0, 0 ); + const TRgb KPoiTextShadowColor( 224, 224, 224 ); + const TRgb KLmColor( 255, 0, 0 ); + const TRgb KLmTextColor( 255, 0, 0 ); + const TRgb KLmTextShadowColor( 224, 224, 224 ); + + TArray items = Items(); + + RArray textBoxes; + + for ( TInt i = 0; i < items.Count(); i++ ) + { + const TPoint& pos = items[i]->Position(); + if ( pos.iX >= 0 && pos.iX < aBoxSize.iWidth && + pos.iY >= 0 && pos.iY < aBoxSize.iHeight ) + { + CFbsBitmap* icon = items[i]->Bitmap(); + CFbsBitmap* mask = items[i]->Mask(); + + if ( icon && mask ) + { + AknIconUtils::SetSize( icon, KItemIconSize ); + + TRect iconBox( pos, KItemIconSize ); + iconBox.Move( -iconBox.Width() / 2, -iconBox.Height() / 2 ); + + aGc.DrawBitmapMasked( + iconBox, + icon, + KItemIconSize, + mask, + EFalse ); + } + else + { + if ( items[i]->IsPoi() ) + { + aGc.SetPenColor( KPoiColor ); + } + else + { + aGc.SetPenColor( KLmColor ); + } + + TRect markBox( pos, KItemMarkSize ); + markBox.Move( -markBox.Width() / 2, -markBox.Height() / 2 ); + aGc.SetPenSize( KItemMarkSize ); + aGc.Plot( pos ); + } + + if ( items[i]->Text().Length() ) + { + TPoint textPos( pos ); + textPos.iX += KLmTextOffset; + + TSize textSize( aFont.TextWidthInPixels( items[i]->Text() ), aFont.HeightInPixels() ); + TRect textBox( textPos, textSize ); + + // verify this textbox does not intersect any previous ones + TBool overlaps = EFalse; + for ( TInt b = 0; b < textBoxes.Count(); b++ ) + { + if ( textBox.Intersects( textBoxes[b] ) ) + { + overlaps = ETrue; + break; + } + } + + if ( !overlaps ) + { + textBoxes.Append( textBox ); + + aGc.SetPenSize( TSize( 1, 1 ) ); + + TRgb textColor, textShadowColor; + + if ( items[i]->IsPoi() ) + { + textColor = KPoiTextColor; + textShadowColor = KPoiTextShadowColor; + } + else + { + textColor = KLmTextColor; + textShadowColor = KLmTextShadowColor; + } + + // text shadow + TPoint shadowPos( textPos + TPoint( KLmTextShadowOffset, KLmTextShadowOffset ) ); + aGc.SetPenColor( aSwitchColorAndShadow ? textColor : textShadowColor ); + aGc.DrawText( items[i]->Text(), shadowPos ); + + // text itself + aGc.SetPenColor( aSwitchColorAndShadow ? textShadowColor : textColor ); + aGc.DrawText( items[i]->Text(), textPos ); + } + } + } + } + textBoxes.Close(); + } + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// +void CMnrpMapModel::DrawCurrentLocation( + CFbsBitGc& aGc, + const TSize& aBoxSize ) const + { + const TSize KPositionPenSize( 20, 20 ); + const TSize KPositionErrorPenSize( 1, 1 ); + const TRgb KPositionColor( 255, 255, 0 ); + + // draw current location + CMnrpMapModel::TCurrentLocation location = CurrentLocation(); + + if ( location.iIsValid ) + { + TPoint& pos = location.iLocation; + + if ( pos.iX >= 0 && pos.iX < aBoxSize.iWidth && + pos.iY >= 0 && pos.iY < aBoxSize.iHeight ) + { + if ( location.iErrorRadius ) + { + TRect circleBox( pos.iX, pos.iY, pos.iX, pos.iY ); + circleBox.Grow( location.iErrorRadius, location.iErrorRadius ); + + aGc.SetPenSize( KPositionErrorPenSize ); + aGc.SetBrushStyle( CGraphicsContext::EVerticalHatchBrush ); + aGc.SetBrushColor( KPositionColor ); + aGc.DrawEllipse( circleBox ); + } + + aGc.SetPenColor( KPositionColor ); + aGc.SetPenSize( KPositionPenSize ); + aGc.Plot( pos ); + } + } + } +