Картографический пакет для ЗОСРВ Нейтрино

Этот коммит содержится в:
Коммит 2c9ea196e4
1702 изменённых файлов: 125348 добавлений и 0 удалений

12
.gitmodules поставляемый Обычный файл
Просмотреть файл

@ -0,0 +1,12 @@
[submodule "src/lib/gdal"]
path = src/lib/gdal
url = https://git.kpda.ru/gis/gdal.git
[submodule "src/lib/openjpeg"]
path = src/lib/openjpeg
url = https://git.kpda.ru/gis/openjpeg.git
[submodule "src/lib/geos"]
path = src/lib/geos
url = https://git.kpda.ru/gis/geos.git
[submodule "src/lib/proj"]
path = src/lib/proj
url = https://git.kpda.ru/gis/proj.git

26
CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,26 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( GIS )
add_subdirectory( src )

19
LICENSE Обычный файл
Просмотреть файл

@ -0,0 +1,19 @@
MIT License
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

157
README.md Обычный файл
Просмотреть файл

@ -0,0 +1,157 @@
<h1 align="center">ПК ЦКИ (Программый Комплекс поддержки ЦКИ)</h1>
<div align="center">
<p><img src="doc/readme_content/animated_gis_logo_no_loop.gif" alt="ПК ЦКИ" align="top"></p>
<p>
<img src="https://img.shields.io/badge/c-%2300599C.svg?style=for-the-badge&logo=c&logoColor=white" alt="C">&nbsp;
<img src="https://img.shields.io/badge/c++-%2300599C.svg?style=for-the-badge&logo=c%2B%2B&logoColor=white" alt="C++">&nbsp;
<img src="https://img.shields.io/badge/CMake-%23008FBA.svg?style=for-the-badge&logo=cmake&logoColor=white" alt="CMake">&nbsp;
</p>
<img src="https://img.shields.io/badge/PVS_stat_analyzer-Enabled-green%20" alt="PVS_stat_analyzer-Enabled">&nbsp;
<img src="https://img.shields.io/badge/GCOV_code_coverage-Enabled-green%20" alt="GCOV_code_coverage-Enabled">&nbsp;
</div>
<h1></h1>
<p>Картографический пакет ПК ЦКИ предназначен для обработки и визуализации цифровой картографической информации в защищенной операционной системе реального времени «Нейтрино».</p>
<p>ПК ЦКИ оптимизирован для работы на широком спектре оборудования, включая аппаратные платформы на базе российских процессоров, и применяется в качестве базового ПО при построении ГИС различного назначения для мобильных, бортовых и стационарных систем и комплексов.</p>Подробнее о продукте можно прочитать <a href="https://kpda.ru/products/gis/">здесь</a>.
<h1></h1>
<table>
<tr>
<td>
<table>
<tr>
<th>Поддерживаемые платформы</th>
</tr>
<tr>
<td>
<p><img src="https://img.shields.io/badge/x86-blue" alt="x86">&nbsp;</p>
<p><img src="https://img.shields.io/badge/ARM_v7-blue" alt="ARM_v7">&nbsp;</p>
<p><img src="https://img.shields.io/badge/PowerPC_BE_%2F_BE_SPE-blue" alt="PowerPC">&nbsp;</p>
<p><img src="https://img.shields.io/badge/%D0%AD%D0%BB%D1%8C%D0%B1%D1%80%D1%83%D1%81-blue" alt="Эльбрус">&nbsp;</p>
<p><img src="https://img.shields.io/badge/MIPS-blue" alt="MIPS">&nbsp;</p>
</td>
</tr>
</table>
</td>
<td width="1000px" align="center">
<img src="doc/readme_content/supported_formats.png" alt="Поддерживаемые форматы" width="750px">
</td>
</tr>
</table>
# Обзор
## Содержание
- [Компоненты](#компоненты)
- [Зависимости](#зависимости)
- [Сборка](#сборка)
- [Запуск](#запуск)
## Компоненты
- [doc](doc) - справка по формату GCM, и др.
- [src](src) - исходные компоненты проекта
- [apps](src/apps) - демонстрационные и тестовые приложения
- [lib](src/lib) - исходники используемых библиотек
- [services](src/services) - компоненты ядра, драйверов для работы с серверами и имитаторов серверов
- [gis-core](src/services/core) - ядро картографического пакета
- [drivers](src/services/drivers) - исходники драйверов форматов картографической информации
- [utils](src/utils) - конвертеры карт и дополнительные утилиты для работы
Подробную информацию по конкретному компоненту (приложению, утилите, драйверу и т. д.) можно найти в файлах `README.md`, находящихся в директории этого компонента.
## Зависимости
<div align="center">
<img src="doc/readme_content/GIS.drawio.svg" alt="Зависимости" width="1000px">
</div>
## Сборка
*ПК ЦКИ поддерживается на ЗОСРВ "Нейтрино" версий 2024 и 2021.*
**Для комплекта разработчика 2021 необходимо дополнительно подключить sqlite3:**
1. Установить sqlite3 на свое устройство. Например, для Debian/Ubuntu ввести следующую команду:
<code>sudo apt update && sudo apt install sqlite3</code>
2. Собрать <a href="https://git.kpda.ru/gis/sqlite">sqlite3</a> под требуемую аппаратную платформу, установив библиотеки в указанную вами папку.
- Например, для armle-v7:
<code>make CPULIST=arm VARIANTLIST=le.v7 INSTALL_ROOT_nto=my_sqlite_install_dir install && make clean</code>
- Для x86:
<code>make CPULIST=x86 INSTALL_ROOT_nto=my_sqlite_install_dir install && make clean</code>
3. Полученные библиотеки необходимо поместить на целевое устройство с ОС "Нейтрино" версии 2021 в папку `/opt/gis/lib`.
4. Установить переменные окружения, используя ранее выбранную папку установки:
<code>export SQLite3_INCLUDE_DIR=my_sqlite_install_dir/armle-v7/usr/include/sqlite</code>
<code>export SQLite3_LIBRARY=my_sqlite_install_dir/armle-v7/usr/lib/libsqlite3.so.8</code>
**Сборка ПК ЦКИ для 2021 и 2024:**
1. Перейти в выбранную для сборки папку:
<code>mkdir my_gis_build && cd my_gis_build</code>
2. Настроить cmake:
<code>cmake --toolchain=$KPDA_HOST/mk/cmake/toolchain-nto-armle-v7.cmake *path-from-my_gis_build-folder*/kpda-gis</code>
3. Собрать проект:
<code>cmake --build . -jn</code>, где n - количество потоков.
4. Установить в выбранную папку:
<code>cmake --install . --prefix my_gis_install_dir</code>
*Примечание: при развертывании на целевое устройство *`my_gis_install_dir`* должно быть присвоено значение *`/opt/gis`*.*
## Запуск
**Пример запуска приложения gis-monitor**
1. Установить необходимые переменные окружения
<code>export PATH=/opt/gis/bin:/opt/gis/sbin:$PATH</code>
<code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/gis/lib</code>
2. Дополнительные настройки
<table>
<tr>
<td>Изменение языка</td>
<td><code>export ABLANG=ru_RU</code></td>
</tr>
<tr>
<td>Уровень отладочного вывода (Error - 1, Warning - 2, Info - 3)</td>
<td><code>export GIS_DEBUG_LEVEL=3</code></td>
</tr>
<tr>
<td>Установка размера кэша в байтах</td>
<td><code>export GIS_CORE_DATABUFFER_SIZE_LIMIT=960000000</code></td>
</tr>
</table>
3. Добавить файлы цифровой картографической информации в директорию, соответствующую исходному формату ЦКИ, в <a href="http://gis.help.kpda.ru/help/topic/ru.kpda.doc.gis/html/dev_guide/articles/gis-environment.html?resultof=%22%47%49%53%5f%43%4f%52%45%5f%4d%41%50%5f%43%41%43%48%45%22%20">$GIS_CORE_MAP_CACHE</a> (по умолчанию /opt/gis/data/maps/cache).
4. Запуск ядра и приложения
При запуске ядра c опцией `-d` передается название драйвера требуемого формата. Подробнее об имеющихся драйверах можно прочитать [тут](http://gis.help.kpda.ru/help/topic/ru.kpda.doc.gis/html/utilities/reference-book/gis-core.html?cp=0_2_1_0_0).
Пример запуска с драйвером для формата SXF:
<code>gis-core -dsxf-local,sync=hard</code> [справка](http://gis.help.kpda.ru/help/topic/ru.kpda.doc.gis/html/utilities/reference-book/gis-core.html?cp=0_2_1_0_0)
Запуск демонстрационного приложения gis-monitor:
<code>gis-monitor -x50 -y50</code> [справка](http://gis.help.kpda.ru/help/topic/ru.kpda.doc.gis/html/utilities/reference-book/gis-monitor.html?cp=0_2_0_0_0)

Двоичные данные
doc/GCM-format-description.pdf Обычный файл

Двоичный файл не отображается.

4
doc/readme_content/GIS.drawio.svg Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 101 KiB

Двоичные данные
doc/readme_content/animated_gis_logo_no_loop.gif Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 297 KiB

Двоичные данные
doc/readme_content/supported_formats.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 82 KiB

29
src/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,29 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( src )
add_subdirectory( apps )
add_subdirectory( lib )
add_subdirectory( services )
add_subdirectory( utils )

44
src/apps/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,44 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( apps )
if ( DEFINED GIS_ENABLE_GCOV )
set( CMAKE_C_FLAGS "-O0 -Wall -fprofile-arcs -ftest-coverage" )
set( CMAKE_CXX_FLAGS "-O0 -Wall -fprofile-arcs -ftest-coverage" )
set( CMAKE_C_OUTPUT_EXTENSION_REPLACE ON )
set( CMAKE_CXX_OUTPUT_EXTENSION_REPLACE ON )
endif()
add_subdirectory( gis-filter-generator )
add_subdirectory( gis-map-linker )
add_subdirectory( gis-map-viewer )
add_subdirectory( gis-monitor )
add_subdirectory( gis-raster-preview )
add_subdirectory( gis-rb-viewer )
if ( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/gis-client-render )
add_subdirectory( gis-client-render )
endif()

76
src/apps/gis-filter-generator/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,76 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-filter-generator LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -Wno-ignored-attributes )
add_compile_options( -Wno-deprecated-declarations )
find_package( Qt5
COMPONENTS
Core
Gui
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
images.qrc
translations.qrc )
add_executable( gis-filter-generator ${SOURCES} )
add_custom_command( OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-filter-generator_ru.qm
COMMAND
$ENV{KPDA_HOST}/usr/lib/Qt/bin/lrelease -silent ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts )
add_custom_target( generate_translations_filter_generator
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-filter-generator_ru.qm )
target_include_directories( gis-filter-generator
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/kd-tree/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/private
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/config_parser )
add_dependencies( gis-filter-generator generate_translations_filter_generator )
target_link_libraries( gis-filter-generator
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
gishelper )
install( TARGETS gis-filter-generator DESTINATION bin )

107
src/apps/gis-filter-generator/main.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,107 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <QApplication>
#include <QTranslator>
#include <libgen.h>
#include "mainwindow.h"
int wgt_x = 0,
wgt_y = 0,
wgt_width = 400,
wgt_height = 500;
int main(int argc, char *argv[])
{
int opt = 0;
extern char *optarg;
while ( (opt = getopt( argc, argv,"w::h::x::y::" )) != -1 )
{
switch ( opt )
{
case 'w':
wgt_width = strtoul( optarg, NULL, 0 );
break;
case 'h':
wgt_height = strtoul( optarg, NULL, 0 );
break;
case 'x':
wgt_x = strtoul( optarg, NULL, 0 );
break;
case 'y':
wgt_y = strtoul( optarg, NULL, 0 );
break;
case '?':
printf( "Error: unknown option\n" );
exit(1);
};
};
char logname[GIS_MAX_NAME_LENGTH];
char *executable_path = strdup( argv[0] );
if ( executable_path == NULL )
{
printf( "Error: missed executable path (argv[0])!\n" );
exit(1);
}
const char *executable_name = basename( executable_path );
if ( executable_name == NULL || strlen( executable_name ) > GIS_MAX_NAME_LENGTH - 5 )
{
printf( "Error: missed executable name (argv[0]) or it's too big \n" );
exit(1);
}
else
{
sprintf( logname, "%s.log", executable_name );
gis_helper_debug_mode_setmask( GIS_DEBUG_MODE_STD | GIS_DEBUG_MODE_FD );
gis_helper_debug_file_setname( logname );
}
CleanExit cleanExit;
QApplication a(argc, argv);
const char *lang = getenv( "ABLANG" );
QString locale = "en_EN";
if ( lang )
{
locale = QString( lang );
}
QTranslator myTranslator;
myTranslator.load( ":/translations/gis-filter-generator_" + locale );
a.installTranslator(&myTranslator);
MainWindow w;
w.show();
return a.exec();
}

320
src/apps/gis-filter-generator/mainwindow.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,320 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mainwindow.h"
#include <QDebug>
#include <QDir>
#include <QTextCodec>
#include <QComboBox>
#include <QGroupBox>
#include <QHeaderView>
#include <QHBoxLayout>
#include <QPushButton>
#include <QVBoxLayout>
#include <QtGlobal>
#include <class_filter_cfg_parser_api.h>
#include <gis_types_internal.h>
extern int wgt_x,
wgt_y,
wgt_width,
wgt_height;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
style_creator = new MapStyleCreator();
resize( wgt_width, wgt_height );
move( wgt_x, wgt_y );
setWindowTitle( tr("Class filter") );
QWidget *mainWidget = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainWidget->setLayout( mainLayout );
setCentralWidget( mainWidget );
QString gcmFolder = QString( gis_helper_env_get_maps_cache_directory() ) + "/gcm/";
fillClassifiersList( gcmFolder );
for ( int idx = 0; idx < classifierList.size(); idx++ )
{
QVector<gis_core_class_code_t> filter_table;
std::vector<gis_core_class_code_t> class_codes;
if ( filter_config_get_classes_list( classifierList[idx].toStdString(), class_codes ) == 0 )
{
if ( !class_codes.empty() )
filter_table = filter_table.fromStdVector( class_codes );
}
gis_core_map_data_source_t ds = getDataSourceType( classifierList[idx] );
QString filepath( classifierList[idx] );
classifierStates << ClassifierState( ds, filepath, filter_table, style_creator );
}
classifierCurrIdx = 0;
QVBoxLayout *openFileLayout = new QVBoxLayout;
QGroupBox *classifierFileGrpBx = new QGroupBox(tr("Open file"));
classifierFileGrpBx->setLayout( openFileLayout );
QComboBox *classifierListComboBx = new QComboBox;
classifierListComboBx->addItem( tr("< Choose classifier file >") );
classifierListComboBx->addItems( classifierList );
connect( classifierListComboBx, SIGNAL(currentIndexChanged(int)), this, SLOT(rscListIdxChanged(int)) );
openFileLayout->addWidget( classifierListComboBx );
mainLayout->addWidget( classifierFileGrpBx );
classListTreeWgt = new QTreeWidget;
mainLayout->addWidget( classListTreeWgt );
classListTreeWgt->setColumnCount( 4 );
classListTreeWgt->setHeaderLabels( QStringList() << "#" << tr("Enable") << tr("Class code") << tr("Acronym") );
QWidget *btnsBoxWgt = new QWidget;
QHBoxLayout *btnsBoxLayout = new QHBoxLayout;
btnsBoxWgt->setLayout( btnsBoxLayout );
mainLayout->addWidget( btnsBoxWgt );
QPushButton *updateButton = new QPushButton;
updateButton->setText( tr("Generate / Update") );
connect( updateButton, SIGNAL( clicked( bool ) ), this, SLOT( updateBtnClicked( bool ) ) );
btnsBoxLayout->addWidget( updateButton );
QPushButton *selectAllBtn = new QPushButton;
selectAllBtn->setText( tr("Select All") );
connect( selectAllBtn, SIGNAL( clicked( bool ) ), this, SLOT( selectAllBtnClicked( bool ) ) );
btnsBoxLayout->addWidget( selectAllBtn );
QPushButton *deselectAllBtn = new QPushButton;
deselectAllBtn->setText( tr("Deselect All") );
connect( deselectAllBtn, SIGNAL( clicked( bool ) ), this, SLOT( deselectAllBtnClicked( bool ) ) );
btnsBoxLayout->addWidget( deselectAllBtn );
}
MainWindow::~MainWindow()
{
}
void MainWindow::selectAllBtnClicked( bool clicked )
{
Q_UNUSED(clicked);
QVector<ClassEntry> &classEntries = classifierStates[classifierCurrIdx].m_classEntries;
for ( auto &entry : classEntries )
entry.m_enabled = true;
fillTreeWidget();
}
void MainWindow::deselectAllBtnClicked( bool clicked )
{
Q_UNUSED(clicked);
QVector<ClassEntry> &classEntries = classifierStates[classifierCurrIdx].m_classEntries;
for ( auto &entry : classEntries )
entry.m_enabled = false;
fillTreeWidget();
}
void MainWindow::updateBtnClicked( bool clicked )
{
Q_UNUSED(clicked);
qDebug() << "Update class filter";
std::map<std::string,Config::ClassFilterConfigParser::configData*> filter_data_map;
for ( int idx = 0; idx < classifierStates.size(); idx++ )
{
ClassifierState &rscState = classifierStates[idx];
QVector<ClassEntry> &classEntries = rscState.m_classEntries;
QString rscFname = rscState.m_filename;
auto *data = new Config::ClassFilterConfigParser::configData();
for ( auto &entry : classEntries )
{
if ( entry.m_enabled )
{
data->class_code_vector.push_back( entry.m_code );
}
}
filter_data_map.emplace( rscFname.toStdString(), data );
}
filter_config_write_new( filter_data_map );
qDebug() << "Completed!";
}
void MainWindow::rscListIdxChanged( int index )
{
if ( index != 0 )
{
classifierCurrIdx = index-1;
fillTreeWidget();
}
else
{
classListTreeWgt->clear();
}
}
#define TREE_WIDGET_COLUMN_IDX 0
#define TREE_WIDGET_COLUMN_INCLUDE_CHK 1
#define TREE_WIDGET_COLUMN_CLASS_CODE 2
#define TREE_WIDGET_COLUMN_ACRONYM 3
void MainWindow::treeItemChangedSlot( QTreeWidgetItem * item, int column )
{
int itemIdx = item->text( TREE_WIDGET_COLUMN_IDX ).toInt();
if ( column == TREE_WIDGET_COLUMN_INCLUDE_CHK )
{
QVector<ClassEntry> &classEntries = classifierStates[classifierCurrIdx].m_classEntries;
classEntries[itemIdx].m_enabled = (item->checkState( TREE_WIDGET_COLUMN_INCLUDE_CHK ) == Qt::Checked);
}
}
void MainWindow::fillTreeWidget()
{
classListTreeWgt->clear();
#if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0))
classListTreeWgt->header()->setResizeMode( QHeaderView::ResizeToContents );
#else
classListTreeWgt->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
#endif
connect( classListTreeWgt, SIGNAL( itemChanged(QTreeWidgetItem *, int) ),
this, SLOT( treeItemChangedSlot(QTreeWidgetItem *, int) ) );
QVector<ClassEntry> &classEntries = classifierStates[classifierCurrIdx].m_classEntries;
for ( auto &entry : classEntries )
{
QTreeWidgetItem *item = new QTreeWidgetItem( classListTreeWgt );
item->setFlags( item->flags() | Qt::ItemIsUserCheckable );
item->setText( TREE_WIDGET_COLUMN_IDX, QString::number(entry.m_id) );
if ( entry.m_enabled )
{
item->setCheckState( TREE_WIDGET_COLUMN_INCLUDE_CHK, Qt::Checked );
}
else
{
item->setCheckState( TREE_WIDGET_COLUMN_INCLUDE_CHK, Qt::Unchecked );
}
item->setText( TREE_WIDGET_COLUMN_CLASS_CODE, QString::number(entry.m_code, 16) );
item->setText( TREE_WIDGET_COLUMN_ACRONYM, entry.m_acronym );
classListTreeWgt->addTopLevelItem( item );
}
}
ClassifierState::ClassifierState( gis_core_map_data_source_t data_source,
QString &filepath,
QVector<gis_core_class_code_t> &filter_table,
MapStyleCreator *style_creator )
{
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
m_classEntries.clear();
this->m_filepath = filepath;
this->m_filename = QFileInfo( m_filepath ).fileName();
this->m_ds = data_source;
gis_map_style_t type = gis_helper_get_map_style_by_data_source( m_ds );
this->m_style = style_creator->createObject( type, m_filepath.toStdString().c_str(), true );
std::vector <gis_core_class_info_t> codes = m_style->get_class_code_list_with_acronyms();
size_t class_count = codes.size();
for ( auto i_class = 0; i_class < class_count; ++i_class )
{
bool foundInFilter = false;
if ( filter_table.size() != 0 )
{
for ( const auto& filter_code : filter_table )
{
if ( codes.at( i_class ).class_data.code == filter_code )
{
foundInFilter = true;
break;
}
}
}
else
{
foundInFilter = true;
}
m_classEntries << ClassEntry( codes[i_class].class_data.code, foundInFilter, i_class,
codec->toUnicode( codes[i_class].acronym ) );
}
}
void MainWindow::fillClassifiersList( QString& gcmFolder )
{
std::vector <QStringList> ext_list;
ext_list.resize( GIS_CORE_DRIVER_COUNT );
ext_list[GIS_CORE_DRIVERS_S57_LOCAL] = QStringList() << "S-52 format";
ext_list[GIS_CORE_DRIVERS_SXF_LOCAL] = QStringList() << "*.rsc*" << "*.RSC*";
ext_list[GIS_CORE_DRIVERS_SHP_LOCAL] = QStringList() << "*.sld*" << "*.SLD*";
classifierList.clear();
classifierList << ext_list[GIS_CORE_DRIVERS_S57_LOCAL];
classifierList << QDir(gcmFolder).entryList( ext_list[GIS_CORE_DRIVERS_SXF_LOCAL], QDir::Files );
classifierList << QDir(gcmFolder).entryList( ext_list[GIS_CORE_DRIVERS_SHP_LOCAL], QDir::Files );
}
gis_core_map_data_source_t MainWindow::getDataSourceType( QString classifierName )
{
if ( classifierName == "S-52 format" )
{
return GIS_CORE_MAP_DATA_SOURCE_S57;
}
if ( classifierName.contains( ".rsc", Qt::CaseInsensitive ) )
{
return GIS_CORE_MAP_DATA_SOURCE_SXF;
}
if ( classifierName.contains( ".sld", Qt::CaseInsensitive ) )
{
return GIS_CORE_MAP_DATA_SOURCE_SHP;
}
return GIS_CORE_MAP_DATA_SOURCE_NONE;
}

135
src/apps/gis-filter-generator/mainwindow.h Обычный файл
Просмотреть файл

@ -0,0 +1,135 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <csignal>
#include <QCoreApplication>
#include <QMainWindow>
#include <QTreeWidget>
#include <gis/gishelper.h>
#include <gis/gis_types.h>
#include <gishelper_service.h>
#include <gis_mapstyle.h>
struct CleanExit
{
CleanExit()
{
signal(SIGINT, &CleanExit::exitQt);
signal(SIGTERM, &CleanExit::exitQt);
}
static void exitQt( int sig )
{
Q_UNUSED(sig);
QCoreApplication::quit();
}
};
namespace Ui {
class MainWindow;
}
class ClassEntry
{
public:
ClassEntry( gis_core_class_code_t code, bool enabled, uint32_t id, QString acronym )
{
m_code = code;
m_enabled = enabled;
m_id = id;
m_acronym = std::move( acronym );
}
ClassEntry()
{
m_code = GIS_CLASS_CODE_UNDEFINED;
m_enabled = false;
m_id = 0;
m_acronym = "";
}
gis_core_class_code_t m_code;
bool m_enabled;
uint32_t m_id;
QString m_acronym;
};
class ClassifierState
{
public:
ClassifierState( gis_core_map_data_source_t ds,
QString &filepath,
QVector<gis_core_class_code_t> &filter_table,
MapStyleCreator *style_creator );
ClassifierState()
{
m_ds = GIS_CORE_MAP_DATA_SOURCE_NONE;
m_filename = "";
m_filepath = "";
m_style = nullptr;
}
QVector<ClassEntry> m_classEntries;
gis_core_map_data_source_t m_ds;
QString m_filename;
private:
MapStyle *m_style;
QString m_filepath;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
MapStyleCreator *style_creator;
QVector<ClassifierState> classifierStates;
QStringList classifierList;
QTreeWidget *classListTreeWgt;
int classifierCurrIdx;
void fillTreeWidget();
gis_core_map_data_source_t getDataSourceType( QString classifierName );
void fillClassifiersList(QString &gcmFolder);
private slots:
void deselectAllBtnClicked(bool clicked);
void rscListIdxChanged(int index);
void selectAllBtnClicked(bool clicked);
void treeItemChangedSlot(QTreeWidgetItem *item, int column);
void updateBtnClicked(bool clicked);
};
#endif

Просмотреть файл

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>translations/gis-filter-generator_ru.ts</file>
<file>translations/gis-filter-generator_ru.qm</file>
</qresource>
</RCC>

Просмотреть файл

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="ru_RU">
<context>
<name>MainWindow</name>
<message>
<source>&lt; Choose classifier file &gt;</source>
<translation>&lt; Выберите классификатор &gt;</translation>
</message>
<message>
<source>Open file</source>
<translation>Открыть</translation>
</message>
<message>
<source>Class filter</source>
<translation>Фильтр классов</translation>
</message>
<message>
<source>Acronym</source>
<translation>Акроним</translation>
</message>
<message>
<source>Class code</source>
<translation>Код класса</translation>
</message>
<message>
<source>Enable</source>
<translation>Включить</translation>
</message>
<message>
<source>Generate / Update</source>
<translation>Создать / Обновить</translation>
</message>
<message>
<source>Select All</source>
<translation>Выбрать все</translation>
</message>
<message>
<source>Deselect All</source>
<translation>Снять выделение</translation>
</message>
</context>
</TS>

78
src/apps/gis-map-linker/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,78 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-map-linker LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -Wno-ignored-attributes )
add_compile_options( -Wno-deprecated-declarations )
find_package( Qt5
COMPONENTS
Core
Gui
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
images.qrc
translations.qrc )
add_executable( gis-map-linker ${SOURCES} )
add_custom_command( OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-map-linker_ru.qm
COMMAND
$ENV{KPDA_HOST}/usr/lib/Qt/bin/lrelease -silent ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts )
add_custom_target( generate_translations_map_linker
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-map-linker_ru.qm )
target_include_directories( gis-map-linker
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gisrender/api/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/formats/gcm
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/private )
add_dependencies( gis-map-linker generate_translations_map_linker )
target_link_libraries( gis-map-linker
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
gishelper
gisrender )
install( TARGETS gis-map-linker DESTINATION bin )

82
src/apps/gis-map-linker/main.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,82 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <QTranslator>
#include "mainwindow.h"
int wgt_x = 0,
wgt_y = 0,
wgt_width = 600,
wgt_height = 500;
int main( int argc, char *argv[] )
{
int opt = 0;
extern char * optarg;
while ( (opt = getopt( argc, argv,"w::h::x::y::" ) ) != -1 )
{
switch ( opt )
{
case 'w':
wgt_width = strtoul( optarg, NULL, 0 );
break;
case 'h':
wgt_height = strtoul( optarg, NULL, 0 );
break;
case 'x':
wgt_x = strtoul( optarg, NULL, 0 );
break;
case 'y':
wgt_y = strtoul( optarg, NULL, 0 );
break;
case '?':
printf( "Error: unknown option\n" );
exit(1);
};
};
gis_helper_debug_mode_setmask( GIS_DEBUG_MODE_STD | GIS_DEBUG_MODE_FD );
gis_helper_debug_file_setname( "gis-map-linker.log" );
CleanExit cleanExit;
QApplication a( argc, argv );
const char *lang = getenv( "ABLANG" );
QString locale = "en_EN";
if ( lang )
{
locale = QString( lang );
}
QTranslator myTranslator;
myTranslator.load( ":/translations/gis-map-linker_" + locale );
a.installTranslator(&myTranslator);
MainWindow w;
w.show();
return a.exec();
}

782
src/apps/gis-map-linker/mainwindow.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,782 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mainwindow.h"
#include <sys/syspage.h>
#include <iostream>
#include <QDesktopWidget>
#include <QGroupBox>
#include <QHeaderView>
#include <QString>
#include <QtGlobal>
#include <gis/gisrender.h>
#include <gis/gishelper.h>
#include <gis/gis_core_cfg_parser.h>
#include <gcm_format.h>
#include <gis_types_internal.h>
#include <projection.h>
#define GCM_SUFFIX "gcm"
#define COLUMN_IDX 0
#define COLUMN_IS_MAP_CONVERTED 1
#define COLUMN_MAP_NAME 2
#define COLUMN_STYLE_NAME 3
#define COLUMN_MAP_SCALE 4
#define COLUMN_MAP_DATA_SOURCE 5
#define COLUMN_COUNT 6
extern int wgt_x,
wgt_y,
wgt_width,
wgt_height;
int MainWindow::CHECKBOX_SIZE = 15;
QString S57MapComboBox::UNUSED_DIR_NAME = ".unused";
MainWindow::MainWindow( QWidget *parent ) :
QMainWindow( parent ),
map_uidx( 0 ),
style_uidx( 2 ),
classFilterProcess( nullptr ),
processing_idx( 0 ),
deltaProgress( 0 ),
taskCount( 0 )
{
resize( wgt_width, wgt_height );
move( wgt_x, wgt_y );
setWindowTitle( tr("Map Configurator") );
QWidget *mainWidget = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainWidget->setLayout( mainLayout );
setCentralWidget( mainWidget );
mapsCachePath = QString( gis_helper_env_get_maps_cache_directory() );
gis_core_link_init( &connection );
int result = gis_core_link_connect( &connection, SHID_NULL );
if ( result != EOK && result != EALREADY )
{
qDebug() << QString( "GIS Core connection failed" );
exit( EINVAL );
}
mapTreeListWgt = new QTreeWidget;
QString style_mapTreeListWgt( "QAbstractItemView::indicator{"
"width: px;"
"height: px;"
"subcontrol-position: left; }" );
style_mapTreeListWgt.replace( "width: ", "width: " + QString::number( CHECKBOX_SIZE ) );
style_mapTreeListWgt.replace( "height: ", "height: " + QString::number( CHECKBOX_SIZE ) );
mapTreeListWgt->setStyleSheet( style_mapTreeListWgt );
mainLayout->addWidget( mapTreeListWgt );
offProjBtn = new QPushButton( QString( tr("Configuration") ) );
offProjEnChk = new QCheckBox( QString( tr("Enabled") ) );
QString style_offProjEnChk( "QCheckBox::indicator{"
"width: px;"
"height: px;"
"subcontrol-position: left; }" );
style_offProjEnChk.replace( "width: ", "width: " + QString::number( MainWindow::CHECKBOX_SIZE ) );
style_offProjEnChk.replace( "height: ", "height: " + QString::number( MainWindow::CHECKBOX_SIZE ) );
offProjEnChk->setStyleSheet( style_offProjEnChk );
connect( offProjEnChk, SIGNAL( stateChanged(int) ), this, SLOT( offProjCheckBoxStateChangedSlot(int) ) );
offProjEnChk->setChecked( false );
offProjCheckBoxStateChangedSlot( 0 );
connect( offProjBtn, SIGNAL( clicked( bool ) ), this, SLOT( offProjConfigBtnClickedSlot( bool ) ) );
QGroupBox *projectionGrpWgt = new QGroupBox(tr("Offline projection"));
QHBoxLayout *projectionGrpLayout = new QHBoxLayout;
projectionGrpLayout->addWidget( offProjEnChk );
projectionGrpLayout->addWidget( offProjBtn );
projectionGrpWgt->setLayout( projectionGrpLayout );
mainLayout->addWidget( projectionGrpWgt );
applyButton = new QPushButton;
applyButton->setText( tr("Apply") );
connect( applyButton, SIGNAL( clicked( bool ) ),
this, SLOT( applyBtnClicked( bool ) ) );
recacheAllBtn = new QPushButton;
recacheAllBtn->setText( tr("Recache") );
connect( recacheAllBtn, SIGNAL( clicked( bool ) ),
this, SLOT( recacheAllBtnClicked( bool ) ) );
filterConfigBtn = new QPushButton;
filterConfigBtn->setText( tr("Filter Config") );
connect( filterConfigBtn, SIGNAL( clicked( bool ) ),
this, SLOT( filterConfigBtnClicked( bool ) ) );
conversionBar = new QProgressBar;
conversionBar->setValue( 0 );
controlWgt = new QWidget;
controlLayout = new QHBoxLayout;
controlWgt->setLayout( controlLayout );
controlLayout->addWidget( applyButton );
controlLayout->addWidget( recacheAllBtn );
controlLayout->addWidget( filterConfigBtn );
mainLayout->addWidget( controlWgt );
mainLayout->addWidget( conversionBar );
char opt_val[GIS_MAX_PATH_LENGTH];
QString extension;
MapFormatStrings s57_format;
s57_format.dataSource = GIS_CORE_MAP_DATA_SOURCE_S57;
gis_core_config_get_driver_value( DRIVER_S57_CFG_SECTION, DRIVER_CFG_CONVERTER_PATH, &opt_val );
s57_format.converterName = QString( opt_val );
gis_core_config_get_driver_value( DRIVER_S57_CFG_SECTION, DRIVER_CFG_MAP_FOLDER, &opt_val );
s57_format.cacheFolder = mapsCachePath + QString( opt_val ) + "/";
gis_core_config_get_driver_value( DRIVER_S57_CFG_SECTION, DRIVER_CFG_FMT_EXTENSION, &opt_val );
extension = QString( opt_val );
s57_format.src_extension = QString( "*." + extension );
s57_format.suffix = "." + extension + ".local.gcm";
MapFormatStrings sxf_format;
sxf_format.dataSource = GIS_CORE_MAP_DATA_SOURCE_SXF;
gis_core_config_get_driver_value( DRIVER_SXF_CFG_SECTION, DRIVER_CFG_CONVERTER_PATH, &opt_val );
sxf_format.converterName = QString( opt_val );
gis_core_config_get_driver_value( DRIVER_SXF_CFG_SECTION, DRIVER_CFG_MAP_FOLDER, &opt_val );
sxf_format.cacheFolder = mapsCachePath + QString( opt_val ) + "/";
gis_core_config_get_driver_value( DRIVER_SXF_CFG_SECTION, DRIVER_CFG_FMT_EXTENSION, &opt_val );
extension = QString( opt_val );
sxf_format.src_extension = QString( "*." + extension );
sxf_format.suffix = "." + extension + ".local.gcm";
MapFormatStrings shp_format;
shp_format.dataSource = GIS_CORE_MAP_DATA_SOURCE_SHP;
gis_core_config_get_driver_value( DRIVER_SHP_CFG_SECTION, DRIVER_CFG_CONVERTER_PATH, &opt_val );
shp_format.converterName = QString( opt_val );
gis_core_config_get_driver_value( DRIVER_SHP_CFG_SECTION, DRIVER_CFG_MAP_FOLDER, &opt_val );
shp_format.cacheFolder = mapsCachePath + QString( opt_val ) + "/";
gis_core_config_get_driver_value( DRIVER_SHP_CFG_SECTION, DRIVER_CFG_FMT_EXTENSION, &opt_val );
extension = QString( opt_val );
shp_format.src_extension = QString( "*." + extension );
shp_format.suffix = "." + extension + ".local.gcm";
format_string[GIS_CORE_MAP_DATA_SOURCE_S57] = s57_format;
format_string[GIS_CORE_MAP_DATA_SOURCE_SXF] = sxf_format;
format_string[GIS_CORE_MAP_DATA_SOURCE_SHP] = shp_format;
updateFilesList();
updateExternalState();
addWidgetView();
gis_map_projection_init( &proj_params );
}
MainWindow::~MainWindow()
{
if ( classFilterProcess )
{
disconnect( classFilterProcess, SIGNAL( finished(int,QProcess::ExitStatus) ),
this, SLOT(classFilterExitCodeParser(int,QProcess::ExitStatus)) );
if ( ( classFilterProcess->state() == QProcess::Running ) ||
( classFilterProcess->state() == QProcess::Starting) )
{
classFilterProcess->terminate();
classFilterProcess->waitForFinished();
}
}
delete mapTreeListWgt;
}
void MainWindow::updateFilesList()
{
QString gcmFolder = mapsCachePath + GCM_SUFFIX + "/";
MapFormatStrings &s57_format = format_string[GIS_CORE_MAP_DATA_SOURCE_S57];
MapFormatStrings &sxf_format = format_string[GIS_CORE_MAP_DATA_SOURCE_SXF];
MapFormatStrings &shp_format = format_string[GIS_CORE_MAP_DATA_SOURCE_SHP];
mapStyleGCMList.clear();
mapStyleGCMList << "Default";
mapStyleGCMList << QDir( gcmFolder ).entryList( { "*.rsc.gcm", "*.sld.gcm" }, QDir::Files );
map_list.clear();
map_uidx = 0;
MapEntry map_src;
QStringList s57_maps = QDir( s57_format.cacheFolder ).entryList(
QStringList( s57_format.src_extension ), QDir::Files );
for ( QString name : s57_maps )
{
map_src.dataSource = GIS_CORE_MAP_DATA_SOURCE_S57;
map_src.isConverted = false;
map_src.name = name;
map_src.scale = 0;
map_src.style_uidx = 0;
map_list[map_uidx++] = map_src;
}
QStringList sxf_maps = QDir( sxf_format.cacheFolder ).entryList(
QStringList( sxf_format.src_extension ), QDir::Files );
for ( QString name : sxf_maps )
{
map_src.dataSource = GIS_CORE_MAP_DATA_SOURCE_SXF;
map_src.isConverted = false;
map_src.name = name;
map_src.scale = 0;
map_src.style_uidx = 0;
map_list[map_uidx++] = map_src;
}
QStringList shp_maps = QDir( shp_format.cacheFolder ).entryList(
QStringList( shp_format.src_extension ), QDir::Dirs );
for ( QString name : shp_maps )
{
map_src.dataSource = GIS_CORE_MAP_DATA_SOURCE_SHP;
map_src.isConverted = false;
map_src.name = name;
map_src.scale = 0;
map_src.style_uidx = 0;
map_list[map_uidx++] = map_src;
}
mapGCMList.clear();
mapGCMList << QDir( gcmFolder ).entryList( QStringList( ("*" + s57_format.suffix) ), QDir::Files );
mapGCMList << QDir( gcmFolder ).entryList( QStringList( ("*" + sxf_format.suffix) ), QDir::Files );
mapGCMList << QDir( gcmFolder ).entryList( QStringList( ("*" + shp_format.suffix) ), QDir::Files );
}
void MainWindow::updateExternalState()
{
for ( int gcm_idx = 0; gcm_idx < mapGCMList.size(); gcm_idx++ )
{
QString gcm_fpath = QString( mapsCachePath + GCM_SUFFIX + "/" + mapGCMList[gcm_idx] );
gcm_map_header_t header;
gcm_read_file_header( gcm_fpath.toStdString().c_str(), &header );
for ( MapEntry &map : map_list )
{
if ( map.name.contains( header.src_filename ) )
{
map.isConverted = true;
map.gcm_name = mapGCMList[gcm_idx];
if ( map.dataSource == GIS_CORE_MAP_DATA_SOURCE_SXF ||
map.dataSource == GIS_CORE_MAP_DATA_SOURCE_SHP )
{
map.style_uidx = mapStyleGCMList.indexOf( QRegExp( QString( header.style_filename ) ) );
}
map.dataSource = (gis_core_map_data_source_t)header.data_source;
map.scale = header.map_scale_denominator;
map.update = header.src_version;
break;
}
}
}
}
void MainWindow::offProjCheckBoxStateChangedSlot( int state )
{
offProjBtn->setEnabled( state );
}
void MainWindow::offProjConfigBtnClickedSlot( bool state )
{
Q_UNUSED( state );
gis_gui_get_projection_parameters( &proj_params, this );
}
void MainWindow::mapStyleChangedSlot()
{
QComboBox *map_style_combobox = qobject_cast<QComboBox*>( sender() );
QTreeWidgetItem *item = NULL;
for ( int idx = 0; idx < mapTreeListWgt->topLevelItemCount(); ++idx )
{
item = mapTreeListWgt->topLevelItem( idx );
if ( map_style_combobox == qobject_cast<QComboBox*>( mapTreeListWgt->itemWidget( item, COLUMN_STYLE_NAME ) ) )
{
break;
}
}
if ( item == NULL )
return;
item->setCheckState( COLUMN_IS_MAP_CONVERTED, Qt::Checked );
}
void MainWindow::addWidgetView()
{
mapTreeListWgt->setColumnCount( COLUMN_COUNT );
mapTreeListWgt->setHeaderLabels(
QStringList() << "#" << " " << tr("Map") << tr("Map style") << tr("Scale") << tr("Type") );
mapTreeListWgt->setColumnWidth( COLUMN_IDX, 50 );
mapTreeListWgt->setColumnWidth( COLUMN_IS_MAP_CONVERTED, 50 );
#if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0))
mapTreeListWgt->header()->setResizeMode( QHeaderView::ResizeToContents );
#else
mapTreeListWgt->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
#endif
for ( int i = 0; i < map_uidx; ++i )
{
QTreeWidgetItem *item = new QTreeWidgetItem( mapTreeListWgt );
item->setText( COLUMN_IDX, QString::number(i) );
MapEntry &map = map_list[i];
if ( map.dataSource == GIS_CORE_MAP_DATA_SOURCE_S57 )
{
MapFormatStrings &s57_format = format_string[GIS_CORE_MAP_DATA_SOURCE_S57];
QString map_name_filter = map.name;
map_name_filter.replace( ".000", ".*" );
QRegularExpression files_ext_filter_rx( "\\A.*\\.{1}[0-9][0-9][0-9]" );
QString working_dir = s57_format.cacheFolder;
QString hidden_dir = s57_format.cacheFolder + S57MapComboBox::UNUSED_DIR_NAME;
QStringList s57_map_name_files = QDir( working_dir ).entryList( { map_name_filter }, QDir::Files );
QStringList s57_map_files = s57_map_name_files.filter( files_ext_filter_rx );
QStringList s57_map_update_files_hidden = QDir( hidden_dir ).entryList( { map_name_filter }, QDir::Files );
if ( s57_map_files.size() > 1 || s57_map_update_files_hidden.size() > 0 )
{
S57MapComboBox *interactive_map_name = new S57MapComboBox( working_dir,
s57_map_files,
s57_map_update_files_hidden );
mapTreeListWgt->setItemWidget( item, COLUMN_MAP_NAME, interactive_map_name );
}
else
item->setText( COLUMN_MAP_NAME, map.name );
}
else
item->setText( COLUMN_MAP_NAME, map.name );
item->setText( COLUMN_MAP_SCALE, QString::number(map.scale) );
item->setText( COLUMN_MAP_DATA_SOURCE, gis_helper_get_core_data_source_name( map.dataSource ) );
QComboBox *map_style_combobox = new QComboBox;
map_style_combobox->addItems( mapStyleGCMList );
map_style_combobox->setCurrentIndex( map.style_uidx );
if ( map.dataSource == GIS_CORE_MAP_DATA_SOURCE_S57 )
map_style_combobox->setEnabled( false );
connect( map_style_combobox, SIGNAL( currentIndexChanged(int) ),
this, SLOT( mapStyleChangedSlot() ) );
mapTreeListWgt->setItemWidget( item, COLUMN_STYLE_NAME, map_style_combobox );
item->setFlags( item->flags() | Qt::ItemIsUserCheckable );
if ( map.isConverted )
item->setCheckState( COLUMN_IS_MAP_CONVERTED, Qt::Checked );
else
item->setCheckState( COLUMN_IS_MAP_CONVERTED, Qt::Unchecked );
mapTreeListWgt->addTopLevelItem( item );
}
}
void MainWindow::updateWidgetView()
{
for ( int i = 0; i < map_uidx; ++i )
{
QTreeWidgetItem *item = mapTreeListWgt->topLevelItem( i );
MapEntry &map = map_list[i];
item->setCheckState( COLUMN_IS_MAP_CONVERTED, map.isConverted ? Qt::Checked : Qt::Unchecked );
QComboBox *map_style_combobox = qobject_cast<QComboBox*>( mapTreeListWgt->itemWidget( item, COLUMN_STYLE_NAME ) );
map_style_combobox->clear();
map_style_combobox->addItems( mapStyleGCMList );
map_style_combobox->setCurrentIndex( map.style_uidx );
item->setText( COLUMN_MAP_SCALE, QString::number( map.scale ) );
item->setText( COLUMN_MAP_DATA_SOURCE, gis_helper_get_core_data_source_name( map.dataSource ) );
}
}
void MainWindow::taskExecutedSlot( void )
{
++processing_idx;
conversionBar->setValue( processing_idx * deltaProgress );
if ( processing_idx >= taskCount )
{
conversionBar->setValue( 100 );
}
}
void MainWindow::executeTasks( QVector<ConversionTask> &tasks )
{
if ( tasks.size() == 0 )
{
qDebug() << "No tasks";
}
else
{
deltaProgress = 100.0 / (tasks.size() + 1);
processing_idx = 0;
taskCount = tasks.size();
conversionBar->setValue( 0 );
QThreadPool *threadPool = QThreadPool::globalInstance();
threadPool->setMaxThreadCount( _syspage_ptr->num_cpu );
qDebug() << "Processing through" << _syspage_ptr->num_cpu << "threads";
foreach ( ConversionTask task, tasks )
{
static uint64_t g_taskId = 0;
qDebug() << "Task #" << g_taskId << " " << gis_helper_get_core_data_source_name( task.m_dataSource );
switch( task.m_type )
{
case ConversionTask::TASK_CONVERT:
{
const char *gis_root = gis_helper_env_get_gis_root_directory();
QString program = QString( gis_root ) + "/" + format_string[task.m_dataSource].converterName;
QStringList arguments;
arguments << "-m" << task.m_srcMapFilepath;
if ( !task.m_styleFilepath.isEmpty() )
arguments << "-r" << task.m_styleFilepath;
arguments << "-o" << task.m_gcmFilepath;
arguments << "-f";
if ( offProjEnChk->checkState() == Qt::Checked )
{
char buffer[GIS_MAX_PATH_LENGTH];
gishelper_math_encode_proj_string( &proj_params, buffer );
arguments << "-c" << QString::fromLatin1( buffer );
}
qDebug() << "Program" << program << "Convert" << arguments;
ConversionTaskWork *work = new ConversionTaskWork( program, arguments, g_taskId );
connect( work, SIGNAL( taskExecutedSignal( void ) ), this, SLOT( taskExecutedSlot( void ) ) );
threadPool->start( work );
break;
}
case ConversionTask::TASK_REMOVE:
{
qDebug() << "Remove" << task.m_gcmFilepath;
QFile gcmFile( task.m_gcmFilepath );
gcmFile.remove();
taskExecutedSlot();
break;
}
default:
{
taskExecutedSlot();
break;
}
}
++g_taskId;
}
while ( 1 )
{
if ( threadPool->waitForDone( 100 ) )
break;
QCoreApplication::processEvents();
}
qDebug() << "Done!";
gis_core_request_update_cache( &connection, GIS_CORE_DRIVERS_ALL, GIS_CORE_UPDATE_CACHE_MODE_SOFT_UPDATE );
}
}
void MainWindow::filterConfigBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
QString program = QString( gis_helper_env_get_gis_root_directory() ) +
"/" + QString( GIS_EXEC_PATH_FILTER_GENERATOR );
classFilterProcess = new QProcess( this );
connect( classFilterProcess, SIGNAL( finished( int,QProcess::ExitStatus ) ),
this, SLOT(classFilterExitCodeParser( int,QProcess::ExitStatus ) ) );
classFilterProcess->setProcessChannelMode( QProcess::ForwardedChannels );
QPoint pos = this->mapToGlobal( QPoint( 0,0 ) );
classFilterProcess->start( program, { "-x" + QString::number( pos.x() ),
"-y" + QString::number( pos.y() ) } );
}
void MainWindow::classFilterExitCodeParser( int exitCode, QProcess::ExitStatus status )
{
Q_UNUSED( status );
qDebug() << "Result: " << QString::number( exitCode );
if ( exitCode > 0 )
recacheAllBtnClicked( false );
}
void MainWindow::recacheAllBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
QVector<ConversionTask> tasks;
for ( int i = 0; i < map_uidx; i++ )
{
QTreeWidgetItem *item = mapTreeListWgt->topLevelItem( i );
MapEntry &map = map_list[i];
auto ds = map.dataSource;
bool need_to_convert = item->checkState( COLUMN_IS_MAP_CONVERTED ) == Qt::Checked;
QString styleName = ( (QComboBox *)mapTreeListWgt->itemWidget( item, COLUMN_STYLE_NAME ) )->currentText();
int style_idx = mapStyleGCMList.indexOf( styleName );
QString map_path = format_string[ds].cacheFolder + "/" + map.name;
QString classificator_path;
if ( style_idx != 0 )
classificator_path = mapsCachePath + GCM_SUFFIX + "/" + mapStyleGCMList[style_idx];
QString gcm_map_path = mapsCachePath + GCM_SUFFIX +
"/" + ( map.gcm_name.isEmpty() ? map.name + ".local.gcm" : map.gcm_name );
ConversionTask task_remove( map_path, classificator_path, gcm_map_path, ConversionTask::TASK_REMOVE, ds );
ConversionTask task_convert( map_path, classificator_path, gcm_map_path, ConversionTask::TASK_CONVERT, ds );
if ( need_to_convert )
{
tasks << task_remove;
tasks << task_convert;
}
else
{
if ( map.isConverted )
{
tasks << task_remove;
}
}
}
executeTasks( tasks );
updateFilesList();
updateExternalState();
updateWidgetView();
}
void MainWindow::applyBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
QVector<ConversionTask> tasks;
for ( int i = 0; i < map_uidx; i++ )
{
QTreeWidgetItem *item = mapTreeListWgt->topLevelItem( i );
MapEntry &map = map_list[i];
bool need_to_convert = item->checkState( COLUMN_IS_MAP_CONVERTED ) == Qt::Checked;
int styleIndex = ( (QComboBox *)mapTreeListWgt->itemWidget( item, COLUMN_STYLE_NAME ) )->currentIndex();
gis_core_map_data_source_t ds = map.dataSource;
QString srcMapPath = format_string[ds].cacheFolder + "/" + map.name;
QString stylePathStr;
if ( styleIndex != 0 )
stylePathStr = mapsCachePath + GCM_SUFFIX + "/" + mapStyleGCMList[styleIndex];
QString outPath = mapsCachePath + GCM_SUFFIX +
"/" + ( map.gcm_name.isEmpty() ? ( map.name + ".local.gcm" ) : map.gcm_name );
int type = ConversionTask::TASK_NONE;
if ( need_to_convert )
{
if ( styleIndex != map.style_uidx )
{
type = ConversionTask::TASK_CONVERT;
}
if ( map.dataSource == GIS_CORE_MAP_DATA_SOURCE_S57 )
{
S57MapComboBox *map_updates_cb = qobject_cast<S57MapComboBox*>(
mapTreeListWgt->itemWidget( item, COLUMN_MAP_NAME ) );
if ( map_updates_cb )
{
QString update_filename = map_updates_cb->currentText();
QString extension = update_filename.remove( 0, update_filename.lastIndexOf( '.' ) + 1 );
if ( extension != map.update )
{
type = ConversionTask::TASK_CONVERT;
}
}
}
}
else
{
if ( map.isConverted )
{
type = ConversionTask::TASK_REMOVE;
}
}
ConversionTask task( srcMapPath, stylePathStr, outPath, type, ds );
tasks << task;
}
executeTasks( tasks );
qDebug() << "apply";
updateFilesList();
qDebug() << "updateFilesList() \t- done";
updateExternalState();
qDebug() << "updateExternalState() \t- done";
updateWidgetView();
qDebug() << "updateWidgetView() \t- done";
}
S57MapComboBox::S57MapComboBox( QString s57_cache_folder,
QStringList map_files_list,
QStringList update_files_list_hidden,
QWidget *parent ) :
QComboBox( parent ),
m_working_dir( s57_cache_folder ),
m_hidden_files_list( update_files_list_hidden )
{
m_unused_upd_files_dir = new QDir( m_working_dir + S57MapComboBox::UNUSED_DIR_NAME );
if ( !m_unused_upd_files_dir->exists() )
m_unused_upd_files_dir->mkdir( m_working_dir );
if ( !m_unused_upd_files_dir->exists() )
{
qDebug() << "S57MapUpdateFilesDialog: Failed to create dir: " <<
m_unused_upd_files_dir->absolutePath();
return;
}
m_all_files_list.append( map_files_list );
m_all_files_list.append( update_files_list_hidden );
m_all_files_list.sort();
addItems( m_all_files_list );
connect( this, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( updateFileMove( int ) ) );
setCurrentIndex( findText( map_files_list.back() ) );
}
S57MapComboBox::~S57MapComboBox()
{
delete m_unused_upd_files_dir;
}
void S57MapComboBox::updateFileMove( int curr_idx )
{
for ( int idx = 1; idx < this->count(); ++idx )
{
QString filename = this->itemText( idx );
QString filepath = m_working_dir + "/" + filename;
QString hidden_filepath = m_unused_upd_files_dir->absolutePath() + "/" + filename;
if ( idx <= curr_idx && m_hidden_files_list.contains( filename ) )
{
QFile( hidden_filepath ).rename( filepath );
m_hidden_files_list.removeAll( filename );
}
else if ( idx > curr_idx && !m_hidden_files_list.contains( filename ) )
{
QFile( filepath ).rename( hidden_filepath );
m_hidden_files_list.append( filename );
}
}
}

293
src/apps/gis-map-linker/mainwindow.h Обычный файл
Просмотреть файл

@ -0,0 +1,293 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <csignal>
#include <QDir>
#include <QFile>
#include <QLabel>
#include <QComboBox>
#include <QPointer>
#include <QProcess>
#include <QMouseEvent>
#include <QThreadPool>
#include <QApplication>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QCoreApplication>
#include <QHBoxLayout>
#include <QMainWindow>
#include <QProgressBar>
#include <QPushButton>
#include <QTreeWidget>
#include <QDebug>
#include <gis/gishelper.h>
#define SXF_LINKER_PREFIX "[sxf_linker] "
struct CleanExit
{
CleanExit()
{
signal(SIGINT, &CleanExit::exitQt);
signal(SIGTERM, &CleanExit::exitQt);
}
static void exitQt( int sig )
{
Q_UNUSED(sig);
QCoreApplication::quit();
}
};
struct MapState
{
int gcmIdx;
bool isConverted;
int styleIndex;
uint32_t scale;
gis_core_map_data_source_t dataSource;
};
struct MapFormatStrings
{
gis_core_map_data_source_t dataSource;
QString converterName;
QString cacheFolder;
QString suffix;
QString src_extension;
};
struct MapEntry
{
bool isConverted;
QString name;
QString gcm_name;
QString update;
int style_uidx;
uint32_t scale;
gis_core_map_data_source_t dataSource;
};
struct StyleEntry
{
QString name;
};
struct ConversionTask
{
public:
ConversionTask()
{
m_srcMapFilepath = "";
m_styleFilepath = "";
m_gcmFilepath = "";
m_dataSource = GIS_CORE_MAP_DATA_SOURCE_NONE;
m_type = TASK_NONE;
}
ConversionTask( QString map_path,
QString classificator_path,
QString gcm_map_path,
int type,
gis_core_map_data_source_t dataSource ):
m_srcMapFilepath( map_path ),
m_styleFilepath( classificator_path ),
m_gcmFilepath( gcm_map_path ),
m_type( type ),
m_dataSource( dataSource )
{}
ConversionTask( const ConversionTask &task )
{
Copy( task );
}
ConversionTask &operator =( const ConversionTask &task )
{
Copy( task );
return *this;
}
QString m_srcMapFilepath;
QString m_styleFilepath;
QString m_gcmFilepath;
gis_core_map_data_source_t m_dataSource;
enum {
TASK_NONE,
TASK_CONVERT,
TASK_REMOVE
};
int m_type;
private:
void Copy( const ConversionTask &task )
{
m_srcMapFilepath = task.m_srcMapFilepath;
m_styleFilepath = task.m_styleFilepath;
m_gcmFilepath = task.m_gcmFilepath;
m_dataSource = task.m_dataSource;
m_type = task.m_type;
}
};
class ConversionTaskWork : public QObject, public QRunnable
{
QString m_prog;
QStringList m_args;
uint64_t m_id;
Q_OBJECT
public:
ConversionTaskWork( QString prog, QStringList args, uint64_t taskId, QObject *parent = nullptr ) :
QObject( parent ), m_prog( prog ), m_args( args ), m_id( taskId )
{}
void run()
{
QProcess *myProcess = new QProcess();
myProcess->setProcessChannelMode( QProcess::SeparateChannels );
int ret = myProcess->execute( m_prog, m_args );
delete myProcess;
qDebug() << "Result #" << m_id << ": " << QString::number( ret );
emit taskExecutedSignal();
}
signals:
void taskExecutedSignal( void );
};
class S57MapComboBox : public QComboBox
{
Q_OBJECT
public:
S57MapComboBox( QString s57_cache_folder,
QStringList map_files_list,
QStringList update_files_list_hidden,
QWidget *parent = 0 );
~S57MapComboBox();
static QString UNUSED_DIR_NAME;
private:
QDir *m_unused_upd_files_dir;
QString m_working_dir;
QStringList m_all_files_list;
QStringList m_hidden_files_list;
private slots:
void updateFileMove( int sender_box_state );
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0 );
~MainWindow();
static int CHECKBOX_SIZE;
public slots:
void taskExecutedSlot();
private:
QMap<gis_core_map_data_source_t, MapFormatStrings> format_string;
int map_uidx;
int style_uidx;
QMap<int, MapEntry> map_list;
QMap<int, StyleEntry> style_list;
QString mapsCachePath;
gis_core_connection_t connection;
gis_map_projection_t proj_params;
QProcess *classFilterProcess;
QPushButton *offProjBtn;
QCheckBox *offProjEnChk;
QStringList mapStyleGCMList;
QStringList mapGCMList;
QPushButton *applyButton;
QPushButton *recacheAllBtn;
QPushButton *filterConfigBtn;
QProgressBar *conversionBar;
QWidget *controlWgt;
QHBoxLayout *controlLayout;
QTreeWidget *mapTreeListWgt;
int processing_idx;
double deltaProgress;
int taskCount;
protected:
void addWidgetView();
void updateWidgetView();
void updateFilesList();
void updateExternalState();
void executeTasks(QVector<ConversionTask> &tasks);
signals:
private slots:
void offProjConfigBtnClickedSlot(bool state);
void offProjCheckBoxStateChangedSlot(int state);
void filterConfigBtnClicked(bool clicked);
void recacheAllBtnClicked(bool clicked);
void mapStyleChangedSlot();
void applyBtnClicked( bool clicked );
void classFilterExitCodeParser(int,QProcess::ExitStatus);
};
#endif

6
src/apps/gis-map-linker/translations.qrc Обычный файл
Просмотреть файл

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>translations/gis-map-linker_ru.ts</file>
<file>translations/gis-map-linker_ru.qm</file>
</qresource>
</RCC>

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>MainWindow</name>
<message>
<source>Configuration</source>
<translation>Настройка</translation>
</message>
<message>
<source>Enabled</source>
<translation>Задействовать</translation>
</message>
<message>
<source>Offline projection</source>
<translation>Офлайн проецирование</translation>
</message>
<message>
<source>Apply</source>
<translation>Применить</translation>
</message>
<message>
<source>Recache</source>
<translation>Обновить кэш</translation>
</message>
<message>
<source>Filter Config</source>
<translation>Настройка фильтра</translation>
</message>
<message>
<source>Scale</source>
<translation>Масштаб</translation>
</message>
<message>
<source>Map</source>
<translation>Карта</translation>
</message>
<message>
<source>Map style</source>
<translation>Классификатор</translation>
</message>
<message>
<source>Type</source>
<translation>Тип</translation>
</message>
<message>
<source>Map Configurator</source>
<translation>Редактор связей карт и стилей</translation>
</message>
</context>
</TS>

87
src/apps/gis-map-viewer/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,87 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-map-viewer LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -Wno-ignored-attributes )
add_compile_options( -Wno-deprecated-declarations )
if( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm" )
add_compile_options( -Wno-psabi )
endif()
find_package( Qt5
COMPONENTS
Core
Gui
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/configuration/*.conf
userdialog.ui
resources.qrc
translations.qrc )
add_executable( gis-map-viewer ${SOURCES} )
add_custom_command( OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-map-viewer_ru.qm
COMMAND
$ENV{KPDA_HOST}/usr/lib/Qt/bin/lrelease -silent ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts )
add_custom_target( generate_translations_map_viewer
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-map-viewer_ru.qm )
target_include_directories( gis-map-viewer
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gisrender/api/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/surfacemanager/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} )
add_dependencies( gis-map-viewer generate_translations_map_viewer )
target_link_libraries( gis-map-viewer
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
gishelper
gisrender
surfacemanager )
install( TARGETS gis-map-viewer
RUNTIME DESTINATION bin )
install( FILES configuration/gis-map-viewer.conf DESTINATION data/config )

16
src/apps/gis-map-viewer/README.md Обычный файл
Просмотреть файл

@ -0,0 +1,16 @@
Утилита для просмотра визуальной картографической информации.
Описание:
Предназначена для отображения картографической информации и демонстрации возможностей API КПО ГИС . Программа позволяет управлять типами отображаемой информации, параметрами отображения и взаимодействовать с картографическим ядром.
Структура:
* distancemeter.(cpp/h) Виджет, предоставляющий интерфейс измерений длин и площадей.
* heightscale.(cpp/h) Визуализация растровой палитры.
* layerwindow.(cpp/h) Интерфейс управления слоями движка рендеринга.
* mainwindow.(cpp/h) Главное окно программы просмотра картографической информации.
* mapstylelayerwindow.(cpp/h) Интерфейс управления слоями карты.
* mapwidget.(cpp/h) Виджет, предоставляющий интерфейс для работы с картографическим пакетом.
* objectinfo.(cpp/h) Виджет, отображающий сведения о выбранном объекте.
* userdialog.(cpp/h) Интерфейс создания пользовательских объектов.
* viewparameters.(cpp/h) Виджет, предоставляющий интерфейс настройки яркости и контрастности отображения.

Двоичные данные
src/apps/gis-map-viewer/asserts/view.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 406 KiB

Просмотреть файл

@ -0,0 +1,34 @@
[InterfaceParameters]
buttonBorderOffset=16
iconSideSizePx=32
maxHeight=2106
maxWidth=1910
minHeight=400
minWidth=400
objectSearchSideSizePx=100
[MainWindow]
window_x=0
window_y=0
width=800
height=644
lastOpenedTabIndex=0
oneMapMode=true
sharedMemoryUserId=777
[MapDisplayParameters]
brightness=0
contrast=0
invalidRasterHeightColor=0x00FF0000
maximumRasterHeightMeters=1666
minimumRasterHeightMeters=0
[MapWidget]
scales=20000000, 10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000, 50000, 25000, 10000, 5000, 2000
size=2
[SurfaceManager]
allocInRam=false
blitRegionRate=0.5
offscreenExtension=500
smMode=0

150
src/apps/gis-map-viewer/deptheditor.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,150 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "deptheditor.h"
DepthEditor::DepthEditor( QWidget *parent ) :
QDialog( parent )
{
setWindowTitle( tr( "Depth Editor" ) );
vlayout = new QVBoxLayout();
shallow_contour_lay = new QHBoxLayout();
safety_contour_lay = new QHBoxLayout();
safety_depth_lay = new QHBoxLayout();
deep_contour_lay = new QHBoxLayout();
two_color_depth_lay = new QHBoxLayout();
shallow_pattern_lay = new QHBoxLayout();
buttons_lay = new QHBoxLayout();
double *s57_SFD{new double};
double *s57_SHC{new double};
double *s57_SFC{new double};
double *s57_DPC{new double};
bool *s57_two_shades{new bool};
bool *s57_shallow_pattern{new bool};
gis_map_style_get_SEABED( s57_SFD, s57_SHC, s57_SFC, s57_DPC, s57_two_shades, s57_shallow_pattern );
initSpinBox( shallow_contour_spinbox, *s57_SHC );
shallow_contour_lay->addWidget( new QLabel( tr( "Shallow Contour" ) ) );
shallow_contour_lay->addWidget( shallow_contour_spinbox );
initSpinBox( safety_contour_spinbox, *s57_SFC );
safety_contour_lay->addWidget( new QLabel( tr( "Safety Contour" ) ) );
safety_contour_lay->addWidget( safety_contour_spinbox );
initSpinBox( safety_depth_spinbox, *s57_SFD );
safety_depth_lay->addWidget( new QLabel( tr( "Safety Depth" ) ) );
safety_depth_lay->addWidget( safety_depth_spinbox );
initSpinBox( deep_contour_spinbox, *s57_DPC );
deep_contour_lay->addWidget( new QLabel( tr( "Deep Contour" ) ) );
deep_contour_lay->addWidget( deep_contour_spinbox );
initCheckBox( two_color_depth_chkbox, *s57_two_shades );
two_color_depth_lay->addWidget( new QLabel( tr( "Use Two Color Depth" ) ) );
two_color_depth_lay->addWidget( two_color_depth_chkbox );
initCheckBox( shallow_pattern_chkbox, *s57_shallow_pattern );
shallow_pattern_lay->addWidget( new QLabel( tr( "Use Shallow Pattern" ) ) );
shallow_pattern_lay->addWidget( shallow_pattern_chkbox );
accept_btn = new QPushButton( tr( "Accept" ) );
connect( accept_btn, SIGNAL( released() ),
this, SLOT( acceptAndChange() ) );
cancel_btn = new QPushButton( tr( "Cancel" ) );
connect( cancel_btn, SIGNAL( released() ),
this, SLOT( close() ) );
buttons_lay->addWidget( accept_btn );
buttons_lay->addWidget( cancel_btn );
vlayout->addLayout( shallow_contour_lay );
vlayout->addLayout( safety_contour_lay );
vlayout->addLayout( safety_depth_lay );
vlayout->addLayout( deep_contour_lay );
vlayout->addLayout( two_color_depth_lay );
vlayout->addLayout( shallow_pattern_lay );
vlayout->addLayout( buttons_lay );
setLayout( vlayout );
delete s57_SFD;
delete s57_SHC;
delete s57_SFC;
delete s57_DPC;
delete s57_two_shades;
delete s57_shallow_pattern;
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
void DepthEditor::showEvent( QShowEvent *event )
{
if ( parentWidget() )
{
int x = ( parentWidget()->width() - ( 15 + sizeHint().width() ) );
int y = ( parentWidget()->height() - sizeHint().height() ) / 2;
QPoint relative_pos = parentWidget()->mapToGlobal( QPoint( x, y ) );
QWidget::move( relative_pos );
}
else
qDebug() << "DepthEditor: can't get pointer to parent Widget!";
event->accept();
}
void DepthEditor::initSpinBox( QDoubleSpinBox *&spin_box, double value )
{
spin_box = new QDoubleSpinBox();
spin_box->setRange( 0, 50000 );
spin_box->setSingleStep( 1 );
spin_box->setDecimals( 2 );
spin_box->setValue( value );
spin_box->adjustSize();
spin_box->setFixedSize( spin_box->size() );
}
void DepthEditor::initCheckBox( QCheckBox *&check_box, bool value )
{
check_box = new QCheckBox();
check_box->setStyleSheet( "QCheckBox::indicator{ width:20px; height: 20px; subcontrol-position: right; }" );
check_box->setChecked( value );
}
void DepthEditor::acceptAndChange()
{
gis_map_style_set_SEABED( safety_depth_spinbox->value(),
shallow_contour_spinbox->value(),
safety_contour_spinbox->value(),
deep_contour_spinbox->value(),
two_color_depth_chkbox->isChecked(),
shallow_pattern_chkbox->isChecked() );
accept();
}

76
src/apps/gis-map-viewer/deptheditor.h Обычный файл
Просмотреть файл

@ -0,0 +1,76 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef DEPTHEDITOR_H
#define DEPTHEDITOR_H
#include <QDebug>
#include <QLabel>
#include <QDialog>
#include <QCheckBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QShowEvent>
#include <QDoubleSpinBox>
#include <gis/gishelper.h>
class DepthEditor : public QDialog
{
Q_OBJECT
public:
explicit DepthEditor( QWidget *parent = nullptr );
private:
QVBoxLayout *vlayout;
QHBoxLayout *shallow_contour_lay;
QHBoxLayout *safety_contour_lay;
QHBoxLayout *safety_depth_lay;
QHBoxLayout *deep_contour_lay;
QHBoxLayout *two_color_depth_lay;
QHBoxLayout *shallow_pattern_lay;
QHBoxLayout *buttons_lay;
QDoubleSpinBox *shallow_contour_spinbox;
QDoubleSpinBox *safety_contour_spinbox;
QDoubleSpinBox *safety_depth_spinbox;
QDoubleSpinBox *deep_contour_spinbox;
QCheckBox *two_color_depth_chkbox;
QCheckBox *shallow_pattern_chkbox;
QPushButton *accept_btn;
QPushButton *cancel_btn;
void showEvent( QShowEvent *event );
void initSpinBox( QDoubleSpinBox *&spin_box, double value );
void initCheckBox( QCheckBox *&check_box, bool value );
private slots:
void acceptAndChange();
};
#endif

247
src/apps/gis-map-viewer/distancemeter.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,247 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "distancemeter.h"
#include <QDebug>
#include <QGridLayout>
#include <QLabel>
DistanceMeter::DistanceMeter( gis_render_sm_context_t ext_sm_ctx, QWidget *parent ) :
QWidget( parent ),
sm_ctx( ext_sm_ctx ),
meter_line( nullptr ),
contour_first_obj( nullptr ),
firstLineDraw( true )
{
QGridLayout *grid_layout = new QGridLayout();
pointList = new QListWidget();
QLabel *dist_lbl = new QLabel( tr( "Distance (km):" ) );
dist_edit = new QLineEdit();
QLabel *area_lbl = new QLabel( tr( "Area (sq km):" ) );
area_edit = new QLineEdit();
add_btn = new QPushButton( tr( "Add ") );
QPushButton *delete_btn = new QPushButton( tr( "Delete" ) );
QPushButton *reset_btn = new QPushButton( tr( "Reset" ) );
reset_btn->setStyleSheet( "QPushButton {"
"background-color: qradialgradient( cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, "
"radius: 1.35, stop: 0 #FFFFFF, stop: 1 #ad2c23 );"
"color: rgb( 0, 0, 0 );"
"border-radius: 2px;"
"border-width: 1px;"
"border-style: solid;"
"border-color: rgb( 162, 162, 162 );"
"}"
"QPushButton:hover {"
"background-color: #ad463e;"
"}"
"QPushButton:pressed {"
"background-color: #b37c78;"
"}" );
dist_edit->setReadOnly( true );
area_edit->setReadOnly( true );
add_btn->setCheckable( true );
connect( delete_btn, SIGNAL( pressed() ), this, SLOT( slotDeletePnt() ) );
connect( reset_btn, SIGNAL( pressed() ), this, SLOT( slotReset() ) );
grid_layout->addWidget( dist_lbl, 1, 1, 1, 2 );
grid_layout->addWidget( dist_edit, 1, 3, 1, 1 );
grid_layout->addWidget( area_lbl, 2, 1, 1, 2 );
grid_layout->addWidget( area_edit, 2, 3, 1, 1 );
grid_layout->addWidget( pointList, 3, 1, 3, 2 );
grid_layout->addWidget( add_btn, 3, 3, 1, 1 );
grid_layout->addWidget( delete_btn, 4, 3, 1, 1 );
grid_layout->addWidget( reset_btn, 5, 3, 1, 1 );
grid_layout->setHorizontalSpacing( 10 );
grid_layout->setVerticalSpacing( 10 );
setLayout( grid_layout );
setWindowTitle( tr( "Meter" ) );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
void DistanceMeter::createFirstPoint()
{
uint32_t contour_color = 0xF0FF0000;
uint32_t contour_pen_width = 5;
contour_first_obj = gis_render_sm_userdata_add_contour_object( sm_ctx,
degree_vector.data(),
degree_vector.size(),
contour_color,
contour_pen_width );
}
void DistanceMeter::deleteFirstPoint()
{
if ( contour_first_obj != nullptr )
{
gis_render_sm_userdata_delete_contour_object( sm_ctx, contour_first_obj );
contour_first_obj = nullptr;
}
}
void DistanceMeter::slotClickPoint( double_point_t degree_pnt )
{
if ( add_btn->isChecked() )
{
degree_vector.append( degree_pnt );
if ( degree_vector.size() == 1 )
{
createFirstPoint();
}
pointList->addItem( tr("lat:") + QString::number( degree_pnt.y ) +
tr(" lon:") + QString::number( degree_pnt.x ) );
pointList->update();
pointList->setMinimumWidth( pointList->sizeHintForColumn( 0 ) );
pointList->setCurrentItem( pointList->item( pointList->count() - 1 ) );
if ( ( degree_vector.size() >= 2 ) )
{
measureDistance();
}
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
}
void DistanceMeter::slotDeletePnt()
{
add_btn->setChecked( false );
if ( degree_vector.empty() )
{
return;
}
degree_vector.remove( pointList->currentRow() );
delete pointList->currentItem();
pointList->update();
setDistance( 0 );
setArea( 0 );
if ( degree_vector.size() >= 2 )
measureDistance();
else if ( degree_vector.size() == 1 )
{
deleteMeterLine();
firstLineDraw = true;
}
else
{
deleteFirstPoint();
}
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
void DistanceMeter::slotReset()
{
setDistance( 0 );
setArea( 0 );
pointList->clear();
degree_vector.resize( 0 );
add_btn->setChecked( false );
deleteMeterLine();
deleteFirstPoint();
firstLineDraw = true;
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
void DistanceMeter::showEvent( QShowEvent *event )
{
emit widgetVisibilityChanged( true );
event->accept();
}
void DistanceMeter::closeEvent( QCloseEvent *event )
{
slotReset();
emit widgetVisibilityChanged( false );
event->accept();
}
void DistanceMeter::meterListener( QPoint pos )
{
double_point_t degree_pnt;
int32_point_t px_pos = { pos.x(), pos.y() };
gis_render_sm_convert_px2degree( sm_ctx, px_pos, &degree_pnt );
slotClickPoint( degree_pnt );
}
void DistanceMeter::measureDistance()
{
double distance = 0, area = 0, perimeter = 0;
gis_render_sm_calculate_distance( sm_ctx,
degree_vector.data(),
degree_vector.size(),
&distance );
setDistance( distance );
gis_render_sm_calculate_polygon( sm_ctx,
degree_vector.data(),
degree_vector.size(),
&area, &perimeter );
setArea( area );
uint32_t color = 0xF0FF0000;
uint32_t pen_width = 3;
if ( !firstLineDraw )
{
gis_render_sm_userdata_edit_object_points( sm_ctx,
meter_line,
degree_vector.data(),
degree_vector.size() );
}
else
{
meter_line = gis_render_sm_userdata_add_polyline( sm_ctx,
degree_vector.data(),
degree_vector.size(),
color, pen_width, 1 );
firstLineDraw = false;
}
}
void DistanceMeter::deleteMeterLine()
{
if ( meter_line != nullptr )
{
gis_render_sm_userdata_delete_object( sm_ctx, meter_line );
meter_line = nullptr;
}
}

76
src/apps/gis-map-viewer/distancemeter.h Обычный файл
Просмотреть файл

@ -0,0 +1,76 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef DISTANCEMETER_H
#define DISTANCEMETER_H
#include <QCloseEvent>
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QWidget>
#include <gis/gis_math.h>
#include <gis/gis_surfacemanager.h>
class DistanceMeter : public QWidget
{
Q_OBJECT
public:
explicit DistanceMeter( gis_render_sm_context_t ext_sm_ctx, QWidget *parent = 0 );
private:
void closeEvent( QCloseEvent *event );
void showEvent(QShowEvent *event);
void setDistance( double distance ) { dist_edit->setText( QString::number( distance / 1000, 'f', 3 ) ); }
void setArea( double area ) { area_edit->setText( QString::number( area / 1000000, 'f', 3 ) ); }
QVector <double_point_t> degree_vector;
gis_render_sm_context_t sm_ctx;
gis_userobject_t meter_line;
gis_userobject_t contour_first_obj;
QLineEdit *dist_edit;
QLineEdit *area_edit;
QListWidget *pointList;
QPushButton *add_btn;
bool firstLineDraw;
void createFirstPoint();
void deleteFirstPoint();
public slots:
void slotClickPoint(double_point_t );
private slots:
void slotReset();
void slotDeletePnt();
void deleteMeterLine();
void measureDistance();
void meterListener( QPoint pos );
signals:
void updateMapWidget();
void widgetVisibilityChanged(bool);
};
#endif

158
src/apps/gis-map-viewer/heightscale.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,158 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "heightscale.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
HeightScale::HeightScale( QWidget *parent ) :
QWidget( parent, Qt::Window ),
maximal_height( 0 ),
minimal_height( 0 ),
delta( 0 )
{
height_scale = new QTableWidget();
maxEdit = new QLineEdit();
minEdit = new QLineEdit();
QHBoxLayout *hlay1 = new QHBoxLayout();
QHBoxLayout *hlay2 = new QHBoxLayout();
QVBoxLayout *vlay1 = new QVBoxLayout();
QLabel *min_lbl = new QLabel( tr( "Min: " ) );
QLabel *max_lbl = new QLabel( tr( "Max: " ) );
QPushButton *set_btn = new QPushButton( tr( "Set" ) );
connect( set_btn, SIGNAL( released() ), this, SLOT( setHeightValues() ) );
height_scale->setEditTriggers( QAbstractItemView::NoEditTriggers );
height_scale->setShowGrid( false );
height_scale->horizontalHeader()->hide();
height_scale->verticalHeader()->hide();
height_scale->setColumnCount( 2 );
height_scale->setColumnWidth( 1, 50 );
height_scale->setFixedWidth( 120 );
height_scale->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
hlay1->addWidget( max_lbl );
hlay1->addWidget( maxEdit );
hlay2->addWidget( min_lbl );
hlay2->addWidget( minEdit );
vlay1->addWidget( height_scale );
vlay1->addLayout( hlay1 );
vlay1->addLayout( hlay2 );
vlay1->addWidget( set_btn );
setLayout( vlay1 );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
void HeightScale::showEvent( QShowEvent *event )
{
if ( parentWidget() )
{
int x = 10;
int y = ( parentWidget()->height() - sizeHint().height() / 2 ) / 2;
QPoint relative_pos = parentWidget()->mapToGlobal( QPoint( x, y ) );
move( relative_pos );
}
else
qDebug() << "HeightScale: can't get pointer to parent Widget!";
event->accept();
}
void HeightScale::setHeightLimits( double min, double max )
{
if ( min > max )
std::swap( min, max );
minEdit->setText( QString::number( min ) );
maxEdit->setText( QString::number( max ) );
maximal_height = max;
minimal_height = min;
delta = ( maximal_height - minimal_height ) / ( colorMap.size() - 1 );
updateColorScale();
}
void HeightScale::updateColorScale()
{
height_scale->clear();
for ( int i = 0; i < colorMap.size(); i++ )
{
QTableWidgetItem *value_item = new QTableWidgetItem;
QTableWidgetItem *color_item = new QTableWidgetItem;
value_item->setText( QString::number( minimal_height + delta * i, 'f', 1) );
color_item->setBackground( QBrush( QColor( colorMap.at(i) ) ) );
height_scale->setItem( colorMap.size() - i - 1, 0, value_item);
height_scale->setItem( colorMap.size() - i - 1, 1, color_item);
}
}
void HeightScale::updateColorScale( QVector <uint32_t> extColorMap,
double max_height,
double min_height )
{
colorMap = extColorMap;
height_scale->setRowCount( colorMap.size() );
maximal_height = max_height;
minimal_height = min_height;
delta = ( maximal_height - minimal_height ) / colorMap.size();
maxEdit->setText( QString::number(maximal_height) );
minEdit->setText( QString::number(minimal_height) );
updateColorScale();
height_scale->resizeRowsToContents();
height_scale->resizeColumnsToContents();
height_scale->setColumnWidth( 1, 50 );
height_scale->setMaximumWidth( 120 );
height_scale->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setFixedWidth( height_scale->width() );
}
void HeightScale::setHeightValues()
{
maximal_height = maxEdit->text().toDouble();
minimal_height = minEdit->text().toDouble();
setHeightLimits( maximal_height, minimal_height );
updateColorScale();
emit limitsChanged( maximal_height, minimal_height );
}

63
src/apps/gis-map-viewer/heightscale.h Обычный файл
Просмотреть файл

@ -0,0 +1,63 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef HEIGHTSCALE_H
#define HEIGHTSCALE_H
#include <QTableWidget>
#include <QWidget>
#include <QShowEvent>
class HeightScale : public QWidget
{
Q_OBJECT
public:
explicit HeightScale( QWidget *parent = 0 );
double getMinHeight() { return minimal_height; }
double getMaxHeight() { return maximal_height; }
void setHeightLimits( double min, double max );
void updateColorScale( QVector <uint32_t> colorMap, double min, double max );
private:
QVector <uint32_t> colorMap;
double minimal_height;
double maximal_height;
double delta;
QTableWidget *height_scale;
QLineEdit *minEdit;
QLineEdit *maxEdit;
void updateColorScale();
void showEvent( QShowEvent *event );
signals:
void limitsChanged( double max, double min );
void minHeight( double );
void maxHeight( double );
public slots:
void setHeightValues();
};
#endif

Двоичные данные
src/apps/gis-map-viewer/icons/pin.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 13 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/ruler.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/save_pin.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 13 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/shutdown.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.2 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/swd_logo.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/undo.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.1 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/zoomin50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Двоичные данные
src/apps/gis-map-viewer/icons/zoomout50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1021 B

459
src/apps/gis-map-viewer/layerwindow.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,459 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "layerwindow.h"
#include <QApplication>
#include <algorithm>
#define RASTER_TABLE_ROW 0
#define VECTOR_TABLE_ROW 1
#define USER_TABLE_ROW 2
int LayerWindow::CHECKBOX_SIZE = 25;
int LayerHeaderWithWidgets::PADDING_FOR_WIDGET = 6;
LayerHeaderCheckBox::LayerHeaderCheckBox( int index, const QString &text, QWidget *parent ) :
QCheckBox( text, parent ),
m_row( index )
{
QString style_sheet_str( "QCheckBox::indicator{"
"width: px;"
"height: px;"
"subcontrol-position: left; }" );
style_sheet_str.replace( "width: ", "width: " + QString::number( LayerWindow::CHECKBOX_SIZE ) );
style_sheet_str.replace( "height: ", "height: " + QString::number( LayerWindow::CHECKBOX_SIZE ) );
this->setStyleSheet( style_sheet_str );
connect( this, SIGNAL( stateChanged( int ) ), this, SLOT( doStateChanged( int ) ) );
}
void LayerHeaderWithWidgets::addSectionWidget( int section, QWidget* widget )
{
if ( !widget )
return;
if ( section < 0 || section >= this->count() )
return;
QWidget *old = m_widgets_map[section];
delete old;
m_widgets_map[section] = widget;
widget->setParent( this );
int header_width = this->sizeHint().width();
int widget_width = widget->sizeHint().width();
switch( this->orientation() )
{
case Qt::Orientation::Horizontal:
{
qDebug() << "LayerHeaderWithWidgets: h_header resizing is unsupported!";
break;
}
case Qt::Orientation::Vertical:
{
if ( widget_width > header_width && widget_width > m_max_widget_width )
{
m_max_widget_width = widget_width;
this->setFixedWidth( m_max_widget_width + PADDING_FOR_WIDGET );
}
break;
}
}
fixWidgetPosition( section );
}
QWidget *LayerHeaderWithWidgets::getSectionWidget( int section ) const
{
auto iter = m_widgets_map.find( section );
if ( iter == m_widgets_map.end() )
return nullptr;
return iter->second;
}
int LayerHeaderWithWidgets::getMaxWidthFromWidgets()
{
return m_max_widget_width;
}
void LayerHeaderWithWidgets::showEvent( QShowEvent *e )
{
QHeaderView::showEvent( e );
for ( int s = 0; s < count(); ++s )
{
QWidget* widget = getSectionWidget( s );
if ( !widget )
continue;
fixWidgetPosition( s );
widget->show();
}
}
void LayerHeaderWithWidgets::fixWidgetPosition( int section )
{
QWidget *widget = getSectionWidget( section );
if ( !widget )
return;
switch( this->orientation() )
{
case Qt::Orientation::Horizontal:
{
widget->setGeometry( sectionViewportPosition( section ) + PADDING_FOR_WIDGET / 2,
0,
sectionSize( section ) - PADDING_FOR_WIDGET, height() );
break;
}
case Qt::Orientation::Vertical:
{
widget->setGeometry( PADDING_FOR_WIDGET / 2,
sectionViewportPosition( section ),
width() - 4, sectionSize( section ) );
break;
}
}
}
void LayerWindow::fillTableRow( std::vector<format_info_t> &formats, int row )
{
for ( uint i = 0; i < formats.size(); ++i )
{
QTableWidgetItem *item = new QTableWidgetItem();
item->setText( formats.at(i).format_acronym );
item->setTextAlignment( Qt::AlignLeft | Qt::AlignVCenter );
item->setFlags( item->flags() | Qt::ItemIsUserCheckable );
item->setCheckState( Qt::Unchecked );
this->setItem( row, i, item );
}
}
void LayerWindow::fillVerticalHeader( QStringList header_text_list )
{
if ( !v_header )
return;
for ( int i = 0; i < header_text_list.size(); ++i )
{
auto *v_header_box = new LayerHeaderCheckBox( i, header_text_list.at( i ) );
connect( v_header_box, SIGNAL( layerBoxStateChanged( int, int ) ),
this, SLOT( slotSetNewStateAll( int, int ) ) );
v_header->addSectionWidget( i, v_header_box );
}
}
LayerWindow::LayerWindow( QWidget *parent ) :
QTableWidget( parent ),
min_width( 0 ),
min_height( 0 )
{
setEditTriggers( QAbstractItemView::NoEditTriggers );
setFocusPolicy( Qt::NoFocus );
setSelectionMode( QAbstractItemView::NoSelection );
uint32_t format_iterator;
GIS_CORE_DRIVER_FOR_LOOP_HEAD( format_iterator )
{
gis_core_map_data_source_t data_source = gis_helper_get_map_source_by_driver_id( (gis_core_driver_id_t)format_iterator );
if ( GIS_IS_CORE_MAP_DATA_SOURCE_VECTOR( data_source ) )
{
vector_formats.push_back( { gis_helper_get_core_data_source_name( data_source ), data_source, true } );
}
else
{
raster_formats.push_back( { gis_helper_get_core_data_source_name( data_source ), data_source, true } );
}
}
setColumnCount( std::max( vector_formats.size(), raster_formats.size() ) );
setRowCount( GIS_RENDER_SM_SURFACE_NUMBER );
QString style_sheet_str( "QTableWidget::item{padding: 5px;}"
"QAbstractItemView::indicator{"
"width: px;"
"height: px;"
"subcontrol-position: left; }" );
style_sheet_str.replace( "width: ", "width: " + QString::number( CHECKBOX_SIZE ) );
style_sheet_str.replace( "height: ", "height: " + QString::number( CHECKBOX_SIZE ) );
this->setStyleSheet( style_sheet_str );
v_header = new LayerHeaderWithWidgets( Qt::Orientation::Vertical, this );
this->setVerticalHeader( v_header );
this->setVerticalHeaderLabels( {"", "", ""} );
h_header = this->horizontalHeader();
fillTableRow( raster_formats, RASTER_TABLE_ROW );
fillTableRow( vector_formats, VECTOR_TABLE_ROW );
this->resizeColumnsToContents();
this->resizeRowsToContents();
int max_col_width = 0;
for( int col = 0; col < this->columnCount(); ++col )
{
h_header->resizeSection( col, h_header->sectionSize( col ) + CHECKBOX_SIZE );
int section_size = h_header->sectionSize( col );
max_col_width = std::max( max_col_width, section_size );
}
for( int col = 0; col < this->columnCount(); ++col )
{
min_width += max_col_width;
setColumnWidth( col, max_col_width );
}
for ( int row = 0; row < this->rowCount(); ++row )
{
v_header->resizeSection( row, v_header->sectionSize( row ) + CHECKBOX_SIZE );
}
fillVerticalHeader( { tr( "Raster maps" ), tr( "Vector maps" ), tr( "User objects" ) } );
min_width += v_header->width() + 2;
min_height += 2;
for ( int row = 0; row < this->rowCount(); ++row )
{
min_height += v_header->sectionSize( row );
}
h_header->setSectionResizeMode( QHeaderView::Fixed );
v_header->setSectionResizeMode( QHeaderView::Fixed );
h_header->hide();
this->setFixedSize( min_width, min_height );
connect( this, SIGNAL( itemChanged( QTableWidgetItem* ) ),
this, SLOT( slotSetNewState( QTableWidgetItem* ) ) );
setWindowTitle( tr( "Surfaces and data formats" ) );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::Window |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
void LayerWindow::showEvent( QShowEvent *event )
{
if ( parentWidget() )
{
int x = ( parentWidget()->width() - width() ) / 2;
int y = ( parentWidget()->height() - height() ) / 2;
QPoint relative_pos = parentWidget()->mapToGlobal( QPoint( x, y ) );
QWidget::move( relative_pos );
}
else
qDebug() << "LayerWindow: can't get pointer to parent Widget!";
event->accept();
}
void LayerWindow::updateStates( QVector <LayerInfo> &layer_list )
{
if ( layer_list.size() != GIS_RENDER_SM_SURFACE_NUMBER )
return;
for ( int i = 0; i < this->rowCount(); ++i )
{
QCheckBox *all_layers_box = qobject_cast<QCheckBox *>( v_header->getSectionWidget( i ) );
if ( layer_list[i].layer_type == GIS_RENDER_SM_LAYER_TYPE_DISABLED )
all_layers_box->setCheckState( Qt::Unchecked );
else
all_layers_box->setCheckState( Qt::Checked );
}
}
void LayerWindow::switch_all_data_sources_for_layer( int row,
std::vector<format_info_t> &all_data_sources )
{
int enabled_data_sources_counter = 0, enabled_data_source_index = 0;
{
for ( uint i = 0; i < all_data_sources.size(); ++i )
{
if ( all_data_sources[i].is_enabled == true )
{
++enabled_data_sources_counter;
enabled_data_source_index = i;
}
}
}
QCheckBox *all_layers_box = qobject_cast<QCheckBox *>( v_header->getSectionWidget( row ) );
if ( enabled_data_sources_counter == 1 && all_layers_box->checkState() == Qt::Checked )
{
item( row, enabled_data_source_index )->setCheckState( Qt::Checked );
}
else
{
for ( uint i = 0; i < all_data_sources.size(); ++i )
{
item( row, i )->setCheckState( all_layers_box->checkState() );
}
}
}
void LayerWindow::set_data_sources_for_layer( std::vector<format_info_t> &all_data_sources,
gis_render_sm_layer_type_t layer_type,
QTableWidgetItem *table_item )
{
int row_idx = ( layer_type == GIS_RENDER_SM_LAYER_TYPE_MTW ) ?
RASTER_TABLE_ROW :
VECTOR_TABLE_ROW;
{
uint counter = 0;
for ( uint i = 0; i < all_data_sources.size(); ++i )
{
if ( all_data_sources[i].is_enabled == false )
++counter;
}
QCheckBox *all_layers_box = qobject_cast<QCheckBox *>( v_header->getSectionWidget( row_idx ) );
if ( counter == all_data_sources.size() &&
all_layers_box->checkState() == Qt::Unchecked )
{
all_data_sources[table_item->column()].is_enabled = true;
all_layers_box->setCheckState( Qt::Checked );
}
}
for ( uint i = 0; i < all_data_sources.size(); ++i )
{
if ( item( row_idx, i )->checkState() == Qt::Checked )
{
picked_data_sources.push_back( all_data_sources[i].format_data_source );
all_data_sources[i].is_enabled = true;
}
}
for ( uint i = 0; i < all_data_sources.size(); ++i )
{
bool match = false;
for ( uint j = 0; j < picked_data_sources.size(); ++j )
{
if ( all_data_sources[i].format_data_source == picked_data_sources[j] )
match = true;
}
if ( match )
all_data_sources[i].is_enabled = true;
else
all_data_sources[i].is_enabled = false;
}
if ( picked_data_sources.size() == 0 )
{
QCheckBox *all_layers_box = qobject_cast<QCheckBox *>( v_header->getSectionWidget( table_item->row() ) );
all_layers_box->setCheckState( Qt::Unchecked );
}
}
void LayerWindow::slotSetNewStateAll( int row, int state )
{
switch ( row )
{
case RASTER_TABLE_ROW:
if ( state == Qt::Unchecked )
emit setLayer( 0, GIS_RENDER_SM_LAYER_TYPE_DISABLED );
else
emit setLayer( 0, GIS_RENDER_SM_LAYER_TYPE_MTW );
switch_all_data_sources_for_layer( RASTER_TABLE_ROW, raster_formats );
break;
case VECTOR_TABLE_ROW:
if ( state == Qt::Unchecked )
emit setLayer( 1, GIS_RENDER_SM_LAYER_TYPE_DISABLED );
else
emit setLayer( 1, GIS_RENDER_SM_LAYER_TYPE_2DMAP );
switch_all_data_sources_for_layer( VECTOR_TABLE_ROW, vector_formats );
break;
case USER_TABLE_ROW:
if ( state == Qt::Unchecked )
emit setLayer( 2, GIS_RENDER_SM_LAYER_TYPE_DISABLED );
else
emit setLayer( 2, GIS_RENDER_SM_LAYER_TYPE_USROBJ );
break;
default:
break;
}
}
void LayerWindow::slotSetNewState( QTableWidgetItem *table_cell_item )
{
picked_data_sources.clear();
switch ( table_cell_item->row() )
{
case RASTER_TABLE_ROW:
set_data_sources_for_layer( raster_formats,
GIS_RENDER_SM_LAYER_TYPE_MTW,
table_cell_item );
emit setDataSourcesForLayer( GIS_RENDER_SM_LAYER_TYPE_MTW,
picked_data_sources.size(),
&picked_data_sources[0] );
break;
case VECTOR_TABLE_ROW:
set_data_sources_for_layer( vector_formats,
GIS_RENDER_SM_LAYER_TYPE_2DMAP,
table_cell_item );
emit setDataSourcesForLayer( GIS_RENDER_SM_LAYER_TYPE_2DMAP,
picked_data_sources.size(),
&picked_data_sources[0] );
break;
default:
break;
}
}

144
src/apps/gis-map-viewer/layerwindow.h Обычный файл
Просмотреть файл

@ -0,0 +1,144 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef LAYERWINDOW_H
#define LAYERWINDOW_H
#include <QTableWidget>
#include <QDebug>
#include <QLabel>
#include <QString>
#include <QCheckBox>
#include <QHeaderView>
#include <QShowEvent>
#include <gis/gis_surfacemanager.h>
struct format_info_t
{
QString format_acronym;
gis_core_map_data_source_t format_data_source;
bool is_enabled;
};
class LayerHeaderCheckBox : public QCheckBox
{
Q_OBJECT
public:
LayerHeaderCheckBox( int index, const QString &text, QWidget *parent = nullptr );
signals:
void layerBoxStateChanged( int row, int state );
private slots:
void doStateChanged( int state )
{
emit layerBoxStateChanged( m_row, state );
}
private:
int m_row;
};
class LayerHeaderWithWidgets : public QHeaderView
{
Q_OBJECT
public:
LayerHeaderWithWidgets( Qt::Orientation orientation, QWidget *parent = nullptr ) :
QHeaderView( orientation, parent ),
m_max_widget_width( 0 )
{}
virtual ~LayerHeaderWithWidgets()
{
m_widgets_map.clear();
}
void addSectionWidget( int section, QWidget* widget );
QWidget *getSectionWidget( int section ) const;
protected:
void showEvent( QShowEvent *e );
int getMaxWidthFromWidgets();
void fixWidgetPosition( int section );
private:
static int PADDING_FOR_WIDGET;
std::map<int, QWidget*> m_widgets_map;
int m_max_widget_width;
};
class LayerWindow : public QTableWidget
{
Q_OBJECT
public:
friend LayerHeaderCheckBox;
friend LayerHeaderWithWidgets;
explicit LayerWindow( QWidget *parent = 0 );
private:
void fillTableRow( std::vector<format_info_t> &formats, int row );
void fillVerticalHeader( QStringList header_text_list );
void showEvent( QShowEvent *event );
void switch_all_data_sources_for_layer( int row, std::vector<format_info_t> &all_data_sources );
void set_data_sources_for_layer( std::vector<format_info_t> &all_data_sources,
gis_render_sm_layer_type_t layer_type,
QTableWidgetItem *table_item );
QHeaderView *h_header;
LayerHeaderWithWidgets *v_header;
int min_width;
int min_height;
static int CHECKBOX_SIZE;
std::vector<format_info_t> vector_formats;
std::vector<format_info_t> raster_formats;
std::vector<gis_core_map_data_source_t> picked_data_sources;
public slots:
void updateStates( QVector<LayerInfo> &layer_list );
private slots:
void slotSetNewState( QTableWidgetItem *it );
void slotSetNewStateAll( int row, int state );
signals:
void changeLayerName();
void changeLayerState();
void setLayer( int, gis_render_sm_layer_type_t );
void setDataSourcesForLayer( gis_render_sm_layer_type_t, int, gis_core_map_data_source_t* );
};
#endif

178
src/apps/gis-map-viewer/main.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,178 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <QTranslator>
#include <QFontDatabase>
#include <QDirIterator>
#include <gis/gis_types.h>
#define MAP_VIEWER_PREFIX ("[gis-map-viewer] ")
int main(int argc, char *argv[])
{
gis_core_driver_id_t enabledDriverId = GIS_CORE_DRIVERS_ALL;
gis_helper_debug_mode_setmask( GIS_DEBUG_MODE_STD | GIS_DEBUG_MODE_FD );
gis_helper_debug_file_setname( "gis-map-viewer.log" );
QString gis_config( gis_helper_env_get_config_directory() );
QSettings settings( gis_config + "gis-map-viewer.conf", QSettings::IniFormat );
bool oneMapMode = settings.value( "MainWindow/oneMapMode" ).toBool();
settings.beginGroup( "MapWidget" );
if ( oneMapMode )
{
QStringList old_map_widgets = settings.childGroups();
for( auto child : old_map_widgets )
{
settings.remove( child );
}
}
int index = settings.childGroups().size();
settings.endGroup();
bool new_map_tab_added = false;
int opt = 0;
extern char *optarg;
while ( (opt = getopt( argc, argv,"X::Y::w::h::x::y::s::D::ti::" ) ) != -1 )
{
switch ( opt )
{
case 'X':
settings.setValue( "MainWindow/window_x", atoi( optarg ) );
break;
case 'Y':
settings.setValue( "MainWindow/window_y", atoi( optarg ) );
break;
case 'w':
settings.setValue( "MainWindow/width", atoi( optarg ) );
break;
case 'h':
settings.setValue( "MainWindow/height", atoi( optarg ) );
break;
case 'x':
settings.beginGroup( "MapWidget" );
settings.beginGroup( QString::number( index ) );
settings.setValue( "longitude", std::strtod( optarg, NULL ) );
settings.endGroup();
settings.endGroup();
new_map_tab_added = true;
break;
case 'y':
settings.beginGroup( "MapWidget" );
settings.beginGroup( QString::number( index ) );
settings.setValue( "latitude", std::strtod( optarg, NULL ) );
settings.endGroup();
settings.endGroup();
new_map_tab_added = true;
break;
case 's':
settings.beginGroup( "MapWidget" );
settings.beginGroup( QString::number( index ) );
settings.setValue( "scaleVectorIndex", atoi( optarg ) );
settings.endGroup();
settings.endGroup();
new_map_tab_added = true;
break;
case 'D':
{
int option_driver_enable = atoi( optarg );
if ( GIS_CORE_DRIVER_ID_CHECK(option_driver_enable) )
{
enabledDriverId = (gis_core_driver_id_t)option_driver_enable;
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_INFO, MAP_VIEWER_PREFIX,
"Current driver id %d is only enabled [%s()]", option_driver_enable, __FUNCTION__ );
}
else
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_WARNING, MAP_VIEWER_PREFIX,
"Invalid driver id %d, all drivers enabled by default [%s()]",
option_driver_enable, __FUNCTION__ );
}
break;
}
case 't':
settings.setValue( "SurfaceManager/allocInRam", true );
break;
case 'i':
settings.setValue( "MainWindow/sharedMemoryUserId", atoi( optarg ) );
break;
case '?':
printf( "Error: unknown option\n" );
exit( 1 );
break;
};
};
if ( new_map_tab_added )
{
settings.setValue( "MainWindow/lastOpenedTabIndex", index );
}
CleanExit cleanExit;
QApplication a( argc, argv );
const char *lang = getenv( "ABLANG" );
QString locale = "en_EN";
if ( lang )
{
locale = QString( lang );
}
QTranslator myTranslator;
myTranslator.load( ":/translations/gis-map-viewer_" + locale );
a.installTranslator( &myTranslator );
MainWindow w;
if ( w.connectGisCore( enabledDriverId ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_WARNING, MAP_VIEWER_PREFIX,
"Conection to gis-core failed. Retry... [%s()]", __FUNCTION__ );
if ( w.connectGisCore( enabledDriverId ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, MAP_VIEWER_PREFIX,
"Conection failed. Exiting... [%s()]", __FUNCTION__ );
exit(1);
}
}
w.createMapWidgets();
w.show();
return a.exec();
}

532
src/apps/gis-map-viewer/mainwindow.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,532 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QGridLayout>
MainWindow::MainWindow( QWidget *parent ) :
QMainWindow(parent)
{
loadSettings();
setGeometry( windowX, windowY, widthPx, heightPx );
tab_wgt = new MapTabWidget( this );
connect( tab_wgt, SIGNAL( firstTabAdded( int ) ), this, SLOT( processTabChanging( int ) ) );
tab_wgt->setDocumentMode( true );
setCentralWidget( tab_wgt );
layer_window = new LayerWindow( this );
connect( layer_window, SIGNAL( setLayer( int,gis_render_sm_layer_type_t ) ),
tab_wgt, SLOT( updateLayerOrder( int,gis_render_sm_layer_type_t ) ) );
connect( layer_window, SIGNAL( setDataSourcesForLayer( gis_render_sm_layer_type_t, int, gis_core_map_data_source_t* ) ),
tab_wgt, SLOT( updateDataSourcesForLayer( gis_render_sm_layer_type_t, int, gis_core_map_data_source_t* ) ) );
mapstyle_layer_window = new MapStyleLayerWindow( this );
connect( mapstyle_layer_window, SIGNAL( updateMapWidget() ),
tab_wgt, SLOT( syncCurrentTab() ) );
view_params = new ViewParameters( this );
connect( view_params, SIGNAL( signalNewBrightnessContrastValues( float, float ) ),
tab_wgt, SLOT( updateBrightnessContrast( float, float ) ) );
height_scale = new HeightScale( this );
connect( height_scale, SIGNAL( limitsChanged( double, double ) ),
this, SLOT( setManualHeightLimits( double, double ) ) );
object_search = new ObjectSearch( this );
setMaximumSize( 1910, 1053 * 2 + menuBar()->height() - 1 - 3 );
fillMenuBar();
setWindowTitle( tr( "Map Viewer" ) );
}
MainWindow::~MainWindow()
{
saveSettings();
gis_core_databuffer_detach();
gis_core_link_destroy( &connection, true );
}
void MainWindow::closeEvent( QCloseEvent *event )
{
tab_wgt->close();
layer_window->close();
mapstyle_layer_window->close();
view_params->close();
height_scale->close();
object_search->close();
depth_editor->close();
event->accept();
}
void MainWindow::loadSettings()
{
QString config_dir( gis_helper_env_get_config_directory() );
QSettings settings( config_dir + "gis-map-viewer.conf", QSettings::IniFormat );
windowX = settings.value( "MainWindow/window_x" ).toInt();
windowY = settings.value( "MainWindow/window_y" ).toInt();
windowX = windowX < 0 ? 0 : windowX;
windowY = windowY < 0 ? 0 : windowY;
widthPx = settings.value( "MainWindow/width" ).toInt();
heightPx = settings.value( "MainWindow/height" ).toInt();
lastOpenedTabIndex = settings.value( "MainWindow/lastOpenedTabIndex" ).toInt();
oneMapMode = settings.value( "MainWindow/oneMapMode" ).toBool();
sharedMemoryUserId = settings.value( "MainWindow/sharedMemoryUserId" ).toInt();
settings.beginGroup( "MapWidget" );
nTabs = settings.childGroups().size();
settings.endGroup();
}
void MainWindow::saveSettings()
{
QString config_dir( gis_helper_env_get_config_directory() );
QSettings settings( config_dir + "gis-map-viewer.conf", QSettings::IniFormat);
settings.setValue( "MainWindow/window_x", x() );
settings.setValue( "MainWindow/window_y", y() );
settings.setValue( "MainWindow/width", width() );
settings.setValue( "MainWindow/height", height() );
settings.setValue( "MainWindow/oneMapMode", oneMapMode );
settings.setValue( "MainWindow/lastOpenedTabIndex", lastOpenedTabIndex );
settings.beginGroup( "MapWidget" );
QStringList old_map_widgets = settings.childGroups();
for( auto child : old_map_widgets )
{
settings.remove( child );
}
settings.endGroup();
}
void MainWindow::fillMenuBar()
{
QMenu *menuMain = new QMenu( tr( "Main" ), this );
QAction *oneMapAction = menuMain->addAction( tr( "Show only one map" ), this, SLOT( flipOneMapMode() ) );
oneMapAction->setCheckable( true );
if( oneMapMode )
oneMapAction->setChecked( true );
menuMain->addSeparator();
menuMain->addAction( tr( "About" ), this, SLOT( showAboutDialog() ) );
menuMain->addAction( tr( "Exit" ), QApplication::instance(), SLOT( quit() ),
QKeySequence( Qt::CTRL | Qt::Key_Q ) );
QMenu *menuView = new QMenu( tr( "View parameters" ), this );
menuView->addAction( tr( "Projections" ), tab_wgt, SLOT( showProjectionDialog() ) );
menuView->addAction( tr( "Screen parameters" ), tab_wgt, SLOT( showScreenParametersDialog() ) );
menuView->addAction( tr( "Layers" ), layer_window, SLOT( show() ) );
menuView->addSeparator();
menuView->addAction( tr( "Brighntess / Contrast" ), view_params, SLOT( show() ) );
scaling_action = new QAction( tr( "New scaling mode" ), this );
scaling_action->setCheckable( true );
connect( scaling_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setConstScalingMode( bool )) );
menuView->addAction( scaling_action );
menuView->addSeparator();
aliasing_action = new QAction( tr( "Aliasing" ), this );
aliasing_action->setCheckable( true );
connect( aliasing_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setAliasingMode( bool )) );
menuView->addAction( aliasing_action );
menuView->addSeparator();
center_scaling_action = new QAction( tr( "Center at cursor" ), this );
center_scaling_action->setCheckable( true );
connect( center_scaling_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setCenterAtCursor( bool ) ) );
menuView->addAction( center_scaling_action );
menuView->addSeparator();
rescale_by_wheel_action = new QAction( tr( "Scale by scroll" ), this );
rescale_by_wheel_action->setCheckable( true );
rescale_by_wheel_action->setChecked( true );
connect( rescale_by_wheel_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setRescaleByWheel( bool ) ) );
menuView->addAction( rescale_by_wheel_action );
menuView->addSeparator();
QMenu *menuVector = new QMenu( tr( "Vector" ), this );
menuPalette = new QMenu( tr( "Palette" ), this );
menuLanguage = new QMenu( tr( "Language" ), this );
menuFormatFeatures = new QMenu( tr( "Format features" ), this );
menuVector->addMenu( menuPalette );
menuVector->addMenu( menuLanguage );
menuVector->addMenu( menuFormatFeatures );
menuView->addMenu( menuVector );
menuView->addSeparator();
QMenu *menuRaster = new QMenu( tr("Raster"), this );
menuRaster->addAction( tr("Raster scale"), height_scale, SLOT( show() ) );
auto_height_action = new QAction( tr( "Auto height mode" ), this );
auto_height_action->setCheckable( true );
connect( auto_height_action, SIGNAL( triggered( bool ) ),
this, SLOT( autoHeightChecked( bool ) ) );
menuRaster->addAction( auto_height_action );
invalid_height_action = new QAction( tr( "Show out of limits height" ), this );
invalid_height_action->setCheckable( true );
connect( invalid_height_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setRasterInvalidHeightMode( bool ) ) );
menuRaster->addAction( invalid_height_action );
palette_action = new QAction( tr( "Discrete palette" ), this );
palette_action->setCheckable( true );
connect( palette_action, SIGNAL( triggered( bool ) ),
tab_wgt, SLOT( setDiscretePaletteEnabled( bool ) ) );
menuRaster->addAction( palette_action );
menuView->addMenu( menuRaster );
menuView->addSeparator();
QMenu *menuTools = new QMenu( tr( "Tools" ), this );
menuTools->addAction( tr( "Refresh" ), this, SLOT( refreshMapData() ), QKeySequence( Qt::Key_F5 ) );
menuTools->addSeparator();
menuTools->addAction( tr( "User objects" ), tab_wgt, SLOT( showUserForm() ) );
menuTools->addAction( tr( "Map ruler" ), tab_wgt, SLOT( showMeter() ) );
QMenu *menuFilter = new QMenu( tr( "Filters" ), this );
menuFilter->addAction( tr( "Map style layers" ), mapstyle_layer_window, SLOT( show()) );
menuFilter->addAction( tr( "Type of primitive" ) )->setVisible( false );
menuFilter->addAction( tr( "Map type" ) )->setVisible( false );
menuTools->addMenu( menuFilter );
menuTools->addAction( tr( "Search" ), object_search, SLOT( show() ) );
menuBar()->addMenu( menuMain );
menuBar()->addMenu( menuView );
menuBar()->addMenu( menuTools );
}
void MainWindow::flipOneMapMode()
{
oneMapMode = !oneMapMode;
int current = lastOpenedTabIndex;
for ( int i = 0; i >= 0 && i < tab_wgt->count(); i++ )
{
MapWidget *map_widget = qobject_cast<MapWidget *>( tab_wgt->widget( i ) );
if ( map_widget->getIndex() == current )
{
continue;
}
tab_wgt->removeTab( i );
map_widget->close();
i--;
}
tab_wgt->currentMapWidget()->setIndex( 0 );
}
void MainWindow::createMapWidgets()
{
int current_from_cfg = lastOpenedTabIndex;
for ( int i = 0; i < nTabs; i++ )
{
tab_wgt->addMapWidget( &connection );
}
connect( tab_wgt, SIGNAL( currentChanged( int ) ),
this, SLOT( processTabChanging( int ) ) );
tab_wgt->setCurrentIndex( current_from_cfg );
}
int MainWindow::connectGisCore( gis_core_driver_id_t enabledDriverId )
{
gis_core_link_init( &connection );
gis_core_request_parameters_t map;
gis_core_request_parameters_init( &map );
if ( enabledDriverId != GIS_CORE_DRIVERS_ALL )
{
gis_core_request_parameters_set_driver( &map, enabledDriverId );
}
sharedMemoryUserId += 100;
qDebug() << QTime::currentTime().toString() << " SHID: " << sharedMemoryUserId;
int result = gis_core_link_connect( &connection, sharedMemoryUserId );
if ( result != EOK && result != EALREADY )
{
qDebug() << QTime::currentTime().toString() << " GIS Core connection failed";
return result;
}
result = gis_core_databuffer_attach( &connection );
if ( result != EOK && result != EALREADY )
{
qDebug() << QTime::currentTime().toString() << " GIS Core draw buffer attach failed";
return result;
}
if ( (result = gis_core_databuffer_data_request( &connection, &map, 1 ) ) != EOK )
{
if ( result != EOVERFLOW )
{
qDebug() << QTime::currentTime().toString() << " GIS Core map draw request failed";
return result;
}
else
{
qDebug() << QTime::currentTime().toString() << " GIS Core map draw request EOVERFLOW";
}
}
return EOK;
}
void MainWindow::refreshMapData()
{
gis_core_request_update_cache( &connection, GIS_CORE_DRIVERS_ALL, GIS_CORE_UPDATE_CACHE_MODE_SOFT_UPDATE );
gis_core_request_parameters_t map;
gis_core_request_parameters_init( &map );
gis_core_databuffer_data_request( &connection, &map, 1 );
emit updateAllDataEngines();
}
void MainWindow::flipLocale()
{
QAction *action = qobject_cast<QAction *>( sender() );
gis_map_style_flip_language( static_cast<gis_map_style_t>( action->data().toInt() ) );
tab_wgt->updateCurrentTabMap();
}
void MainWindow::changePalette()
{
QAction *action = qobject_cast<QAction *>( sender() );
QMenu *menu = qobject_cast<QMenu *>( action->parent() );
auto pair = palettes_map.find( menu->title() );
if ( pair != palettes_map.end() )
{
gis_vector_palette_list_t *palettes = pair->second;
gis_map_style_set_active_palette_idx( palettes, action->data().toInt() );
tab_wgt->updateCurrentTabMap();
}
}
void MainWindow::updateMapStyles( std::vector<ClassifierInfo> &classifier_list )
{
map_style_vector.clear();
for ( auto classifier : classifier_list )
{
gis_core_map_data_source_t map_data_source = classifier.layers.at( 0 ).classes.at( 0 ).class_data.src;
gis_map_style_t map_style = gis_helper_get_map_style_by_data_source( map_data_source );
if ( std::find( map_style_vector.begin(), map_style_vector.end(), map_style ) == map_style_vector.end() )
{
map_style_vector.push_back( map_style );
}
}
updatePaletteMenu( map_style_vector );
updateLanguageMenu( map_style_vector );
updateFormatFeaturesMenu( map_style_vector );
}
void MainWindow::updateFormatFeaturesMenu( std::vector<gis_map_style_t> &mapstyle_list )
{
menuFormatFeatures->clear();
for ( auto map_style : mapstyle_list )
{
const QString &submenu_name = QString::fromLatin1( gis_helper_get_map_style_name( map_style ) );
QMenu *submenu = menuFormatFeatures->addMenu( submenu_name );
if ( map_style == GIS_MAP_STYLE_S52 )
{
depth_editor = new DepthEditor( this );
connect( depth_editor, SIGNAL( accepted() ), tab_wgt, SLOT( updateCurrentTabMap() ) );
submenu->addAction( tr( "Depth editor" ), depth_editor, SLOT( show() ) );
}
}
menuFormatFeatures->update();
}
void MainWindow::updateLanguageMenu( std::vector<gis_map_style_t> &mapstyle_list )
{
menuLanguage->clear();
for ( auto map_style : mapstyle_list )
{
const QString &submenu_name = QString::fromLatin1( gis_helper_get_map_style_name( map_style ) );
QMenu *submenu = menuLanguage->addMenu( submenu_name );
if ( map_style == GIS_MAP_STYLE_S52 )
{
QAction *action = submenu->addAction( tr( "National language" ), this, SLOT( flipLocale() ) );
action->setCheckable( true );
action->setData( map_style );
}
}
menuLanguage->update();
}
void MainWindow::updatePaletteMenu( std::vector<gis_map_style_t> &mapstyle_list )
{
if ( mapstyle_list.size() == 0 )
{
return;
}
if ( menuPalette == NULL )
{
return;
}
for ( auto pair : palettes_map )
{
gis_map_style_palette_list_free( &pair.second );
}
menuPalette->clear();
palettes_map.clear();
for ( auto map_style : mapstyle_list )
{
const QString &submenu_name = QString::fromLatin1( gis_helper_get_map_style_name( map_style ) );
QMenu *submenu = menuPalette->addMenu( submenu_name );
gis_vector_palette_list_t *palettes = gis_map_style_get_palette_list( map_style );
if ( palettes == NULL )
{
continue;
}
palettes_map.emplace( submenu_name, palettes );
for ( unsigned int i = 0; i < gis_map_style_palette_get_entry_count( palettes ); i++ )
{
const QString &submenu_action_name =
QString::fromLatin1( gis_map_style_palette_get_entry_list( palettes )[i].name );
QAction *action = submenu->addAction( submenu_action_name, this, SLOT( changePalette() ) );
action->setData( i );
}
}
menuPalette->update();
}
void MainWindow::processTabChanging( int idx )
{
if ( idx < 0 )
{
return;
}
if ( tab_wgt->checkLock( idx ) )
{
return;
}
lastOpenedTabIndex = idx;
MapWidget *mw = tab_wgt->currentMapWidget();
aliasing_action->setChecked( mw->isAliasingEnabled );
scaling_action->setChecked( mw->isConstScalingEnabled );
center_scaling_action->setChecked( mw->centerOnScaling );
rescale_by_wheel_action->setChecked( mw->rescaleByWheel );
auto_height_action->setChecked( mw->autoRasterHeightLimits );
palette_action->setChecked( mw->rasterDiscretePalette );
invalid_height_action->setChecked( mw->rasterInvalidHeightMode );
layer_window->updateStates( mw->layer_list );
height_scale->updateColorScale( mw->colorMap, mw->maxRasterHeight, mw->minRasterHeight );
view_params->updateBrightnessContrast( mw->brightness, mw->contrast );
mapstyle_layer_window->updateLists( mw->classifiers );
object_search->updateLists( mw->classifiers );
if ( object_search->getCurrentTab() != NULL )
{
disconnect( object_search, SIGNAL( centerAtObject( double_point_t ) ),
object_search->getCurrentTab(), SLOT( setMapWidgetCenterAtPoint( double_point_t ) ) );
disconnect( object_search, SIGNAL( showInfoForFoundObject( gis_object_t ) ),
object_search->getCurrentTab(), SLOT( showObjectInfoWindow( gis_object_t ) ) );
}
connect( object_search, SIGNAL( centerAtObject( double_point_t ) ),
mw, SLOT( setMapWidgetCenterAtPoint( double_point_t ) ) );
connect( object_search, SIGNAL( showInfoForFoundObject( gis_object_t ) ),
mw, SLOT( showObjectInfoWindow( gis_object_t ) ) );
object_search->setCurrentTab( mw );
mapstyle_layer_window->setCurrentTab( mw );
updateMapStyles( mw->classifiers );
}

177
src/apps/gis-map-viewer/mainwindow.h Обычный файл
Просмотреть файл

@ -0,0 +1,177 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <csignal>
#include <QCoreApplication>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QPointer>
#include <QSettings>
#include <QTabBar>
#include <QTabWidget>
#include <QWidget>
#include "heightscale.h"
#include "mapstylelayerwindow.h"
#include "mapwidget.h"
#include "layerwindow.h"
#include "viewparameters.h"
#include "objectsearch.h"
#include "deptheditor.h"
#include <gis/gishelper.h>
#include <gis/gisrender.h>
struct CleanExit
{
CleanExit()
{
signal( SIGINT, &CleanExit::exitQt );
signal( SIGTERM, &CleanExit::exitQt );
}
static void exitQt( int sig )
{
Q_UNUSED( sig );
QCoreApplication::quit();
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0 );
~MainWindow();
int nTabs;
int lastOpenedTabIndex;
bool oneMapMode;
int connectGisCore( gis_core_driver_id_t enabledDriverId );
void addTabWidget();
private:
void loadSettings();
void saveSettings();
MapTabWidget *tab_wgt;
QAction *aliasing_action;
QAction *center_scaling_action;
QAction *rescale_by_wheel_action;
QAction *palette_action;
QAction *scaling_action;
QAction *auto_height_action;
QAction *invalid_height_action;
QAction *test_action;
QPointer <ViewParameters> view_params;
QPointer <LayerWindow> layer_window;
QPointer <MapStyleLayerWindow> mapstyle_layer_window;
QPointer <HeightScale> height_scale;
QPointer <ObjectSearch> object_search;
QPointer <DepthEditor> depth_editor;
gis_core_connection_t connection;
std::vector<gis_map_style_t> map_style_vector;
std::map<const QString, gis_vector_palette_list_t *> palettes_map;
QMenu *menuPalette;
QMenu *menuLanguage;
QMenu *menuFormatFeatures;
int windowX;
int windowY;
int widthPx;
int heightPx;
int32_t sharedMemoryUserId;
void closeEvent( QCloseEvent *event );
void updateMapStyles( std::vector<ClassifierInfo> &classifier_list );
void updateFormatFeaturesMenu( std::vector<gis_map_style_t> &mapstyle_list );
void updatePaletteMenu( std::vector<gis_map_style_t> &mapstyle_list );
void updateLanguageMenu( std::vector<gis_map_style_t> &mapstyle_list );
private slots:
void fillMenuBar();
void autoHeightChecked( bool checked )
{
MapWidget *mw = tab_wgt->currentMapWidget();
mw->setAutoRasterHeightLimits( checked );
if ( checked )
height_scale->updateColorScale( mw->colorMap,
mw->maxRasterHeight,
mw->minRasterHeight );
}
void changePalette();
void flipLocale();
void flipOneMapMode();
public slots:
void createMapWidgets();
void processTabChanging( int idx );
void refreshMapData();
void setManualHeightLimits( double max, double min )
{
tab_wgt->currentMapWidget()->setRasterHeightLimits( min, max );
auto_height_action->setChecked( false );
}
void setMapWidgetCenterAtPoint( double_point_t object_center )
{
tab_wgt->currentMapWidget()->setMapWidgetCenterAtPoint( object_center );
}
void showObjectInfoWindow( gis_object_t current_object )
{
tab_wgt->currentMapWidget()->showObjectInfoWindow( current_object );
}
void showAboutDialog()
{
gis_gui_about( &connection, this );
}
signals:
void resetMapWidget();
void updateAllDataEngines();
};
#endif

Просмотреть файл

@ -0,0 +1,296 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mapstylelayerwindow.h"
#include <QDebug>
#include <QLabel>
#define TYPE_LAYER_ITEM 6
MapStyleLayerWindow::MapStyleLayerWindow( QWidget *parent ) :
QWidget( parent, Qt::Window ),
cont( nullptr ),
check_column( 0 ),
acronym_column( 1 ),
idx_column( 2 ),
sequence_column( 3 )
{
borders.degrees.west = 180;
borders.degrees.east = 180;
borders.degrees.north = 90;
borders.degrees.south = 90;
grid_layout = new QGridLayout;
mapstyle_box = new QComboBox;
listLayers = new QTreeWidget;
listLayers->setColumnCount( 4 );
QStringList listLayersHeaders;
listLayersHeaders << tr( "State" )
<< tr( "Layer name" )
<< tr( "Layer number" )
<< tr( "Sequence number" );
listLayers->setHeaderLabels( listLayersHeaders );
listLayers->setColumnWidth( acronym_column, 170 );
listLayers->setMaximumHeight( 350 );
listLayers->setUniformRowHeights( true );
btnsBoxLayout = new QHBoxLayout;
selectAllBtn = new QPushButton;
selectAllBtn->setText( tr("Select All") );
connect( selectAllBtn, SIGNAL( clicked( bool ) ),
this, SLOT( selectAllBtnClicked( bool ) ) );
btnsBoxLayout->addWidget( selectAllBtn );
removeAllBtn = new QPushButton;
removeAllBtn->setText( tr("Remove All") );
connect( removeAllBtn, SIGNAL( clicked( bool ) ),
this, SLOT( removeAllBtnClicked( bool ) ) );
btnsBoxLayout->addWidget( removeAllBtn );
grid_layout->addWidget( new QLabel( tr( "Classifier name: " ) ), 1, 1 );
grid_layout->addWidget( mapstyle_box, 1, 2 );
grid_layout->addWidget( listLayers, 2, 1, 2, 2 );
grid_layout->addLayout( btnsBoxLayout, 4, 1, 1, 2 );
grid_layout->setHorizontalSpacing( 10 );
grid_layout->setVerticalSpacing( 10 );
connect( mapstyle_box, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( slotMapIndexChanged( int ) ) );
connect( listLayers, SIGNAL( itemChanged( QTreeWidgetItem*, int ) ),
this, SLOT( slotItemChanged( QTreeWidgetItem*, int ) ) );
connect( this, SIGNAL( layerChecked( QTreeWidgetItem* ) ),
this, SLOT( slotLayerChecked( QTreeWidgetItem* ) ) );
connect( this, SIGNAL( layerUnchecked( QTreeWidgetItem* ) ),
this, SLOT( slotLayerUnchecked( QTreeWidgetItem* ) ) );
setGeometry( 0, 0, 500, 300 );
setFixedSize( 500, 300 );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
setLayout( grid_layout );
setWindowTitle( tr( "Classifier layer management" ) );
}
MapStyleLayerWindow::~MapStyleLayerWindow()
{
delete removeAllBtn;
delete selectAllBtn;
delete btnsBoxLayout;
delete listLayers;
delete mapstyle_box;
delete grid_layout;
}
void MapStyleLayerWindow::setCurrentTab( MapWidget *wgt )
{
currentMapWidget = wgt;
}
bool MapStyleLayerWindow::updateBorders()
{
gis_render_sm_context_t current_sm_ctx = currentMapWidget->getSurfacemanagerContext();
if ( !current_sm_ctx )
{
return false;
}
int res = gis_render_sm_get_draw_canvas_borders( current_sm_ctx, &borders );
if ( res != EOK )
{
qDebug() << "MapStyleLayerWindow: Failed to get canvas borders (" << strerror( res ) << ")";
return false;
}
return true;
}
void MapStyleLayerWindow::showEvent( QShowEvent *event )
{
if ( parentWidget() )
{
int x = ( parentWidget()->width() - width() ) / 2;
int y = ( parentWidget()->height() - height() ) / 2;
QPoint relative_pos = parentWidget()->mapToGlobal( QPoint( x, y ) );
QWidget::move( relative_pos );
}
else
qDebug() << "MapStyleLayerWindow: can't get pointer to parent Widget!";
if ( updateBorders() )
{
char **classifier_list = gis_map_style_fill_active_classifier_name_list( &borders );
if ( !classifier_list )
{
qDebug() << "MapStyleLayerWindow: active classifier list is nullptr!";
event->accept();
return;
}
if ( !classifier_list[0] )
{
mapstyle_box->setCurrentIndex( 0 );
event->accept();
return;
}
if ( classifier_list[1] == nullptr )
{
int new_idx = mapstyle_box->findText( QString::fromLatin1( classifier_list[0] ) );
mapstyle_box->setCurrentIndex( new_idx );
}
else
mapstyle_box->setCurrentIndex( 0 );
gis_helper_free_string_list( &classifier_list );
}
event->accept();
}
void MapStyleLayerWindow::selectAllBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
int nLayer = listLayers->invisibleRootItem()->childCount();
for ( int i = 0; i < nLayer; i++ )
{
auto item = listLayers->invisibleRootItem()->child( i );
item->setCheckState( check_column, Qt::Checked );
}
}
void MapStyleLayerWindow::removeAllBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
int nLayer = listLayers->invisibleRootItem()->childCount();
for ( int i = 0; i < nLayer; i++ )
{
auto item = listLayers->invisibleRootItem()->child(i);
item->setCheckState( check_column, Qt::Unchecked );
}
}
void MapStyleLayerWindow::updateLists( std::vector<ClassifierInfo> &classifier_list )
{
if ( cont )
{
delete cont;
}
cont = new MapStyleLayerContainer( classifier_list );
mapstyle_box->clear();
for ( auto style : cont->_classifier_list )
{
mapstyle_box->addItem( QString::fromUtf8( style.name.c_str() ) );
}
mapstyle_box->setCurrentIndex( 0 );
slotMapIndexChanged( 0 );
}
void MapStyleLayerWindow::slotMapIndexChanged( int map_idx )
{
listLayers->clear();
if ( map_idx < 0 || cont->_classifier_list.empty() )
{
return;
}
ClassifierInfo &info = cont->_classifier_list.at( map_idx );
for ( auto &layer : info.layers )
{
QTreeWidgetItem *item = new QTreeWidgetItem( TYPE_LAYER_ITEM );
item->setFlags(item->flags() | Qt::ItemIsUserCheckable );
if ( layer.layerIsActive )
{
item->setCheckState( check_column, Qt::Checked );
}
else
{
item->setCheckState( check_column, Qt::Unchecked );
}
item->setText( acronym_column, QString::fromUtf8( layer.layerAcronym.c_str() ) );
item->setText( idx_column, QString::number( layer.layerNumber ) );
item->setText( sequence_column, QString::number( layer.sequenceNumber ) );
listLayers->addTopLevelItem( item );
}
listLayers->resizeColumnToContents( check_column );
}
void MapStyleLayerWindow::slotItemChanged( QTreeWidgetItem *item, int column )
{
if ( column == check_column )
{
if ( item->checkState( check_column ) == Qt::Checked)
{
emit layerChecked( item );
}
if ( item->checkState( check_column ) == Qt::Unchecked)
{
emit layerUnchecked( item );
}
}
}
void MapStyleLayerWindow::slotLayerChecked( QTreeWidgetItem *item )
{
if ( item->type() == TYPE_LAYER_ITEM )
{
ClassifierInfo &info = cont->_classifier_list.at( mapstyle_box->currentIndex() );
int32_t l_idx = listLayers->invisibleRootItem()->indexOfChild(item);
info.layers[l_idx].layerIsActive = true;
}
emit updateMapWidget();
}
void MapStyleLayerWindow::slotLayerUnchecked( QTreeWidgetItem *item )
{
if ( item->type() == TYPE_LAYER_ITEM )
{
ClassifierInfo &info = cont->_classifier_list.at( mapstyle_box->currentIndex() );
int32_t l_idx = listLayers->invisibleRootItem()->indexOfChild( item );
info.layers[l_idx].layerIsActive = false;
}
emit updateMapWidget();
}

Просмотреть файл

@ -0,0 +1,92 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAPSTYLELAYERWINDOW_H
#define MAPSTYLELAYERWINDOW_H
#include <QComboBox>
#include <QGridLayout>
#include <QMainWindow>
#include <QPushButton>
#include <QTreeWidget>
#include <QShowEvent>
#include <gis/gis_databuffer.h>
#include "mapwidget.h"
class MapStyleLayerContainer
{
public:
explicit MapStyleLayerContainer( std::vector<ClassifierInfo> &classifier_list ) :
_classifier_list(classifier_list) {}
std::vector <ClassifierInfo> &_classifier_list;
};
class MapStyleLayerWindow : public QWidget
{
Q_OBJECT
public:
explicit MapStyleLayerWindow( QWidget *parent = 0 );
~MapStyleLayerWindow();
void updateLists( std::vector<ClassifierInfo> &classifier_list );
void setCurrentTab( MapWidget *wgt );
private:
MapStyleLayerContainer *cont;
QGridLayout *grid_layout;
QComboBox *mapstyle_box;
QTreeWidget *listLayers;
QPushButton *removeAllBtn;
QPushButton *selectAllBtn;
QHBoxLayout *btnsBoxLayout;
QPointer<MapWidget> currentMapWidget;
int check_column;
int acronym_column;
int idx_column;
int sequence_column;
gis_borders_t borders;
void showEvent( QShowEvent *event );
bool updateBorders();
private slots:
void removeAllBtnClicked( bool clicked);
void selectAllBtnClicked( bool clicked);
void slotMapIndexChanged( int);
void slotItemChanged( QTreeWidgetItem*, int );
void slotLayerChecked( QTreeWidgetItem* );
void slotLayerUnchecked( QTreeWidgetItem* );
signals:
void layerChecked( QTreeWidgetItem* );
void layerUnchecked( QTreeWidgetItem* );
void updateMapWidget();
};
#endif

966
src/apps/gis-map-viewer/mapwidget.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,966 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mapwidget.h"
#include <QApplication>
#include <QDebug>
#include <QGridLayout>
#include <QPainter>
#include <QSettings>
#include <gis/gis_objects.h>
MapWidget::MapWidget( gis_core_connection_t *outer_connection, int idx, QWidget *parent ) :
QWidget( parent ),
isAliasingEnabled( false ),
isConstScalingEnabled( true ),
centerOnScaling( true ),
rescaleByWheel( true ),
autoRasterHeightLimits( true ),
rasterDiscretePalette( false ),
rasterInvalidHeightMode( false ),
index( idx ),
connection( outer_connection ),
pin( true ),
dont_save_to_config( false ),
initialized( false ),
userForm( nullptr ),
distance_meter( nullptr ),
objInfo( nullptr )
{
if( loadSettings() != EOK )
{
qDebug() << "Failed reading settings for this[" << index << "] mapwidget config!" << endl;
}
setMinimumSize( minimumWidgetWidth, minimumWidgetHeight );
setMaximumSize( maximumWidgetWidth, maximumWidgetHeight );
setAttribute( Qt::WA_OpaquePaintEvent );
QGridLayout *layout = new QGridLayout( this );
increaseButton = new QPushButton( QIcon( ":/icons/zoomin50.png" ), "" );
decreaseButton = new QPushButton( QIcon( ":/icons/zoomout50.png" ), "" );
closeButton = new QPushButton( QIcon( ":/icons/shutdown.png" ), "" );
meterButton = new QPushButton( QIcon( ":/icons/ruler.png" ), "" );
savePinButton = new QPushButton( QIcon( ":/icons/save_pin.png" ), "" );
showPinButton = new QPushButton( QIcon( ":/icons/pin.png" ), "" );
QSize iconSize( iconSideSizePx, iconSideSizePx );
increaseButton->setIconSize( iconSize );
decreaseButton->setIconSize( iconSize );
closeButton->setIconSize( iconSize );
meterButton->setIconSize( iconSize );
savePinButton->setIconSize( iconSize );
showPinButton->setIconSize( iconSize );
scaleLabel = new QLabel();
scaleLabel->setAutoFillBackground( true );
scaleLabel->setBackgroundRole( QPalette::Base );
scaleLabel->setAlignment( Qt::AlignRight );
positionLabel = new QLabel();
positionLabel->setAutoFillBackground( true );
positionLabel->setBackgroundRole( QPalette::Base );
layout->setSpacing( buttonBorderOffset );
QHBoxLayout *h_lay = new QHBoxLayout;
h_lay->addWidget( increaseButton );
h_lay->addWidget( decreaseButton );
h_lay->addWidget( meterButton );
h_lay->addWidget( savePinButton );
h_lay->addWidget( showPinButton );
layout->addLayout( h_lay, 0, 0, Qt::AlignLeft | Qt::AlignTop );
layout->addWidget( closeButton, 0, 2, 1, 1, Qt::AlignRight | Qt::AlignTop );
layout->addWidget( scaleLabel, 2, 2, 1, 1, Qt::AlignRight | Qt::AlignBottom );
layout->addWidget( positionLabel, 2, 0, 1, 1, Qt::AlignLeft | Qt::AlignBottom );
setLayout(layout);
connect( increaseButton, SIGNAL( released() ), this, SLOT( increaseScale() ) );
connect( decreaseButton, SIGNAL( released() ), this, SLOT( decreaseScale() ) );
connect( meterButton, SIGNAL( released() ), this, SLOT( showMeter() ) );
connect( savePinButton, SIGNAL( released() ), this, SLOT( savePin() ) );
connect( showPinButton, SIGNAL( released() ), this, SLOT( showPin() ) );
connect( closeButton, SIGNAL( released() ), QApplication::instance(), SLOT( quit() ) );
connect( this, SIGNAL( getMouseRelease( QPoint ) ), this, SLOT( updatePositionLabel( QPoint ) ) );
connect( this, SIGNAL( scaleValueChanged( uint32_t ) ), this, SLOT( updateScaleLabel( uint32_t ) ) );
QList<Qt::GestureType> gestures;
gestures << Qt::PinchGesture;
grabGestures( gestures );
if ( idx_scale >= scale_values.size() )
{
qWarning() << QTime::currentTime().toString() << "Scale limit";
idx_scale = ( scale_values.size() - 1 ) / 2;
}
setScaleValue( scale_values[idx_scale] );
}
MapWidget::~MapWidget()
{
if ( !dont_save_to_config )
{
saveSettings();
}
gis_render_sm_free( &sm_ctx );
gis_data_engine_free( &data_engine_ctx );
}
int MapWidget::loadSettings()
{
QString gis_config( gis_helper_env_get_config_directory() );
QSettings settings( gis_config + "gis-map-viewer.conf", QSettings::IniFormat);
settings.beginGroup("MapWidget");
QVector<QVariant> scales_str = settings.value( "scales", 0 ).toList().toVector();
for( int i = 0; i < scales_str.size(); i++)
{
scale_values.push_back( scales_str[i].toInt() );
}
settings.beginGroup( QString::number( index ) );
geo_center.x = settings.value( "longitude", 0 ).toDouble();
geo_center.y = settings.value( "latitude", 0 ).toDouble();
idx_scale = settings.value("scaleVectorIndex", ( scale_values.size() - 1 ) / 2 ).toInt();
settings.endGroup();
settings.endGroup();
offscreen_ext_px = settings.value( "SurfaceManager/offscreenExtension", 0 ).toInt();
blit_region_rate = settings.value( "SurfaceManager/blitRegionRate", 0.5 ).toFloat();
allocInRam = settings.value( "SurfaceManager/allocInRam", false ).toBool();
smMode = settings.value( "SurfaceManager/smMode", GIS_RENDER_SM_MODE_ASYNC ).toInt();
brightness = settings.value( "MapDisplayParameters/brightness" ).toFloat();
contrast = settings.value( "MapDisplayParameters/contrast" ).toFloat();
invalidRasterHeightColor =
settings.value( "MapDisplayParameters/invalidRasterHeightColor" ).toString().toUInt( nullptr, 16 );
maxRasterHeight = settings.value( "MapDisplayParameters/maximumRasterHeightMeters" ).toDouble();
minRasterHeight = settings.value( "MapDisplayParameters/minimumRasterHeightMeters" ).toDouble();
minimumWidgetWidth = settings.value( "InterfaceParameters/minWidth" ).toInt();
minimumWidgetHeight = settings.value( "InterfaceParameters/minHeight" ).toInt();
maximumWidgetWidth = settings.value( "InterfaceParameters/maxWidth" ).toInt();
maximumWidgetHeight = settings.value( "InterfaceParameters/maxHeight" ).toInt();
objectSearchSideSizePx = settings.value( "InterfaceParameters/objectSearchSideSizePx" ).toInt();
buttonBorderOffset = settings.value( "InterfaceParameters/buttonBorderOffset" ).toInt();
iconSideSizePx = settings.value( "InterfaceParameters/iconSideSizePx" ).toInt();
settings.beginGroup( "MapWidget" );
if ( !settings.childGroups().contains( QString::number( index ) ) )
{
return 1;
}
settings.endGroup();
return EOK;
}
void MapWidget::saveSettings()
{
QString gis_config( gis_helper_env_get_config_directory() );
QSettings settings( gis_config + "gis-map-viewer.conf", QSettings::IniFormat);
gis_mdp_t mdp = gis_data_engine_get_display_parameters( data_engine_ctx );
double_point_t center;
gis_mdp_get_center_point_deg( mdp, &center );
settings.beginGroup( "MapWidget" );
settings.beginGroup( QString::number( index ) );
settings.setValue( "longitude", center.x );
settings.setValue( "latitude", center.y );
settings.setValue( "scaleVectorIndex", idx_scale );
settings.endGroup();
settings.endGroup();
settings.setValue( "MapDisplayParameters/brightness", brightness );
settings.setValue( "MapDisplayParameters/contrast", contrast );
}
void MapWidget::initialize()
{
if ( gis_data_engine_alloc( width(),
height(),
GIS_DATA_ENGINE_MODE_SM,
GIS_DATA_ENGINE_BPP_32,
connection,
&data_engine_ctx ) != EOK )
{
qWarning() << QTime::currentTime().toString() << "Failed to alloc data engine";
exit(1);
}
gis_data_engine_set_notify_func( &data_engine_ctx, this );
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_map_projection_init( &proj_params );
if ( gis_map_projection_init( &proj_params ) != EOK )
{
qWarning( "Failed to init projection\n" );
exit(1);
}
gis_data_engine_get_maps_projection( data_engine_ctx, &geo_center, &proj_params );
gis_mdp_set_projection( disp_param, &proj_params );
gis_mdp_set_center_point( disp_param, geo_center );
gis_mdp_set_phys_scale( disp_param, scale_value );
gis_mdp_set_background_color( disp_param, 0xffffff );
gis_mdp_set_scaling_mode( disp_param, true );
gis_mdp_set_map_antialiasing_level( disp_param, 0 );
uint32_t flags = 0;
if ( allocInRam )
{
flags |= GIS_RENDER_SM_ALLOC_RAM;
}
if ( gis_render_sm_alloc( &sm_ctx,
data_engine_ctx,
offscreen_ext_px,
blit_region_rate,
flags ) != EOK )
{
qWarning( "Failed to alloc surface manager" );
exit(1);
}
gis_render_sm_set_update_func( sm_ctx, (SMCallbacks*)this );
if ( allocInRam )
{
gis_render_sm_set_render_mode( sm_ctx, GIS_RENDER_SM_MODE_SYNC );
}
else
{
gis_render_sm_set_render_mode( sm_ctx, smMode );
}
setRasterPalette();
fillClassifierInfo();
fillLayerTypeList();
distance_meter = new DistanceMeter( sm_ctx );
connect( distance_meter, SIGNAL( updateMapWidget() ), this, SLOT( update() ) );
connect( this, SIGNAL( getNewMeterPoint( QPoint ) ), distance_meter, SLOT( meterListener( QPoint ) ) );
connect( distance_meter, SIGNAL( widgetVisibilityChanged( bool ) ), this, SLOT( setTabBlockingFlag( bool ) ) );
objInfo = new ObjectInfo( sm_ctx );
connect( objInfo, SIGNAL( updateMapWidget() ), this, SLOT( update() ) );
connect( objInfo, SIGNAL( widgetVisibilityChanged( bool ) ), this, SLOT( setTabBlockingFlag( bool ) ) );
userForm = new UserDialog( sm_ctx, disp_param, scale_values );
connect( userForm, SIGNAL( updateMapWidget() ), this, SLOT( update() ) );
connect( this, SIGNAL( getNewUserObjPoint( QPoint ) ), userForm, SLOT( userObjListener( QPoint ) ) );
connect( userForm, SIGNAL( widgetVisibilityChanged( bool ) ), this, SLOT( setTabBlockingFlag( bool ) ) );
initialized = true;
emit getMouseRelease( QPoint( width() / 2, height() / 2 ) );
gis_render_sm_sync( sm_ctx, true );
update();
}
gis_render_sm_context_t MapWidget::getSurfacemanagerContext()
{
if ( initialized )
{
return sm_ctx;
}
else
{
return nullptr;
}
}
void MapWidget::updateDatabufferDescriptor()
{
if ( gis_data_engine_update( data_engine_ctx ) != EOK )
{
qDebug() << QTime::currentTime().toString() << "Failed to update databuffer descriptor";
exit( EFAULT );
}
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::updateProjectionParameters()
{
gis_map_projection_t saved_params = proj_params;
if ( gis_gui_get_projection_parameters( &proj_params, this ) == EOK )
{
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
if ( gis_mdp_set_projection( disp_param, &proj_params ) != EOK )
{
qDebug() << QTime::currentTime().toString() << "Failed to set projection";
proj_params = saved_params;
return;
}
qDebug() << QTime::currentTime().toString() << "Projection:" << gis_map_projection_get_full_name( &proj_params );
qDebug() << QTime::currentTime().toString() << "Ellipsoid:" << gis_map_ellipsoid_get_full_name( &proj_params );
qDebug() << QTime::currentTime().toString() << "EPSG:" << proj_params.EPSG;
gis_render_sm_sync( sm_ctx, true );
update();
}
}
void MapWidget::updateScreenParameters()
{
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
if ( gis_gui_get_screen_parameters( dp, this ) == EOK )
{
gis_render_sm_sync( sm_ctx, true );
update();
}
}
void MapWidget::setIndex( int idx )
{
this->index = idx;
}
int MapWidget::getIndex()
{
return this->index;
}
void MapWidget::resizeEvent( QResizeEvent *event )
{
Q_UNUSED( event );
if ( initialized )
{
if ( gis_data_engine_set_canvas_size( data_engine_ctx, width(), height() ) == EOK )
{
if ( gis_render_sm_update( sm_ctx, offscreen_ext_px, blit_region_rate ) != EOK )
{
qWarning( "Failed to update surface manager context" );
}
}
}
}
void MapWidget::paintEvent( QPaintEvent * event )
{
if ( event->rect().size() != size() )
{
return QWidget::paintEvent( event );
}
if ( initialized )
{
gis_render_sm_draw( sm_ctx );
QPixmap *pixmap = (QPixmap*)gis_render_sm_get_view_pixmap( sm_ctx, &viewport_pos );
QPainter painter( this );
painter.drawPixmap( 0, 0, *pixmap, viewport_pos.x, viewport_pos.y, width(), height() );
}
}
void MapWidget::updatePositionLabel( QPoint pos )
{
double_point_t degree_pos = { 0, 0 };
double_point_t meter_pos = { 0, 0 };
int32_point_t px_pos = { pos.x(), pos.y() };
gis_render_sm_convert_px2degree( sm_ctx, px_pos, &degree_pos );
gis_render_sm_convert_px2meters( sm_ctx, px_pos, &meter_pos );
QString positionString;
positionString = tr(" Lat: ") + QString::number( degree_pos.y, 'f', 5 ) + QString::fromUtf8("°")
+ tr(" Long: ") + QString::number( degree_pos.x, 'f', 5 ) + QString::fromUtf8("°");
positionString += " X: " + QString::number( meter_pos.x, 'f', 2 )
+ "m Y: " + QString::number( meter_pos.y, 'f', 2 ) + "m";
positionLabel->setText( positionString );
QString croppedDegreePosition = tr(" Lat: ") + QString::number( degree_pos.y, 'f', 2 ) + QString::fromUtf8("°")
+ tr(" Long: ") + QString::number( degree_pos.x, 'f', 2 ) + QString::fromUtf8("°");
emit positionLabelChanged( index, croppedDegreePosition );
}
void MapWidget::setMapWidgetCenterAtPoint( double_point_t object_center )
{
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_center_point( disp_param, object_center );
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::updateScaleLabel( uint32_t scale_val )
{
QString scaleString = "1:" + QString::number( (long)scale_val );
scaleLabel->setText( scaleString );
}
void MapWidget::increaseScale()
{
if ( idx_scale + 1 >= scale_values.size() )
{
return;
}
setScaleValue( scale_values[++idx_scale] );
gis_render_sm_rescale( sm_ctx, scale_value );
update();
}
void MapWidget::decreaseScale()
{
if ( idx_scale - 1 < 0 )
{
return;
}
setScaleValue( scale_values[--idx_scale] );
gis_render_sm_rescale( sm_ctx, scale_value );
update();
}
void MapWidget::sync()
{
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::mousePressEvent( QMouseEvent *event )
{
if ( event->button() == Qt::LeftButton )
{
last_position = event->pos();
if ( !distance_meter->isHidden() )
{
emit getNewMeterPoint( event->pos() );
}
if ( !userForm->isHidden() )
{
emit getNewUserObjPoint( event->pos() );
}
}
if ( event->button() == Qt::RightButton )
{
last_position = event->pos();
}
event->ignore();
}
void MapWidget::mouseMoveEvent( QMouseEvent *event )
{
QPoint delta = event->pos() - last_position;
last_position = event->pos();
gis_render_sm_move( sm_ctx, delta.x(), delta.y() );
update();
}
void MapWidget::mouseReleaseEvent( QMouseEvent *event )
{
emit getMouseRelease( event->pos() );
event->ignore();
}
void MapWidget::wheelEvent( QWheelEvent *event )
{
double_point_t center;
int32_point_t scale_pnt_px;
scale_pnt_px.x = event->x();
scale_pnt_px.y = event->y();
if ( centerOnScaling )
{
if ( gis_render_sm_convert_px2degree( sm_ctx, scale_pnt_px, &center ) == EOK )
{
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_center_point( disp_param, center );
if ( !rescaleByWheel )
{
gis_render_sm_sync( sm_ctx, true );
update();
}
}
}
if ( rescaleByWheel )
{
if ( event->delta() > 0 )
increaseScale();
else if ( event->delta() < 0 )
decreaseScale();
}
}
void MapWidget::mouseDoubleClickEvent( QMouseEvent *event )
{
if ( event->button() == Qt::LeftButton )
showObjectInfo(event->pos());
}
void MapWidget::closeEvent( QCloseEvent *event )
{
dont_save_to_config = true;
event->accept();
}
void MapWidget::grabGestures( const QList<Qt::GestureType> &gestures )
{
foreach ( Qt::GestureType gesture, gestures )
grabGesture( gesture );
}
bool MapWidget::event( QEvent *event )
{
if ( event->type() == QEvent::Gesture )
{
event->accept();
return gestureEvent( static_cast<QGestureEvent*>(event) );
}
return QWidget::event( event );
}
bool MapWidget::gestureEvent( QGestureEvent *event )
{
if ( QGesture *swipe = event->gesture( Qt::SwipeGesture ) )
{
swipeTriggered( (QSwipeGesture*)swipe );
}
else if ( QGesture *pan = event->gesture( Qt::PanGesture ) )
{
panTriggered( (QPanGesture*)pan );
}
else if ( QGesture *pinch = event->gesture( Qt::PinchGesture ) )
{
pinchTriggered( (QPinchGesture*)pinch );
}
return true;
}
void MapWidget::pinchTriggered( QPinchGesture *gesture )
{
QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
if ( changeFlags & QPinchGesture::ScaleFactorChanged )
{
currentStepScaleFactor = gesture->totalScaleFactor();
}
if ( gesture->state() == Qt::GestureFinished )
{
if ( gesture->scaleFactor() > currentStepScaleFactor )
{
decreaseScale();
}
else
{
increaseScale();
}
currentStepScaleFactor = 1;
}
update();
}
void MapWidget::swipeTriggered( QSwipeGesture *swipe )
{
Q_UNUSED( swipe );
}
void MapWidget::panTriggered( QPanGesture *pan )
{
Q_UNUSED( pan );
}
void MapWidget::updateBrightnessContrast( float br, float cn )
{
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_brightness_contrast( disp_param, br, cn );
brightness = br;
contrast = cn;
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::updateLayerOrder( int idx, gis_render_sm_layer_type_t type )
{
layer_list[idx].layer_type = type;
layer_list[idx].z_idx = idx;
gis_render_sm_set_layer_type( sm_ctx, idx, type );
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::updateDataSourcesForLayer( gis_render_sm_layer_type_t layer_type,
int num_of_data_sources,
gis_core_map_data_source_t *data_sources )
{
gis_render_sm_set_layer_data_sources( sm_ctx,
layer_type,
num_of_data_sources,
data_sources );
gis_render_sm_update( sm_ctx, offscreen_ext_px, 0.5 );
update();
}
void MapWidget::fillClassifierInfo()
{
if ( gis_data_engine_get_classifier_list( data_engine_ctx, classifiers ) != EOK )
{
qWarning( "Failed to fill classifier info" );
}
if ( gis_data_engine_get_map_list( data_engine_ctx, maps ) != EOK )
{
qWarning( "Failed to fill map list" );
}
if ( classifiers.empty() || maps.empty() )
{
return;
}
std::vector<ClassifierInfo> new_classifiers;
for ( const auto &map : maps )
{
bool already_have = false;
for ( const auto &new_classifier : new_classifiers )
{
if ( new_classifier.name.compare( map.classifierName ) == 0 )
{
already_have = true;
break;
}
}
if ( already_have )
{
continue;
}
for ( const auto &classifier : classifiers )
{
if ( classifier.name.compare( map.classifierName ) == 0 )
{
new_classifiers.push_back( classifier );
break;
}
}
}
classifiers = new_classifiers;
}
void MapWidget::fillLayerTypeList()
{
layer_list.clear();
LayerInfo info;
for ( int i = 0; i < GIS_RENDER_SM_SURFACE_NUMBER; i++ )
{
info.layer_type = gis_render_sm_get_layer_type( sm_ctx, i );
info.z_idx = i;
layer_list.append( info );
}
}
void MapWidget::setAliasingMode( bool enable )
{
isAliasingEnabled = enable;
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
if ( isAliasingEnabled )
{
int level = 1;
gis_mdp_set_map_antialiasing_level( dp, level );
}
else
{
gis_mdp_set_map_antialiasing_level( dp, 0 );
}
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::setRasterPalette()
{
colorMap.clear();
colorMap << 0x00004030 << 0x00186424 << 0x0048AC0C << 0x00ACC800
<< 0x00D0E000 << 0x00F4F800 << 0x00E4C400 << 0x00D29A00
<< 0x00C07000 << 0x00AE4600 << 0x00A22A00 << 0x00960E00;
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_raster_color_mode( dp, rasterDiscretePalette );
setRasterInvalidHeightMode( rasterInvalidHeightMode );
#if 0
gis_mdp_set_raster_height_limits( dp, min_h, max_h );
#else
setAutoRasterHeightLimits( true );
#endif
gis_mdp_set_raster_palette( dp, colorMap.data(), colorMap.size() );
}
void MapWidget::setRasterHeightLimits( double new_min, double new_max )
{
minRasterHeight = new_min;
maxRasterHeight = new_max;
setAutoRasterHeightLimits( false );
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_raster_height_limits( dp, minRasterHeight, maxRasterHeight );
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::setDiscretePalette( bool enabled )
{
rasterDiscretePalette = enabled;
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_raster_color_mode( dp, rasterDiscretePalette );
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::setRasterInvalidHeightMode( bool show )
{
rasterInvalidHeightMode = show;
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
if ( rasterInvalidHeightMode )
{
gis_mdp_set_raster_invalid_height_color( dp, invalidRasterHeightColor );
}
else
{
uint32_t background_color = gis_mdp_get_background_color( dp );
gis_mdp_set_raster_invalid_height_color( dp, background_color );
}
gis_render_sm_sync( sm_ctx, true );
update();
}
void MapWidget::showObjectInfo( QPoint px_click )
{
std::vector<gis_core_class_code_t> class_list;
class_list.clear();
gis_data_engine_get_class_list( data_engine_ctx, classifiers, class_list );
if ( class_list.empty() )
{
class_list.push_back( GIS_CLASS_CODE_UNDEFINED );
}
int result = -1;
size_t step = 1;
gis_object_t _obj;
gis_object_init( &_obj );
do {
double_point_t deg_pos = { 0, 0 };
double_point_t east_south_box_point = { 0, 0 };
double_point_t west_north_box_point = { 0, 0 };
int32_point_t px_pos = { px_click.x(), px_click.y() };
int32_point_t east_south_box_pos;
east_south_box_pos.x = px_click.x() + step * objectSearchSideSizePx;
east_south_box_pos.y = px_click.y() + step * objectSearchSideSizePx;
int32_point_t west_north_box_pos;
west_north_box_pos.x = px_click.x() - step * objectSearchSideSizePx;
west_north_box_pos.y = px_click.y() - step * objectSearchSideSizePx;
gis_render_sm_convert_px2degree( sm_ctx, px_pos, &deg_pos );
gis_render_sm_convert_px2degree( sm_ctx, east_south_box_pos, &east_south_box_point );
gis_render_sm_convert_px2degree( sm_ctx, west_north_box_pos, &west_north_box_point );
gis_borders_t region_of_interest;
region_of_interest.degrees.west = west_north_box_point.x;
region_of_interest.degrees.east = east_south_box_point.x;
region_of_interest.degrees.south = east_south_box_point.y;
region_of_interest.degrees.north = west_north_box_point.y;
object_point_t point_pos;
point_pos.degrees.x = deg_pos.x;
point_pos.degrees.y = deg_pos.y;
GisObjectList list(&region_of_interest, class_list);
int idx = list.find_nearest_object(point_pos);
if ( idx < 0 )
return;
result = list.get_object(idx, _obj);
step++;
} while ( result != EOK );
objInfo->updateInfo( &_obj );
objInfo->move( mapToGlobal( px_click + QPoint( buttonBorderOffset, buttonBorderOffset ) ) );
objInfo->show();
gis_object_free( &_obj );
}
void MapWidget::showObjectInfoWindow( gis_object_t current_object )
{
objInfo->updateInfo( &current_object );
int x = ( this->width() / 2 ) + buttonBorderOffset;
int y = ( this->height() / 2 ) + buttonBorderOffset;
QPoint relative_pos = this->mapToGlobal( QPoint( x, y ) );
objInfo->move( relative_pos );
objInfo->show();
}
void MapWidget::showUserForm()
{
int x = ( this->width() - userForm->width() ) / 2;
int y = ( this->height() - userForm->height() ) / 2;
QPoint relative_pos = this->mapToGlobal( QPoint( x, y ) );
userForm->move( relative_pos );
userForm->show();
}
void MapWidget::showMeter()
{
int x = this->width() - ( 15 + distance_meter->sizeHint().width() );
int y = 10;
QPoint relative_pos = this->mapToGlobal( QPoint( x, y ) );
distance_meter->move( relative_pos );
distance_meter->show();
}
void MapWidget::savePin()
{
QPushButton *button = static_cast<QPushButton*>( sender() );
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
if ( pin )
{
button->setToolTip( tr("Delete screen position") );
button->setStyleSheet( "QPushButton { background-color: rgb( 162, 162, 162 ); }" );
pinned_scale = gis_mdp_get_phys_scale( disp_param );
gis_mdp_get_center_point_deg(disp_param, &pinned_position);
pin = false;
}
else
{
button->setToolTip( tr("Save screen position") );
button->setStyleSheet( "QPushButton { background-color: rgb( 239, 239, 239 ); }" );
pin = true;
}
}
void MapWidget::showPin()
{
if ( !pin )
{
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_phys_scale( disp_param, pinned_scale );
gis_mdp_set_center_point(disp_param, pinned_position );
gis_render_sm_sync( sm_ctx, true );
update();
}
}
void MapWidget::updateMapDrawing()
{
gis_render_sm_update( sm_ctx, offscreen_ext_px, 0.5 );
update();
}
void MapWidget::setConstScalingMode( bool enabled )
{
isConstScalingEnabled = enabled;
gis_mdp_t disp_param = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_scaling_mode( disp_param, isConstScalingEnabled );
gis_render_sm_sync( sm_ctx, true );
update();
}

451
src/apps/gis-map-viewer/mapwidget.h Обычный файл
Просмотреть файл

@ -0,0 +1,451 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAPWIDGET_H
#define MAPWIDGET_H
#include <QDebug>
#include <QGestureEvent>
#include <QGridLayout>
#include <QLabel>
#include <QMessageBox>
#include <QPanGesture>
#include <QPinchGesture>
#include <QPointer>
#include <QPushButton>
#include <QSwipeGesture>
#include <gis/gishelper.h>
#include <gis/gisrender.h>
#include "distancemeter.h"
#include "objectinfo.h"
#include "userdialog.h"
#define DEBUG_TOUCH
#define MAPWIDGET_PREFIX const_cast<char*>("[MapWidget] ")
class MapWidget : public QWidget,
public SMCallbacks,
public DBCallbacks
{
Q_OBJECT
public:
friend class MapTabWidget;
explicit MapWidget( gis_core_connection_t *connection, int idx,
QWidget *parent = 0 );
~MapWidget();
void initialize();
void databufferValidityChangedCallback( bool isValid )
{
if ( !isValid )
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_INFO, MAPWIDGET_PREFIX,
"Databuffer is invalid [%s()]", __FUNCTION__ );
else
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_INFO, MAPWIDGET_PREFIX,
"Databuffer is valid [%s()]", __FUNCTION__ );
}
void errorCallback( int err_code )
{
switch ( err_code )
{
case ETIME:
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_INFO, MAPWIDGET_PREFIX,
"Too long drawing [%s()]", __FUNCTION__ );
break;
}
default:
break;
}
}
void surfaceCompleteCallback( int32_t surface_z_idx )
{
Q_UNUSED( surface_z_idx );
update();
}
void mapLayerCompleteCallback( int32_t rsc_key, int32_t layer_number )
{
Q_UNUSED( rsc_key );
Q_UNUSED( layer_number );
update();
}
bool mapLayerRequiredCallback( int32_t classifier_key, int32_t layer_number )
{
for ( size_t idx = 0; idx < classifiers.size(); idx++ )
{
ClassifierInfo &info = classifiers[idx];
if ( info.idx == classifier_key )
{
for ( size_t layer_idx = 0; layer_idx < classifiers[idx].layers.size(); layer_idx++ )
{
if ( layer_number == classifiers[idx].layers[layer_idx].layerNumber )
return info.layers[layer_idx].layerIsActive;
}
}
}
return true;
}
bool mapClassRequiredCallback( int32_t classifier_key, gis_core_class_code_t class_code )
{
Q_UNUSED( classifier_key );
Q_UNUSED( class_code );
return true;
}
void updateProjectionParameters();
void updateScreenParameters();
void setIndex( int index );
int getIndex();
gis_render_sm_context_t getSurfacemanagerContext();
float brightness = 0;
float contrast = 0;
uint32_t invalidRasterHeightColor;
double maxRasterHeight;
double minRasterHeight;
bool isAliasingEnabled;
bool isConstScalingEnabled;
bool centerOnScaling;
bool rescaleByWheel;
bool autoRasterHeightLimits;
bool rasterDiscretePalette;
bool rasterInvalidHeightMode;
QVector <uint32_t> colorMap;
QVector <LayerInfo> layer_list;
std::vector <ClassifierInfo> classifiers;
std::vector <MapInfo> maps;
QLabel *positionLabel;
uint32_t wgt_width;
uint32_t wgt_height;
private:
int index;
gis_map_projection_t proj_params;
gis_data_engine_context_t data_engine_ctx;
gis_render_sm_context_t sm_ctx;
gis_core_connection_t *connection;
uint32_t offscreen_ext_px;
float blit_region_rate;
double_point_t geo_center;
double_point_t pinned_position;
uint32_t pinned_scale;
uint32_t map_widget_scale;
bool allocInRam;
int smMode;
int minimal_size;
QVector<int> scale_values;
int buttonBorderOffset;
int objectSearchSideSizePx;
int iconSideSizePx;
int minimumWidgetHeight;
int minimumWidgetWidth;
int maximumWidgetHeight;
int maximumWidgetWidth;
bool pin;
bool dont_save_to_config;
bool initialized;
int idx_scale;
uint32_t scale_value;
int32_point_t viewport_pos;
QPoint last_position;
bool update_scaling_center;
QLabel *scaleLabel;
QPushButton *increaseButton;
QPushButton *decreaseButton;
QPushButton *closeButton;
QPushButton *meterButton;
QPushButton *savePinButton;
QPushButton *showPinButton;
bool userFormBlockingFlag;
gis_userobject_t obj;
QPointer <UserDialog> userForm;
QPointer <DistanceMeter> distance_meter;
QPointer <ObjectInfo> objInfo;
int loadSettings();
void saveSettings();
void setScaleValue( uint32_t value )
{
scale_value = value;
emit scaleValueChanged( scale_value );
}
bool event(QEvent *event);
void fillClassifierInfo();
bool gestureEvent( QGestureEvent *event );
void mousePressEvent( QMouseEvent *event );
void mouseReleaseEvent( QMouseEvent *event );
void mouseMoveEvent( QMouseEvent *event );
void mouseDoubleClickEvent(QMouseEvent *event);
virtual void paintEvent(QPaintEvent * event);
void resizeEvent( QResizeEvent *event );
void closeEvent( QCloseEvent *event );
void panTriggered( QPanGesture *gesture );
void pinchTriggered( QPinchGesture *gesture );
void swipeTriggered( QSwipeGesture *gesture );
void syncHeightLimits();
void wheelEvent(QWheelEvent *event);
#ifdef DEBUG_TOUCH
void grabGestures(const QList<Qt::GestureType> &gestures);
qreal scaleFactor;
qreal currentStepScaleFactor;
#endif
bool hasChildWidgets;
public slots:
void setTabBlockingFlag( bool blocked )
{
hasChildWidgets = blocked;
emit hasLockingWidgets( hasChildWidgets );
}
void fillLayerTypeList();
void showMeter();
void savePin();
void showPin();
void showUserForm();
void updateDatabufferDescriptor();
void showObjectInfo( QPoint px_click );
void showObjectInfoWindow( gis_object_t current_object );
void sync();
void updateMapDrawing();
void setDiscretePalette( bool enabled );
void setRasterInvalidHeightMode( bool show );
void setCenterOnScaling( bool enabled ) { centerOnScaling = enabled; }
void setRescaleByWheel( bool enabled ) { rescaleByWheel = enabled; }
void setAutoRasterHeightLimits( bool enabled )
{
autoRasterHeightLimits = enabled;
gis_mdp_t dp = gis_data_engine_get_display_parameters( data_engine_ctx );
gis_mdp_set_raster_height_mode( dp, autoRasterHeightLimits );
if ( autoRasterHeightLimits )
{
minRasterHeight = gis_mdp_get_raster_lower_height_limit( dp );
maxRasterHeight = gis_mdp_get_raster_upper_height_limit( dp );
}
}
void setInvalidHeightMode( bool enabled ) { rasterInvalidHeightMode = enabled; }
void setConstScalingMode( bool enabled );
void setAliasingMode( bool enable );
void setRasterHeightLimits( double new_min, double new_max );
void setMapWidgetCenterAtPoint( double_point_t object_center );
void updateBrightnessContrast( float br, float cn );
void updateLayerOrder( int index, gis_render_sm_layer_type_t type );
void updateDataSourcesForLayer( gis_render_sm_layer_type_t layer_type,
int num_of_data_sources,
gis_core_map_data_source_t *data_sources );
private slots:
void increaseScale();
void decreaseScale();
void updatePositionLabel( QPoint );
void updateScaleLabel( uint32_t );
void setRasterPalette();
signals:
void hasLockingWidgets( bool );
void eraseList();
void getNewMeterPoint( QPoint );
void getNewUserObjPoint( QPoint );
void getMouseRelease( QPoint );
void positionLabelChanged( int, QString );
void scaleValueChanged( uint32_t );
void showList();
void shutdownButtonPressed();
void sizeChanged();
void widgetIsReady();
};
class MapTabWidget : public QTabWidget
{
Q_OBJECT
public:
explicit MapTabWidget( QWidget *parent = 0 ) : QTabWidget( parent ),
lock_tab_idx( -1 ),
is_tab_locked( false )
{
setTabsClosable( true );
connect( this->tabBar(), SIGNAL( tabCloseRequested( int ) ),
this, SLOT( closeTab( int ) ) );
}
MapWidget* currentMapWidget() { return static_cast<MapWidget*>( currentWidget() ); }
void addMapWidget( gis_core_connection_t *connection )
{
MapWidget *mw = nullptr;
try
{
mw = new MapWidget( connection, count(), this );
}
catch( const std::bad_alloc & )
{
qDebug () << "Failed to allocate memory for MapWidget";
exit( 1 );
}
connect( mw, SIGNAL( positionLabelChanged( int, QString ) ),
this, SLOT( updateTabText( int, QString ) ) );
connect( mw, SIGNAL( hasLockingWidgets( bool ) ),
this, SLOT( setCurrentTabLocked( bool ) ) );
addTab( mw, "-" );
mw->initialize();
if ( count() == 1 )
{
emit firstTabAdded(0);
}
}
bool checkLock( int tab_idx )
{
Q_UNUSED( tab_idx );
if ( is_tab_locked )
setCurrentIndex( lock_tab_idx );
return is_tab_locked;
}
protected:
void tabInserted(int index)
{
emit tabInsert(index);
}
private:
int lock_tab_idx;
bool is_tab_locked;
signals:
void tabInsert(int index);
void firstTabAdded(int);
public slots:
void closeEvent( QCloseEvent *event )
{
for( int i = 0; i < this->count(); ++i )
{
MapWidget *map_w = qobject_cast<MapWidget *>( this->widget( i ) );
map_w->userForm->close();
map_w->distance_meter->close();
map_w->objInfo->close();
}
}
void closeTab( int index )
{
QWidget *map_widget = this->widget( index );
removeTab( index );
map_widget->close();
for( int i = index; i < this->count(); ++i )
{
qobject_cast<MapWidget *>(this->widget( i ))->setIndex( i );
}
}
void setCurrentTabLocked( bool locked )
{
if ( locked ) {
lock_tab_idx = currentIndex();
is_tab_locked = true;
} else {
is_tab_locked = false;
}
}
void refreshMapData()
{
for ( int i = 0; i < count(); ++i )
{
qobject_cast<MapWidget*>( widget(i) )->updateDatabufferDescriptor();
}
}
void setAliasingMode( bool enabled ) { currentMapWidget()->setAliasingMode( enabled ); }
void setCenterAtCursor( bool enabled ) { currentMapWidget()->setCenterOnScaling( enabled ); }
void setRescaleByWheel( bool enabled ) { currentMapWidget()->setRescaleByWheel( enabled ); }
void setConstScalingMode( bool enabled ) { currentMapWidget()->setConstScalingMode( enabled ); }
void setDiscretePaletteEnabled( bool enabled ) { currentMapWidget()->setDiscretePalette( enabled ); }
void setRasterAutoHeightMode( bool enabled )
{
currentMapWidget()->setAutoRasterHeightLimits( enabled );
}
void setRasterInvalidHeightMode( bool enabled ) { currentMapWidget()->setRasterInvalidHeightMode( enabled ); }
void showMeter() { currentMapWidget()->showMeter(); }
void showProjectionDialog() { currentMapWidget()->updateProjectionParameters(); }
void showScreenParametersDialog() { currentMapWidget()->updateScreenParameters(); }
void showUserForm() { currentMapWidget()->showUserForm(); }
void syncCurrentTab() { currentMapWidget()->sync(); }
void updateCurrentTabMap() { currentMapWidget()->updateMapDrawing(); }
void updateBrightnessContrast( float br, float cn ) { currentMapWidget()->updateBrightnessContrast( br, cn ); }
void updateLayerOrder( int idx, gis_render_sm_layer_type_t type ) { currentMapWidget()->updateLayerOrder( idx, type ); }
void updateTabText( int idx, QString str ) { setTabText( idx, str ); }
void updateDataSourcesForLayer( gis_render_sm_layer_type_t layer_type,
int num_of_data_sources,
gis_core_map_data_source_t *data_sources )
{
currentMapWidget()->updateDataSourcesForLayer( layer_type, num_of_data_sources, data_sources );
}
};
#endif

145
src/apps/gis-map-viewer/objectinfo.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,145 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "objectinfo.h"
#include <QDebug>
ObjectInfo::ObjectInfo( gis_render_sm_context_t sm_ctx, QWidget *parent ) :
QTreeWidget( parent ),
_sm_ctx( sm_ctx ),
selectionLine( nullptr )
{
setColumnCount( 2 );
setHeaderHidden( true );
setWindowTitle( tr( "Object Info" ) );
setFixedSize( 400, 120 );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
void ObjectInfo::showEvent( QShowEvent *event )
{
Q_UNUSED( event );
emit widgetVisibilityChanged( true );
}
void ObjectInfo::closeEvent( QCloseEvent *event )
{
Q_UNUSED( event );
deleteSelectionLine();
emit widgetVisibilityChanged( false );
}
void ObjectInfo::updateInfo( gis_object_t *obj )
{
fillObjectInfo( obj );
addSelectionLine( obj );
}
void ObjectInfo::fillObjectInfo( gis_object_t *obj )
{
clear();
QStringList list;
list << tr( "Class code:" ) << "0x" + QString::number( obj->class_code, 16 ).toUpper();
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
list << tr( "Class acronym:" ) << QString::fromUtf8( obj->class_acronym );
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
list << tr( "Type:" ) << QString::fromUtf8( gis_object_primitive_type_get_full_name( obj->type ) );
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
if ( obj->has_height )
{
list << tr( "Height:" ) << QString::number( obj->height );
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
}
list << tr( "Number of points:" ) << QString::number( obj->point_count );
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
if ( strlen( obj->attributes ) )
{
list << tr( "Attributes:" ) << QString::fromUtf8( obj->attributes );
addTopLevelItem( new QTreeWidgetItem( list ) );
list.clear();
}
resizeColumnToContents( 0 );
resizeColumnToContents( 1 );
}
void ObjectInfo::addSelectionLine( gis_object_t *obj )
{
uint32_t color = 0xF0FF0000;
uint32_t pen_width = 3;
QVector <double_point_t> points;
for ( uint32_t i = 0; i < obj->point_count; i++ )
{
double_point_t tmp;
tmp.x = obj->points[i].degrees.x;
tmp.y = obj->points[i].degrees.y;
points.push_back(tmp);
}
if ( selectionLine )
{
gis_render_sm_userdata_edit_object_points( _sm_ctx,
selectionLine,
points.data(),
obj->point_count );
}
else
{
selectionLine = gis_render_sm_userdata_add_polyline( _sm_ctx,
points.data(),
obj->point_count,
color, pen_width, 1 );
}
gis_render_sm_redraw_userobject( _sm_ctx, true );
}
void ObjectInfo::deleteSelectionLine()
{
if ( selectionLine )
{
gis_render_sm_userdata_delete_object( _sm_ctx, selectionLine );
selectionLine = nullptr;
gis_render_sm_redraw_userobject( _sm_ctx, true );
emit updateMapWidget();
}
}

58
src/apps/gis-map-viewer/objectinfo.h Обычный файл
Просмотреть файл

@ -0,0 +1,58 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef OBJECTINFO_H
#define OBJECTINFO_H
#include <QTreeWidget>
#include <gis/gis_objects.h>
#include <gis/gis_math.h>
#include <gis/gis_surfacemanager.h>
class ObjectInfo : public QTreeWidget
{
Q_OBJECT
public:
explicit ObjectInfo( gis_render_sm_context_t sm_ctx,
QWidget *parent = 0 );
void updateInfo( gis_object_t *obj );
private:
void showEvent( QShowEvent *event );
void closeEvent( QCloseEvent *event );
void fillObjectInfo( gis_object_t *obj );
void addSelectionLine( gis_object_t *obj );
void deleteSelectionLine();
gis_render_sm_context_t _sm_ctx;
gis_userobject_t selectionLine;
signals:
void updateMapWidget();
void widgetVisibilityChanged( bool );
};
#endif

1695
src/apps/gis-map-viewer/objectsearch.cpp Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

351
src/apps/gis-map-viewer/objectsearch.h Обычный файл
Просмотреть файл

@ -0,0 +1,351 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef OBJECTSEARCH_H
#define OBJECTSEARCH_H
#include <QTime>
#include <QDebug>
#include <QLabel>
#include <QWidget>
#include <QPointer>
#include <QLineEdit>
#include <QComboBox>
#include <QCompleter>
#include <QPushButton>
#include <QHeaderView>
#include <QTableWidget>
#include <QCloseEvent>
#include <QMouseEvent>
#include <QScrollBar>
#include <QScrollArea>
#include <QMessageBox>
#include <gis/gishelper.h>
#include <gis/gisrender.h>
#include <gis/gis_objects.h>
#include <gis/gis_surfacemanager.h>
#include "mapwidget.h"
#include <mapstylelayerwindow.h>
typedef struct {
uint32_t number;
uint32_t obj_idx;
QString class_acronym;
QString attributes;
} search_result_t;
class FilterLayout : public QGridLayout
{
Q_OBJECT
public:
FilterLayout( QWidget *parent = nullptr );
QSize getSizeWithWidth();
void setFilterPosition( int pos );
void setMyPosition( int pos );
int getFilterPosition();
int getMyPosition();
private:
int filter_pos;
int my_pos;
};
class FilterLabel : public QLabel
{
Q_OBJECT
public:
FilterLabel( QWidget *parent = nullptr );
void setMyRowLayout( FilterLayout *layout );
FilterLayout *getMyRowLayout();
private:
FilterLayout *my_row_layout;
};
class ClassAttrConfig : public QWidget
{
Q_OBJECT
public:
explicit ClassAttrConfig( QString class_acr,
QWidget *parent = nullptr );
void fillInfoTables( std::map<QString, std::map<QString, QStringList *> *> &class_attr_map );
private:
QString class_acronym;
QStringList attrFilters;
QVBoxLayout *vlayout;
QHBoxLayout *hlayout;
QHBoxLayout *buttons_lay;
QWidget *scroll_area_content;
QScrollArea *scroll_area;
QTableWidget *attr_info_table;
QStringList attr_info_header;
QPushButton *accept_btn;
QPushButton *cancel_btn;
const int MIN_WIDTH = 600;
const int MAX_HEIGHT = 900;
void showEvent( QShowEvent *event );
signals:
void giveAttrFilters( QString class_acr, QStringList attrFilters );
private slots:
void takeStoredAttrFilters( QStringList *storedAttrFilters );
void AddNewAttrFilter( int row );
void closeAndSave();
};
class WhereToSearchComboBox : public QComboBox
{
Q_OBJECT
public:
enum Where
{
ON_SHOWN_MAPS,
ON_ALL_MAPS
};
WhereToSearchComboBox( QWidget *parent = nullptr ) : QComboBox( parent )
{
this->setEditable( false );
this->setDuplicatesEnabled( false );
this->setMaxCount( 2 );
this->addItems( { tr( "On shown maps" ), tr( "On all maps" ) } );
}
};
class ObjectSearch : public QWidget
{
Q_OBJECT
public:
explicit ObjectSearch( QWidget *parent = nullptr );
~ObjectSearch();
void setCurrentTab( MapWidget *wgt );
MapWidget* getCurrentTab();
void updateLists( std::vector<ClassifierInfo> &classifier_list );
private:
QPointer<MapWidget> currentMapWidget;
QPointer<ClassAttrConfig> configWindow;
QStringList classAcronymList;
QStringList classifiersList;
QStringList searchResultsHeader;
GisObjectList *ptr_gis_obj_list;
QVBoxLayout *vlayout;
QHBoxLayout *hlayout;
QHBoxLayout *classifier_layout;
QHBoxLayout *wts_layout;
QHBoxLayout *class_key_layout;
QHBoxLayout *key_layout;
QVBoxLayout *tool_layout;
QVBoxLayout *all_filters_layout;
QWidget *scroll_area_content;
QScrollArea *scroll_area;
QVBoxLayout *scroll_with_btns;
QSpacerItem *horizontal_spacer;
FilterLayout *filter_layout;
QList<FilterLayout *> filter_lays_list;
QList<FilterLabel *> filter_label_list;
QComboBox *classifier_combobox;
QLineEdit *key_string;
QLineEdit *class_key_string;
QList<QTableWidgetItem *> cells_blocked;
QStringList class_search_header;
QTableWidget *class_search_table;
QTableWidget *search_results;
WhereToSearchComboBox *wts_combobox;
QPushButton *attr_filter_btn;
QPushButton *stop_btn;
QLabel *status_lbl;
gis_borders_t borders;
MapStyleLayerContainer *ptr_layer_container;
bool search_stopped;
bool search_stopped_by_button;
bool configure_btn_pressed;
int filter_pos;
static QString ALL_STR;
const int MIN_WIDTH = 640;
const int MAX_HEIGHT = 900;
const int SA_FIXED_WIDTH = 320;
const int SPACER_WIDTH = 1;
const int MARGIN = 10;
std::vector<ClassifierInfo> all_classifiers_info;
std::map<int32_t, std::vector<gis_core_class_info_t> *> all_classes_info_map;
std::vector<search_result_t> internalSearchResults;
std::vector<search_result_t> attrFilteredSearchResults;
std::map<QString, std::map<QString, QStringList *> *> class_attr_map;
std::map<QString, QStringList *> stored_filters_map;
template<typename T1,typename T2>
void clearMapWithPointers( std::map<T1, T2 *> &map )
{
for ( auto &pair : map )
{
delete pair.second;
}
map.clear();
}
template<typename T1,typename T2>
void eraseFromMapWithPointers( std::map<T1, T2 *> &map,
std::_Rb_tree_iterator<std::pair<const T1, T2 *>> &pair )
{
delete pair->second;
map.erase( pair );
}
void enableWidgets();
void disableWidgets();
void clearSearchData_SOFT();
void clearSearchData_HARD();
QString wrapToQStringUTF8( const char *string );
void addToClassAttrMap( search_result_t search_result );
void clearFromClassAttrMap( QString class_acr );
void clearFromStoredFiltersMap( QString class_acr );
void drawResTableRow( search_result_t res_item );
bool updateBorders();
gis_core_map_data_source_t getClassifierMapSource( const ClassifierInfo &classifier );
bool checkObjFormat( gis_object_t &obj,
int32_t classifier_idx,
const std::vector<gis_core_class_info_t> &classes,
gis_core_map_data_source_t format );
void searchInfoForLabel( QString class_acr );
void clearClassInfoFromResTable( QString class_acr );
void addInfoToResultTable( char *all_attributes_of_object,
char* class_acronym,
uint32_t idx );
void deleteFilterLabel( FilterLabel *label );
void mousePressEvent( QMouseEvent *event );
void showClassAttrConfig( FilterLabel *label );
void showEvent( QShowEvent *event );
void closeEvent( QCloseEvent *event );
signals:
void giveStoredAttrFilters( QStringList *storedAttrFilters );
void centerAtObject( double_point_t object_center );
void showInfoForFoundObject( gis_object_t current_object );
private slots:
void searchInfoForCurrentLabels();
void resizeResultTable();
void updateResultTable( QString key );
void stopSearch();
void configureAttr();
void rejectConfigureAttr();
void target_to_object( int row );
void fillClassesInfoMap( const ClassifierInfo &classifier );
void fillClassesAcrList( const ClassifierInfo &classifier );
void updateListsForClassifier( int classifier_combobox_idx );
void addNewFilterLabel( int row );
void searchClassTable( QString search_key );
void takeAttrFilters( QString class_acr, QStringList attrFilters );
};
#endif

12
src/apps/gis-map-viewer/resources.qrc Обычный файл
Просмотреть файл

@ -0,0 +1,12 @@
<RCC>
<qresource prefix="/">
<file>icons/zoomin50.png</file>
<file>icons/zoomout50.png</file>
<file>icons/shutdown.png</file>
<file>icons/ruler.png</file>
<file>icons/pin.png</file>
<file>icons/save_pin.png</file>
<file>icons/swd_logo.png</file>
<file>icons/undo.png</file>
</qresource>
</RCC>

6
src/apps/gis-map-viewer/translations.qrc Обычный файл
Просмотреть файл

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>translations/gis-map-viewer_ru.ts</file>
<file>translations/gis-map-viewer_ru.qm</file>
</qresource>
</RCC>

Просмотреть файл

@ -0,0 +1,571 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>ClassAttrConfig</name>
<message>
<source>Class attributes filter</source>
<translation>Фильтр атрибутов класса</translation>
</message>
<message>
<source>Accept</source>
<translation>Применить</translation>
</message>
<message>
<source>Cancel</source>
<translation>Отмена</translation>
</message>
</context>
<context>
<name>DepthEditor</name>
<message>
<source>Depth Editor</source>
<translation>Редактор Глубин</translation>
</message>
<message>
<source>Safety Depth</source>
<translation>Безопасная глубина</translation>
</message>
<message>
<source>Shallow Contour</source>
<translation>Контур мелководья</translation>
</message>
<message>
<source>Safety Contour</source>
<translation>Контур безопасной глубины</translation>
</message>
<message>
<source>Deep Contour</source>
<translation>Контур большой глубины</translation>
</message>
<message>
<source>Use Two Color Depth</source>
<translation>Два цвета области глубины</translation>
</message>
<message>
<source>Use Shallow Pattern</source>
<translation>Выделить мелководье</translation>
</message>
<message>
<source>Accept</source>
<translation>Применить</translation>
</message>
<message>
<source>Cancel</source>
<translation>Отмена</translation>
</message>
</context>
<context>
<name>DistanceMeter</name>
<message>
<source>Distance (km):</source>
<translation>Расстояние (км)</translation>
</message>
<message>
<source>Area (sq km):</source>
<translation>Площадь (кв. км):</translation>
</message>
<message>
<source>Add </source>
<translation>Добавить</translation>
</message>
<message>
<source>Delete</source>
<translation>Удалить</translation>
</message>
<message>
<source>Reset</source>
<translation>Сброс</translation>
</message>
<message>
<source>Meter</source>
<translation>Измеритель</translation>
</message>
<message>
<source>lat:</source>
<translation>ш:</translation>
</message>
<message>
<source> lon:</source>
<translation> д:</translation>
</message>
</context>
<context>
<name>HeightScale</name>
<message>
<source>Min: </source>
<translation>Мин: </translation>
</message>
<message>
<source>Max: </source>
<translation>Макс: </translation>
</message>
<message>
<source>Set</source>
<translation>Установить</translation>
</message>
</context>
<context>
<name>LayerWindow</name>
<message>
<source>User objects</source>
<translation>Польз. объекты</translation>
</message>
<message>
<source>Raster maps</source>
<translation>Растровые карты</translation>
</message>
<message>
<source>Vector maps</source>
<translation>Векторные карты</translation>
</message>
<message>
<source>Surfaces and data formats</source>
<translation>Поверхности и форматы карт</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<source>Map Viewer</source>
<translation>Средство просмотра</translation>
</message>
<message>
<source>Center at cursor</source>
<translation>Центр по курсору</translation>
</message>
<message>
<source>Main</source>
<translation>Меню</translation>
</message>
<message>
<source>Show only one map</source>
<translation>Показывать одну карту</translation>
</message>
<message>
<source>About</source>
<translation>О программе</translation>
</message>
<message>
<source>Exit</source>
<translation>Выход</translation>
</message>
<message>
<source>View parameters</source>
<translation>Вид</translation>
</message>
<message>
<source>Projections</source>
<translation>Проекции</translation>
</message>
<message>
<source>Screen parameters</source>
<translation>Параметры экрана</translation>
</message>
<message>
<source>Layers</source>
<translation>Слои</translation>
</message>
<message>
<source>Brighntess / Contrast</source>
<translation>Яркость/Констрастность</translation>
</message>
<message>
<source>New scaling mode</source>
<translation>Чертёжный режим</translation>
</message>
<message>
<source>Aliasing</source>
<translation>Сглаживание</translation>
</message>
<message>
<source>Scale by scroll</source>
<translation>Масштабирование колёсиком мыши</translation>
</message>
<message>
<source>Vector</source>
<translation>Вектор</translation>
</message>
<message>
<source>Palette</source>
<translation>Палитра</translation>
</message>
<message>
<source>Language</source>
<translation>Язык</translation>
</message>
<message>
<source>Format features</source>
<translation>Особые настройки формата</translation>
</message>
<message>
<source>Raster</source>
<translation>Растр</translation>
</message>
<message>
<source>Raster scale</source>
<translation>Шкала высот</translation>
</message>
<message>
<source>Auto height mode</source>
<translation>Автограницы высот</translation>
</message>
<message>
<source>Show out of limits height</source>
<translation>Показать высоты вне диапазона</translation>
</message>
<message>
<source>Discrete palette</source>
<translation>Дискретная палитра</translation>
</message>
<message>
<source>Tools</source>
<translation>Инструменты</translation>
</message>
<message>
<source>Refresh</source>
<translation>Обновить</translation>
</message>
<message>
<source>User objects</source>
<translation>Польз. объекты</translation>
</message>
<message>
<source>Map ruler</source>
<translation>Измеритель</translation>
</message>
<message>
<source>Search</source>
<translation>Поиск</translation>
</message>
<message>
<source>Depth editor</source>
<translation>Редактор Глубин</translation>
</message>
<message>
<source>National language</source>
<translation>Национальный язык</translation>
</message>
<message>
<source>Filters</source>
<translation>Фильтры</translation>
</message>
<message>
<source>Map style layers</source>
<translation>Слои классификатора</translation>
</message>
<message>
<source>Type of primitive</source>
<translation>Тип примитива</translation>
</message>
<message>
<source>Map type</source>
<translation>Тип карты</translation>
</message>
</context>
<context>
<name>MapStyleLayerWindow</name>
<message>
<source>State</source>
<translation>Состояние</translation>
</message>
<message>
<source>Layer name</source>
<translation>Имя слоя</translation>
</message>
<message>
<source>Layer number</source>
<translation>Номер слоя</translation>
</message>
<message>
<source>Sequence number</source>
<translation>Последовательный номер</translation>
</message>
<message>
<source>Select All</source>
<translation>Выбрать все</translation>
</message>
<message>
<source>Remove All</source>
<translation>Снять все</translation>
</message>
<message>
<source>Classifier name: </source>
<translation>Классификатор: </translation>
</message>
<message>
<source>Classifier layer management</source>
<translation>Управление слоями классификатора</translation>
</message>
</context>
<context>
<name>MapWidget</name>
<message>
<source>Save screen position</source>
<translation>Сохранить позицию на карте</translation>
</message>
<message>
<source> Lat: </source>
<translation> Ш: </translation>
</message>
<message>
<source> Long: </source>
<translation> Д: </translation>
</message>
<message>
<source>Delete screen position</source>
<translation>Удалить сохраненную позицию</translation>
</message>
</context>
<context>
<name>ObjectInfo</name>
<message>
<source>Object Info</source>
<translation>Сведения об объекте</translation>
</message>
<message>
<source>Class code:</source>
<translation>Код класса:</translation>
</message>
<message>
<source>Class acronym:</source>
<translation>Акроним:</translation>
</message>
<message>
<source>Type:</source>
<translation>Тип:</translation>
</message>
<message>
<source>Height:</source>
<translation>Высота:</translation>
</message>
<message>
<source>Number of points:</source>
<translation>Кол-во точек:</translation>
</message>
<message>
<source>Attributes:</source>
<translation>Атрибуты:</translation>
</message>
</context>
<context>
<name>ObjectSearch</name>
<message>
<source>Search objects</source>
<translation>Поиск объектов</translation>
</message>
<message>
<source>Classifier:</source>
<translation>Классификатор:</translation>
</message>
<message>
<source>Search class:</source>
<translation>Поиск класса</translation>
</message>
<message>
<source>Search attribute:</source>
<translation>Поиск атрибута</translation>
</message>
<message>
<source>Stop Searching</source>
<translation>Остановить поиск</translation>
</message>
<message>
<source>Configure class attributes</source>
<translation>Выбрать атрибуты класса</translation>
</message>
<message>
<source>Objects found: 0</source>
<translation>Найдено объектов: 0</translation>
</message>
<message>
<source>Class</source>
<translation>Класс</translation>
</message>
<message>
<source>Attributes</source>
<translation>Атрибуты</translation>
</message>
<message>
<source>Class Filter</source>
<translation>Фильтр по классам</translation>
</message>
<message>
<source>You must stop searching before exiting!</source>
<translation>Вы должны остановить поиск перед выходом!</translation>
</message>
<message>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<source>Stop the current search or wait for it to complete.</source>
<translation>Остановите текущий поиск или дождитесь его завершения.</translation>
</message>
<message>
<source>Warning</source>
<translation>Предупреждение</translation>
</message>
<message>
<source>Cancel</source>
<translation>Отмена</translation>
</message>
<message>
<source>Searching...</source>
<translation>Поиск...</translation>
</message>
<message>
<source>Objects found: %1</source>
<translation>Найдено объектов: %1</translation>
</message>
<message>
<source>Where to search:</source>
<translation>Где искать:</translation>
</message>
<message>
<source>All</source>
<translation>Все</translation>
</message>
</context>
<context>
<name>UserDialog</name>
<message>
<source>Dialog</source>
<translation>Диалог</translation>
</message>
<message>
<source>Color</source>
<translation>Цвет</translation>
</message>
<message>
<source>R:</source>
<translation>R:</translation>
</message>
<message>
<source>0</source>
<translation>0</translation>
</message>
<message>
<source>G:</source>
<translation>G:</translation>
</message>
<message>
<source>B:</source>
<translation>B:</translation>
</message>
<message>
<source>A:</source>
<translation>A:</translation>
</message>
<message>
<source>254</source>
<translation>254</translation>
</message>
<message>
<source>Border Color</source>
<translation>Цвет границы</translation>
</message>
<message>
<source>Line Width</source>
<translation>Толщина линии</translation>
</message>
<message>
<source>Pixels: </source>
<translation>Пикселей:</translation>
</message>
<message>
<source>Coordinates</source>
<translation>Координаты</translation>
</message>
<message>
<source>Longitude (x):</source>
<translation>Долгота (х):</translation>
</message>
<message>
<source>Latitude (y): </source>
<translation>Широта (у): </translation>
</message>
<message>
<source>Add point</source>
<translation>Добавить точку</translation>
</message>
<message>
<source>Clear list</source>
<translation>Очистить список</translation>
</message>
<message>
<source>Object type</source>
<translation>Тип объекта</translation>
</message>
<message>
<source>Po&amp;lygon</source>
<translation>Полигон</translation>
</message>
<message>
<source>Pol&amp;yline</source>
<translation>Полилиния</translation>
</message>
<message>
<source>Bit&amp;map</source>
<translation>Картинка</translation>
</message>
<message>
<source>Add object</source>
<translation>Добавить объект</translation>
</message>
<message>
<source>User Objects</source>
<translation>Польз. объекты</translation>
</message>
<message>
<source>( </source>
<translation>( </translation>
</message>
<message>
<source>; </source>
<translation>; </translation>
</message>
<message>
<source> )</source>
<translation> )</translation>
</message>
<message>
<source>Additional Settings</source>
<translation>Доп. настройки</translation>
</message>
<message>
<source>Scale bitmap</source>
<translation>Масштабировать картинку</translation>
</message>
<message>
<source>Remove All</source>
<translation>Удалить все</translation>
</message>
</context>
<context>
<name>ViewParameters</name>
<message>
<source>Brightness</source>
<translation>Яркость</translation>
</message>
<message>
<source>Contrast</source>
<translation>Контрастность</translation>
</message>
<message>
<source>Brightness/Contrast</source>
<translation>Яркость/Контрастность</translation>
</message>
</context>
<context>
<name>WhereToSearchComboBox</name>
<message>
<source>On shown maps</source>
<translation>Отображенные карты</translation>
</message>
<message>
<source>On all maps</source>
<translation>Все карты</translation>
</message>
</context>
</TS>

354
src/apps/gis-map-viewer/userdialog.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,354 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "userdialog.h"
#include "ui_userdialog.h"
#include <QDebug>
UserDialog::UserDialog( gis_render_sm_context_t external_sm_ctx,
gis_mdp_t external_mdp_ctx,
QVector<int> scale_vals,
QWidget *parent) :
QMainWindow( parent ),
ui( new Ui::UserDialog ),
sm_ctx( external_sm_ctx ),
disp_param( external_mdp_ctx ),
scales_v( scale_vals )
{
ui->setupUi( this );
setWindowTitle( tr( "User Objects" ) );
crutch_spacer = new QSpacerItem( 1, 158, QSizePolicy::Minimum, QSizePolicy::Minimum );
color = 0x8000FF00;
connect( ui->addObjectButton, SIGNAL( pressed() ),
this, SLOT( addObject() ) );
connect( ui->undoButton, SIGNAL( pressed() ),
this, SLOT( removeLast() ) );
connect( ui->removeAllButton, SIGNAL( pressed() ),
this, SLOT( removeAll() ) );
connect( ui->addPointBtn, SIGNAL( pressed() ),
this, SLOT( addPoint() ) );
connect( ui->clearPointList, SIGNAL( pressed() ),
this, SLOT( slotEraseList() ) );
ui->PolygonButton->setChecked( true );
v = new QIntValidator( 0, 255 );
ui->redEdit->setValidator( v );
ui->greenEdit->setValidator( v );
ui->blueEdit->setValidator( v );
ui->alphaEdit->setValidator( v );
ui->redEdit_2->setValidator( v );
ui->greenEdit_2->setValidator( v );
ui->blueEdit_2->setValidator( v );
ui->alphaEdit_2->setValidator( v );
ui->alphaEdit->setText( "255" );
ui->alphaEdit_2->setText( "255" );
ui->cb_scaleBitmap->setChecked( true );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
}
UserDialog::~UserDialog()
{
delete ui;
}
void UserDialog::showEvent( QShowEvent *event )
{
emit widgetVisibilityChanged( true );
event->accept();
}
void UserDialog::closeEvent( QCloseEvent *event )
{
deleteContourData();
emit widgetVisibilityChanged( false );
event->accept();
}
void UserDialog::setColor()
{
color = ( ui->alphaEdit->text().toUInt() << 24 )
+ ( ui->redEdit->text().toUInt() << 16 )
+ ( ui->greenEdit->text().toUInt() << 8 )
+ ( ui->blueEdit->text().toUInt() );
}
void UserDialog::setBorderColor()
{
border_color = ( ui->alphaEdit_2 ->text().toUInt() << 24 )
+ ( ui->redEdit_2->text().toUInt() << 16 )
+ ( ui->greenEdit_2->text().toUInt() << 8 )
+ ( ui->blueEdit_2->text().toUInt() );
}
void UserDialog::setPenWidth()
{
pen_width = ui->lineWidthEdit->text().toInt();
}
void UserDialog::addPoint()
{
point.x = ui->longitudeSpinBox->value();
point.y = ui->latitudeSpinBox->value();
QString str;
str = tr("( ") + ui->longitudeSpinBox->text() + tr("; ") +
ui->latitudeSpinBox->text() + tr(" )");
ui->pointList->addItem( str );
obj_points.append( point );
uint32_t contour_color = 0xF0FF0000;
uint32_t contour_pen_width = 5;
gis_userobject_t contour_obj = gis_render_sm_userdata_add_contour_object( sm_ctx,
obj_points.data(),
obj_points.size(),
contour_color,
contour_pen_width );
u_contour_v.push_back( contour_obj );
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
void UserDialog::userObjListener( QPoint pos )
{
double_point_t degree_pnt;
int32_point_t px_pos = { pos.x(), pos.y() };
gis_render_sm_convert_px2degree( sm_ctx, px_pos, &degree_pnt );
ui->longitudeSpinBox->setValue( degree_pnt.x );
ui->latitudeSpinBox->setValue( degree_pnt.y );
}
void UserDialog::deleteObjectsData()
{
if ( u_objects_v.empty() )
{
return;
}
for ( auto obj : u_objects_v )
{
gis_render_sm_userdata_delete_object( sm_ctx, obj );
}
u_objects_v.clear();
}
void UserDialog::deleteContourData()
{
if ( u_contour_v.empty() )
{
return;
}
for ( auto obj : u_contour_v )
{
gis_render_sm_userdata_delete_contour_object( sm_ctx, obj );
}
u_contour_v.clear();
}
void UserDialog::slotEraseList()
{
ui->pointList->clear();
obj_points.clear();
deleteContourData();
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
void UserDialog::addObject()
{
setColor();
setBorderColor();
setPenWidth();
if ( ui->PolylineButton->isChecked() )
{
addPolyline();
}
else if ( ui->PolygonButton->isChecked() )
{
addPolygon();
}
else if ( ui->BitmapButton->isChecked() )
{
addImage();
}
else
{
qDebug() << "toggled to unknown radio btn";
return;
}
slotEraseList();
}
void UserDialog::removeLast()
{
if ( !u_contour_v.empty() )
{
ui->pointList->takeItem( ui->pointList->count() - 1 );
gis_render_sm_userdata_delete_contour_object( sm_ctx, u_contour_v.back() );
u_contour_v.pop_back();
}
else if ( !u_objects_v.empty() )
{
gis_render_sm_userdata_delete_object( sm_ctx, u_objects_v.back() );
u_objects_v.pop_back();
}
gis_render_sm_redraw_userobject( sm_ctx, true );
emit updateMapWidget();
}
void UserDialog::removeAll()
{
deleteObjectsData();
slotEraseList();
}
void UserDialog::on_PolygonButton_toggled( bool checked )
{
if ( checked )
{
ui->widthBox_5->hide();
ui->cb_scaleBitmap->hide();
ui->mainLayout->removeItem( crutch_spacer );
ui->colorBox->show();
ui->borderColorBox->show();
}
}
void UserDialog::on_PolylineButton_toggled( bool checked )
{
if ( checked )
{
ui->borderColorBox->hide();
ui->cb_scaleBitmap->hide();
ui->mainLayout->removeItem( crutch_spacer );
ui->colorBox->show();
ui->widthBox_5->show();
}
}
void UserDialog::on_BitmapButton_toggled( bool checked )
{
if ( checked )
{
ui->mainLayout->insertItem( 0, crutch_spacer );
ui->borderColorBox->hide();
ui->widthBox_5->hide();
ui->colorBox->hide();
ui->cb_scaleBitmap->show();
}
}
void UserDialog::addPolyline()
{
obj = gis_render_sm_userdata_add_polyline( sm_ctx,
obj_points.data(),
obj_points.size(),
color,
pen_width, 0 );
u_objects_v.push_back( obj );
return;
}
void UserDialog::addPolygon()
{
obj = gis_render_sm_userdata_add_polygon( sm_ctx,
obj_points.data(),
obj_points.size(),
color,
border_color );
u_objects_v.push_back( obj );
return;
}
void UserDialog::addImage()
{
if ( ui->cb_scaleBitmap->isChecked() )
{
int max_scale = scales_v.back();
double scale_factor = (double)( gis_mdp_get_phys_scale( disp_param ) ) / max_scale;
QPixmap tmp_img( ":/icons/swd_logo.png" );
int scaled_width = tmp_img.width() * scale_factor;
image = new QPixmap( tmp_img.scaledToWidth( scaled_width ) );
if( image->isNull() )
{
int scaled_height = tmp_img.height() * scale_factor;
qDebug() << "Can't create QPixmap (width =" << scaled_width << " height =" << scaled_height << ")";
return;
}
}
else
{
image = new QPixmap( ":/icons/swd_logo.png" );
if( image->isNull() )
{
qDebug() << "Can't create QPixmap from standart image!";
return;
}
}
obj = gis_render_sm_userdata_add_bitmap( sm_ctx,
obj_points.data(),
obj_points.size(),
image );
u_objects_v.push_back( obj );
return;
}

101
src/apps/gis-map-viewer/userdialog.h Обычный файл
Просмотреть файл

@ -0,0 +1,101 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef USERDIALOG_H
#define USERDIALOG_H
#include <QCloseEvent>
#include <QMainWindow>
#include <QValidator>
#include <QSpacerItem>
#include <gis/gis_math.h>
#include <gis/gis_surfacemanager.h>
namespace Ui {
class UserDialog;
}
class UserDialog : public QMainWindow
{
Q_OBJECT
public:
explicit UserDialog( gis_render_sm_context_t external_sm_ctx,
gis_mdp_t external_mdp_ctx,
QVector<int> scale_vals,
QWidget *parent = 0 );
~UserDialog();
void addPolyline();
void addPolygon();
void addImage();
uint32_t getFillColor() { return color; }
uint32_t getBorderColor() { return border_color; }
uint32_t getPenWidth() { return pen_width; }
QVector <double_point_t> obj_points;
QPixmap *image;
private:
Ui::UserDialog *ui;
uint32_t color;
uint32_t border_color;
QValidator *v;
uint32_t pen_width;
gis_userobject_t obj;
gis_render_sm_context_t sm_ctx;
gis_mdp_t disp_param;
double_point_t point;
QVector<int> scales_v;
QSpacerItem *crutch_spacer;
std::vector<gis_userobject_t> u_objects_v;
std::vector<gis_userobject_t> u_contour_v;
void showEvent( QShowEvent *event );
void closeEvent( QCloseEvent *event );
void deleteContourData();
void deleteObjectsData();
private slots:
void setColor();
void setBorderColor();
void setPenWidth();
void addPoint();
void userObjListener( QPoint pos );
void addObject();
void removeAll();
void removeLast();
void slotEraseList();
void on_PolygonButton_toggled( bool checked );
void on_PolylineButton_toggled( bool checked );
void on_BitmapButton_toggled( bool checked );
signals:
void updateMapWidget();
void widgetVisibilityChanged( bool );
};
#endif

761
src/apps/gis-map-viewer/userdialog.ui Обычный файл
Просмотреть файл

@ -0,0 +1,761 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserDialog</class>
<widget class="QMainWindow" name="UserDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>332</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>332</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>332</width>
<height>600</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>332</width>
<height>600</height>
</size>
</property>
<widget class="QWidget" name="verticalLayoutWidget_3">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>312</width>
<height>591</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mainLayout">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QGroupBox" name="colorBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="title">
<string>Color</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>291</width>
<height>41</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="redEdit">
<property name="inputMethodHints">
<set>Qt::ImhNone</set>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="greenEdit">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="blueEdit">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>A:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="alphaEdit">
<property name="text">
<string>254</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="borderColorBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="title">
<string>Border Color</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_5">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>291</width>
<height>41</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>R:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="redEdit_2">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>G:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="greenEdit_2">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>B:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="blueEdit_2">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>A:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="alphaEdit_2">
<property name="text">
<string>254</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="widthBox_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>310</width>
<height>70</height>
</size>
</property>
<property name="title">
<string>Line Width</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_6">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>292</width>
<height>41</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="leftMargin">
<number>5</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Pixels: </string>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineWidthEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="coordinatesBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>200</height>
</size>
</property>
<property name="title">
<string>Coordinates</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>291</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Longitude (x):</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="longitudeSpinBox">
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_3">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>291</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Latitude (y): </string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="latitudeSpinBox">
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>-90.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_7">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>291</width>
<height>101</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="1,1">
<item>
<widget class="QListWidget" name="pointList">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0,1">
<item>
<widget class="QPushButton" name="addPointBtn">
<property name="text">
<string>Add point</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearPointList">
<property name="text">
<string>Clear list</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="objectTypeBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>60</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>310</width>
<height>60</height>
</size>
</property>
<property name="title">
<string>Object type</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_4">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>291</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>5</number>
</property>
<item>
<widget class="QRadioButton" name="PolygonButton">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Po&amp;lygon</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="PolylineButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Pol&amp;yline</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="BitmapButton">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bit&amp;map</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="additionalSettingsBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>60</height>
</size>
</property>
<property name="title">
<string>Additional Settings</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>11</x>
<y>19</y>
<width>291</width>
<height>41</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="cb_scaleBitmap">
<property name="text">
<string>Scale bitmap</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="0,1">
<property name="rightMargin">
<number>2</number>
</property>
<item>
<widget class="QPushButton" name="addObjectButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>Add object</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="undoButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="removeAllButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>310</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>310</width>
<height>30</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">
QPushButton {
background-color: qradialgradient( cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #FFFFFF, stop: 1 #ad2c23);
color: rgb( 0, 0, 0 );
border-radius: 2px;
border-width: 1px;
border-style: solid;
border-color: rgb( 162, 162, 162 );
}
QPushButton:hover {
background-color: #ad463e;
}
QPushButton:pressed {
background-color: #b37c78;
}</string>
</property>
<property name="text">
<string>Remove All</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<tabstops>
<tabstop>redEdit</tabstop>
<tabstop>greenEdit</tabstop>
<tabstop>blueEdit</tabstop>
<tabstop>alphaEdit</tabstop>
<tabstop>redEdit_2</tabstop>
<tabstop>greenEdit_2</tabstop>
<tabstop>blueEdit_2</tabstop>
<tabstop>alphaEdit_2</tabstop>
<tabstop>lineWidthEdit</tabstop>
<tabstop>longitudeSpinBox</tabstop>
<tabstop>latitudeSpinBox</tabstop>
<tabstop>addPointBtn</tabstop>
<tabstop>PolylineButton</tabstop>
<tabstop>BitmapButton</tabstop>
<tabstop>pointList</tabstop>
</tabstops>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

167
src/apps/gis-map-viewer/viewparameters.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,167 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "viewparameters.h"
#include <QDebug>
void ViewSlider::init( int interval )
{
setRange( m_range_min, m_range_max );
setTickPosition( QSlider::TicksBelow );
setTracking( false );
m_interval = abs( interval );
setTickInterval( interval );
setPageStep( interval );
}
ViewSlider::ViewSlider( int interval, QWidget *parent, int range_min, int range_max )
: QSlider( parent ), m_range_min( range_min ), m_range_max( range_max )
{
init( interval );
}
ViewSlider::ViewSlider( int interval, Qt::Orientation orientation, QWidget *parent, int range_min, int range_max )
: QSlider( orientation, parent ), m_range_min( range_min ), m_range_max( range_max )
{
init( interval );
}
void ViewSlider::updateTickValuesDisplay( QHBoxLayout *layout, size_t &tick_value_width )
{
QFont f( "monospace", 10 );
QLabel value_label;
size_t standart_w = 0;
int tick_count = (int)( abs( m_range_max - m_range_min ) / (float)m_interval + 0.5 ) + 1;
QLabel *last_value_label = new QLabel( QString::number( ( tick_count - 1 ) * m_interval ) );
last_value_label->setFont( f );
last_value_label->setAlignment( Qt::AlignCenter );
last_value_label->adjustSize();
last_value_label->setFixedSize( last_value_label->size() );
standart_w = last_value_label->size().width();
tick_value_width = standart_w;
for ( int i = 0; i < tick_count - 1; ++i )
{
QLabel *value_label = new QLabel( QString::number( i * m_interval ) );
value_label->setFont( f );
value_label->setAlignment( Qt::AlignCenter );
value_label->setFixedWidth( standart_w );
layout->addWidget( value_label );
layout->insertStretch( -1,1 );
}
layout->addWidget( last_value_label );
}
ViewParameters::ViewParameters( QWidget *parent ) : QWidget( parent, Qt::Window )
{
QGridLayout *main_lay = new QGridLayout();
brightness_slider = new ViewSlider( 10, Qt::Horizontal, this, 0, 100 );
contrast_slider = new ViewSlider( 10, Qt::Horizontal, this, 0, 100 );
br_slider_tick_val_hlay = new QHBoxLayout();
cn_slider_tick_val_hlay = new QHBoxLayout();
QLabel *br_label = new QLabel( tr( "Brightness" ), this );
QLabel *cn_label = new QLabel( tr( "Contrast" ), this );
size_t tick_value_width = 0;
brightness_slider->updateTickValuesDisplay( br_slider_tick_val_hlay, tick_value_width );
tick_value_width = tick_value_width / 2 - 5;
br_slider_hlay = new QHBoxLayout();
br_slider_hlay->addSpacerItem( new QSpacerItem( tick_value_width, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ) );
br_slider_hlay->addWidget( brightness_slider );
br_slider_hlay->addSpacerItem( new QSpacerItem( tick_value_width, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ) );
contrast_slider->updateTickValuesDisplay( cn_slider_tick_val_hlay, tick_value_width );
tick_value_width = tick_value_width / 2 - 5;
cn_slider_hlay = new QHBoxLayout();
cn_slider_hlay->addSpacerItem( new QSpacerItem( tick_value_width, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ) );
cn_slider_hlay->addWidget( contrast_slider );
cn_slider_hlay->addSpacerItem( new QSpacerItem( tick_value_width, 0, QSizePolicy::Fixed, QSizePolicy::Minimum ) );
main_lay->addWidget( br_label, 0, 1 );
main_lay->addLayout( br_slider_hlay, 1, 1, 1, 2 );
main_lay->addLayout( br_slider_tick_val_hlay, 2, 1, 1, 2 );
main_lay->addWidget( cn_label, 3, 1 );
main_lay->addLayout( cn_slider_hlay, 4, 1, 1, 2 );
main_lay->addLayout( cn_slider_tick_val_hlay, 5, 1, 1, 2 );
connect( brightness_slider, SIGNAL( valueChanged( int ) ),
this, SLOT( slotGetNewBrightnessContrast( int ) ) );
connect( contrast_slider, SIGNAL( valueChanged( int ) ),
this, SLOT( slotGetNewBrightnessContrast( int ) ) );
auto flags = windowFlags();
setWindowFlags( flags |
Qt::WindowStaysOnTopHint |
Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint );
setLayout( main_lay );
setWindowTitle( tr( "Brightness/Contrast" ) );
main_lay->setSizeConstraint( QLayout::SetFixedSize );
}
void ViewParameters::showEvent( QShowEvent *event )
{
if ( parentWidget() )
{
int x = 10;
int y = ( 15 + height() );
QPoint relative_pos = parentWidget()->mapToGlobal( QPoint( x, y ) );
move( relative_pos );
}
else
{
qDebug() << "ViewParameters: can't get pointer to parent Widget!";
}
event->accept();
}
void ViewParameters::updateBrightnessContrast( float brightness,
float contrast )
{
brightness_slider->setValue( 50 + brightness * 50 );
contrast_slider->setValue( 50 + contrast * 50 );
}
void ViewParameters::slotGetNewBrightnessContrast( int value )
{
Q_UNUSED( value );
emit signalNewBrightnessContrastValues( brightness_slider->value() / 50. - 1.,
contrast_slider->value() / 50. - 1. );
}

81
src/apps/gis-map-viewer/viewparameters.h Обычный файл
Просмотреть файл

@ -0,0 +1,81 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef VIEWPARAMETERS_H
#define VIEWPARAMETERS_H
#include <QGridLayout>
#include <QLabel>
#include <QSlider>
#include <QWidget>
#include <QShowEvent>
class ViewSlider : public QSlider
{
Q_OBJECT
public:
explicit ViewSlider( int interval,
QWidget *parent = 0,
int range_min = 0,
int range_max = 100 );
explicit ViewSlider( int interval,
Qt::Orientation orientation,
QWidget *parent = 0,
int range_min = 0,
int range_max = 100 );
void updateTickValuesDisplay( QHBoxLayout *layout, size_t &tick_value_width );
private:
int m_interval;
const int m_range_min;
const int m_range_max;
void init( int interval );
};
class ViewParameters : public QWidget
{
Q_OBJECT
public:
explicit ViewParameters( QWidget *parent = 0 );
void updateBrightnessContrast( float brightness, float contrast );
private:
QHBoxLayout *br_slider_hlay;
QHBoxLayout *cn_slider_hlay;
QHBoxLayout *br_slider_tick_val_hlay;
QHBoxLayout *cn_slider_tick_val_hlay;
ViewSlider *brightness_slider;
ViewSlider *contrast_slider;
void showEvent( QShowEvent *event );
private slots:
void slotGetNewBrightnessContrast( int value );
signals:
void signalNewBrightnessContrastValues( float br, float cn );
};
#endif

79
src/apps/gis-monitor/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,79 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-monitor LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -Wno-ignored-attributes )
add_compile_options( -Wno-deprecated-declarations )
find_package( Qt5
COMPONENTS
Core
Gui
Svg
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
mainwindow.ui
images.qrc
translations.qrc )
add_executable( gis-monitor ${SOURCES} )
add_custom_command( OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-monitor_ru.qm
COMMAND
$ENV{KPDA_HOST}/usr/lib/Qt/bin/lrelease -silent ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts )
add_custom_target( generate_translations_monitor
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/translations/gis-monitor_ru.qm )
target_include_directories( gis-monitor
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gisrender/api/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} )
add_dependencies( gis-monitor generate_translations_monitor )
target_link_libraries( gis-monitor
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Svg
Qt5::Widgets
gishelper
gisrender )
install( TARGETS gis-monitor DESTINATION bin )

Двоичные данные
src/apps/gis-monitor/asserts/view.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 151 KiB

876
src/apps/gis-monitor/background/mercator.svg Обычный файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 877 KiB

724
src/apps/gis-monitor/drivermappage.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,724 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "drivermappage.h"
#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>
#include <QFileInfo>
#include <QMessageBox>
#include <QTextCodec>
#include "engine.h"
#include "mapcanvas.h"
#include "mapview.h"
extern bool demo_mode;
int DriverMapPage::VIEWER_COUNTER = 0;
DriverMapPage::DriverMapPage( QObject *ext_e, gis_core_driver_info_t *i, QWidget *parent ) :
QWidget( parent ),
scaling_point( { 0, 0 } ),
scrollBarFlag( true ),
gridFlag( false ),
suffixFlag( false ),
driver_info( *i ),
viewerProcess( nullptr ),
rasterViewProcess( nullptr )
{
e = static_cast<Engine*>( ext_e );
connect( e, SIGNAL( setStatusBusy() ),
this, SLOT( setDriverStateBusy() ) );
connect( this, SIGNAL( updateSelectedMapInfo( gis_core_map_information_t* ) ),
this, SLOT( fillAdditionalInfo( gis_core_map_information_t* ) ) );
connect( this, SIGNAL( updateSelectedMapInfo( gis_core_map_information_t* ) ),
this, SLOT( fillClassList( gis_core_map_information_t* ) ) );
page_type = gis_helper_get_map_source_by_driver_id( getDriverId() );
initializeWidgetAppearance();
loadMaps();
}
DriverMapPage::~DriverMapPage()
{
if ( viewerProcess )
{
disconnect( viewerProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
disconnect( viewerProcess, SIGNAL( started() ),
this, SLOT( processStarted() ) );
disconnect( viewerProcess, SIGNAL( error( QProcess::ProcessError ) ),
this, SLOT( processErrorHandler( QProcess::ProcessError ) ) );
if ( ( viewerProcess->state() == QProcess::Running ) ||
( viewerProcess->state() == QProcess::Starting) )
{
viewerProcess->terminate();
viewerProcess->waitForFinished();
}
}
if ( rasterViewProcess )
{
disconnect( rasterViewProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
disconnect( rasterViewProcess, SIGNAL( started() ),
this, SLOT( processStarted() ) );
disconnect( rasterViewProcess, SIGNAL( error( QProcess::ProcessError ) ),
this, SLOT( processErrorHandler( QProcess::ProcessError ) ) );
if ( ( rasterViewProcess->state() == QProcess::Running ) ||
( rasterViewProcess->state() == QProcess::Starting) )
{
rasterViewProcess->terminate();
rasterViewProcess->waitForFinished();
}
}
delete actionScaleArea;
delete gsView;
delete gsCanvas;
delete listMapInfo;
delete listClasses;
delete listMaps;
e->deleteMaps( mlist );
}
gis_borders_t DriverMapPage::mapBordersTo_MERC_WGS84( gis_core_map_information_t *map_info )
{
gis_borders_t new_borders = map_info->borders;
switch ( map_info->meters_projection.projection_idx )
{
case GIS_PROJECTION_CONIC_CONFORMAL:
{
new_borders.degrees.north = GIS_MERC_WGS84_NORTH_BOUND;
break;
}
default:
{
break;
}
}
return new_borders;
}
QString DriverMapPage::degrees2string( double d )
{
int degrees, minutes, seconds;
QString info;
degrees = d;
minutes = (d - degrees) * 60;
seconds = ((d - degrees) * 60 - minutes) * 60;
minutes = minutes < 0 ? -minutes : minutes;
seconds = seconds < 0 ? -seconds : seconds;
info = QString::number( degrees ) +
QObject::trUtf8( "°" ) +
QString::number( minutes ) + "\'" +
QString::number( seconds ) + "\"";
return info;
}
void DriverMapPage::mapListItemChanged( QListWidgetItem *item, QListWidgetItem *prev )
{
Q_UNUSED( item );
Q_UNUSED( prev );
int mapIndex = listMaps->currentIndex().row();
if ( mapIndex >= 0 )
{
gis_core_map_information_t *map = &mlist->entry_list[mapIndex];
gsCanvas->addSelectionRectangle( mapBordersTo_MERC_WGS84( map ) );
emit updateSelectedMapInfo( map );
}
}
void DriverMapPage::fillAdditionalInfo( gis_core_map_information_t *map )
{
QString info_name, info_value;
QStringList listClassData;
listMapInfo->clear();
if ( gis_map_projection_is_filled( &map->meters_projection ) )
{
if ( map->meters_projection.EPSG )
{
listClassData << "EPSG: " << QString::number( map->meters_projection.EPSG );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
listClassData << tr( "Projection: " ) << tr( gis_map_projection_get_full_name( &map->meters_projection ) );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
listClassData << tr( "Ellipsoid: " ) << tr( gis_map_ellipsoid_get_full_name( &map->meters_projection ) );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
if ( map->meters_projection.height_system_idx != GIS_HEIGHT_SYSTEM_EMPTY )
{
listClassData << tr( "Height system: " )
<< tr( gis_map_height_system_get_full_name( map->meters_projection.height_system_idx ) );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
if ( gis_map_projection_has_zone( map->meters_projection.projection_idx ) )
{
listClassData << tr( "Zone: " ) << QString::number( map->meters_projection.zone );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
}
gis_borders_t merc_borders = mapBordersTo_MERC_WGS84( map );
QString origin_borders_N = fabs( merc_borders.degrees.north - map->borders.degrees.north ) > DBL_EPSILON ?
" (" + degrees2string( map->borders.degrees.north ) + ")" : "";
QString origin_borders_W = fabs( merc_borders.degrees.west - map->borders.degrees.west ) > DBL_EPSILON ?
" (" + degrees2string( map->borders.degrees.west ) + ")" : "";
QString origin_borders_S = fabs( merc_borders.degrees.south - map->borders.degrees.south ) > DBL_EPSILON ?
" (" + degrees2string( map->borders.degrees.south ) + ")" : "";
QString origin_borders_E = fabs( merc_borders.degrees.east - map->borders.degrees.east ) > DBL_EPSILON ?
" (" + degrees2string( map->borders.degrees.east ) + ")" : "";
info_name = "N: ";
info_value = degrees2string( merc_borders.degrees.north ) + origin_borders_N;
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
info_name = "S: ";
info_value = degrees2string( merc_borders.degrees.south ) + origin_borders_S;
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
info_name = "W: ";
info_value = degrees2string( merc_borders.degrees.west ) + origin_borders_W;
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
info_name = "E: ";
info_value = degrees2string( merc_borders.degrees.east ) + origin_borders_E;
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
if ( map->scale_denominator )
{
info_name = tr( "Scale: " );
info_value = "1:" + QString::number( map->scale_denominator );
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
if ( e->isVectorMap( getDriverId() ) )
{
info_name = tr( "Class count: " );
info_value = QString::number( map->class_count );
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
info_name = tr( "Object count: " );
info_value = QString::number(map->object_count);
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
info_name = tr( "Classifier: " );
info_value = QString( map->formats.vector.classifier_filename );
info_value = QString::fromUtf8( info_value.toLatin1().constData() );
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
if ( map->data_source == GIS_CORE_MAP_DATA_SOURCE_S57 )
{
info_name = tr( "Update: " );
info_value = QString( map->src_version );
info_value = QString::fromUtf8( info_value.toLatin1().constData() );
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
}
else
{
info_name = tr("Height: ");
if ( fabs( map->formats.raster.min_height - GIS_INVALID_HEIGHT_VALUE ) > DBL_EPSILON &&
fabs( map->formats.raster.max_height - GIS_INVALID_HEIGHT_VALUE ) > DBL_EPSILON )
{
info_value = QString::number( map->formats.raster.min_height ) + " - "
+ QString::number( map->formats.raster.max_height ) + tr( " m" );
listClassData << info_name << info_value;
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
listClassData.clear();
}
}
}
void DriverMapPage::fillClassList( gis_core_map_information_t *actual_map )
{
listClasses->clear();
if ( e->isVectorMap( getDriverId() ) )
{
gis_core_class_list_t *clist = e->getClassList( actual_map );
if ( clist )
{
for ( uint32_t i = 0; i < clist->entry_count; i++ )
{
QStringList listClassData;
gis_core_class_info_t *actual_class = &clist->entry_list[i];
listClassData << QString::number( actual_class->class_data.code, 16 );
listClassData << QString::fromUtf8( actual_class->acronym );
listClassData << QString::number( actual_class->object_count );
listClasses->addTopLevelItem( new QTreeWidgetItem( listClassData ) );
}
e->deleteClassList( clist );
}
}
}
void DriverMapPage::slotSelectMapRect( QPointF p )
{
int min_rect_index = gsCanvas->getMapIndexFromClickedRect( p );
if ( min_rect_index < 0 || min_rect_index > (int)mlist->entry_count )
{
return;
}
gis_core_map_information_t *map = &mlist->entry_list[min_rect_index];
gsCanvas->addSelectionRectangle( mapBordersTo_MERC_WGS84( map ) );
listMaps->setCurrentRow( min_rect_index );
}
void DriverMapPage::setScrollBarsEnabled( bool enabled )
{
scrollBarFlag = enabled;
if( scrollBarFlag )
{
gsView->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
gsView->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
}
else
{
gsView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
gsView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
}
}
void DriverMapPage::scaleAreaTriggered( bool checked )
{
Q_UNUSED( checked );
if ( gsCanvas->scalingAreaFlag )
{
actionScaleArea->setChecked( false );
gsView->setDragMode( QGraphicsView::ScrollHandDrag );
gsCanvas->scalingAreaFlag = false;
}
else
{
actionScaleArea->setChecked( true );
gsView->setDragMode( QGraphicsView::NoDrag );
gsCanvas->scalingAreaFlag = true;
}
}
void DriverMapPage::changeGridState( bool flag )
{
gridFlag = flag;
emit showGrid( flag );
}
void DriverMapPage::changeSuffixState( bool flag )
{
suffixFlag = flag;
updatePage();
}
void DriverMapPage::startViewer( double_point_t degree_center )
{
QString program = QCoreApplication::applicationDirPath() + "/gis-map-viewer";
QStringList arguments;
arguments << "-x" << QString::number( degree_center.x );
arguments << "-y" << QString::number( degree_center.y );
if ( demo_mode )
arguments << "-D" << QString::number( getDriverId() );
arguments << "-i" << QString::number( driver_info.driver_id + DriverMapPage::VIEWER_COUNTER++ );
if ( viewerProcess )
{
viewerProcess->kill();
delete viewerProcess;
}
viewerProcess = new QProcess( this );
connect( viewerProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
connect( viewerProcess, SIGNAL( started() ),
this, SLOT( processStarted() ) );
connect( viewerProcess, SIGNAL( error( QProcess::ProcessError ) ),
this, SLOT( processErrorHandler( QProcess::ProcessError ) ) );
viewerProcess->setProcessChannelMode( QProcess::ForwardedChannels );
viewerProcess->start( program, arguments );
gsView->setDragMode( QGraphicsView::ScrollHandDrag );
}
void DriverMapPage::processErrorHandler( QProcess::ProcessError err )
{
QString appName;
if ( sender() == viewerProcess )
{
appName = "gis-map-viewer";
}
else if ( sender() == rasterViewProcess )
{
appName = "gis-raster-preview";
}
switch( err )
{
case QProcess::ProcessError::FailedToStart:
qDebug() << "Failed to start " << appName;
break;
case QProcess::ProcessError::Crashed:
qDebug() << "Crashed" << appName;
break;
default:
break;
}
}
void DriverMapPage::initializeWidgetAppearance()
{
QGridLayout *layout = new QGridLayout;
QSplitter *vspl = new QSplitter( Qt::Vertical );
QSplitter *hspl2 = new QSplitter( Qt::Horizontal );
QSplitter *hspl3 = new QSplitter( Qt::Horizontal );
listMaps = new QListWidget( this );
listClasses = new QTreeWidget;
listMapInfo = new QTreeWidget;
gsCanvas = new MapCanvas;
gsView = new MapView( static_cast<QGraphicsScene*>( gsCanvas ), static_cast<QWidget*>( this ) );
QToolBar *tools = new QToolBar;
listMaps->setMaximumWidth( 200 );
listMaps->setMinimumWidth( 110 );
listClasses->setColumnCount( 3 );
QStringList listClassesHeaders;
listClassesHeaders << tr( "Class code" ) << tr( "Acronym" ) << tr( "Object count" );
listClasses->setHeaderLabels( listClassesHeaders );
listClasses->setColumnWidth( 0, 120 );
listClasses->setColumnWidth( 1, 170 );
listClasses->setMaximumHeight( 350 );
labelMaps.setText( tr( "Maps:" ) );
QString str;
str.clear();
str.append( "N-W:\n" );
str.append( "S-E: \n" );
str.append( tr( "Scale:\n" ) );
str.append( tr( "Class count:\n" ) );
str.append( tr( "Object count:" ) );
labelAdditionalInfo.setText( str );
listMapInfo->setColumnCount( 2 );
listMapInfo->setColumnWidth( 0, 111 );
QStringList headerLabels;
headerLabels << tr( "Map property" ) << tr( "Value" );
listMapInfo->setHeaderLabels( headerLabels );
QStringList listMapData;
listMapData << labelAdditionalInfo.text();
listMapInfo->setMaximumSize( 300, 350 );
listMapInfo->setMinimumSize( 300, 130 );
listMapInfo->addTopLevelItem( new QTreeWidgetItem( listMapData ) );
gsView->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
gsView->setMinimumSize( 400, 200 );
layout->addWidget( &labelMaps, 0, 0, 1, 1 );
layout->addWidget( tools, 0, 7, 1, 1 );
labelSubStatus.setContentsMargins( 0,0,6,0 );
labelMainStatus.setMaximumHeight( 20 );
labelSubStatus.setMaximumHeight( 20 );
layout->addWidget( &labelMainStatus, 5, 0, 1, 4 );
layout->addWidget( &labelSubStatus, 5, 4, 1, 4 );
hspl2->addWidget( listMaps );
hspl2->addWidget( gsView );
gsView->slotFitScale( true );
hspl2->setCollapsible( 0, false );
hspl2->setCollapsible( 1, false );
hspl3->addWidget( listMapInfo );
hspl3->addWidget( listClasses );
hspl3->setCollapsible( 0, false );
hspl3->setCollapsible( 1, false );
vspl->addWidget( hspl2 );
vspl->addWidget( hspl3 );
vspl->setCollapsible( 0, false );
vspl->setCollapsible( 1, false );
layout->addWidget( vspl, 1, 0, 4, 8 );
layout->setRowMinimumHeight( 1, 400 );
setLayout( layout );
connect( listMaps, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ),
this, SLOT( mapListItemChanged( QListWidgetItem*, QListWidgetItem* ) ) );
connect( listMaps, SIGNAL( itemDoubleClicked( QListWidgetItem* ) ),
this, SLOT( mapItemDblClicked( QListWidgetItem* ) ) );
connect( gsCanvas, SIGNAL( scalingAreaFlagChanged( bool ) ),
this, SLOT( scaleAreaTriggered( bool ) ) );
connect( gsCanvas, SIGNAL( getDoubleClick( double_point_t ) ),
this, SLOT( startViewer( double_point_t ) ) );
QAction *actionIncreaseScale = new QAction( QIcon( ":/icons/zoomin50.png" ), "+", this );
actionIncreaseScale->setShortcuts( QList<QKeySequence>() << QKeySequence( Qt::CTRL + Qt::Key_Equal ) << QKeySequence::ZoomIn );
QAction *actionReduceScale = new QAction( QIcon( ":/icons/zoomout50.png" ), "-", this );
actionReduceScale->setShortcut( QKeySequence::ZoomOut );
QAction *actionFitScale = new QAction( QIcon( ":/icons/fit50.png" ), tr( "Fit" ), this );
actionScaleArea = new QAction( QIcon( ":/icons/area.png" ), tr( "Area" ), this );
actionScaleArea->setCheckable( true );
connect( actionScaleArea, SIGNAL( triggered( bool ) ), this, SLOT( scaleAreaTriggered( bool ) ) );
connect( actionIncreaseScale, SIGNAL( triggered( bool ) ), gsView, SLOT( slotIncreaseScale( bool ) ) );
connect( actionReduceScale, SIGNAL( triggered( bool ) ), gsView, SLOT( slotDecreaseScale( bool ) ) );
connect( actionFitScale, SIGNAL( triggered( bool ) ), gsView, SLOT( slotFitScale( bool ) ) );
QActionGroup *actionGroup = new QActionGroup( this );
actionGroup->addAction( actionIncreaseScale );
actionGroup->addAction( actionReduceScale );
actionGroup->addAction( actionFitScale );
actionGroup->addAction( actionScaleArea );
tools->addActions( actionGroup->actions() );
gsView->setDragMode( QGraphicsView::ScrollHandDrag );
gsView->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
gsView->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
connect( gsCanvas, SIGNAL( increaseScale( bool ) ),
gsView, SLOT( slotIncreaseScale( bool ) ) );
connect( gsCanvas, SIGNAL( decreaseScale( bool ) ),
gsView, SLOT( slotDecreaseScale( bool ) ) );
connect( gsCanvas, SIGNAL( scalingAreaByRect( QRectF ) ),
gsView, SLOT( scaleAreaByRect( QRectF ) ) );
connect( this, SIGNAL( showGrid( bool ) ),
gsCanvas, SLOT( slotShowGrid( bool ) ) );
geometry_rect = QApplication::desktop()->screenGeometry( this );
}
void DriverMapPage::setScaleFilter( int lower_limit, int upper_limit )
{
scaling_point.x = lower_limit;
scaling_point.y = upper_limit;
gsCanvas->removeAllSelection();
if ( lower_limit == 0 && upper_limit == 0 )
{
for ( uint32_t i = 0; i < mlist->entry_count; i++ )
{
listMaps->item( i )->setHidden( false );
gsCanvas->setMapRectEnabled( i, true );
}
}
else
{
for ( unsigned int i = 0; i < mlist->entry_count; i++ )
{
listMaps->item( i )->setHidden( true );
gsCanvas->setMapRectEnabled( i, false );
}
for ( unsigned int i = 0; i < mlist->entry_count; i++ )
{
int scale = mlist->entry_list[i].scale_denominator;
if ( ( scale >= lower_limit ) && ( ( scale < upper_limit ) || ( upper_limit == 10000000 ) ) )
{
listMaps->item( i )->setHidden( false );
gsCanvas->setMapRectEnabled( i, true );
}
}
}
}
void DriverMapPage::loadMaps()
{
mlist = e->getMaps( getDriverId() );
if ( mlist )
{
for ( unsigned int i = 0; i < mlist->entry_count; i++ )
{
gis_core_map_information_t *map = &mlist->entry_list[i];
QString display_string;
if ( suffixFlag )
{
display_string = QString( map->gcm_fname );
display_string = QString::fromUtf8( display_string.toLatin1().constData() );
listMaps->addItem( new QListWidgetItem( display_string ));
}
else
{
display_string = QString( map->src_fname );
display_string = QString::fromUtf8( display_string.toLatin1().constData() );
listMaps->addItem( new QListWidgetItem( display_string ));
}
gsCanvas->addMapRectangle( i, mapBordersTo_MERC_WGS84( map ), this );
}
listMaps->setSelectionMode( QAbstractItemView::SingleSelection );
QString substatusString;
substatusString = tr( "Number of loaded maps: " )
+ QString::number( mlist->entry_count );
labelSubStatus.setText( substatusString );
labelSubStatus.setAlignment( Qt::AlignRight );
setDriverStateReady();
}
else
{
setDisabled(true);
QPalette palette = labelSubStatus.palette();
palette.setColor( labelSubStatus.foregroundRole(), Qt::red );
labelSubStatus.setPalette( palette );
setDriverStateReady();
labelSubStatus.setText( tr( "Connection status: request failed" ) );
}
}
void DriverMapPage::updatePage()
{
listMaps->clear();
listMaps->setSelectionMode( QAbstractItemView::NoSelection );
listClasses->clear();
listMapInfo->clear();
gsCanvas->removeAllRects();
e->deleteMaps( mlist );
loadMaps();
update();
}
void DriverMapPage::setDriverStateBusy()
{
QPalette palette = labelMainStatus.palette();
palette.setColor( labelMainStatus.foregroundRole(), Qt::red );
labelMainStatus.setPalette( palette );
labelMainStatus.setText( tr( "Driver status: " ) + tr( "busy" ) );
}
void DriverMapPage::setDriverStateReady()
{
QPalette palette = labelMainStatus.palette();
palette.setColor( labelMainStatus.foregroundRole(), Qt::black );
labelMainStatus.setPalette( palette );
labelMainStatus.setText( tr( "Driver status: " ) + tr( "ready" ) );
}
void DriverMapPage::mapItemDblClicked( QListWidgetItem* item )
{
int map_idx = listMaps->row( item );
gis_core_map_information_t *map = &mlist->entry_list[map_idx];
gsView->centerOn( gsCanvas->getMapRectItemToCenter( map_idx ) );
if ( GIS_IS_CORE_MAP_DATA_SOURCE_VECTOR( map->data_source ) )
{
return;
}
QString program = QCoreApplication::applicationDirPath() + "/gis-raster-preview";
QStringList arguments;
QString map_path = gis_helper_env_get_maps_cache_directory();
map_path += "/gcm/";
map_path += map->gcm_fname;
QRect r = listMaps->visualItemRect( item );
QPoint selected_item_position( r.x() + 10, r.y() + r.height() );
QRect mw_rect = parentWidget()->parentWidget()->parentWidget()->window()->geometry();
arguments << "-x" << QString::number(selected_item_position.x() + 10 + mw_rect.x());
arguments << "-y" << QString::number(selected_item_position.y() + 125 + mw_rect.y());;
arguments << "-f" << map_path;
if ( rasterViewProcess )
{
rasterViewProcess->kill();
delete rasterViewProcess;
}
rasterViewProcess = new QProcess( this );
connect( rasterViewProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( processFinished( int, QProcess::ExitStatus ) ) );
connect( rasterViewProcess, SIGNAL( started() ),
this, SLOT( processStarted() ) );
connect( rasterViewProcess, SIGNAL( error( QProcess::ProcessError ) ),
this, SLOT( processErrorHandler( QProcess::ProcessError ) ) );
rasterViewProcess->setProcessChannelMode( QProcess::ForwardedChannels );
rasterViewProcess->start( program, arguments );
}

126
src/apps/gis-monitor/drivermappage.h Обычный файл
Просмотреть файл

@ -0,0 +1,126 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef DRIVERMAPPAGE_H
#define DRIVERMAPPAGE_H
#include <QAction>
#include <QGridLayout>
#include <QLabel>
#include <QListWidget>
#include <QPointer>
#include <QProcess>
#include <QSplitter>
#include <QToolBar>
#include <QTreeWidget>
#include <gis/gis_databuffer.h>
#include <gis/gis_math.h>
#include <gis/gis_path.h>
#include "engine.h"
class MapCanvas;
class MapView;
class DriverMapPage : public QWidget
{
Q_OBJECT
public:
DriverMapPage( QObject *e, gis_core_driver_info_t *i, QWidget *parent = 0 );
~DriverMapPage();
gis_core_driver_id_t getDriverId() { return driver_info.driver_id; }
gis_core_map_data_source_t getPageType() { return page_type; }
void changeGridState( bool );
void changeSuffixState( bool );
void setScrollBarsEnabled( bool enabled );
void setScaleFilter( int lower_limit, int upper_limit );
void updatePage();
int32_point_t scaling_point;
bool scrollBarFlag;
bool gridFlag;
bool suffixFlag;
private:
void initializeWidgetAppearance();
void loadMaps();
gis_borders_t mapBordersTo_MERC_WGS84( gis_core_map_information_t *map_info );
QString degrees2string( double d );
QPointer <Engine> e;
gis_core_map_data_source_t page_type;
gis_core_driver_info_t driver_info;
gis_core_map_list_t *mlist;
static int VIEWER_COUNTER;
QRect geometry_rect;
QProcess *viewerProcess;
QProcess *rasterViewProcess;
QListWidget *listMaps;
QTreeWidget *listMapInfo;
QTreeWidget *listClasses;
MapCanvas *gsCanvas;
MapView *gsView;
QLabel labelMaps;
QLabel labelAdditionalInfo;
QLabel labelMainStatus;
QLabel labelSubStatus;
QAction *actionScaleArea;
QAction *actionGrid;
public slots:
void startViewer( double_point_t center );
private slots:
void fillAdditionalInfo( gis_core_map_information_t *actual_map );
void fillClassList( gis_core_map_information_t *actual_map );
void mapItemDblClicked( QListWidgetItem* );
void mapListItemChanged( QListWidgetItem*, QListWidgetItem* );
void scaleAreaTriggered( bool checked );
void slotSelectMapRect( QPointF point );
void processErrorHandler(QProcess::ProcessError);
void processStarted() { setEnabled( false ); }
void processFinished( int exitCode, QProcess::ExitStatus exitStatus )
{
Q_UNUSED( exitCode ); Q_UNUSED( exitStatus );
setEnabled( true );
}
void setDriverStateBusy();
void setDriverStateReady();
signals:
void showGrid( bool flag );
void updateSelectedMapInfo( gis_core_map_information_t *map );
void scalingAreaByRect( QRectF );
};
#endif

89
src/apps/gis-monitor/drivertabs.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,89 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "drivertabs.h"
#include <QDebug>
#include <QKeySequence>
#include "drivermappage.h"
DriverTabs::DriverTabs( QWidget *parent ) :
QTabWidget( parent )
{
setMovable( true );
}
DriverTabs::~DriverTabs()
{
}
void DriverTabs::closeTab( int index )
{
QWidget *d = widget( index );
this->removeTab( index );
delete( d );
}
void DriverTabs::addTab( gis_core_driver_info_t *info, QString acronym )
{
DriverMapPage *page;
try
{
page = new DriverMapPage( sender(), info, this );
}
catch( const std::bad_alloc & )
{
qDebug() << "Failed to create DriverMapPage";
return;
}
QTabWidget::addTab( page, acronym );
}
DriverMapPage * DriverTabs::getCurrentPage()
{
DriverMapPage *current_page = static_cast <DriverMapPage*>( currentWidget() );
if ( !current_page )
{
qDebug() << "No current driver tab";
}
return current_page;
}
void DriverTabs::keyPressEvent( QKeyEvent *event )
{
if ( event->matches( QKeySequence::StandardKey::MoveToNextWord ) )
{
setCurrentIndex( currentIndex() + 1 );
}
if ( event->matches( QKeySequence::StandardKey::MoveToPreviousWord ) )
{
setCurrentIndex( currentIndex() - 1 );
}
}

46
src/apps/gis-monitor/drivertabs.h Обычный файл
Просмотреть файл

@ -0,0 +1,46 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef DRIVERTABS_H
#define DRIVERTABS_H
#include <QKeyEvent>
#include <QTabWidget>
#include <gis/gishelper.h>
class DriverMapPage;
class DriverTabs : public QTabWidget
{
Q_OBJECT
public:
explicit DriverTabs( QWidget *parent );
~DriverTabs();
DriverMapPage * getCurrentPage();
virtual void keyPressEvent( QKeyEvent *event );
public slots:
void addTab( gis_core_driver_info_t *info, QString acronym );
void closeTab( int tabIndex );
};
#endif

221
src/apps/gis-monitor/engine.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,221 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "engine.h"
#include <QDebug>
#include <QMessageBox>
gis_core_driver_info_t Engine::drivers[GIS_CORE_DRIVER_COUNT];
Engine::Engine( QObject *parent ) : QObject( parent ),
connection( nullptr ),
m_isConnected( false )
{}
Engine::~Engine()
{
disconnectCore();
}
int Engine::connectCore()
{
connection = new gis_core_connection_t;
gis_core_link_init( connection );
int status = gis_core_link_connect( connection, SHID_NULL );
if ( status != EOK )
{
QMessageBox box;
box.setText("GIS Core connection failed");
box.exec();
m_isConnected = false;
}
else
{
m_isConnected = true;
}
return status;
}
void Engine::disconnectCore()
{
if ( connection )
{
gis_core_link_destroy( connection, false );
delete connection;
m_isConnected = false;
}
}
void Engine::getDrivers()
{
if ( isCoreConnected() )
{
int id;
GIS_CORE_DRIVER_FOR_LOOP_HEAD( id )
{
getDriver( id );
}
}
}
void Engine::getDriver( int id )
{
gis_core_driver_info_t *info = &drivers[id];
info->driver_id = (gis_core_driver_id_t)id;
gis_core_request_driver_info( connection, info );
char acronym[GIS_MAX_ACRONYM_LENGTH];
gis_core_request_driver_acronym( connection, info->driver_id, acronym );
if ( info->initialized )
{
emit createDriverTab( info, QString( acronym ) );
}
}
gis_core_map_list_t * Engine::getMaps( gis_core_driver_id_t driver_id )
{
gis_core_map_list_t *mlist = new gis_core_map_list_t;
gis_core_map_list_init( mlist );
gis_core_request_parameters_t map_desc;
gis_core_request_parameters_init( &map_desc );
int result = gis_core_request_maps_list( connection, &map_desc, driver_id, mlist );
if ( result != EOK )
{
if ( result != ENODATA )
{
fprintf( stderr,
"GIS Core request maps list failed - driver_id = %d (e:%d) [%s()]\n",
driver_id, result, __FUNCTION__ );
return NULL;
}
}
return mlist;
}
void Engine::deleteMaps( gis_core_map_list_t *mlist )
{
gis_core_map_list_free( mlist );
delete mlist;
}
gis_core_class_list_t *Engine::getClassList( gis_core_map_information_t *map )
{
gis_core_class_list_t *list = new gis_core_class_list_t;
gis_core_class_list_init( list );
int result = gis_core_request_map_class_list( connection, map, list );
if ( result != EOK )
{
if ( result != ENODATA )
{
fprintf( stderr,
"GIS Core request class list failed - map id = %d [%s()]\n",
map->id, __FUNCTION__ );
return NULL;
}
}
return list;
}
void Engine::deleteClassList( gis_core_class_list_t *clist )
{
gis_core_class_list_free( clist );
delete clist;
}
bool Engine::isVectorMap( gis_core_driver_id_t driver_id )
{
return GIS_IS_CORE_MAP_DATA_SOURCE_VECTOR( gis_helper_get_map_source_by_driver_id( driver_id ) );
}
void Engine::updateCache()
{
emit setStatusBusy();
if ( isCoreConnected() )
{
int i;
GIS_CORE_DRIVER_FOR_LOOP_HEAD(i)
{
if ( drivers[i].initialized )
gis_core_request_update_cache( connection,
drivers[i].driver_id,
GIS_CORE_UPDATE_CACHE_MODE_SYNC_UPDATE );
}
}
emit cacheProcessingFinished();
}
void Engine::updateCacheSoft()
{
emit setStatusBusy();
if ( isCoreConnected() )
{
int i;
GIS_CORE_DRIVER_FOR_LOOP_HEAD(i)
{
if ( drivers[i].initialized )
gis_core_request_update_cache( connection,
drivers[i].driver_id,
GIS_CORE_UPDATE_CACHE_MODE_SOFT_UPDATE );
}
}
emit cacheProcessingFinished();
}
void Engine::overwriteCache()
{
emit setStatusBusy();
if ( isCoreConnected() )
{
int i;
GIS_CORE_DRIVER_FOR_LOOP_HEAD(i)
{
if ( drivers[i].initialized )
gis_core_request_update_cache( connection,
drivers[i].driver_id,
GIS_CORE_UPDATE_CACHE_MODE_HARD_RESET );
}
}
emit cacheProcessingFinished();
}
bool Engine::isCoreConnected()
{
return m_isConnected;
}

92
src/apps/gis-monitor/engine.h Обычный файл
Просмотреть файл

@ -0,0 +1,92 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QThread>
#include <gis/gishelper.h>
#include <gis/gis_databuffer.h>
class Engine : public QObject
{
Q_OBJECT
public:
Engine( QObject *parent = nullptr );
~Engine();
int connectCore();
void disconnectCore();
bool isCoreConnected();
gis_core_map_list_t * getMaps( gis_core_driver_id_t driver_id );
gis_core_class_list_t * getClassList( gis_core_map_information_t *map );
void deleteMaps( gis_core_map_list_t *mlist );
void deleteClassList( gis_core_class_list_t *clist );
bool isVectorMap(gis_core_driver_id_t driver_id);
gis_core_connection_t *connection;
private:
static gis_core_driver_info_t drivers[GIS_CORE_DRIVER_COUNT];
bool m_isConnected;
public slots:
void getDrivers();
void getDriver( int id );
void overwriteCache();
void updateCache();
void updateCacheSoft();
signals:
void createDriverTab( gis_core_driver_info_t *, QString );
void cacheProcessingFinished();
void setStatusBusy();
};
class EngineController : public QObject
{
Q_OBJECT
QThread workerThread;
public:
EngineController( QObject *parent = nullptr ) : QObject( parent )
{
e = new Engine;
workerThread.setObjectName( "Engine" );
e->moveToThread(&workerThread);
workerThread.start();
}
~EngineController()
{
workerThread.quit();
workerThread.wait();
}
Engine *e;
};
#endif

Двоичные данные
src/apps/gis-monitor/icons/area.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
src/apps/gis-monitor/icons/area55.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.9 KiB

Двоичные данные
src/apps/gis-monitor/icons/eye.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

Двоичные данные
src/apps/gis-monitor/icons/fit50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 841 B

Двоичные данные
src/apps/gis-monitor/icons/request.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 21 KiB

Двоичные данные
src/apps/gis-monitor/icons/request2.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.5 KiB

Двоичные данные
src/apps/gis-monitor/icons/select-area.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.8 KiB

Двоичные данные
src/apps/gis-monitor/icons/zoomin50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Двоичные данные
src/apps/gis-monitor/icons/zoomout50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1021 B

10
src/apps/gis-monitor/images.qrc Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/">
<file>icons/fit50.png</file>
<file>icons/zoomin50.png</file>
<file>icons/zoomout50.png</file>
<file>icons/area.png</file>
<file>icons/eye.png</file>
<file>background/mercator.svg</file>
</qresource>
</RCC>

111
src/apps/gis-monitor/main.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,111 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <unistd.h>
#include <QApplication>
#include <QDebug>
#include <QLocale>
#include <QSettings>
#include <QMenu>
#include <QTranslator>
#include <gis/gis_databuffer.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "engine.h"
bool demo_mode = false;
int window_x = 0,
window_y = 0,
window_width = 0,
window_height = 0;
void gis_map_viewer_config_edit()
{
QString config_dir( gis_helper_env_get_config_directory() );
QSettings settings( config_dir + "gis-map-viewer.conf", QSettings::IniFormat);
settings.setValue( "MainWindow/oneMapMode", true );
}
int main(int argc, char *argv[])
{
gis_helper_debug_mode_setmask( GIS_DEBUG_MODE_STD | GIS_DEBUG_MODE_FD );
gis_helper_debug_file_setname( "gis-monitor.log" );
int opt = 0;
extern char *optarg;
while ( ( opt = getopt( argc, argv,"x:y:w:h:D" ) ) != -1 )
{
switch ( opt )
{
case 'x':
window_x = atoi( optarg );
break;
case 'y':
window_y = atoi( optarg );
break;
case 'w':
window_width = atoi( optarg );
break;
case 'h':
window_height = atoi( optarg );
break;
case 'D':
demo_mode = true;
break;
case '?':
printf( "Error: unknown option\n" );
exit(1);
}
}
CleanExit cleanExit;
QApplication a( argc, argv );
const char *lang = getenv( "ABLANG" );
QString locale = "en_EN";
if ( lang )
{
locale = QString( lang );
}
QTranslator myTranslator;
myTranslator.load( ":/translations/gis-monitor_" + locale );
a.installTranslator( &myTranslator );
gis_map_viewer_config_edit();
EngineController *ctrl = new EngineController;
MainWindow w( ctrl->e );
w.show();
return a.exec();
}

439
src/apps/gis-monitor/mainwindow.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,439 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mainwindow.h"
#include <csignal>
#include <iostream>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include <QMenu>
#include <QMenuBar>
#include <QResizeEvent>
#include "mapadder.h"
extern int window_x, window_y, window_width, window_height;
MainWindow::MainWindow( Engine *ext_e, QWidget *parent ) :
QMainWindow( parent ),
ui( new Ui::MainWindow ),
linkerProcess( nullptr ),
linkerProcessBlockingFlag( false ),
loaderProcess( nullptr ),
min_height( 550 ),
min_width( 750 )
{
ui->setupUi( this );
tabs = new DriverTabs( this );
e = ext_e;
initializeMenu();
setCentralWidget( tabs );
connect( tabs, SIGNAL( currentChanged( int ) ),
this, SLOT( slotChangeTabAnalyzer( int ) ) );
e->connectCore();
connect( e, SIGNAL( createDriverTab( gis_core_driver_info_t *, QString ) ),
tabs, SLOT( addTab( gis_core_driver_info_t *, QString ) ) );
connect( e, SIGNAL( cacheProcessingFinished() ),
this, SLOT( slotSoftReset() ) );
e->getDrivers();
window_x = window_x < 0 ? 0 : window_x;
window_y = window_y < 0 ? 0 : window_y;
setGeometry( window_x, window_y, window_width, window_height );
emit endInit();
}
MainWindow::~MainWindow()
{
if ( linkerProcess )
{
disconnect( linkerProcess, SIGNAL( finished( int ) ),
this, SLOT( slotResetPage( int ) ) );
disconnect( linkerProcess, SIGNAL( finished( int ) ),
this, SLOT(slotLinkerFlag( int ) ) );
disconnect( linkerProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT( slotLinkerDebug( int, QProcess::ExitStatus ) ) );
if ( ( linkerProcess->state() == QProcess::Running ) ||
( linkerProcess->state() == QProcess::Starting ) )
{
linkerProcess->terminate();
linkerProcess->waitForFinished();
}
}
if ( loaderProcess )
loaderProcess->terminate();
delete menuMain;
delete tabs;
delete ui;
}
void MainWindow::slotHardReset()
{
e->disconnectCore();
int size = tabs->count();
for ( int j = 0; j < size; j++)
{
tabs->closeTab( 0 );
}
if ( e->connectCore() == EOK )
{
e->getDrivers();
qDebug() << "Successful reset";
}
else
{
qDebug() << "Failed to connect in reset";
}
}
void MainWindow::slotSoftReset()
{
int size = tabs->count();
for ( int j = 0; j < size; j++)
{
tabs->setCurrentIndex(j);
slotResetPage( 0 );
}
}
void MainWindow::resizeEvent( QResizeEvent *event )
{
QMainWindow::resizeEvent( event );
if ( event->size().width() < min_width ||
event->size().height() < min_height )
{
resize( event->size().width() < min_width ? min_width : event->size().width(),
event->size().height() < min_height ? min_height : event->size().height() );
}
}
void MainWindow::initializeMenu()
{
menuMain = new QMenu( tr( "Main" ), this );
menuMain->addAction( tr( "Reset" ), this, SLOT( slotHardReset() ), QKeySequence( Qt::CTRL | Qt::Key_R ) );
menuMain->addSeparator();
menuMain->addAction( tr( "Add map" ), this, SLOT( slotAddMap() ), QKeySequence( Qt::CTRL | Qt::Key_O ) );
linkerAction = new QAction( tr( "Maps and Styles" ), menuMain );
connect( linkerAction, SIGNAL( triggered(bool) ), this, SLOT( slotStartLinker( bool ) ) );
menuMain->addAction( linkerAction );
menuMain->addSeparator();
menuMain->addAction( tr( "About" ), this, SLOT( showAboutDialog() ) );
menuMain->addAction( tr( "Exit" ), QApplication::instance(), SLOT( quit() ), QKeySequence( Qt::CTRL | Qt::Key_Q ) );
QMenu *menuView = new QMenu( tr("View"), this );
scaleVector.append( { 0, 0 } );
scaleVector.append( { 1, 5000 } );
scaleVector.append( { 5000, 10000 } );
scaleVector.append( { 10000, 25000 } );
scaleVector.append( { 25000, 50000 } );
scaleVector.append( { 50000, 100000 } );
scaleVector.append( { 100000, 200000 } );
scaleVector.append( { 200000, 500000 } );
scaleVector.append( { 500000, 1000000 } );
scaleVector.append( { 1000000, 10000000 } );
QMenu *menuScales = new QMenu( tr( "Scales" ), this );
menuView->addMenu( menuScales );
menuView->addSeparator();
scaleGroup = new QActionGroup( menuScales );
QAction *allScales = new QAction( tr( "All scales" ), menuScales );
allScales->setCheckable( true );
scaleGroup->addAction( allScales );
allScales->setChecked( true );
menuScales->addAction( allScales );
actionVector.append( allScales );
connect( allScales , SIGNAL( triggered( bool ) ), this, SLOT( slotGetScaleIndex( bool ) ) );
for( int i = 1; i < scaleVector.size(); ++i )
{
QString str;
int j;
if ( ( i != 1 ) && ( i != scaleVector.size() - 1 ) )
{
str.append( " [" );
for ( j = 0; j < ( 6 - QString::number( scaleVector.at( i ).x ).length() ); ++j )
str.append( " " );
}
if ( i == scaleVector.size() - 1 )
str.append( QChar( 0x2265 ) );
if ( i != 1)
str.append( QString::number( scaleVector.at( i ).x ) );
if ( ( i != 1 ) && ( i != scaleVector.size() - 1 ) )
str.append( ";" );
if ( i != 1 )
{
for ( j = 0; j < ( 8 - QString::number( scaleVector.at( i ).y ).length() ); ++j )
str.append( " " );
}
if ( i == 1 )
{
str.append( " < " );
}
if ( i != scaleVector.size() - 1 )
{
str.append( QString::number( scaleVector.at( i ).y ) );
}
if ( ( i != 1 ) && ( i != scaleVector.size() - 1 ) )
{
str.append( ") " );
}
QAction *scales = new QAction( str , menuScales );
scales->setCheckable( true );
menuScales->addAction( scales );
actionVector.append( scales );
connect( scales , SIGNAL( triggered( bool ) ), this, SLOT( slotGetScaleIndex( bool ) ) );
scaleGroup->addAction( scales );
}
connect( this, SIGNAL( actionScaleIndex(int) ), this, SLOT( slotFilterMap( int ) ) );
scrollBarAction = new QAction( tr( "Scroll Bars" ), menuView );
scrollBarAction->setCheckable( true );
scrollBarAction->setChecked( true );
menuView->addAction( scrollBarAction );
connect( scrollBarAction, SIGNAL( triggered(bool) ), this, SLOT( slotScrollBarsView( bool ) ) );
gridAction = new QAction( tr( "Grid"), menuView );
gridAction->setCheckable( true );
gridAction->setChecked( false );
menuView->addAction( gridAction );
connect( gridAction, SIGNAL( triggered( bool ) ), this, SLOT( slotGrid( bool ) ) );
suffixAction = new QAction( tr( "Show GCM name" ), menuView );
suffixAction->setCheckable( true );
suffixAction->setChecked( false );
menuView->addAction( suffixAction );
connect( suffixAction, SIGNAL( triggered( bool ) ), this, SLOT( slotShowSuffix( bool ) ) );
QMenu* menuControl = new QMenu( tr( "Control" ), this );
menuControl->addAction( tr( "Download maps" ), this, SLOT( slotDownloadMaps() ) );
menuControl->addSeparator();
menuControl->addAction( tr( "Overwrite cache" ), e, SLOT( overwriteCache() ) );
menuControl->addAction( tr( "Syncronize cache" ), e, SLOT( updateCache() ) );
menuControl->addAction( tr( "Update cache" ), e, SLOT( updateCacheSoft() ) );
ui->mainMenu->addMenu( menuMain );
ui->mainMenu->addMenu( menuView );
ui->mainMenu->addMenu( menuControl );
}
void MainWindow::slotScrollBarsView( bool flag )
{
DriverMapPage *w = tabs->getCurrentPage();
if ( w )
{
w->setScrollBarsEnabled( flag );
}
}
void MainWindow::slotGrid( bool flag )
{
DriverMapPage *w = tabs->getCurrentPage();
if ( w )
{
w->changeGridState( flag );
}
}
void MainWindow::slotShowSuffix( bool flag )
{
DriverMapPage *w = tabs->getCurrentPage();
if ( w )
{
w->changeSuffixState( flag );
}
}
void MainWindow::slotFilterMap( int index )
{
DriverMapPage *w = tabs->getCurrentPage();
if ( w )
{
int32_point_t tmp = scaleVector.value( index );
int lower_limit = tmp.x;
int upper_limit = tmp.y;
w->setScaleFilter( lower_limit, upper_limit );
}
}
void MainWindow::slotSetFullScreenGeometry()
{
geometry_rect = QApplication::desktop()->screenGeometry( this );
setGeometry( 0, 0, geometry_rect.width() - 9, geometry_rect.height() - menuBar()->height() );
}
void MainWindow::slotGetScaleIndex( bool flag )
{
if ( flag )
{
emit actionScaleIndex( actionVector.indexOf( dynamic_cast <QAction*>( sender() ) ) );
}
}
void MainWindow::slotChangeTabAnalyzer( int index )
{
Q_UNUSED(index);
DriverMapPage *current_page = tabs->getCurrentPage();
if ( current_page )
{
int scale_index = 0;
for( int i = 0; i < scaleVector.size(); i++ )
{
if ( ( scaleVector.value( i ).x == current_page->scaling_point.x ) &&
( scaleVector.value( i ).y == current_page->scaling_point.y ) )
{
scale_index = i;
}
}
actionVector.at( scale_index )->setChecked( true );
scrollBarAction->setChecked( current_page->scrollBarFlag );
gridAction->setChecked( current_page->gridFlag );
suffixAction->setChecked( current_page->suffixFlag );
update();
}
}
void MainWindow::slotStartLinker( bool flag )
{
Q_UNUSED(flag);
if ( !linkerProcessBlockingFlag )
{
linkerProcessBlockingFlag = true;
DriverMapPage *current_page = tabs->getCurrentPage();
if ( current_page )
{
const char *gis_root = gis_helper_env_get_gis_root_directory();
QString program = QString( gis_root ) + "/" + QString( GIS_EXEC_PATH_SXF_LINKER );
linkerProcess = new QProcess( this );
connect( linkerProcess, SIGNAL( finished( int ) ), this, SLOT( slotResetPage( int ) ) );
connect( linkerProcess, SIGNAL( finished( int ) ), this, SLOT( slotLinkerFlag( int ) ) );
connect( linkerProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ),
this, SLOT(slotLinkerDebug( int, QProcess::ExitStatus ) ) );
linkerProcess->setProcessChannelMode( QProcess::ForwardedChannels );
QPoint pos = this->mapToGlobal( QPoint( 0,0 ) );
linkerProcess->start( program, { "-x" + QString::number( pos.x() ),
"-y" + QString::number( pos.y() ) } );
}
}
}
void MainWindow::slotLinkerFlag( int exitCode )
{
Q_UNUSED( exitCode );
linkerProcessBlockingFlag = false;
linkerProcess = nullptr;
}
void MainWindow::slotLinkerDebug( int exitCode, QProcess::ExitStatus status )
{
qDebug() << "exitcode" << exitCode << "status" << status;
}
void MainWindow::slotResetPage( int flag )
{
Q_UNUSED( flag );
DriverMapPage *current_page = tabs->getCurrentPage();
if ( current_page )
{
current_page->updatePage();
}
}
void MainWindow::slotAddMap()
{
MapAdder add( this );
add.exec();
e->updateCache();
}
void MainWindow::slotDownloadMaps()
{
if ( !loaderProcessBlockingFlag )
{
loaderProcessBlockingFlag = true;
DriverMapPage *current_page = tabs->getCurrentPage();
if ( current_page )
{
const char *gis_root = gis_helper_env_get_gis_root_directory();
QString program = QString( gis_root ) + "/" + QString( GIS_EXEC_PATH_MAP_LOADER );
QStringList arguments;
arguments << "-d" << QString::number( current_page->getDriverId() );
loaderProcess = new QProcess( this );
connect( loaderProcess, SIGNAL( finished( int ) ), this, SLOT( slotResetPage( int ) ) );
connect( loaderProcess, SIGNAL( finished( int ) ), this, SLOT( slotLoaderFlag( int ) ) );
loaderProcess->setProcessChannelMode( QProcess::ForwardedChannels );
loaderProcess->start( program, arguments );
}
}
}
void MainWindow::slotLoaderFlag( int exitCode )
{
Q_UNUSED(exitCode);
loaderProcessBlockingFlag = false;
}

128
src/apps/gis-monitor/mainwindow.h Обычный файл
Просмотреть файл

@ -0,0 +1,128 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <csignal>
#include <QCoreApplication>
#include <QMainWindow>
#include <QPointer>
#include "drivermappage.h"
#include "drivertabs.h"
#include "engine.h"
#include "ui_mainwindow.h"
#include <gis/gisrender.h>
struct CleanExit
{
CleanExit()
{
signal( SIGINT, &CleanExit::exitQt );
signal( SIGTERM, &CleanExit::exitQt );
}
static void exitQt( int sig )
{
Q_UNUSED( sig );
QCoreApplication::quit();
}
};
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow( Engine *en, QWidget *parent = 0 );
~MainWindow();
QPointer <Engine> e;
private:
void initializeMenu();
void scalesInitialize();
QRect geometry_rect;
QVector <QAction*> actionVector;
QVector <int32_point_t> scaleVector;
Ui::MainWindow *ui;
QMenu *menuMain;
DriverTabs *tabs;
QAction *scrollBarAction;
QAction *gridAction;
QAction *suffixAction;
QAction *controlAction;
QAction *scalesAction;
QAction *linkerAction;
QActionGroup *scaleGroup;
QProcess *linkerProcess;
bool linkerProcessBlockingFlag;
QProcess *loaderProcess;
bool loaderProcessBlockingFlag;
const int min_height;
const int min_width;
protected:
void resizeEvent( QResizeEvent * event );
private slots:
void slotChangeTabAnalyzer( int index );
void slotHardReset();
void slotSoftReset();
void slotResetPage( int flag );
void slotScrollBarsView( bool );
void slotGrid( bool );
void slotSetFullScreenGeometry();
void slotGetScaleIndex( bool );
void slotFilterMap( int );
void slotStartLinker( bool flag );
void slotLinkerFlag( int );
void slotShowSuffix( bool );
void slotDownloadMaps();
void slotAddMap();
void slotLoaderFlag( int exitCode );
void showAboutDialog() { gis_gui_about( e->connection, this ); }
void slotLinkerDebug( int exitCode, QProcess::ExitStatus status );
signals:
void endInit();
void actionScaleIndex( int );
void closeDriverMapPage(int);
};
#endif

49
src/apps/gis-monitor/mainwindow.ui Обычный файл
Просмотреть файл

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>731</width>
<height>599</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>615</width>
<height>460</height>
</size>
</property>
<property name="windowTitle">
<string>GIS Monitor</string>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QMenuBar" name="mainMenu">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>731</width>
<height>25</height>
</rect>
</property>
<property name="defaultUp">
<bool>false</bool>
</property>
<property name="nativeMenuBar">
<bool>false</bool>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

222
src/apps/gis-monitor/mapadder.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,222 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mapadder.h"
#include <QDebug>
#include <QFileDialog>
#include <QGridLayout>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <gis/gishelper.h>
#include <gis/gis_types.h>
MapAdder::MapAdder( QWidget *parent ) :
QDialog( parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint ),
mapNames( new QTextEdit(this) )
{
mapNames->setReadOnly( true );
QPushButton *applyBtn = new QPushButton( tr( "Apply" ) );
connect( applyBtn, SIGNAL( clicked( bool ) ), this, SLOT( applyBtnClicked( bool ) ) );
QPushButton *openMapBtn = new QPushButton( tr( "Add file" ) );
connect( openMapBtn, SIGNAL( clicked( bool ) ), this, SLOT( mapOpenDialog( bool ) ) );
QPushButton *openMapFolderButton = new QPushButton( tr( "Add folder (SHP only)" ) );
connect( openMapFolderButton, SIGNAL( clicked( bool ) ), this, SLOT( mapFolderOpenDialog( bool ) ) );
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget( new QLabel( tr( "Files to copy:" ) ), 0, 0, 1, 6 );
mainLayout->addWidget( mapNames, 1, 0, 3, 6 );
mainLayout->addWidget( openMapBtn, 1, 6, 1, 1 );
mainLayout->addWidget( openMapFolderButton, 2, 6, 1, 1 );
mainLayout->addWidget( applyBtn, 3, 6, 1, 1 );
setLayout( mainLayout );
setWindowTitle( tr( "Add map" ) );
setMaximumSize( 400, 200 );
}
void MapAdder::applyBtnClicked( bool clicked )
{
Q_UNUSED( clicked );
QString format_folder;
for ( auto path : mapPaths )
{
QFileInfo fi( path );
QString cached_copy_path;
bool isDir = false;
QString map_name = fi.fileName();
if ( map_name.contains( ".000", Qt::CaseInsensitive ) )
{
format_folder = "/S-57/";
}
else if ( map_name.contains( ".sxf", Qt::CaseInsensitive ) )
{
format_folder = "/sxf/";
}
else if ( map_name.contains( ".rsc", Qt::CaseInsensitive ) )
{
format_folder = "/sxf/rsc/";
}
else if ( map_name.contains( ".shp", Qt::CaseInsensitive ) )
{
format_folder = "/Shapefile/";
isDir = true;
}
else if ( map_name.contains( ".mtw", Qt::CaseInsensitive ) )
{
format_folder = "/mtw/";
}
else if ( map_name.contains( ".tif", Qt::CaseInsensitive ) )
{
format_folder = "/GeoTIFF/";
}
else if ( map_name.contains( ".jp2", Qt::CaseInsensitive ) ||
map_name.contains( ".j2k", Qt::CaseInsensitive ) ||
map_name.contains( ".jpf", Qt::CaseInsensitive ) ||
map_name.contains( ".jpm", Qt::CaseInsensitive ) ||
map_name.contains( ".jpg2", Qt::CaseInsensitive ) ||
map_name.contains( ".j2c", Qt::CaseInsensitive ) ||
map_name.contains( ".jpc", Qt::CaseInsensitive ) ||
map_name.contains( ".jpx", Qt::CaseInsensitive ) ||
map_name.contains( ".mj2", Qt::CaseInsensitive ) )
{
format_folder = "/JPEG2000/";
}
cached_copy_path += gis_helper_env_get_maps_cache_directory() +
QString( "/" ) + format_folder + QString( "/" ) + fi.fileName();
bool isCopied = false;
if ( !isDir )
{
isCopied = QFile::copy( path, cached_copy_path );
}
else
{
isCopied = MapAdder::cpDir( path, cached_copy_path );
}
if ( !isCopied )
{
QMessageBox box;
box.setText( tr( "Failed to copy file:" ) + path + "\n" + tr( "File exists" ) );
box.setIcon( QMessageBox::Warning );
box.exec();
}
}
accept();
}
void MapAdder::mapOpenDialog( bool unused )
{
Q_UNUSED( unused );
QFileDialog dialog( this );
dialog.setFileMode( QFileDialog::ExistingFiles );
dialog.setViewMode( QFileDialog::Detail );
if ( dialog.exec() )
{
for ( auto path : dialog.selectedFiles() )
{
mapNames->append( path );
mapPaths.append( path );
}
}
}
void MapAdder::mapFolderOpenDialog( bool unused )
{
Q_UNUSED( unused );
QFileDialog dialog( this );
dialog.setFileMode( QFileDialog::Directory );
dialog.setViewMode( QFileDialog::Detail );
if ( dialog.exec() )
{
for ( auto path : dialog.selectedFiles() )
{
mapNames->append( path );
mapPaths.append( path );
}
}
}
bool MapAdder::cpDir( const QString &srcPath, const QString &dstPath )
{
QFileInfo dstDir( dstPath );
if ( dstDir.exists() )
{
return false;
}
QDir parentDstDir( dstDir.path() );
if ( !parentDstDir.mkdir( dstDir.fileName() ) )
{
return false;
}
QDir srcDir( srcPath );
foreach ( const QFileInfo &info, srcDir.entryInfoList( QDir::Dirs |
QDir::Files |
QDir::NoDotAndDotDot ) )
{
QString srcItemPath = srcPath + "/" + info.fileName();
QString dstItemPath = dstPath + "/" + info.fileName();
if ( info.isDir() )
{
if ( !cpDir( srcItemPath, dstItemPath ) )
{
return false;
}
}
else if ( info.isFile() )
{
if ( !QFile::copy( srcItemPath, dstItemPath ) )
{
return false;
}
}
else
{
qDebug() << "Unhandled item" << info.filePath() << "in cpDir";
}
}
return true;
}

47
src/apps/gis-monitor/mapadder.h Обычный файл
Просмотреть файл

@ -0,0 +1,47 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAPADDER_H
#define MAPADDER_H
#include <QDialog>
#include <QTextEdit>
#include <QWidget>
class MapAdder : public QDialog
{
Q_OBJECT
public:
explicit MapAdder( QWidget *parent = NULL );
private:
static bool cpDir( const QString &srcPath, const QString &dstPath );
QStringList mapPaths;
QTextEdit *mapNames;
private slots:
void applyBtnClicked( bool clicked );
void mapOpenDialog( bool unused );
void mapFolderOpenDialog( bool unused );
};
#endif

640
src/apps/gis-monitor/mapcanvas.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,640 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mapcanvas.h"
#include <QDebug>
#define GIS_MONITOR_MAP_CANVAS_PREFIX "[MapCanvas] "
double MapCanvas::SVG_W_PIXELS = 1049;
double MapCanvas::SVG_H_PIXELS = 898;
MapCanvas::MapCanvas( QObject *parent ) : QGraphicsScene( parent ),
current_rect( nullptr ),
svgMap( nullptr ),
scalingRectItem( nullptr ),
brush( QColor( 150, 150, 150, 127 ) ),
pen( QBrush( QColor( 60, 60, 60, 255 ) ), 0,
Qt::SolidLine,
Qt::SquareCap,
Qt::MiterJoin ),
mousePressedFlag( false ),
scalingAreaFlag( false )
{
svg_width_m = 20026376.39 - (-20026376.39);
svg_height_m = 18764656.23 - (-15496570.74);
svg_width = 180.0 - (-180.0);
svg_height = 84.0 - (-80.0);
view_scale.x = svg_width_m / MapCanvas::SVG_W_PIXELS;
view_scale.y = svg_height_m / MapCanvas::SVG_H_PIXELS;
connect( this, SIGNAL( getMousePress( QPointF ) ),
this, SLOT( slotScalingRectangle( QPointF ) ) );
gis_map_projection_init( &projection );
gis_helper_math_init_ctx( &math_ctx );
projection.projection_idx = GIS_PROJECTION_MERC_PSEUDO;
projection.ellipsoid_idx = GIS_ELLIPSOID_WGS84;
gis_helper_math_generate_meters_projection( math_ctx, &projection );
if ( svgMap == NULL )
{
svgMap = new QGraphicsSvgItem( QString(":/background/mercator.svg") );
addItem( svgMap );
}
setSceneRect( svgMap->boundingRect() );
}
MapCanvas::~MapCanvas()
{
foreach ( QGraphicsItem *it, items() )
removeItem( it );
if ( svgMap )
delete svgMap;
for ( auto &current_selected : selected_rects_v )
{
delete current_selected;
}
selected_rects_v.clear();
removeAllRects();
gis_helper_math_free_ctx( &math_ctx );
}
void MapCanvas::removeAllRects()
{
for ( const auto &pair : map_rects_qmap )
{
std::vector<MapRectItem*> &gr_item_rects_vector = *pair.second;
for ( auto &rect : gr_item_rects_vector )
{
delete rect;
}
gr_item_rects_vector.clear();
}
clearMapWithPointers<int, std::vector<MapRectItem*>>( map_rects_qmap );
}
QGraphicsItem *MapCanvas::getMapRectItemToCenter( int map_idx )
{
std::vector<MapRectItem*> *gr_item_rects_vector;
auto pair_map_rects = map_rects_qmap.find( map_idx );
if ( pair_map_rects != map_rects_qmap.end() )
{
gr_item_rects_vector = pair_map_rects->second;
}
else
{
return nullptr;
}
if ( gr_item_rects_vector->empty() )
{
return nullptr;
}
return gr_item_rects_vector->at( 0 );
}
void MapCanvas::addSelectionRectangle( gis_borders_t borders )
{
static QPen selPen( QBrush( QColor( 60, 0, 0, 255) ), 0,
Qt::SolidLine,
Qt::SquareCap,
Qt::MiterJoin );
removeAllSelection();
QVector<QRectF> rects_v;
gis_convert_deg2px( borders, rects_v );
for ( const auto &rect: rects_v )
{
QGraphicsRectItem *current = addRect( rect, selPen, QColor( 150, 0, 0, 127 ) );
selected_rects_v.push_back( current );
}
update();
}
void MapCanvas::addMapRectangle( int map_idx, gis_borders_t borders, QObject* w )
{
removeAllSelection();
QVector<QRectF> rects_v;
MapRectItem::RectType rect_type;
gis_convert_deg2px( borders, rects_v, &rect_type );
std::vector<MapRectItem*> *gr_item_rects_vector;
auto pair_map_rects = map_rects_qmap.find( map_idx );
if ( pair_map_rects != map_rects_qmap.end() )
{
gr_item_rects_vector = pair_map_rects->second;
}
else
{
gr_item_rects_vector = new std::vector<MapRectItem*>;
map_rects_qmap.emplace( map_idx, gr_item_rects_vector );
}
for ( const auto &rect : rects_v )
{
current_rect = new MapRectItem( rect.x(), rect.y(), rect.width(), rect.height(), rect_type );
current_rect->setBrush( brush );
current_rect->setPen( pen );
QObject *o = dynamic_cast<QObject *>( this );
o->connect( current_rect, SIGNAL( getRectClick( QPointF ) ),
w, SLOT( slotSelectMapRect( QPointF ) ) );
o->connect( current_rect, SIGNAL( getRectDoubleClick( QPointF ) ),
this, SLOT( rectDoubleClick( QPointF ) ) );
gr_item_rects_vector->push_back( current_rect );
addItem( current_rect );
}
}
void MapCanvas::slotScalingRectangle( QPointF point )
{
if ( scalingRectItem )
{
removeItem( scalingRectItem );
delete scalingRectItem;
scalingRectItem = nullptr;
}
scalingRectItem = new QGraphicsRectItem( 0, 0, 1, 1 );
scalingRectItem->setBrush( brush );
scalingRectItem->setPen( pen );
addItem( scalingRectItem );
scalingRectItem->setPos( point );
}
void MapCanvas::gis_convert_deg2px( gis_borders_t borders, QVector<QRectF> &rects_v,
MapRectItem::RectType *type )
{
rects_v.clear();
double_point_t upper_left, lower_right, svg_ul;
double_point_t nw_point = { borders.degrees.west, borders.degrees.north };
double_point_t se_point = { borders.degrees.east, borders.degrees.south };
double_point_t ul_point = { -180, 84 };
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, &ul_point, &svg_ul ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, &nw_point, &upper_left ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, &se_point, &lower_right ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
QRectF base_rect;
QRectF odd_rect;
bool flag_need_odd = false;
double top, odd_top = 0;
double bottom, odd_bottom = 0;
double right, odd_right = 0;
double left, odd_left = 0;
left = ( upper_left.x - svg_ul.x ) / view_scale.x;
odd_right = ( lower_right.x - svg_ul.x ) / view_scale.x;
odd_bottom = -1 * ( lower_right.y - svg_ul.y ) / view_scale.y;
MapRectItem::RectType tmp_type = MapRectItem::RectType::COMMON;
if ( upper_left.x > lower_right.x )
{
tmp_type = MapRectItem::RectType::COMPOSITE_HORIZONTAL;
right = MapCanvas::SVG_W_PIXELS;
flag_need_odd = true;
}
else
{
odd_left = left;
right = odd_right;
}
top = -1 * ( upper_left.y - svg_ul.y ) / view_scale.y;
if ( lower_right.y > upper_left.y )
{
tmp_type = MapRectItem::RectType::COMPOSITE_VERTICAL;
bottom = MapCanvas::SVG_H_PIXELS;
flag_need_odd = true;
}
else
{
odd_top = top;
bottom = odd_bottom;
}
if ( type )
{
*type = tmp_type;
}
base_rect.setTopLeft( QPointF( left, top ) );
base_rect.setBottomRight( QPointF( right, bottom ) );
rects_v.push_back( base_rect );
if ( flag_need_odd )
{
odd_rect.setTopLeft( QPointF( odd_left, odd_top ) );
odd_rect.setBottomRight( QPointF( odd_right, odd_bottom ) );
rects_v.push_back( odd_rect );
}
}
double_point_t MapCanvas::gis_convert_deg2px( double_point_t *point )
{
double_point_t m_pnt, svg_ul;
double_point_t ul_point = { -180, 84 };
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, &ul_point, &svg_ul ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, point, &m_pnt ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
m_pnt.x = ( m_pnt.x - svg_ul.x ) / view_scale.x;
m_pnt.y = ( m_pnt.y + svg_ul.y ) / view_scale.y;
return m_pnt;
}
double_point_t MapCanvas::gis_convert_px2deg( double_point_t *point )
{
double_point_t m_pnt, deg_pnt, svg_center;
double_point_t center_point = { -180, 84 };
if ( gis_helper_convert_point_degrees_2_meters( math_ctx, &center_point, &svg_center ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
m_pnt.x = point->x * view_scale.x - svg_center.x;
m_pnt.y = -( point->y * view_scale.y - svg_center.y );
if ( gis_helper_convert_point_meters_2_degrees( math_ctx, &deg_pnt, &m_pnt ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, GIS_MONITOR_MAP_CANVAS_PREFIX,
"Calculation failed [%s()]", __FUNCTION__ );
}
return deg_pnt;
}
void MapCanvas::rectDoubleClick( QPointF point )
{
double_point_t px_pnt;
px_pnt.x = point.x();
px_pnt.y = point.y();
emit getDoubleClick( gis_convert_px2deg( &px_pnt ) );
}
void MapCanvas::slotShowGrid( bool flag )
{
double_point_t point, px_point;
if ( flag )
{
QPen grid_pen( Qt::darkGray );
for ( int i = 0; i < 37; i++ )
{
point.x = -180 + 10 * i;
point.y = 0;
px_point = gis_convert_deg2px( &point );
if ( i == 18 )
grid_pen.setColor( Qt::black );
else
grid_pen.setColor( Qt::darkGray );
addLine( px_point.x, 0, px_point.x, height(), grid_pen );
}
for ( int i = 0; i < 17; i++ )
{
point.x = 0;
point.y = -80 + 10 * i;
px_point = gis_convert_deg2px( &point );
if ( i == 8 )
grid_pen.setColor( Qt::black );
else
grid_pen.setColor( Qt::darkGray );
addLine( 0, px_point.y, width(), px_point.y, grid_pen );
}
update( 0, 0, width(), height() );
}
else
{
for ( int k = 0; k < items().length(); k++ )
{
QGraphicsItem *item = items().at( k );
if ( item->type() == QGraphicsLineItem::Type )
{
removeItem( item );
delete item;
k--;
}
}
}
}
void MapRectItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
if ( m_rect_type == MapRectItem::RectType::COMMON )
{
QGraphicsRectItem::paint( painter, option, widget );
return;
}
QRectF rect = this->rect();
QPen saved_pen = painter->pen();
QBrush saved_brush = painter->brush();
painter->setPen( this->pen() );
if ( m_rect_type == MapRectItem::RectType::COMPOSITE_HORIZONTAL )
{
painter->drawLine( rect.topLeft(), rect.topRight() );
painter->drawLine( rect.bottomLeft(), rect.bottomRight() );
if ( rect.left() > 0 )
{
painter->drawLine( rect.topLeft(), rect.bottomLeft() );
}
if ( rect.right() < MapCanvas::SVG_W_PIXELS )
{
painter->drawLine( rect.topRight(), rect.bottomRight() );
}
}
if ( m_rect_type == MapRectItem::RectType::COMPOSITE_VERTICAL )
{
painter->drawLine( rect.topLeft(), rect.bottomLeft() );
painter->drawLine( rect.topRight(), rect.bottomRight() );
if ( rect.top( ) > 0 )
{
painter->drawLine( rect.topLeft(), rect.topRight() );
}
if ( rect.bottom( ) < MapCanvas::SVG_H_PIXELS )
{
painter->drawLine( rect.bottomLeft(), rect.bottomRight() );
}
}
painter->setPen( Qt::NoPen );
painter->setBrush( this->brush() );
painter->drawRect( rect );
painter->setPen( saved_pen );
painter->setBrush( saved_brush );
}
void MapRectItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
{
if ( event->button() == Qt::LeftButton )
{
emit getRectClick( event->pos() );
}
event->ignore();
}
void MapRectItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event )
{
if ( event->button() == Qt::LeftButton )
{
emit getRectDoubleClick( event->pos() );
}
event->ignore();
}
void MapCanvas::wheelEvent( QGraphicsSceneWheelEvent *event )
{
event->accept();
if ( event->delta() > 0 )
{
emit increaseScale( true );
}
else if ( event->delta() < 0 )
{
emit decreaseScale( true );
}
}
void MapCanvas::mousePressEvent( QGraphicsSceneMouseEvent *event )
{
if ( event->button() == Qt::RightButton )
{
mousePressedFlag = true;
bool unused = false;
emit scalingAreaFlagChanged( unused );
slotScalingRectangle( event->lastScenePos() );
event->ignore();
}
else if ( scalingAreaFlag && ( event->button() == Qt::LeftButton ) )
{
mousePressedFlag = true;
slotScalingRectangle( event->lastScenePos() );
event->ignore();
}
else
{
QGraphicsScene::mousePressEvent( event );
}
}
void MapCanvas::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
{
if ( scalingAreaFlag )
{
if ( scalingRectItem )
{
QPointF pos = scalingRectItem->pos();
QRectF r;
r.setTopLeft( QPointF( 0,0 ) );
r.setWidth( event->scenePos().x() - scalingRectItem->x() );
r.setHeight( event->scenePos().y() - scalingRectItem->y() );
scalingRectItem->setRect( r );
scalingRectItem->setPos( pos );
}
}
}
void MapCanvas::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
{
if ( scalingAreaFlag && mousePressedFlag )
{
mousePressedFlag = false;
bool unused = false;
emit scalingAreaFlagChanged( unused );
if ( scalingRectItem != nullptr )
{
QRectF r;
r.setTopLeft( scalingRectItem->pos() );
r.setWidth( scalingRectItem->boundingRect().width() );
r.setHeight( scalingRectItem->boundingRect().height() );
emit scalingAreaByRect( r.normalized() );
removeItem( scalingRectItem );
delete scalingRectItem;
scalingRectItem = nullptr;
}
else
{
qDebug() << "mouseReleaseEvent(): scalingRectItem == nullptr!";
}
event->ignore();
}
}
void MapCanvas::removeAllSelection()
{
for ( auto &current_selected : selected_rects_v )
{
removeItem( current_selected );
delete current_selected;
}
selected_rects_v.clear();
}
void MapCanvas::setMapRectEnabled( int index, bool enabled )
{
std::vector<MapRectItem*> *gr_item_rects_vector;
auto pair_map_rects = map_rects_qmap.find( index );
if ( pair_map_rects != map_rects_qmap.end() )
{
gr_item_rects_vector = pair_map_rects->second;
}
else
{
return;
}
for ( const auto &rect : *gr_item_rects_vector )
{
if ( enabled )
{
rect->show();
rect->setEnabled( enabled );
}
else
{
rect->hide();
rect->setEnabled( enabled );
}
}
}
int MapCanvas::getMapIndexFromClickedRect( QPointF p )
{
qreal min_width = MapCanvas::SVG_W_PIXELS;
qreal min_height = MapCanvas::SVG_H_PIXELS;
int min_clicked_rect_map_idx = -1;
for ( const auto &pair : map_rects_qmap )
{
std::vector<MapRectItem*> &gr_item_rects_vector = *pair.second;
for ( const auto &rect_gr_item : gr_item_rects_vector )
{
if ( rect_gr_item->contains( p ) && rect_gr_item->isEnabled() )
{
QRectF rect = rect_gr_item->rect();
if ( rect.width() < min_width )
{
min_width = rect.width();
min_clicked_rect_map_idx = pair.first;
}
if ( rect.height() < min_height )
{
min_height = rect.height();
min_clicked_rect_map_idx = pair.first;
}
}
}
}
return min_clicked_rect_map_idx;
}

153
src/apps/gis-monitor/mapcanvas.h Обычный файл
Просмотреть файл

@ -0,0 +1,153 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAPCANVAS_H
#define MAPCANVAS_H
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSvgItem>
#include <QWidget>
#include <QPainter>
#include <gis/gishelper.h>
#include <gis/gis_math.h>
class MapRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
enum RectType
{
COMMON,
COMPOSITE_HORIZONTAL,
COMPOSITE_VERTICAL
};
MapRectItem( qreal x, qreal y, qreal width, qreal height, RectType rect_type, QGraphicsItem *parent = nullptr ) :
QGraphicsRectItem( x, y, width, height, parent ), QObject( nullptr ),
m_rect_type( rect_type )
{}
void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr );
void mousePressEvent( QGraphicsSceneMouseEvent * );
void mouseDoubleClickEvent( QGraphicsSceneMouseEvent * );
signals:
void getRectClick( QPointF point );
void getRectDoubleClick( QPointF point );
void getMousePress( QPointF point );
private:
RectType m_rect_type;
};
class QGraphicsSvgItem;
class DriverMapPage;
class MapCanvas : public QGraphicsScene
{
friend DriverMapPage;
Q_OBJECT
public:
explicit MapCanvas( QObject *parent = nullptr );
~MapCanvas();
void addMapRectangle( int map_idx, gis_borders_t borders, QObject* w );
void addSelectionRectangle( gis_borders_t borders );
int getMapIndexFromClickedRect( QPointF p );
QGraphicsItem *getMapRectItemToCenter( int map_idx );
void removeAllSelection();
void setMapRectEnabled( int index, bool enabled );
void removeAllRects();
void gis_convert_deg2px( gis_borders_t borders, QVector<QRectF> &rects_v,
MapRectItem::RectType *type = nullptr );
double_point_t gis_convert_deg2px( double_point_t* point );
double_point_t gis_convert_px2deg( double_point_t* point );
static double SVG_W_PIXELS;
static double SVG_H_PIXELS;
private:
void setPen(QPen newPen) { pen = newPen; }
void mousePressEvent( QGraphicsSceneMouseEvent * );
void mouseMoveEvent( QGraphicsSceneMouseEvent * );
void mouseReleaseEvent( QGraphicsSceneMouseEvent * );
void wheelEvent( QGraphicsSceneWheelEvent * );
template<typename T1,typename T2>
void clearMapWithPointers( std::map<T1, T2 *> &map )
{
for ( auto &pair : map )
{
delete pair.second;
}
map.clear();
}
QVector<QGraphicsRectItem*> selected_rects_v;
MapRectItem *current_rect;
std::map<int, std::vector<MapRectItem*>*> map_rects_qmap;
QGraphicsSvgItem *svgMap;
QGraphicsRectItem *scalingRectItem;
gis_map_projection_t projection;
gis_helper_math_ctx_t math_ctx;
double svg_width_m;
double svg_height_m;
double svg_width;
double svg_height;
double_point_t view_scale;
QBrush brush;
QPen pen;
bool mousePressedFlag;
bool scalingAreaFlag;
public slots:
void rectDoubleClick( QPointF );
private slots:
void slotScalingRectangle( QPointF );
void slotShowGrid( bool flag );
signals:
void increaseScale( bool );
void decreaseScale( bool );
void getMousePress( QPointF );
void getMouseRelease( QPointF );
void getDoubleClick( double_point_t );
void scalingAreaFlagChanged( bool );
void scalingAreaByRect( QRectF );
};
#endif

163
src/apps/gis-monitor/mapview.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,163 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mapview.h"
#include <cmath>
MapView::MapView( QGraphicsScene *scene, QWidget *parent ):
QGraphicsView( scene, parent ),
totalScaleFactor(1),
_scale(1),
fit( true )
{
setAttribute( Qt::WA_AcceptTouchEvents, true );
}
void MapView::resizeEvent( QResizeEvent *event )
{
Q_UNUSED(event);
if ( fit )
slotFitScale(true);
}
bool MapView::viewportEvent( QEvent *event )
{
switch ( event->type() )
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
QTouchEvent *touchEvent = static_cast<QTouchEvent *>( event );
QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
if ( touchPoints.count() == 2 )
{
const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
qreal currentScaleFactor =
QLineF( touchPoint0.pos(), touchPoint1.pos() ).length() /
QLineF( touchPoint0.startPos(), touchPoint1.startPos() ).length();
if ( touchEvent->touchPointStates() & Qt::TouchPointReleased )
{
totalScaleFactor *= currentScaleFactor;
currentScaleFactor = 1;
}
setTransform(QTransform().scale( totalScaleFactor * currentScaleFactor,
totalScaleFactor * currentScaleFactor ) );
_scale = totalScaleFactor * currentScaleFactor;
}
return true;
}
default:
break;
}
return QGraphicsView::viewportEvent(event);
}
void MapView::slotFitScale( bool flag )
{
Q_UNUSED(flag);
fit = true;
qreal w, h;
double sw, sh;
double factor;
fitInView( sceneRect(), Qt::KeepAspectRatio );
centerOn( sceneRect().center() );
w = scene()->width() * _scale;
h = scene()->height() * _scale;
sw = (double)geometry().width() / w;
sh = (double)geometry().height() / h;
factor = sw < sh ? sw : sh;
_scale *= factor;
}
void MapView::slotIncreaseScale( bool flag )
{
Q_UNUSED( flag );
fit = false;
if ( _scale > 660 )
{
return;
}
_scale *= 1.20;
scale( 1.20, 1.20 );
}
void MapView::slotDecreaseScale( bool flag )
{
Q_UNUSED( flag );
fit = false;
if ( ( scene()->height() * _scale < height() ) &&
( scene()->width() * _scale < width() ) )
{
return;
}
_scale *= 0.8;
scale( 0.8, 0.8 );
}
void MapView::scaleAreaByRect( QRectF rect )
{
uint dx = fabs( rect.width() );
uint dy = fabs( rect.height() );
if ( (dx == 0) || (dy == 0) )
{
return;
}
fit = false;
double sw, sh;
double factor;
sw = (double)geometry().width() / dx;
sh = (double)geometry().height() / dy;
factor = sw < sh ? sw : sh;
_scale = factor;
if ( _scale > 660 )
{
_scale = 660;
}
resetMatrix();
scale( _scale, _scale );
centerOn( rect.center() );
}

52
src/apps/gis-monitor/mapview.h Обычный файл
Просмотреть файл

@ -0,0 +1,52 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef MAPVIEW_H
#define MAPVIEW_H
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QTouchEvent>
#include <QWidget>
class MapView : public QGraphicsView
{
Q_OBJECT
public:
MapView( QGraphicsScene *scene, QWidget *parent );
protected:
bool viewportEvent( QEvent *event );
void resizeEvent( QResizeEvent *event );
private:
qreal totalScaleFactor;
qreal _scale;
bool fit;
public slots:
void slotFitScale( bool );
private slots:
void slotIncreaseScale( bool );
void slotDecreaseScale( bool );
void scaleAreaByRect( QRectF );
};
#endif

6
src/apps/gis-monitor/translations.qrc Обычный файл
Просмотреть файл

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>translations/gis-monitor_ru.ts</file>
<file>translations/gis-monitor_ru.qm</file>
</qresource>
</RCC>

Просмотреть файл

@ -0,0 +1,233 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>DriverMapPage</name>
<message>
<source>Scale: </source>
<translation>Масштаб: </translation>
</message>
<message>
<source>Class count: </source>
<translation>Классы: </translation>
</message>
<message>
<source>Object count: </source>
<translation>Объекты: </translation>
</message>
<message>
<source>Height: </source>
<translation>Высоты: </translation>
</message>
<message>
<source> m</source>
<translation> м</translation>
</message>
<message>
<source>Projection: </source>
<translation>Проекция: </translation>
</message>
<message>
<source>Ellipsoid: </source>
<translation>Эллипсоид: </translation>
</message>
<message>
<source>Height system: </source>
<translation>Система высот: </translation>
</message>
<message>
<source>Zone: </source>
<translation>Зона: </translation>
</message>
<message>
<source>Classifier: </source>
<translation>Классификатор: </translation>
</message>
<message>
<source>Class code</source>
<translation>Код класса</translation>
</message>
<message>
<source>Acronym</source>
<translation>Акроним</translation>
</message>
<message>
<source>Object count</source>
<translation>Число объектов</translation>
</message>
<message>
<source>Maps:</source>
<translation>Карты:</translation>
</message>
<message>
<source>Scale:
</source>
<translation>Масштаб:
</translation>
</message>
<message>
<source>Class count:
</source>
<translation>Классы:
</translation>
</message>
<message>
<source>Object count:</source>
<translation>Объекты:
</translation>
</message>
<message>
<source>Map property</source>
<translation>Параметр</translation>
</message>
<message>
<source>Value</source>
<translation>Значение</translation>
</message>
<message>
<source>Fit</source>
<translation>Подогнать</translation>
</message>
<message>
<source>Area</source>
<translation>Область</translation>
</message>
<message>
<source>Number of loaded maps: </source>
<translation>Количество загруженных карт:</translation>
</message>
<message>
<source>Connection status: request failed</source>
<translation>Статус соединения: запрос не выполнен</translation>
</message>
<message>
<source>Driver status: </source>
<translation>Статус драйвера: </translation>
</message>
<message>
<source>ready</source>
<translation>готов</translation>
</message>
<message>
<source>busy</source>
<translation>занят</translation>
</message>
<message>
<source>Update: </source>
<translation>Корректура: </translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<source>GIS Monitor</source>
<translation>ГИС Монитор</translation>
</message>
<message>
<source>Main</source>
<translation>Меню</translation>
</message>
<message>
<source>Reset</source>
<translation>Сброс</translation>
</message>
<message>
<source>Add map</source>
<translation>Добавить карту</translation>
</message>
<message>
<source>Maps and Styles</source>
<translation>Карты и стили</translation>
</message>
<message>
<source>About</source>
<translation>О программе</translation>
</message>
<message>
<source>Exit</source>
<translation>Выход</translation>
</message>
<message>
<source>View</source>
<translation>Вид</translation>
</message>
<message>
<source>Scales</source>
<translation>Масштаб</translation>
</message>
<message>
<source>All scales</source>
<translation>Все масштабы</translation>
</message>
<message>
<source>Scroll Bars</source>
<translation>Полосы прокрутки</translation>
</message>
<message>
<source>Grid</source>
<translation>Сетка</translation>
</message>
<message>
<source>Show GCM name</source>
<translation>Полное имя GCM</translation>
</message>
<message>
<source>Control</source>
<translation>Управление</translation>
</message>
<message>
<source>Overwrite cache</source>
<translation>Переписать кэш</translation>
</message>
<message>
<source>Syncronize cache</source>
<translation>Синхронизировать кэш</translation>
</message>
<message>
<source>Update cache</source>
<translation>Обновить кэш</translation>
</message>
<message>
<source>Download maps</source>
<translation>Загрузка карт</translation>
</message>
</context>
<context>
<name>MapAdder</name>
<message>
<source>Apply</source>
<translation>Применить</translation>
</message>
<message>
<source>Add file</source>
<translation>Добавить файл</translation>
</message>
<message>
<source>Add folder (SHP only)</source>
<translation>Добавить папку с картой (Shapefile)</translation>
</message>
<message>
<source>Files to copy:</source>
<translation>Список файлов для копирования:</translation>
</message>
<message>
<source>Add map</source>
<translation>Добавление карт</translation>
</message>
<message>
<source>Failed to copy file:</source>
<translation>Не удалось скопировать файл:</translation>
</message>
<message>
<source>File exists</source>
<translation>Файл уже существует</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<source>°</source>
<translation>°</translation>
</message>
</context>
</TS>

68
src/apps/gis-raster-preview/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,68 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-raster-preview LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -enable-checking )
add_compile_options( -Wno-ignored-attributes )
add_definitions( -DQT_DEPRECATED_WARNINGS )
find_package( Qt5
COMPONENTS
Core
Gui
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
images.qrc )
add_executable( gis-raster-preview ${SOURCES} )
target_include_directories( gis-raster-preview
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/private
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/formats/gcm
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gisrender/qt_render/private )
target_link_libraries( gis-raster-preview
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
gishelper
gisrender )
install( TARGETS gis-raster-preview DESTINATION bin )

64
src/apps/gis-raster-preview/main.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,64 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <QApplication>
#include "rasterwidget.h"
int main( int argc, char *argv[] )
{
gis_helper_debug_mode_setmask( GIS_DEBUG_MODE_STD );
const char *filepath = NULL;
uint32_t x_pos = 0;
uint32_t y_pos = 0;
int opt = 0;
extern char *optarg;
while ( ( opt = getopt( argc, argv,"x:y:f:" ) ) != -1 )
{
switch ( opt )
{
case 'x':
x_pos = strtoul( optarg, NULL, 0 );
break;
case 'y':
y_pos = strtoul( optarg, NULL, 0 );
break;
case 'f':
filepath = strdup( optarg );
break;
case '?':
printf( "Error: unknown option\n" );
exit(1);
};
};
CleanExit cleanExit;
QApplication a( argc, argv );
QString path( filepath );
RasterWidget wgt( path );
wgt.show();
wgt.setGeometry( x_pos, y_pos, 0, 0 );
return a.exec();
}

242
src/apps/gis-raster-preview/rastertab.cpp Обычный файл
Просмотреть файл

@ -0,0 +1,242 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "rastertab.h"
#include <raster_render.h>
#include <QDebug>
#define RASTER_VIEWER_PREFIX "[gis-raster-preview] "
extern bool reduce_copy;
extern double prev_scale;
extern int side_size;
RasterTab::RasterTab( const QString &filepath, QWidget *parent ) :
QGraphicsView( new QGraphicsScene(), parent ),
image_size( 0,0 ),
ll( 0,0 ),
ctx( NULL )
{
setDragMode( QGraphicsView::ScrollHandDrag );
setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
ctx = (gcm_raster_map_ctx_t*)calloc( 1, sizeof(*ctx) );
if ( !ctx )
{
exit(1);
}
gcm_map_header_t head;
gcm_read_file_header( filepath.toStdString().c_str(), &head );
if ( GIS_IS_CORE_MAP_DATA_SOURCE_VECTOR(head.data_source) )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, RASTER_VIEWER_PREFIX,
"Got vector map [%s()]", __FUNCTION__ );
free( ctx );
exit( 1 );
}
if ( gcm_raster_parse_map( ctx, &head ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, RASTER_VIEWER_PREFIX,
"Failed to parse raster map [%s()]", __FUNCTION__ );
free( ctx );
exit( 1 );
}
if ( gcm_raster_set_header_by_scale( ctx, prev_scale + 0.01 ) != EOK )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, RASTER_VIEWER_PREFIX,
"Failed to set raster header [%s()]", __FUNCTION__ );
exit( 1 );
}
gcm_raster_header_t *r_header = &ctx->r_headers[ctx->active_header_idx];
m_px = r_header->meters_per_element;
if ( r_header->has_reduced_copy )
{
reduce_copy = true;
prev_scale = ctx->r_headers[ctx->active_header_idx + 1].meters_per_element;
}
else
{
reduce_copy = false;
}
const static double epsilon = 1e-9;
min_height = r_header->min_value - epsilon;
max_height = r_header->max_value + epsilon;
ll = QPointF( r_header->lower_left.x, r_header->lower_left.y );
image = new QImage( r_header->width_in_elements, r_header->height_in_elements, QImage::Format_ARGB32 );
image_size = image->size();
gis_color_t color;
color.full = 0xFF228B22;
colorMap.push_back( color );
color.full = 0xFFADFF2F;
colorMap.push_back( color );
color.full = 0xFF7CFC00;
colorMap.push_back( color );
color.full = 0xFF90EE90;
colorMap.push_back( color );
color.full = 0xFF8B6508;
colorMap.push_back( color );
color.full = 0xFFEE7621;
colorMap.push_back( color );
color.full = 0xFFCD950C;
colorMap.push_back( color );
color.full = 0xFFEEAD0E;
colorMap.push_back( color );
color.full = 0xFFFFB90F;
colorMap.push_back( color );
color.full = 0xFFFFEBCD;
colorMap.push_back( color );
color.full = 0xFFFFFFE0;
colorMap.push_back( color );
const double delta = ( max_height - min_height ) / ( colorMap.size() - 1 );
for ( int i = 0; i < colorMap.size(); ++i )
{
valueMap << min_height + delta * i;
}
uint32_t block_x, block_y;
for ( block_y = 0; block_y < r_header->height_in_blocks; ++block_y )
{
for ( block_x = 0; block_x < r_header->width_in_blocks; ++block_x )
{
draw_block( r_header, block_x, block_y );
}
}
scene()->addPixmap( QPixmap::fromImage( *image ) );
qreal sf = min( static_cast<qreal>( side_size - 50 ) / image->width(),
static_cast<qreal>( side_size - 100 ) / image->height() );
scale( sf, sf );
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
setDragMode( QGraphicsView::NoDrag );
}
RasterTab::~RasterTab()
{
free( ctx );
delete image;
}
void RasterTab::draw_block( gcm_raster_header_t *r_header, const uint32_t index_x, const uint32_t index_y )
{
const bool isCroppedWidth = index_x == r_header->width_in_blocks - 1;
const bool isCroppedHeight = index_y == r_header->height_in_blocks - 1;
const uint32_t block_width = (isCroppedWidth) ? r_header->cropped_block_width : r_header->block_width;
const uint32_t block_height = (isCroppedHeight) ? r_header->cropped_block_height : r_header->block_height;
const uint32_t index = index_x + index_y * r_header->width_in_blocks;
uint32_t draw_x, draw_y,
offset_x = 0,
offset_y = 0;
offset_x = r_header->block_width * index_x;
offset_y = r_header->block_height * index_y;
gis_raster_value_t *block_data = (gis_raster_value_t *)calloc( block_width * block_height, sizeof(*block_data) );
if ( !block_data )
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, RASTER_VIEWER_PREFIX,
"Failed to allocate block_data memory [%s()]", __FUNCTION__ );
return;
}
gcm_raster_read_block_data( ctx, block_data, index );
uint32_t element_offset, str, col, color;
uint32_t invalid_color = 0x00FF0000;
gis_raster_value_t value, element_data;
for ( str = 0; str < block_height; ++str )
{
for ( col = 0; col < block_width; ++col )
{
element_offset = str * block_width + col;
value = block_data[element_offset];
switch( r_header->drawing_style )
{
case GIS_DRAWING_STYLE_MATRIX:
{
element_data = gishelper_raster_data_get_meters( value );
if ( fabs( element_data - r_header->no_data_value ) <
DBL_EPSILON * fmax( fabs( element_data ), fabs( r_header->no_data_value ) ) )
{
continue;
}
if ( element_data > max_height || element_data < min_height )
{
color = invalid_color;
}
else
{
color = gisrender_raster_get_gradient_color( colorMap.data(), valueMap.data(), colorMap.size(),
invalid_color, element_data );
}
break;
}
case GIS_DRAWING_STYLE_RGB:
{
color = value | 0xFF000000;
break;
}
default:
{
gis_helper_debug_write_lvl( GIS_DEBUG_LEVEL_ERROR, RASTER_VIEWER_PREFIX,
"Got unknown drawing style [%s()]", __FUNCTION__ );
color = invalid_color;
break;
}
}
draw_x = offset_x + col;
draw_y = offset_y + str;
image->setPixel( draw_x, draw_y, QRgb( color ) );
}
}
free( block_data );
}

53
src/apps/gis-raster-preview/rastertab.h Обычный файл
Просмотреть файл

@ -0,0 +1,53 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef RASTERTAB_H
#define RASTERTAB_H
#include <QGraphicsView>
#include <gis/gishelper.h>
#include <gcm_raster.h>
#include <gis_types_internal.h>
class RasterTab : public QGraphicsView
{
Q_OBJECT
public:
explicit RasterTab( const QString &filepath, QWidget *parent = 0 );
~RasterTab();
QSize image_size;
QPointF ll;
double m_px;
private:
void draw_block( gcm_raster_header_t* r_header, const uint32_t index_x, const uint32_t index_y );
gcm_raster_map_ctx_t* ctx;
QVector <gis_color_t> colorMap;
QVector <gis_raster_value_t> valueMap;
QImage* image;
double max_height;
double min_height;
};
#endif

Просмотреть файл

@ -0,0 +1,71 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "rasterwidget.h"
#include <QVBoxLayout>
#include <QStatusBar>
#include <QFile>
#include <QDebug>
bool reduce_copy = false;
double prev_scale = 0;
int side_size = 400;
RasterWidget::RasterWidget( const QString filepath, QWidget *parent ) :
QWidget( parent ),
size_label( new QLabel() ),
tabwgt( new QTabWidget() )
{
QVBoxLayout *layout = new QVBoxLayout();
QStatusBar *bar = new QStatusBar();
RasterTab *raster_tab;
if ( !QFile::exists( filepath ) )
{
qFatal( "File does not exist" );
exit( 1 );
}
layout->addWidget( tabwgt );
layout->addWidget( bar );
setLayout( layout );
setWindowTitle( filepath );
setFixedSize( side_size, side_size );
setWindowFlags( Qt::WindowStaysOnTopHint );
do
{
raster_tab = new RasterTab( filepath, this );
if ( tabwgt->currentIndex() == -1)
{
bar->addWidget( new QLabel( doImageLLString( raster_tab->ll ) ) );
size_label->setText( doImageSizeString( raster_tab->image_size ) );
bar->addWidget( size_label );
}
tabwgt->addTab( raster_tab, QString::number( raster_tab->m_px, 'f', 3 ) + " m/px" );
} while ( reduce_copy );
connect( tabwgt, SIGNAL( currentChanged( int ) ), this, SLOT( updateImageSizeLabel( int ) ) );
}

78
src/apps/gis-raster-preview/rasterwidget.h Обычный файл
Просмотреть файл

@ -0,0 +1,78 @@
/*
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef RASTERWIDGET_H
#define RASTERWIDGET_H
#include <csignal>
#include <QCoreApplication>
#include <QLabel>
#include <QTabWidget>
#include <QWidget>
#include "rastertab.h"
struct CleanExit
{
CleanExit()
{
signal( SIGINT, &CleanExit::exitQt );
signal( SIGTERM, &CleanExit::exitQt );
}
static void exitQt( int sig )
{
Q_UNUSED( sig );
QCoreApplication::quit();
}
};
class RasterWidget : public QWidget
{
Q_OBJECT
public:
explicit RasterWidget( const QString filepath, QWidget *parent = 0 );
private:
QLabel *size_label;
QTabWidget *tabwgt;
QString doImageSizeString( QSize size )
{
return QString( "W: " + QString::number( size.width() ) +
" H: " + QString::number( size.height() ) + " px" );
}
QString doImageLLString( QPointF lower_left )
{
return QString( "Lower left X: " + QString::number( lower_left.x(), 'f', 3 ) +
" Y: " + QString::number( lower_left.y(), 'f', 3 ) + " meters" );
}
public slots:
void updateImageSizeLabel( int )
{
RasterTab *cur = static_cast<RasterTab*> ( tabwgt->currentWidget() );
size_label->setText( doImageSizeString( cur->image_size ) );
}
};
#endif

65
src/apps/gis-rb-viewer/CMakeLists.txt Исполняемый файл
Просмотреть файл

@ -0,0 +1,65 @@
#[[
Copyright (c) 2024 SWD Embedded Systems, Ltd. <http://www.kpda.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
cmake_minimum_required( VERSION 3.23 FATAL_ERROR )
project( gis-rb-viewer LANGUAGES CXX )
set( CMAKE_AUTOMOC ON )
set( CMAKE_AUTOUIC ON )
set( CMAKE_AUTORCC ON )
add_compile_options( -std=gnu++11 )
add_compile_options( -Wno-ignored-attributes )
find_package( Qt5
COMPONENTS
Core
Gui
Widgets
REQUIRED )
file( GLOB SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/*.h
images.qrc )
add_executable( gis-rb-viewer ${SOURCES} )
target_include_directories( gis-rb-viewer
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gisrender/api/public
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/renderbuffer/public
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../lib/gishelper/private )
target_link_libraries( gis-rb-viewer
PUBLIC
Qt5::Core
Qt5::Gui
Qt5::Widgets
gishelper
gisrender
renderbuffer )
install( TARGETS gis-rb-viewer DESTINATION bin )

Двоичные данные
src/apps/gis-rb-viewer/icons/zoomin50.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше