648 lines
20 KiB
C++
648 lines
20 KiB
C++
|
|
/**
|
||
|
|
******************************************************************************
|
||
|
|
*
|
||
|
|
* @file core.cpp
|
||
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||
|
|
* @brief
|
||
|
|
* @see The GNU Public License (GPL) Version 3
|
||
|
|
* @defgroup OPMapWidget
|
||
|
|
* @{
|
||
|
|
*
|
||
|
|
*****************************************************************************/
|
||
|
|
/*
|
||
|
|
* 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, write to the Free Software Foundation, Inc.,
|
||
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
*/
|
||
|
|
#include "core.h"
|
||
|
|
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qlonglong internals::Core::debugcounter = 0;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
using namespace projections;
|
||
|
|
|
||
|
|
namespace internals {
|
||
|
|
Core::Core() : MouseWheelZooming(false), currentPosition(0, 0), currentPositionPixel(0, 0), LastLocationInBounds(-1, -1), sizeOfMapArea(0, 0)
|
||
|
|
, minOfTiles(0, 0), maxOfTiles(0, 0), zoom(0), isDragging(false), TooltipTextPadding(10, 10), loaderLimit(5), maxzoom(21), runningThreads(0), started(false)
|
||
|
|
{
|
||
|
|
mousewheelzoomtype = MouseWheelZoomType::MousePositionAndCenter;
|
||
|
|
SetProjection(new MercatorProjection());
|
||
|
|
this->setAutoDelete(false);
|
||
|
|
ProcessLoadTaskCallback.setMaxThreadCount(10);
|
||
|
|
renderOffset = Point(0, 0);
|
||
|
|
dragPoint = Point(0, 0);
|
||
|
|
CanDragMap = true;
|
||
|
|
tilesToload = 0;
|
||
|
|
OPMaps::Instance();
|
||
|
|
}
|
||
|
|
Core::~Core()
|
||
|
|
{
|
||
|
|
ProcessLoadTaskCallback.waitForDone();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Core::run()
|
||
|
|
{
|
||
|
|
MrunningThreads.lock();
|
||
|
|
++runningThreads;
|
||
|
|
MrunningThreads.unlock();
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qlonglong debug;
|
||
|
|
Mdebug.lock();
|
||
|
|
debug = ++debugcounter;
|
||
|
|
Mdebug.unlock();
|
||
|
|
qDebug() << "core:run" << " ID=" << debug;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
bool last = false;
|
||
|
|
|
||
|
|
LoadTask task;
|
||
|
|
|
||
|
|
MtileLoadQueue.lock();
|
||
|
|
{
|
||
|
|
if (tileLoadQueue.count() > 0) {
|
||
|
|
task = tileLoadQueue.dequeue();
|
||
|
|
{
|
||
|
|
last = (tileLoadQueue.count() == 0);
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "TileLoadQueue: " << tileLoadQueue.count() << " Point:" << task.Pos.ToString() << " ID=" << debug;;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MtileLoadQueue.unlock();
|
||
|
|
|
||
|
|
if (task.HasValue()) {
|
||
|
|
if (loaderLimit.tryAcquire(1, OPMaps::Instance()->Timeout)) {
|
||
|
|
MtileToload.lock();
|
||
|
|
--tilesToload;
|
||
|
|
MtileToload.unlock();
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "loadLimit semaphore aquired " << loaderLimit.available() << " ID=" << debug << " TASK=" << task.Pos.ToString() << " " << task.Zoom;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
|
||
|
|
{
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "task as value, begining get" << " ID=" << debug;;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
{
|
||
|
|
Tile *m = Matrix.TileAt(task.Pos);
|
||
|
|
|
||
|
|
if (m == 0 || m->Overlays.count() == 0) {
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "Fill empty TileMatrix: " + task.ToString() << " ID=" << debug;;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
|
||
|
|
Tile *t = new Tile(task.Zoom, task.Pos);
|
||
|
|
QVector<MapType::Types> layers = OPMaps::Instance()->GetAllLayersOfType(GetMapType());
|
||
|
|
|
||
|
|
foreach(MapType::Types tl, layers) {
|
||
|
|
int retry = 0;
|
||
|
|
|
||
|
|
do {
|
||
|
|
QByteArray img;
|
||
|
|
|
||
|
|
// tile number inversion(BottomLeft -> TopLeft) for pergo maps
|
||
|
|
if (tl == MapType::PergoTurkeyMap) {
|
||
|
|
img = OPMaps::Instance()->GetImageFrom(tl, Point(task.Pos.X(), maxOfTiles.Height() - task.Pos.Y()), task.Zoom);
|
||
|
|
} else { // ok
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "start getting image" << " ID=" << debug;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
img = OPMaps::Instance()->GetImageFrom(tl, task.Pos, task.Zoom);
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "Core::run:gotimage size:" << img.count() << " ID=" << debug << " time=" << t.elapsed();
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
}
|
||
|
|
|
||
|
|
if (img.length() != 0) {
|
||
|
|
Moverlays.lock();
|
||
|
|
{
|
||
|
|
t->Overlays.append(img);
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "Core::run append img:" << img.length() << " to tile:" << t->GetPos().ToString() << " now has " << t->Overlays.count() << " overlays" << " ID=" << debug;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
}
|
||
|
|
Moverlays.unlock();
|
||
|
|
|
||
|
|
break;
|
||
|
|
} else if (OPMaps::Instance()->RetryLoadTile > 0) {
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "ProcessLoadTask: " << task.ToString() << " -> empty tile, retry " << retry << " ID=" << debug;;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
{
|
||
|
|
QWaitCondition wait;
|
||
|
|
QMutex m;
|
||
|
|
m.lock();
|
||
|
|
wait.wait(&m, 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} while (++retry < OPMaps::Instance()->RetryLoadTile);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (t->Overlays.count() > 0) {
|
||
|
|
Matrix.SetTileAt(task.Pos, t);
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "Core::run add tile " << t->GetPos().ToString() << " to matrix index " << task.Pos.ToString() << " ID=" << debug;
|
||
|
|
qDebug() << "Core::run matrix index " << task.Pos.ToString() << " as tile with " << Matrix.TileAt(task.Pos)->Overlays.count() << " ID=" << debug;
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
} else {
|
||
|
|
// emit OnTilesStillToLoad(tilesToload);
|
||
|
|
|
||
|
|
delete t;
|
||
|
|
t = 0;
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
}
|
||
|
|
|
||
|
|
// layers = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
{
|
||
|
|
// last buddy cleans stuff ;}
|
||
|
|
if (last) {
|
||
|
|
OPMaps::Instance()->kiberCacheLock.lockForWrite();
|
||
|
|
OPMaps::Instance()->TilesInMemory.RemoveMemoryOverload();
|
||
|
|
OPMaps::Instance()->kiberCacheLock.unlock();
|
||
|
|
|
||
|
|
MtileDrawingList.lock();
|
||
|
|
{
|
||
|
|
Matrix.ClearPointsNotIn(tileDrawingList);
|
||
|
|
}
|
||
|
|
MtileDrawingList.unlock();
|
||
|
|
|
||
|
|
|
||
|
|
emit OnTileLoadComplete();
|
||
|
|
|
||
|
|
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "loaderLimit release:" + loaderLimit.available() << " ID=" << debug;
|
||
|
|
#endif
|
||
|
|
emit OnTilesStillToLoad(tilesToload < 0 ? 0 : tilesToload);
|
||
|
|
loaderLimit.release();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MrunningThreads.lock();
|
||
|
|
--runningThreads;
|
||
|
|
MrunningThreads.unlock();
|
||
|
|
}
|
||
|
|
diagnostics Core::GetDiagnostics()
|
||
|
|
{
|
||
|
|
MrunningThreads.lock();
|
||
|
|
diag = OPMaps::Instance()->GetDiagnostics();
|
||
|
|
diag.runningThreads = runningThreads;
|
||
|
|
MrunningThreads.unlock();
|
||
|
|
return diag;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Core::SetZoom(const int &value)
|
||
|
|
{
|
||
|
|
if (!isDragging) {
|
||
|
|
zoom = value;
|
||
|
|
minOfTiles = Projection()->GetTileMatrixMinXY(value);
|
||
|
|
maxOfTiles = Projection()->GetTileMatrixMaxXY(value);
|
||
|
|
currentPositionPixel = Projection()->FromLatLngToPixel(currentPosition, value);
|
||
|
|
if (started) {
|
||
|
|
MtileLoadQueue.lock();
|
||
|
|
tileLoadQueue.clear();
|
||
|
|
MtileLoadQueue.unlock();
|
||
|
|
MtileToload.lock();
|
||
|
|
tilesToload = 0;
|
||
|
|
MtileToload.unlock();
|
||
|
|
Matrix.Clear();
|
||
|
|
GoToCurrentPositionOnZoom();
|
||
|
|
UpdateBounds();
|
||
|
|
keepInBounds();
|
||
|
|
emit OnMapDrag();
|
||
|
|
emit OnMapZoomChanged();
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Core::SetCurrentPosition(const PointLatLng &value)
|
||
|
|
{
|
||
|
|
if (!IsDragging()) {
|
||
|
|
currentPosition = value;
|
||
|
|
SetCurrentPositionGPixel(Projection()->FromLatLngToPixel(value, Zoom()));
|
||
|
|
|
||
|
|
if (started) {
|
||
|
|
GoToCurrentPosition();
|
||
|
|
emit OnCurrentPositionChanged(currentPosition);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
currentPosition = value;
|
||
|
|
SetCurrentPositionGPixel(Projection()->FromLatLngToPixel(value, Zoom()));
|
||
|
|
|
||
|
|
if (started) {
|
||
|
|
emit OnCurrentPositionChanged(currentPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::SetMapType(const MapType::Types &value)
|
||
|
|
{
|
||
|
|
if (value != GetMapType()) {
|
||
|
|
mapType = value;
|
||
|
|
|
||
|
|
switch (value) {
|
||
|
|
case MapType::ArcGIS_Map:
|
||
|
|
case MapType::ArcGIS_Satellite:
|
||
|
|
case MapType::ArcGIS_ShadedRelief:
|
||
|
|
case MapType::ArcGIS_Terrain:
|
||
|
|
{
|
||
|
|
if (Projection()->Type() != "PlateCarreeProjection") {
|
||
|
|
SetProjection(new PlateCarreeProjection());
|
||
|
|
maxzoom = 13;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MapType::ArcGIS_MapsLT_Map_Hybrid:
|
||
|
|
case MapType::ArcGIS_MapsLT_Map_Labels:
|
||
|
|
case MapType::ArcGIS_MapsLT_Map:
|
||
|
|
case MapType::ArcGIS_MapsLT_OrtoFoto:
|
||
|
|
{
|
||
|
|
if (Projection()->Type() != "LKS94Projection") {
|
||
|
|
SetProjection(new LKS94Projection());
|
||
|
|
maxzoom = 11;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MapType::PergoTurkeyMap:
|
||
|
|
{
|
||
|
|
if (Projection()->Type() != "PlateCarreeProjectionPergo") {
|
||
|
|
SetProjection(new PlateCarreeProjectionPergo());
|
||
|
|
maxzoom = 17;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MapType::YandexMapRu:
|
||
|
|
{
|
||
|
|
if (Projection()->Type() != "MercatorProjectionYandex") {
|
||
|
|
SetProjection(new MercatorProjectionYandex());
|
||
|
|
maxzoom = 13;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
if (Projection()->Type() != "MercatorProjection") {
|
||
|
|
SetProjection(new MercatorProjection());
|
||
|
|
maxzoom = 21;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
minOfTiles = Projection()->GetTileMatrixMinXY(Zoom());
|
||
|
|
maxOfTiles = Projection()->GetTileMatrixMaxXY(Zoom());
|
||
|
|
SetCurrentPositionGPixel(Projection()->FromLatLngToPixel(CurrentPosition(), Zoom()));
|
||
|
|
|
||
|
|
if (started) {
|
||
|
|
CancelAsyncTasks();
|
||
|
|
OnMapSizeChanged(Width, Height);
|
||
|
|
GoToCurrentPosition();
|
||
|
|
ReloadMap();
|
||
|
|
GoToCurrentPosition();
|
||
|
|
emit OnMapTypeChanged(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::StartSystem()
|
||
|
|
{
|
||
|
|
if (!started) {
|
||
|
|
started = true;
|
||
|
|
|
||
|
|
ReloadMap();
|
||
|
|
GoToCurrentPosition();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Core::UpdateCenterTileXYLocation()
|
||
|
|
{
|
||
|
|
PointLatLng center = FromLocalToLatLng(Width / 2, Height / 2);
|
||
|
|
Point centerPixel = Projection()->FromLatLngToPixel(center, Zoom());
|
||
|
|
|
||
|
|
centerTileXYLocation = Projection()->FromPixelToTileXY(centerPixel);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Core::OnMapSizeChanged(int const & width, int const & height)
|
||
|
|
{
|
||
|
|
Width = width;
|
||
|
|
Height = height;
|
||
|
|
|
||
|
|
sizeOfMapArea.SetWidth(1 + (Width / Projection()->TileSize().Width()) / 2);
|
||
|
|
sizeOfMapArea.SetHeight(1 + (Height / Projection()->TileSize().Height()) / 2);
|
||
|
|
|
||
|
|
UpdateCenterTileXYLocation();
|
||
|
|
|
||
|
|
if (started) {
|
||
|
|
UpdateBounds();
|
||
|
|
|
||
|
|
emit OnCurrentPositionChanged(currentPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::OnMapClose()
|
||
|
|
{
|
||
|
|
// if(waitOnEmptyTasks != null)
|
||
|
|
// {
|
||
|
|
// try
|
||
|
|
// {
|
||
|
|
// waitOnEmptyTasks.Set();
|
||
|
|
// waitOnEmptyTasks.Close();
|
||
|
|
// }
|
||
|
|
// catch
|
||
|
|
// {
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
|
||
|
|
CancelAsyncTasks();
|
||
|
|
}
|
||
|
|
GeoCoderStatusCode::Types Core::SetCurrentPositionByKeywords(QString const & keys)
|
||
|
|
{
|
||
|
|
GeoCoderStatusCode::Types status = GeoCoderStatusCode::Unknow;
|
||
|
|
PointLatLng pos = OPMaps::Instance()->GetLatLngFromGeodecoder(keys, status);
|
||
|
|
|
||
|
|
if (!pos.IsEmpty() && (status == GeoCoderStatusCode::G_GEO_SUCCESS)) {
|
||
|
|
SetCurrentPosition(pos);
|
||
|
|
}
|
||
|
|
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
RectLatLng Core::CurrentViewArea()
|
||
|
|
{
|
||
|
|
PointLatLng p = Projection()->FromPixelToLatLng(-renderOffset.X(), -renderOffset.Y(), Zoom());
|
||
|
|
double rlng = Projection()->FromPixelToLatLng(-renderOffset.X() + Width, -renderOffset.Y(), Zoom()).Lng();
|
||
|
|
double blat = Projection()->FromPixelToLatLng(-renderOffset.X(), -renderOffset.Y() + Height, Zoom()).Lat();
|
||
|
|
|
||
|
|
return RectLatLng::FromLTRB(p.Lng(), p.Lat(), rlng, blat);
|
||
|
|
}
|
||
|
|
PointLatLng Core::FromLocalToLatLng(int const & x, int const & y)
|
||
|
|
{
|
||
|
|
return Projection()->FromPixelToLatLng(Point(x - renderOffset.X(), y - renderOffset.Y()), Zoom());
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
Point Core::FromLatLngToLocal(PointLatLng const & latlng)
|
||
|
|
{
|
||
|
|
Point pLocal = Projection()->FromLatLngToPixel(latlng, Zoom());
|
||
|
|
|
||
|
|
pLocal.Offset(renderOffset);
|
||
|
|
return pLocal;
|
||
|
|
}
|
||
|
|
int Core::GetMaxZoomToFitRect(RectLatLng const & rect)
|
||
|
|
{
|
||
|
|
int zoom = 0;
|
||
|
|
|
||
|
|
for (int i = 1; i <= MaxZoom(); i++) {
|
||
|
|
Point p1 = Projection()->FromLatLngToPixel(rect.LocationTopLeft(), i);
|
||
|
|
Point p2 = Projection()->FromLatLngToPixel(rect.Bottom(), rect.Right(), i);
|
||
|
|
|
||
|
|
if (((p2.X() - p1.X()) <= Width + 10) && (p2.Y() - p1.Y()) <= Height + 10) {
|
||
|
|
zoom = i;
|
||
|
|
} else {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return zoom;
|
||
|
|
}
|
||
|
|
void Core::BeginDrag(Point const & pt)
|
||
|
|
{
|
||
|
|
dragPoint.SetX(pt.X() - renderOffset.X());
|
||
|
|
dragPoint.SetY(pt.Y() - renderOffset.Y());
|
||
|
|
isDragging = true;
|
||
|
|
}
|
||
|
|
void Core::EndDrag()
|
||
|
|
{
|
||
|
|
isDragging = false;
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
}
|
||
|
|
void Core::ReloadMap()
|
||
|
|
{
|
||
|
|
if (started) {
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "------------------";
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
|
||
|
|
MtileLoadQueue.lock();
|
||
|
|
{
|
||
|
|
tileLoadQueue.clear();
|
||
|
|
}
|
||
|
|
MtileLoadQueue.unlock();
|
||
|
|
MtileToload.lock();
|
||
|
|
tilesToload = 0;
|
||
|
|
MtileToload.unlock();
|
||
|
|
Matrix.Clear();
|
||
|
|
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::GoToCurrentPosition()
|
||
|
|
{
|
||
|
|
// reset stuff
|
||
|
|
renderOffset = Point::Empty;
|
||
|
|
centerTileXYLocationLast = Point::Empty;
|
||
|
|
dragPoint = Point::Empty;
|
||
|
|
|
||
|
|
// goto location
|
||
|
|
Drag(Point(-(GetcurrentPositionGPixel().X() - Width / 2), -(GetcurrentPositionGPixel().Y() - Height / 2)));
|
||
|
|
}
|
||
|
|
void Core::GoToCurrentPositionOnZoom()
|
||
|
|
{
|
||
|
|
// reset stuff
|
||
|
|
renderOffset = Point::Empty;
|
||
|
|
centerTileXYLocationLast = Point::Empty;
|
||
|
|
dragPoint = Point::Empty;
|
||
|
|
|
||
|
|
// goto location and centering
|
||
|
|
if (MouseWheelZooming) {
|
||
|
|
if (mousewheelzoomtype != MouseWheelZoomType::MousePositionWithoutCenter) {
|
||
|
|
Point pt = Point(-(GetcurrentPositionGPixel().X() - Width / 2), -(GetcurrentPositionGPixel().Y() - Height / 2));
|
||
|
|
renderOffset.SetX(pt.X() - dragPoint.X());
|
||
|
|
renderOffset.SetY(pt.Y() - dragPoint.Y());
|
||
|
|
} else { // without centering
|
||
|
|
renderOffset.SetX(-GetcurrentPositionGPixel().X() - dragPoint.X());
|
||
|
|
renderOffset.SetY(-GetcurrentPositionGPixel().Y() - dragPoint.Y());
|
||
|
|
renderOffset.Offset(mouseLastZoom);
|
||
|
|
}
|
||
|
|
} else { // use current map center
|
||
|
|
mouseLastZoom = Point::Empty;
|
||
|
|
|
||
|
|
Point pt = Point(-(GetcurrentPositionGPixel().X() - Width / 2), -(GetcurrentPositionGPixel().Y() - Height / 2));
|
||
|
|
renderOffset.SetX(pt.X() - dragPoint.X());
|
||
|
|
renderOffset.SetY(pt.Y() - dragPoint.Y());
|
||
|
|
}
|
||
|
|
|
||
|
|
UpdateCenterTileXYLocation();
|
||
|
|
}
|
||
|
|
void Core::DragOffset(Point const & offset)
|
||
|
|
{
|
||
|
|
renderOffset.Offset(offset);
|
||
|
|
|
||
|
|
UpdateCenterTileXYLocation();
|
||
|
|
|
||
|
|
if (centerTileXYLocation != centerTileXYLocationLast) {
|
||
|
|
centerTileXYLocationLast = centerTileXYLocation;
|
||
|
|
UpdateBounds();
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
LastLocationInBounds = CurrentPosition();
|
||
|
|
SetCurrentPosition(FromLocalToLatLng((int)Width / 2, (int)Height / 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
emit OnMapDrag();
|
||
|
|
}
|
||
|
|
void Core::Drag(Point const & pt)
|
||
|
|
{
|
||
|
|
renderOffset.SetX(pt.X() - dragPoint.X());
|
||
|
|
renderOffset.SetY(pt.Y() - dragPoint.Y());
|
||
|
|
keepInBounds();
|
||
|
|
UpdateCenterTileXYLocation();
|
||
|
|
|
||
|
|
if (centerTileXYLocation != centerTileXYLocationLast) {
|
||
|
|
centerTileXYLocationLast = centerTileXYLocation;
|
||
|
|
UpdateBounds();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsDragging()) {
|
||
|
|
LastLocationInBounds = CurrentPosition();
|
||
|
|
SetCurrentPosition(FromLocalToLatLng((int)Width / 2, (int)Height / 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
emit OnNeedInvalidation();
|
||
|
|
|
||
|
|
|
||
|
|
emit OnMapDrag();
|
||
|
|
}
|
||
|
|
void Core::CancelAsyncTasks()
|
||
|
|
{
|
||
|
|
if (started) {
|
||
|
|
ProcessLoadTaskCallback.waitForDone();
|
||
|
|
MtileLoadQueue.lock();
|
||
|
|
{
|
||
|
|
tileLoadQueue.clear();
|
||
|
|
// tilesToload=0;
|
||
|
|
}
|
||
|
|
MtileLoadQueue.unlock();
|
||
|
|
MtileToload.lock();
|
||
|
|
tilesToload = 0;
|
||
|
|
MtileToload.unlock();
|
||
|
|
// ProcessLoadTaskCallback.waitForDone();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::UpdateBounds()
|
||
|
|
{
|
||
|
|
MtileDrawingList.lock();
|
||
|
|
{
|
||
|
|
FindTilesAround(tileDrawingList);
|
||
|
|
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "OnTileLoadStart: " << tileDrawingList.count() << " tiles to load at zoom " << Zoom() << ", time: " << QDateTime::currentDateTime().date();
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
|
||
|
|
emit OnTileLoadStart();
|
||
|
|
|
||
|
|
|
||
|
|
foreach(Point p, tileDrawingList) {
|
||
|
|
LoadTask task = LoadTask(p, Zoom());
|
||
|
|
{
|
||
|
|
MtileLoadQueue.lock();
|
||
|
|
{
|
||
|
|
if (!tileLoadQueue.contains(task)) {
|
||
|
|
MtileToload.lock();
|
||
|
|
++tilesToload;
|
||
|
|
MtileToload.unlock();
|
||
|
|
tileLoadQueue.enqueue(task);
|
||
|
|
#ifdef DEBUG_CORE
|
||
|
|
qDebug() << "Core::UpdateBounds new Task" << task.Pos.ToString();
|
||
|
|
#endif // DEBUG_CORE
|
||
|
|
ProcessLoadTaskCallback.start(this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MtileLoadQueue.unlock();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
MtileDrawingList.unlock();
|
||
|
|
UpdateGroundResolution();
|
||
|
|
}
|
||
|
|
void Core::FindTilesAround(QList<Point> &list)
|
||
|
|
{
|
||
|
|
list.clear();;
|
||
|
|
for (int i = -sizeOfMapArea.Width(); i <= sizeOfMapArea.Width(); i++) {
|
||
|
|
for (int j = -sizeOfMapArea.Height(); j <= sizeOfMapArea.Height(); j++) {
|
||
|
|
Point p = centerTileXYLocation;
|
||
|
|
p.SetX(p.X() + i);
|
||
|
|
p.SetY(p.Y() + j);
|
||
|
|
|
||
|
|
// if(p.X < minOfTiles.Width)
|
||
|
|
// {
|
||
|
|
// p.X += (maxOfTiles.Width + 1);
|
||
|
|
// }
|
||
|
|
|
||
|
|
// if(p.X > maxOfTiles.Width)
|
||
|
|
// {
|
||
|
|
// p.X -= (maxOfTiles.Width + 1);
|
||
|
|
// }
|
||
|
|
|
||
|
|
if (p.X() >= minOfTiles.Width() && p.Y() >= minOfTiles.Height() && p.X() <= maxOfTiles.Width() && p.Y() <= maxOfTiles.Height()) {
|
||
|
|
if (!list.contains(p)) {
|
||
|
|
list.append(p);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void Core::UpdateGroundResolution()
|
||
|
|
{
|
||
|
|
double rez = Projection()->GetGroundResolution(Zoom(), CurrentPosition().Lat());
|
||
|
|
|
||
|
|
pxRes100m = (int)(100.0 / rez); // 100 meters
|
||
|
|
pxRes1000m = (int)(1000.0 / rez); // 1km
|
||
|
|
pxRes10km = (int)(10000.0 / rez); // 10km
|
||
|
|
pxRes100km = (int)(100000.0 / rez); // 100km
|
||
|
|
pxRes1000km = (int)(1000000.0 / rez); // 1000km
|
||
|
|
pxRes5000km = (int)(5000000.0 / rez); // 5000km
|
||
|
|
}
|
||
|
|
void Core::keepInBounds()
|
||
|
|
{
|
||
|
|
if (renderOffset.X() > 0) {
|
||
|
|
renderOffset.SetX(0);
|
||
|
|
}
|
||
|
|
if (renderOffset.Y() > 0) {
|
||
|
|
renderOffset.SetY(0);
|
||
|
|
}
|
||
|
|
int maxDragY = GetCurrentRegion().Height() - GettileRect().Height() * (maxOfTiles.Height() - minOfTiles.Height() + 1);
|
||
|
|
int maxDragX = GetCurrentRegion().Width() - GettileRect().Width() * (maxOfTiles.Width() - minOfTiles.Width() + 1);
|
||
|
|
|
||
|
|
if (maxDragY > renderOffset.Y()) {
|
||
|
|
renderOffset.SetY(maxDragY);
|
||
|
|
}
|
||
|
|
if (maxDragX > renderOffset.X()) {
|
||
|
|
renderOffset.SetX(maxDragX);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|