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 @@
qgsexpressionlineedit.h
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