diff --git a/Mergin/project_settings_widget.py b/Mergin/project_settings_widget.py
index 8936ab00..f4a30097 100644
--- a/Mergin/project_settings_widget.py
+++ b/Mergin/project_settings_widget.py
@@ -6,7 +6,7 @@
import typing
from qgis.PyQt import uic
from qgis.PyQt.QtGui import QIcon, QColor
-from qgis.PyQt.QtCore import Qt
+from qgis.PyQt.QtCore import Qt, QFileInfo
from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox
from qgis.core import (
QgsProject,
@@ -16,8 +16,15 @@
QgsFeatureRequest,
QgsExpression,
QgsMapLayer,
+ QgsCoordinateReferenceSystem,
+)
+from qgis.gui import (
+ QgsOptionsWidgetFactory,
+ QgsOptionsPageWidget,
+ QgsColorButton,
+ QgsCoordinateReferenceSystemProxyModel,
+ QgsProjectionSelectionWidget,
)
-from qgis.gui import QgsOptionsWidgetFactory, QgsOptionsPageWidget, QgsColorButton
from .attachment_fields_model import AttachmentFieldsModel
from .utils import (
mm_symbol_path,
@@ -31,6 +38,7 @@
invalid_filename_character,
qvariant_to_string,
escape_html_minimal,
+ copy_file_new,
)
ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "ui", "ui_project_config.ui")
@@ -118,6 +126,17 @@ def __init__(self, parent=None):
idx = self.cmb_sort_method.findData(mode) if ok else 1
self.cmb_sort_method.setCurrentIndex(idx)
+ self.cmb_vertical_crs.setFilters(QgsCoordinateReferenceSystemProxyModel.FilterVertical)
+ vcrs_def, ok = QgsProject.instance().readEntry("Mergin", "TargetVerticalCRS")
+ vertical_crs = (
+ QgsCoordinateReferenceSystem.fromWkt(vcrs_def) if ok else QgsCoordinateReferenceSystem.fromEpsgId(5773)
+ ) # EGM96 geoid model
+ self.cmb_vertical_crs.crsChanged.connect(self.geoid_model_path_change_state)
+ self.cmb_vertical_crs.setCrs(vertical_crs)
+ self.cmb_vertical_crs.setOptionVisible(QgsProjectionSelectionWidget.CurrentCrs, True)
+ self.cmb_vertical_crs.setDialogTitle("Target Vertical CRS")
+ self.btn_get_geoid_file.clicked.connect(self.get_geoid_path)
+
self.local_project_dir = mergin_project_local_path()
if self.local_project_dir:
@@ -132,6 +151,28 @@ def __init__(self, parent=None):
self.attachment_fields.selectionModel().currentChanged.connect(self.update_expression_edit)
self.edit_photo_expression.expressionChanged.connect(self.expression_changed)
+ def geoid_model_path_change_state(self, newCRS):
+ if newCRS == QgsCoordinateReferenceSystem.fromEpsgId(5773):
+ self.label_geoid_file.hide()
+ self.edit_geoid_file.hide()
+ self.edit_geoid_file.clear()
+ self.btn_get_geoid_file.hide()
+ else:
+ self.label_geoid_file.show()
+ self.edit_geoid_file.show()
+ self.btn_get_geoid_file.show()
+
+ def get_geoid_path(self):
+ # open the set location or user home
+ open_path = (
+ QFileInfo(self.edit_geoid_file.text()).absolutePath()
+ if len(self.edit_geoid_file.text()) > 0
+ else os.path.expanduser("~")
+ )
+ abs_path = QFileDialog.getOpenFileName(None, "Select File", open_path, "Geoid Model Files (*.tif *.gtx)")
+ if len(abs_path[0]) > 0:
+ self.edit_geoid_file.setText(abs_path[0])
+
def get_sync_dir(self):
abs_path = QFileDialog.getExistingDirectory(
None,
@@ -309,6 +350,17 @@ def setup_map_sketches(self):
# create a new layer and add it as a map sketches layer
create_map_sketches_layer(QgsProject.instance().absolutePath())
+ # we could possibly first lookup if the gridfile is available with QGSProjUtils.gridsUsed()`
+ def package_vcrs_file(self, vertical_crs):
+ """
+ Get the grid shift file picked by user and copy it to project proj folder. We do this only for vertical CRS different than EGM96.
+ """
+ if len(self.edit_geoid_file.text()) == 0:
+ return True
+
+ project_proj_dir = os.path.join(mergin_project_local_path(), "proj")
+ return copy_file_new(project_proj_dir, self.edit_geoid_file.text())
+
def apply(self):
QgsProject.instance().writeEntry("Mergin", "PhotoQuality", self.cmb_photo_quality.currentData())
QgsProject.instance().writeEntry("Mergin", "Snapping", self.cmb_snapping_mode.currentData())
@@ -345,10 +397,12 @@ def apply(self):
expression = item.data(AttachmentFieldsModel.EXPRESSION)
QgsProject.instance().writeEntry("Mergin", f"PhotoNaming/{layer_id}/{field_name}", expression)
+ QgsProject.instance().writeEntry("Mergin", "TargetVerticalCRS", self.cmb_vertical_crs.crs().toWkt())
QgsProject.instance().writeEntry("Mergin", "SortLayersMethod/Method", self.cmb_sort_method.currentData())
self.save_config_file()
self.setup_tracking()
self.setup_map_sketches()
+ self.package_vcrs_file(self.cmb_vertical_crs.crs())
def colors_change_state(self) -> None:
"""
diff --git a/Mergin/ui/ui_project_config.ui b/Mergin/ui/ui_project_config.ui
index e29310cc..c54005f2 100644
--- a/Mergin/ui/ui_project_config.ui
+++ b/Mergin/ui/ui_project_config.ui
@@ -44,9 +44,9 @@
0
- -888
- 628
- 1444
+ -1160
+ 621
+ 1716
@@ -153,9 +153,6 @@
Snapping
- -
-
-
-
@@ -163,6 +160,9 @@
+ -
+
+
-
@@ -352,7 +352,7 @@
-
-
+
255
255
@@ -363,7 +363,7 @@
-
-
+
18
24
@@ -374,7 +374,7 @@
-
-
+
94
158
@@ -385,7 +385,7 @@
-
-
+
87
180
@@ -396,7 +396,7 @@
-
-
+
253
203
@@ -407,7 +407,7 @@
-
-
+
255
156
@@ -418,7 +418,7 @@
-
-
+
255
143
@@ -471,6 +471,95 @@
+ -
+
+
+ Vertical CRS
+
+
+
-
+
+
+ ...
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Vertical CRS
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Geoid model file
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Choose which vertical CRS will be used for elevation calculation. By default the mobile application uses EGM96_15 geoid model.
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+
+ 175
+ 0
+
+
+
+
+
+
+ Select geoid model file
+
+
+
+
+
+
-
@@ -493,7 +582,7 @@
Photo sketching lets mobile app users draw freehand annotations directly on captured photos. This feature is in Preview: it works, but may still have some issues.
- true
+ true
@@ -531,6 +620,12 @@
1
+
+ QgsProjectionSelectionWidget
+ QWidget
+ qgsprojectionselectionwidget.h
+ 1
+
chk_sync_enabled
diff --git a/Mergin/utils.py b/Mergin/utils.py
index 812e5f64..23b46f50 100644
--- a/Mergin/utils.py
+++ b/Mergin/utils.py
@@ -1280,6 +1280,21 @@ def copy_datum_shift_grids(grids_dir):
return missed_files
+def copy_file_new(dst_dir, src_file):
+ """
+ Copies file, which doesn't exist in destination directory, specified by absolute path.
+ """
+ os.makedirs(dst_dir, exist_ok=True)
+ copy_ok = False
+ if os.path.exists(src_file):
+ dst = os.path.join(dst_dir, Path(src_file).name)
+ if not os.path.exists(dst):
+ shutil.copy(src_file, dst)
+ copy_ok = True
+
+ return copy_ok
+
+
def project_grids_directory(mp):
"""
Returns location of the "proj" directory inside MerginMaps project root directory