--- /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 <coemain.h>
+#include <barsread.h>
+#include <bautils.h>
+
+#include <aknlists.h>
+#include <AknIconUtils.h>
+#include <AknWaitDialog.h>
+
+#include <fbs.h>
+#include <imageconversion.h>
+#include <icl/imagedata.h>
+
+#include <lbs.h>
+#include <lbsposition.h>
+#include <lbspositioninfo.h>
+
+#include <EPos_CPosLandmark.h>
+#include <EPos_CPosLandmarkDatabase.h>
+#include <EPos_CPosLandmarkCategory.h>
+#include <EPos_CPosLmCategoryManager.h>
+
+#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<TPosLmItemId> 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<CPosLandmark*> 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::CDrawItem*> 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<CMnrpMapModel::CDrawItem*> items = Items();
+
+ RArray<TRect> 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 );
+ }
+ }
+ }
+