Map Viewer

Вопросы по нескольким пакетам сразу, или вопросы, которые непонятно к какой ГИС отнести
virtu
Интересующийся
Сообщения: 17
Зарегистрирован: 20 фев 2015, 07:48
Репутация: 0

Re: Map Viewer

Сообщение virtu » 06 май 2015, 15:27

SergeyRyzhkov писал(а):Небольшая, видимо, кашица у Вас пока в голове, но это не страшно, главное желание.

Лет 10 назад тоже изобретал - очень помогло проникнуться.

Я бы что Вам посоветовал сейчас, посмотреть на типовую архитектуру, например,
https://github.com/pauldendulk/Mapsui
Не важно что на шарпе, сам смысл уловите
(Geometry, Feature, Style, Layer, Map, ViewPort, MapControl)
Посмотрите кто кого "ловит" на событиях, как производится пересчет экранных координат в используемую карт. СК, а затем происходит "фетч" (обновление) данных и обратный "рендеринг" на полотне (MapControl)
Спасибо, вроде компильнулось без проблем, запустил "Mapsui.Samples.WinForms" "Mapsui.Samples.Wpf" - красота :) Шарп не мой язык, буду разбираться, у меня есть книжка Рихтера. Спасибо.

Аватара пользователя
SergeyRyzhkov
Гуру
Сообщения: 909
Зарегистрирован: 02 июл 2014, 19:13
Репутация: 203
Ваше звание: GP-экотеррористы
Откуда: Санкт-Петербург
Контактная информация:

Re: Map Viewer

Сообщение SergeyRyzhkov » 06 май 2015, 15:37

Повторюсь, язык не главное тут, есть решения и на QT и на жабе и т.д.
Вы просто архитектуру посмотрите (классика + MVC через временное хранилище)
Также гляньте на NetTopologySuite (порт с жабы) - много полезного...
BruTile - для доступа к "тайлам" (хотя уж слишком наворочено, трудно "входить")

virtu
Интересующийся
Сообщения: 17
Зарегистрирован: 20 фев 2015, 07:48
Репутация: 0

Re: Map Viewer

Сообщение virtu » 06 май 2015, 15:49

SergeyRyzhkov писал(а):Повторюсь, язык не главное тут, есть решения и на QT и на жабе и т.д.
Вы просто архитектуру посмотрите (классика + MVC через временное хранилище)
Также гляньте на NetTopologySuite (порт с жабы) - много полезного...
BruTile - для доступа к "тайлам" (хотя уж слишком наворочено, трудно "входить")
Да язык не главное, я уже понял.

Аватара пользователя
avk
Новоприбывший
Сообщения: 10
Зарегистрирован: 04 май 2015, 02:30
Репутация: 3
Откуда: Санкт-Петербург

Re: Map Viewer

Сообщение avk » 06 май 2015, 19:13

Александр Мурый писал(а):
avk писал(а):Так, видимо, и с proj.4: сильное распространение, наша природная лень, сложность вопроса - и ву-аля, альтернатив нет.
Альтернативы есть.
Ага, благодарю.
Эта библиотека "прикручена" к Proj.4 начиная с прошлого релиза (4.9.0) и я как-то её стороной обошёл. Досадно. Пойду посмотрю под увеличительным стеклом.

Аватара пользователя
SergeyRyzhkov
Гуру
Сообщения: 909
Зарегистрирован: 02 июл 2014, 19:13
Репутация: 203
Ваше звание: GP-экотеррористы
Откуда: Санкт-Петербург
Контактная информация:

Re: Map Viewer

Сообщение SergeyRyzhkov » 06 май 2015, 19:18

avk ,
Да Вы на счет proj4 не парьтесь :)) , сами то алгоритмы проекций и т.д. просты как тапок (в смысле реализации для программера), вот и не парится уже никто, зачем уж в данной теме изобретать велосипед ..., формулы то уже не изменить ...

Аватара пользователя
avk
Новоприбывший
Сообщения: 10
Зарегистрирован: 04 май 2015, 02:30
Репутация: 3
Откуда: Санкт-Петербург

Re: Map Viewer

Сообщение avk » 06 май 2015, 19:34

Вот и "Панорама" постигает дзэн OpenSource.
Опубликовали исходные коды своих компонент для QtDesigner: ссылка на новость.
Ну, и сам виновник торжества: тыц

Если отбросить код для встраивания в QtDesigner, то останется почти всё необходимое для топикстартера :D

UPD
Поторопился я. Всего интересного там много, но не очень показательно для темы этой ветки. Можно посмотреть qdmwina.cpp (QDMapViewWindow) и то, что с ним связано. Но архитектура ускользает за вызовами функций ядра. Похоже, что визуализатор в данном случае растровый и оперирует только понятием точка (пиксель).

Пытаюсь осмыслить вот это (qdmobj.cpp):

Код: Выделить всё


// Операции пересчета пикселов в микроны
#define MKMINPIX 260 // 1000 * 25.4 / 96 = 264.583333

grig27
Участник
Сообщения: 76
Зарегистрирован: 02 июл 2013, 13:36
Репутация: 1
Откуда: Екатеринбург

Re: Map Viewer

Сообщение grig27 » 07 май 2015, 07:05

Простите, вклинюсь со своим самоваром в дискуссию. Есть ещё же вариант OpenGL.
Пока без загрузки вертексов в память видеокарты... (VBO)
progress________.jpg
progress________.jpg (138.63 КБ) 12878 просмотров

grig27
Участник
Сообщения: 76
Зарегистрирован: 02 июл 2013, 13:36
Репутация: 1
Откуда: Екатеринбург

Re: Map Viewer

Сообщение grig27 » 07 май 2015, 07:07

Конечно на плоскости... но думаю пересчёт в проекцию можно сделать.
Алгоритмы имеются на просторах интернет.
Вложения
csGISWindow.zip
(1.88 МБ) 363 скачивания

Аватара пользователя
avk
Новоприбывший
Сообщения: 10
Зарегистрирован: 04 май 2015, 02:30
Репутация: 3
Откуда: Санкт-Петербург

Re: Map Viewer

Сообщение avk » 08 май 2015, 22:54

virtu писал(а):... но я немного использовал другую либу, вернее исходники проги Merkaator-а, там вроде бы просто, но все же тупой копи-паст без понимания принципа не очень подходит и порядок программирования ускользал.
Попался на просторах Интернета проект поверх merkaartor, proj и gdal. Сам по себе элементарный и на Qt. Есть главное окно и все сигналы. Если есть опыт ковыряния с merkaartor, то Merkopolo, возможно, что-то прояснит (небольшое описание и исходники)

virtu
Интересующийся
Сообщения: 17
Зарегистрирован: 20 фев 2015, 07:48
Репутация: 0

Re: Map Viewer

Сообщение virtu » 14 май 2015, 11:06

Всем спасибо.
Не скажу, что я разобрался на все 100%, но основную мысль создания подобных приложений ухватил...
QMapControl sourceforge.net/projects/qmapcontrol/ - вот эта очень простая библиотека, которую можно использовать велосипедистам для понимания :D

Аватара пользователя
Павиан из Найроби
Новоприбывший
Сообщения: 2
Зарегистрирован: 25 май 2015, 23:23
Репутация: 0
Откуда: Казань
Контактная информация:

Re: Map Viewer

Сообщение Павиан из Найроби » 26 май 2015, 16:43

virtu писал(а):Здравствуйте.
Пытаюсь сделать простой Map Viewer (С++ Qt) - просмотрщик карт (например .mp - польский формат). Понимаю, что изобретаю велосипед, и можно было бы использовать QGIS, но хочется в целях, так сказать, самообразования.
Мне бы понять по какому принципу строятся подобные "вьюверы".
У меня тот же самый вопрос был по приходу на форум. Надеюсь кое-что все же почерпну. ведь кто-то однажды усовершенствовал велосипед до мотоцикла ;)

virtu
Интересующийся
Сообщения: 17
Зарегистрирован: 20 фев 2015, 07:48
Репутация: 0

Re: Map Viewer

Сообщение virtu » 30 май 2015, 15:31

Павиан из Найроби писал(а):
virtu писал(а):Здравствуйте.
Пытаюсь сделать простой Map Viewer (С++ Qt) - просмотрщик карт (например .mp - польский формат). Понимаю, что изобретаю велосипед, и можно было бы использовать QGIS, но хочется в целях, так сказать, самообразования.
Мне бы понять по какому принципу строятся подобные "вьюверы".
У меня тот же самый вопрос был по приходу на форум. Надеюсь кое-что все же почерпну. ведь кто-то однажды усовершенствовал велосипед до мотоцикла ;)
Я сейчас на стадии "до-пиливания" программы. Использую QT(QGraphicsView ..Scene ..Item)+Visual Studio 2013...
Накачал кучу разных исходников, в основном сейчас трассирую QMapControl (Merkaator-ский), QLandkarteGT и QMapShack - последние два родственные и используют такие либы как proj.4 и gdal/ogr...
Вообще, принцип построения таких приложений уже понятен и можно было бы прекратить, но все же я хочу свой велосипед :D
PS: у меня тут на Сахалине посевной сезон начался, так что медленно это все продвигается, но в течении лета постараюсь до-пилить и показать/выложить исходники с комментариями, может кому пригодятся тоже...

virtu
Интересующийся
Сообщения: 17
Зарегистрирован: 20 фев 2015, 07:48
Репутация: 0

Re: Map Viewer

Сообщение virtu » 03 июн 2015, 04:44

Предварительно.
Сделал очень-очень простой вьювер на тайловой основе. Пока только без карты. Умеет изменять масштаб, показывать координаты, переходить или центрировать вид по координатам. В общих чертах я понял, как примерно строятся "Вьюверы"...
Теперь нужно отработать технологию добавления самой карты, тех же самых тайлов того же самого OSM...
---------
Ссылки, которые мне помогли:
---------
http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
---------
http://doc.crossplatform.ru/qt/4.5.0/qgraphicsview.html
http://doc.crossplatform.ru/qt/4.5.0/qg ... scene.html
http://doc.crossplatform.ru/qt/4.5.0/qgraphicsitem.html
---------
http://www.medieninf.de/qmapcontrol/
---------
https://bitbucket.org/maproom/qmapshack/wiki/Home
http://qlandkarte.sourceforge.net/#
----------------------------------Код--[Qt5.4 + MSVS C++ 2013]--------------------------------
tilebase.h

Код: Выделить всё

#ifndef TILEBASE_H
#define TILEBASE_H

#include <QObject>

// Класс для управления тайлами
class TileBase : public QObject
{
	Q_OBJECT

	public:
		TileBase(QObject *parent = 0);
		~TileBase();

		// Количество тайлов по оси в зависимости от масштаба
		quint64 tilesOnZoomLevel(quint8 zoomLevel) const;
		
		quint8 getMinZoomLevel();
		quint8 getMaxZoomLevel();
		quint16 getTileSize() const;
		
		// Конвертация географических координат в пиксельные
		QPointF lonlat2pix(const QPointF &lonlat, quint8 zoomLevel) const;
		// Конвертация пиксельных координат в географические
		QPointF pix2lonlat(const QPointF &pix, quint8 zoomLevel) const;
		
	protected:
		const qreal pi;
		const qreal deg2rad;
		const qreal rad2deg;
		const quint8 minZoomLevel;
		const quint8 maxZoomLevel;
		const quint16 tileSize;
};

#endif // TILEBASE_H
tilebase.cpp

Код: Выделить всё

#include "stdafx.h"
#include "tilebase.h"

TileBase::TileBase(QObject *parent)
	: QObject(parent),
	pi(3.14159265358979323846), deg2rad(pi / 180.0), rad2deg(180.0 / pi),
	minZoomLevel(0), maxZoomLevel(18), tileSize(256)
{
	qDebug() << "TileBase::TileBase() ctor";
}

TileBase::~TileBase()
{
	qDebug() << "TileBase::TileBase() dtor";
}

quint64 TileBase::tilesOnZoomLevel(quint8 zoomLevel) const
{
	qDebug() << "TileBase::tilesOnZoomLevel()";
	return pow(2.0, zoomLevel);
}

QPointF TileBase::lonlat2pix(const QPointF &lonlat, quint8 zoomLevel) const
{
	qDebug() << "TileBase::lonlat2pix()";
	const qreal edge = tilesOnZoomLevel(zoomLevel);
	qreal x = (lonlat.x() + 180) * (edge * tileSize) / 360;
	qreal y = (1 - (log(tan(pi / 4 + (lonlat.y() * deg2rad) / 2)) / pi)) / 2 * (edge * tileSize);
	return QPoint(int(x), int(y));
}

QPointF TileBase::pix2lonlat(const QPointF &pix, quint8 zoomLevel) const
{
	qDebug() << "TileBase::pix2lonlat()";
	const qreal edge = tilesOnZoomLevel(zoomLevel);
	qreal longitude = (pix.x() * (360 / (edge * tileSize))) - 180;
	qreal latitude = rad2deg * (atan(sinh((1 - pix.y() * (2 / (edge * tileSize))) * pi)));
	return QPointF(longitude, latitude);
}

quint8 TileBase::getMinZoomLevel()
{
	qDebug() << "TileBase::getMinZoomLevel()";
	return minZoomLevel;
}

quint8 TileBase::getMaxZoomLevel()
{
	qDebug() << "TileBase::getMaxZoomLevel()";
	return maxZoomLevel;
}

quint16 TileBase::getTileSize() const
{
	qDebug() << "TileBase::getTileSize()";
	return tileSize;
}
qgscene.h

Код: Выделить всё

#ifndef QGSCENE_H
#define QGSCENE_H

class QGraphicsScene;

// Просто сцена
class QGScene : public QGraphicsScene
{
	Q_OBJECT

	public:
		QGScene(QWidget *parent = 0);
		~QGScene();
};

#endif // QGSCENE_H
qgscene.cpp

Код: Выделить всё

#include "stdafx.h"
#include "qgscene.h"

#include <QGraphicsScene>

QGScene::QGScene(QWidget *parent)
	: QGraphicsScene(parent)
{
	qDebug() << "QGScene::QGScene() ctor";
}

QGScene::~QGScene()
{
	qDebug() << "QGScene::QGScene() dtor";
}
qgviewer.h

Код: Выделить всё

#ifndef QGVIEWER_H
#define QGVIEWER_H

class QGraphicsView;

class QGScene;
class QGObject;
class TileBase;

// Класс вида - управляет картой
class QGViewer : public QGraphicsView
{
	Q_OBJECT

	public:
		// Режим масштабирования
		enum ZoomMode
		{
			CenterZoom, // Масштаб по центру
			MouseZoom // Масштаб управляется мышью
		};

		QGViewer(QGScene *scene = 0, QWidget *parent = 0);
		~QGViewer();

		// Установка тайловой соновы
		void setTileBase(TileBase *base);
		// Установка масштаба
		void setZoomLevel(quint8 zoom, ZoomMode mode = CenterZoom);
		// Центрирует карту в нужной точке
		void centerPos(const QPointF &pos);

	private:
		// Возвращает центр вида в географических координатах
		QPointF getCenter(const QPoint viewPos) const;
		// Изменят размер сцены в зависимости от масштаба
		void changeSceneSize();
		// Масштаб больше
		void zoomIn(ZoomMode mode = CenterZoom);
		// Масштаб меньше
		void zoomOut(ZoomMode mode = CenterZoom);

	protected:
		// События мыши
		virtual void mousePressEvent(QMouseEvent *event);
		virtual void mouseReleaseEvent(QMouseEvent *event);
		virtual void mouseMoveEvent(QMouseEvent *event);
		virtual void wheelEvent(QWheelEvent *event);
	
	signals:
		// Для вывода масштаба в строку статуса
		void zoomLevelChanged(quint8 zoom);
		// Для вывода координат в строку статуса
		void mousePosition(QPointF point);

	private:
		QGScene *scene; // Сцена
		TileBase *tileBase; // Тайловая основа
		quint8 zoomLevel; // Масштаб
};

#endif // QGVIEWER_H
qgviewer.cpp

Код: Выделить всё

#include "stdafx.h"
#include "qgviewer.h"
#include "qgscene.h"
#include "tilebase.h"

#include <QGraphicsView>

QGViewer::QGViewer(QGScene *scene, QWidget *parent)
	: QGraphicsView(scene, parent), scene(scene),
	zoomLevel(0)
{
	qDebug() << "QGViewer::QGViewer() ctor";

	//this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	//this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	this->setMouseTracking(true);
	this->setResizeAnchor(QGraphicsView::AnchorViewCenter);
	this->setDragMode(QGraphicsView::ScrollHandDrag);
}

QGViewer::~QGViewer()
{
	qDebug() << "QGViewer::QGViewer() dtor";
}

void QGViewer::setTileBase(TileBase *base)
{
	qDebug() << "QGViewer::setTileBase()";
	tileBase = base;
}

void QGViewer::setZoomLevel(quint8 zoom, ZoomMode mode)
{
	qDebug() << "QGViewer::setZoomLevel() zoom:" << zoom;

	const QPointF centerGeoPos = getCenter(QPoint(this->width() / 2, this->height() / 2));
	qDebug() << "QGViewer::setZoomLevel() centerGeoPos:" << centerGeoPos;

	QPointF mousePoint = this->mapToScene(this->mapFromGlobal(QCursor::pos()));
	qDebug() << "QGViewer::setZoomLevel() mousePoint:" << mousePoint;

	QRectF sceneRect = scene->sceneRect();
	const float xRatio = mousePoint.x() / sceneRect.width();
	const float yRatio = mousePoint.y() / sceneRect.height();
	qDebug() << "QGViewer::setZoomLevel() xRatio:" << xRatio << "yRatio" << yRatio;

	const QPointF centerPixPos = this->mapToScene(QPoint(this->width() / 2, this->height() / 2));
	qDebug() << "QGViewer::setZoomLevel() centerPixPos:" << centerPixPos;

	const QPointF offset = mousePoint - centerPixPos;
	qDebug() << "QGViewer::setZoomLevel() offset:" << offset;

	zoom = qMin(tileBase->getMaxZoomLevel(), qMax(tileBase->getMinZoomLevel(), zoom));
	qDebug() << "QGViewer::setZoomLevel() zoom:" << zoom;

	if (zoom == zoomLevel)
		return;
	zoomLevel = zoom;

	changeSceneSize();

	sceneRect = scene->sceneRect();
	mousePoint = QPointF(sceneRect.width() * xRatio, sceneRect.height() * yRatio) - offset;
	qDebug() << "QGViewer::setZoomLevel() mousePoint:" << mousePoint;

	if (mode == MouseZoom)
	{
		qDebug() << "QGViewer::setZoomLevel() zMode = MouseZoom";
		this->centerOn(mousePoint);
	}
	else
	{
		qDebug() << "QGViewer::setZoomLevel() zMode = CenterZoom";
		centerPos(centerGeoPos);
	}

	emit zoomLevelChanged(zoom);
}

void QGViewer::centerPos(const QPointF &pos)
{
	qDebug() << "QGViewer::centerPos()";
	this->centerOn(tileBase->lonlat2pix(pos, zoomLevel));
}

QPointF QGViewer::getCenter(const QPoint viewPos) const
{
	qDebug() << "QGViewer::getCenter()";
	return tileBase->pix2lonlat(this->mapToScene(viewPos), zoomLevel);
}

void QGViewer::changeSceneSize()
{
	qDebug() << "QGViewer::changeSceneSize()";
	const quint64 dimension = tileBase->tilesOnZoomLevel(zoomLevel) * tileBase->getTileSize();
	if (scene->sceneRect().width() != dimension)
		scene->setSceneRect(0, 0, dimension, dimension);
	qDebug() << "QGViewer::changeSceneSize() sceneRect:" << scene->sceneRect();
}

void QGViewer::zoomIn(ZoomMode mode)
{
	qDebug() << "QGViewer::zoomIn()";
	if (zoomLevel < tileBase->getMaxZoomLevel())
		setZoomLevel(zoomLevel + 1, mode);
}

void QGViewer::zoomOut(ZoomMode mode)
{
	qDebug() << "QGViewer::zoomOut()";
	if (zoomLevel > tileBase->getMinZoomLevel())
		setZoomLevel(zoomLevel - 1, mode);
}

void QGViewer::mousePressEvent(QMouseEvent *event)
{
	qDebug() << "QGViewer::mousePressEvent()";
	event->setAccepted(false);
	if (!event->isAccepted())
		QGraphicsView::mousePressEvent(event);
}

void QGViewer::mouseReleaseEvent(QMouseEvent *event)
{
	qDebug() << "QGViewer::mouseReleaseEvent()";
	event->setAccepted(false);
	if (!event->isAccepted())
		QGraphicsView::mouseReleaseEvent(event);
}

void QGViewer::mouseMoveEvent(QMouseEvent *event)
{
	qDebug() << "QGViewer::mouseMoveEvent()";
	event->setAccepted(false);

	emit mousePosition(getCenter(event->pos()));
	
	if (!event->isAccepted())
		QGraphicsView::mouseMoveEvent(event);
}

void QGViewer::wheelEvent(QWheelEvent *event)
{
	qDebug() << "QGViewer::wheelEvent()";
	event->setAccepted(true);

	if (event->delta() > 0)
		zoomIn(MouseZoom);
	else
		zoomOut(MouseZoom);

	if (!event->isAccepted())
		QGraphicsView::wheelEvent(event);
}
viewer.h

Код: Выделить всё

#ifndef VIEWER_H
#define VIEWER_H

#include <QtWidgets/QMainWindow>
#include "ui_viewer.h"

class QStatusBar;
class QLabel;

class QGScene;
class QGViewer;

// Главный класс программы
class Viewer : public QMainWindow, public Ui::ViewerClass
{
	Q_OBJECT

	public:
		Viewer(QWidget *parent = 0);
		~Viewer();

	private slots :
		// Показывает уровень масштаба в строке статуса
		void zoomLevelChanged(quint8 zoom);
		// Показывает гео.координаты мыши в строке статуса
		void mousePosition(QPointF point);

	private:
		QStatusBar *statusBar;
		QLabel *labelZoomLevel;
		QLabel *labelPosition;
		
		QGScene *scene;
		QGViewer *viewer;
};

#endif // VIEWER_H
viewer.cpp

Код: Выделить всё

#include "stdafx.h"
#include "viewer.h"
#include "qgscene.h"
#include "qgviewer.h"
#include "tilebase.h"

#include <QStatusBar>
#include <QLabel>

Viewer::Viewer(QWidget *parent)
	: QMainWindow(parent)
{
	qDebug() << "Viewer::Viewer() ctor";

	this->setupUi(this);

	statusBar = new QStatusBar(this);
	statusBar->setFont(QFont("Arial", 8));
	this->setStatusBar(statusBar);
	labelZoomLevel = new QLabel();
	labelZoomLevel->setFont(QFont("Arial", 8));
	statusBar->addWidget(labelZoomLevel);
	labelPosition = new QLabel();
	labelPosition->setFont(QFont("Arial", 8));
	statusBar->addWidget(labelPosition);

	scene = new QGScene(this);
	viewer = new QGViewer(scene, this);
	TileBase *tileBase = new TileBase();

	connect(viewer, SIGNAL(mousePosition(QPointF)), this, SLOT(mousePosition(QPointF)));
	connect(viewer, SIGNAL(zoomLevelChanged(quint8)), this, SLOT(zoomLevelChanged(quint8)));

	viewer->setTileBase(tileBase);
	viewer->setZoomLevel(8);
	viewer->centerPos(QPointF(142.500000, 46.500000));
	
	labelPosition->setText(QString("lat: 46.500000 | lon: 142.500000"));
	this->gridLayout->addWidget(viewer);
}

Viewer::~Viewer()
{
	qDebug() << "Viewer::Viewer() dtor";
}

void Viewer::zoomLevelChanged(quint8 zoom)
{
	labelZoomLevel->setText(QString("zoom: %1").arg(zoom));
}

void Viewer::mousePosition(QPointF point)
{
	labelPosition->setText(QString("lat: %1 | lon: %2").arg(point.y(), 0, 'd', 6).arg(point.x(), 0, 'd', 6));
}

Sergey Astakhov
Активный участник
Сообщения: 218
Зарегистрирован: 21 дек 2012, 01:57
Репутация: 52
Откуда: Питер

Re: Map Viewer

Сообщение Sergey Astakhov » 03 июн 2015, 14:27

Выложите на том же github - куда полезнее будет чем здесь выкладывать.

Ответить

Вернуться в «Общий - ПО»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 10 гостей