diff --git a/README.html b/README.html deleted file mode 100644 index 886e7c9..0000000 --- a/README.html +++ /dev/null @@ -1,42 +0,0 @@ - - -

Plugin Builder Results

- -Congratulations! You just built a plugin for QGIS!

- -
-Your plugin LayoutLoader was created in:
-  /home/klakar/plugin_dev/layoutloader -

-Your QGIS plugin directory is located at:
-  /home/klakar/.local/share/QGIS/QGIS3/profiles/default/python/plugins -

-

What's Next

-
    -
  1. In your plugin directory, compile the resources file using pyrcc5 (simply run make if you have automake or use pb_tool) -
  2. Test the generated sources using make test (or run tests from your IDE) -
  3. Copy the entire directory containing your new plugin to the QGIS plugin directory (see Notes below) -
  4. Test the plugin by enabling it in the QGIS plugin manager -
  5. Customize it by editing the implementation file layout_loader.py -
  6. Create your own custom icon, replacing the default icon.png -
  7. Modify your user interface by opening layout_loader_dialog_base.ui in Qt Designer -
-Notes: - -
-
-

-For information on writing PyQGIS code, see http://loc8.cc/pyqgis_resources for a list of resources. -

-
-

-©2011-2018 GeoApt LLC - geoapt.com -

- - diff --git a/README.txt b/README.txt deleted file mode 100644 index 674fbdd..0000000 --- a/README.txt +++ /dev/null @@ -1,32 +0,0 @@ -Plugin Builder Results - -Your plugin LayoutLoader was created in: - /home/klakar/plugin_dev/layoutloader - -Your QGIS plugin directory is located at: - /home/klakar/.local/share/QGIS/QGIS3/profiles/default/python/plugins - -What's Next: - - * Copy the entire directory containing your new plugin to the QGIS plugin - directory - - * Compile the resources file using pyrcc5 - - * Run the tests (``make test``) - - * Test the plugin by enabling it in the QGIS plugin manager - - * Customize it by editing the implementation file: ``layout_loader.py`` - - * Create your own custom icon, replacing the default icon.png - - * Modify your user interface by opening LayoutLoader.ui in Qt Designer - - * You can use the Makefile to compile your Ui and resource files when - you make changes. This requires GNU make (gmake) - -For more information, see the PyQGIS Developer Cookbook at: -http://www.qgis.org/pyqgis-cookbook/index.html - -(C) 2011-2018 GeoApt LLC - geoapt.com diff --git a/__init__.py~ b/__init__.py~ deleted file mode 100644 index d55ae6e..0000000 --- a/__init__.py~ +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -""" -/*************************************************************************** - LayoutLoader - A QGIS plugin - This plugin builds layouts for your map from a number of pre-designed layouts. - Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ - ------------------- - begin : 2018-11-17 - copyright : (C) 2018 by Klas Karlsson - email : klaskarlsson@hotmail.com - git sha : $Format:%H$ - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - This script initializes the plugin, making it known to QGIS. -""" - - -# noinspection PyPep8Naming -def classFactory(iface): # pylint: disable=invalid-name - """Load LayoutLoader class from file LayoutLoader. - - :param iface: A QGIS interface instance. - :type iface: QgsInterface - """ - # - from .layout_loader import LayoutLoader - return LayoutLoader(iface) diff --git a/layout_loader.py~ b/layout_loader.py~ deleted file mode 100644 index eb77c83..0000000 --- a/layout_loader.py~ +++ /dev/null @@ -1,347 +0,0 @@ -# -*- coding: utf-8 -*- -""" -/*************************************************************************** - LayoutLoader - A QGIS plugin - Load and modify layout templates - Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ - ------------------- - begin : 2018-11-18 - git sha : $Format:%H$ - copyright : (C) 2018 by Klas Karlsson - email : klaskarlsson@hotmail.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -""" -from PyQt5.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, QFileInfo -from PyQt5.QtGui import QIcon -from PyQt5.QtWidgets import QAction -# The following two imports are probably a bit overkill... -from PyQt5 import QtGui, QtCore, QtWidgets -from PyQt5.QtWidgets import * - -# Initialize Qt resources from file resources.py -from .resources import * -# Import the code for the dialog and for copying the templates to local profile folder -from .layout_loader_dialog import LayoutLoaderDialog -import os.path -from qgis.core import QgsApplication, QgsProject -from distutils.dir_util import copy_tree -from random import randrange as rand - - -class LayoutLoader: - """QGIS Plugin Implementation.""" - - def __init__(self, iface): - """Constructor. - - :param iface: An interface instance that will be passed to this class - which provides the hook by which you can manipulate the QGIS - application at run time. - :type iface: QgsInterface - """ - # Save reference to the QGIS interface - self.iface = iface - # initialize plugin directory - self.plugin_dir = os.path.dirname(__file__) - # initialize locale - locale = QSettings().value('locale/userLocale')[0:2] - locale_path = os.path.join( - self.plugin_dir, - 'i18n', - 'LayoutLoader_{}.qm'.format(locale)) - - if os.path.exists(locale_path): - self.translator = QTranslator() - self.translator.load(locale_path) - - if qVersion() > '4.3.3': - QCoreApplication.installTranslator(self.translator) - - # Create the dialog (after translation) and keep reference - self.dlg = LayoutLoaderDialog() - # Set Layer Name line edit disabled at the start - self.dlg.txtLayoutName.setEnabled(False) - - # Run the function to load templates into the dialog listWidget (probably not needed, it's called later) - # self.loadTemplates() - - # Declare instance attributes - self.actions = [] - self.menu = self.tr(u'&Layout Loader') - # TODO: We are going to let the user set this up in a future iteration - self.toolbar = self.iface.addToolBar(u'LayoutLoader') - self.toolbar.setObjectName(u'LayoutLoader') - - # Load print layout templates from profile template folder to listWidget in plugin dialogue - def loadTemplates(self): - self.dlg.listWidget.clear() - profile_dir = QgsApplication.qgisSettingsDirPath() - templates_dir = os.path.join(profile_dir,'composer_templates') - - # Does the composer_templates folder exist? Otherwise create it. - if os.path.isdir(templates_dir) == False: - os.mkdir(templates_dir) - - # Search the templates folder and add files to templates list and sort it - templates = [f.name for f in os.scandir(templates_dir) if f.is_file() ] - templates.sort() - - # Get the project file name and if it exist the project title. Use for Title suggestion - project_file_name = QFileInfo(QgsProject.instance().fileName()).baseName() - project_title = QgsProject.instance().title() - if project_title == '': - project_title = project_file_name - self.dlg.txtMapTitle.setText(project_title) - - # Add all the templates from the list to the listWidget - for template in templates: - self.dlg.listWidget.addItem(os.path.splitext(template)[0]) - - # Connect signals from the dialog to functions in this file - self.dlg.listWidget.itemClicked.connect(self.suggestLayoutName) - self.dlg.btnAddMore.clicked.connect(self.addMoreTemplates) - - # Add templates and resources from plugin to user profile (triggers on dialog button clicked signal) - # Somehow a lot of QMessageBox's are generated. TODO fix duplicate creation of the MessageBox - def addMoreTemplates(self): - are_you_sure = self.tr('This will add Templates and resources like SVG files and script functions to your QGIS profile.\n\n') - are_you_sure += self.tr('Do you want to OVERWRITE any existing files with the same filenames?') - dialogBox = QMessageBox() - dialogBox.setWindowTitle(self.tr('Add Templates from Plugin')) - dialogBox.setText(are_you_sure) - more_information = self.tr('If you answer \'No\', no current files will be overwritten, but new files will be copied to their location.\n\n') - more_information += self.tr('If you answer \'Yes\' any current files that you have manually modified, will be overwritten with the new ones from the plugin.\n') - more_information += self.tr('This should be safe if you haven\'t modified any plugin templates and kept the original filename.\n\n') - more_information += self.tr('If you \'Cancel\' No changes to your QGIS profile are made!') - dialogBox.setDetailedText(more_information) - dialogBox.setStandardButtons(QMessageBox.Cancel|QMessageBox.No|QMessageBox.Yes) - - button_pressed = dialogBox.exec_() - - # Paths to source files and qgis profile directory - source_profile = os.path.join(self.plugin_dir, 'profile') - profile_home = QgsApplication.qgisSettingsDirPath() - - if button_pressed == QMessageBox.Yes: - copy_tree(source_profile, profile_home) - self.loadTemplates() - if button_pressed == QMessageBox.No: - copy_tree(source_profile, profile_home, update=1) - self.loadTemplates() - - # Use selected item from listWidget and any Map Title text to suggest new layout name (triggers on listWidget itemClicked signal) - def suggestLayoutName(self): - self.dlg.txtLayoutName.setEnabled(True) - layout_name_string = self.dlg.listWidget.currentItem().text() - if self.dlg.txtMapTitle != '': - layout_name_string += ' ' + self.dlg.txtMapTitle.text() - self.dlg.txtLayoutName.setText(layout_name_string) - - # noinspection PyMethodMayBeStatic - def tr(self, message): - """Get the translation for a string using Qt translation API. - - We implement this ourselves since we do not inherit QObject. - - :param message: String for translation. - :type message: str, QString - - :returns: Translated version of message. - :rtype: QString - """ - # noinspection PyTypeChecker,PyArgumentList,PyCallByClass - return QCoreApplication.translate('LayoutLoader', message) - - - def add_action( - self, - icon_path, - text, - callback, - enabled_flag=True, - add_to_menu=True, - add_to_toolbar=True, - status_tip=None, - whats_this=None, - parent=None): - """Add a toolbar icon to the toolbar. - - :param icon_path: Path to the icon for this action. Can be a resource - path (e.g. ':/plugins/foo/bar.png') or a normal file system path. - :type icon_path: str - - :param text: Text that should be shown in menu items for this action. - :type text: str - - :param callback: Function to be called when the action is triggered. - :type callback: function - - :param enabled_flag: A flag indicating if the action should be enabled - by default. Defaults to True. - :type enabled_flag: bool - - :param add_to_menu: Flag indicating whether the action should also - be added to the menu. Defaults to True. - :type add_to_menu: bool - - :param add_to_toolbar: Flag indicating whether the action should also - be added to the toolbar. Defaults to True. - :type add_to_toolbar: bool - - :param status_tip: Optional text to show in a popup when mouse pointer - hovers over the action. - :type status_tip: str - - :param parent: Parent widget for the new action. Defaults None. - :type parent: QWidget - - :param whats_this: Optional text to show in the status bar when the - mouse pointer hovers over the action. - - :returns: The action that was created. Note that the action is also - added to self.actions list. - :rtype: QAction - """ - - icon = QIcon(icon_path) - action = QAction(icon, text, parent) - action.triggered.connect(callback) - action.setEnabled(enabled_flag) - - if status_tip is not None: - action.setStatusTip(status_tip) - - if whats_this is not None: - action.setWhatsThis(whats_this) - - if add_to_toolbar: - self.toolbar.addAction(action) - - if add_to_menu: - self.iface.addPluginToMenu( - self.menu, - action) - - self.actions.append(action) - - return action - - def initGui(self): - """Create the menu entries and toolbar icons inside the QGIS GUI.""" - - icon_path = ':/plugins/layout_loader/icon.png' - self.add_action( - icon_path, - text=self.tr(u'Layout Loader'), - callback=self.run, - parent=self.iface.mainWindow()) - - - def unload(self): - """Removes the plugin menu item and icon from QGIS GUI.""" - for action in self.actions: - self.iface.removePluginMenu( - self.tr(u'&Layout Loader'), - action) - self.iface.removeToolBarIcon(action) - # remove the toolbar - del self.toolbar - - # Python function that do the main work of setting up the print layout - # The code in the function can work stand alone if you use the commented variables and edit their values - def layoutLoader(self, template_source, layout_name, title_text): - """ Generate the layout """ - from qgis.core import (QgsProject, - QgsPrintLayout, - QgsReadWriteContext) - from qgis.utils import iface - from PyQt5.QtXml import QDomDocument - - #template_source = '/home/user/Document/Template.qpt' - #layout_name = 'NewLayout' - #title_text = 'New Title' - - # Create objects lm = layout manager, l = print layout - lm = QgsProject.instance().layoutManager() - l = QgsPrintLayout(QgsProject.instance()) - l.initializeDefaults() - - # Load template file and load it into the layout (l) - template_file = open(template_source) - template_content = template_file.read() - template_file.close() - document = QDomDocument() - document.setContent(template_content) - context = QgsReadWriteContext() - l.loadFromTemplate(document, context) - - # Give the layout a name (must be unique) - l.setName(layout_name) - - # Get current canvas extent and apply that to all maps (items) in layout - # Replace any text "{{title}}" in any layout label with the dialog Title text - canvas = iface.mapCanvas() - for item in l.items(): - if item.type()==65639: # Map - item.zoomToExtent(canvas.extent()) - if item.type()==65641: # Label - item.setText(item.text().replace('{{title}}',title_text)) - - # Add layout to layout manager - l.refresh() - lm.addLayout(l) - - # Open and show the layout in designer - iface.openLayoutDesigner(l) - - - def run(self): - """Run method that performs all the real work""" - # This loads the dialog with templates (again) TODO check when it's best to do this - self.loadTemplates() - - # show the dialog - self.dlg.show() - # Run the dialog event loop - result = self.dlg.exec_() - - # See if OK was pressed TODO: probably need something to happen when pressing "cancel" too. - if result: - # Get values from dialog list and text fields - try: - template_name = self.dlg.listWidget.currentItem().text() - except: - template_name = '' - layout_name = self.dlg.txtLayoutName.text() - # Generate random layout name for blank names - if layout_name == '': - layout_name += 'Layout ' + str(rand(1000,9999)) - map_title = self.dlg.txtMapTitle.text() - profile_dir = QgsApplication.qgisSettingsDirPath() - # create the template item selected full path (assuming extension is lower case) - template_source = os.path.join(profile_dir,'composer_templates',template_name + '.qpt') - - # Call function to generate layout - if os.path.exists(template_source): - self.layoutLoader(template_source, layout_name, map_title) - else: - infoBox = QMessageBox() - infoBox.setText(self.tr('You must select a template from the list.')) - infoBox.setWindowTitle(self.tr('Layout Loader')) - infoBox.exec_() - - # Clean up - self.dlg.txtLayoutName.clear() - self.dlg.txtLayoutName.setEnabled(False) - self.dlg.txtMapTitle.clear() - self.dlg.txtMapTitle.setFocus() diff --git a/metadata.txt~ b/metadata.txt~ deleted file mode 100644 index 242c8b3..0000000 --- a/metadata.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -# This file contains metadata for your plugin. Since -# version 2.0 of QGIS this is the proper way to supply -# information about a plugin. The old method of -# embedding metadata in __init__.py will -# is no longer supported since version 2.0. - -# This file should be included when you package your plugin.# Mandatory items: - -[general] -name=Layout Loader -qgisMinimumVersion=3.0 -description=Load and modify layout templates -version=0.1 -author=Klas Karlsson -email=klaskarlsson@hotmail.com - -about=Provide a brief description of the plugin and its purpose. - -tracker=http://bugs -repository=http://repo -# End of mandatory metadata - -# Recommended items: - -# Uncomment the following line and add your changelog: -# changelog= - -# Tags are comma separated with spaces allowed -tags=python - -homepage=http://homepage -category=Plugins -icon=icon.png -# experimental flag -experimental=True - -# deprecated flag (applies to the whole plugin, not just a single version) -deprecated=False - diff --git a/pb_tool.cfg~ b/pb_tool.cfg~ deleted file mode 100644 index 16489ff..0000000 --- a/pb_tool.cfg~ +++ /dev/null @@ -1,80 +0,0 @@ -#/*************************************************************************** -# LayoutLoader -# -# Configuration file for plugin builder tool (pb_tool) -# Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ -# ------------------- -# begin : 2018-11-17 -# copyright : (C) 2018 by Klas Karlsson -# email : klaskarlsson@hotmail.com -# ***************************************************************************/ -# -#/*************************************************************************** -# * * -# * This program is free software; you can redistribute it and/or modify * -# * it under the terms of the GNU General Public License as published by * -# * the Free Software Foundation; either version 2 of the License, or * -# * (at your option) any later version. * -# * * -# ***************************************************************************/ -# -# -# You can install pb_tool using: -# pip install http://geoapt.net/files/pb_tool.zip -# -# Consider doing your development (and install of pb_tool) in a virtualenv. -# -# For details on setting up and using pb_tool, see: -# http://g-sherman.github.io/plugin_build_tool/ -# -# Issues and pull requests here: -# https://github.com/g-sherman/plugin_build_tool: -# -# Sane defaults for your plugin generated by the Plugin Builder are -# already set below. -# -# As you add Python source files and UI files to your plugin, add -# them to the appropriate [files] section below. - -[plugin] -# Name of the plugin. This is the name of the directory that will -# be created in .qgis2/python/plugins -name: layout_loader - -# Full path to where you want your plugin directory copied. If empty, -# the QGIS default path will be used. Don't include the plugin name in -# the path. -plugin_path: - -[files] -# Python files that should be deployed with the plugin -python_files: __init__.py layout_loader.py layout_loader_dialog.py - -# The main dialog file that is loaded (not compiled) -main_dialog: layout_loader_dialog_base.ui - -# Other ui files for dialogs you create (these will be compiled) -compiled_ui_files: - -# Resource file(s) that will be compiled -resource_files: resources.qrc - -# Other files required for the plugin -extras: metadata.txt icon.png - -# Other directories to be deployed with the plugin. -# These must be subdirectories under the plugin directory -extra_dirs: templates - -# ISO code(s) for any locales (translations), separated by spaces. -# Corresponding .ts files must exist in the i18n directory -locales: - -[help] -# the built help directory that should be deployed with the plugin -dir: help/build/html -# the name of the directory to target in the deployed plugin -target: help - - - diff --git a/python/expressions/mgrsfunctions.py b/python/expressions/mgrsfunctions.py deleted file mode 100755 index 384401c..0000000 --- a/python/expressions/mgrsfunctions.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Functions to help in creating MGRS notation on map layouts. -Adapted for QGIS 3 using 'mgrspy' from Boundless. - -""" - -from qgis.core import * -from qgis.gui import * - -""" -Functions for MGRS lettering based on UTM easting/northing coordinates. -""" - -from qgis.utils import iface - - -@qgsfunction(args='auto', group='Advanced Layout') -def mgrs(easting, northing, epsg, feature, parent): - """ - - Create MGRS from X and Y coordinate in EPSG.
-
-

Example:


- - mgrs( 495395, 6392411, 32633) -> '33VVD94574973545'

- mgrs( 15.048564, 57.405484, 4326) -> '33VWD1453591543'

-
- """ - crsSrc = QgsCoordinateReferenceSystem(epsg) - crsDst = QgsCoordinateReferenceSystem(4326) - xform = QgsCoordinateTransform(crsSrc, crsDst, QgsProject.instance()) - pt = xform.transform(easting,northing) - from mgrspy import mgrs - mgrs_out = mgrs.toMgrs(pt[1],pt[0],5) # Latitude first... - return mgrs_out diff --git a/python/mgrspy/__init__.py b/python/mgrspy/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/python/mgrspy/__pycache__/__init__.cpython-36.pyc b/python/mgrspy/__pycache__/__init__.cpython-36.pyc deleted file mode 100755 index 66b2eb9..0000000 Binary files a/python/mgrspy/__pycache__/__init__.cpython-36.pyc and /dev/null differ diff --git a/python/mgrspy/__pycache__/mgrs.cpython-36.pyc b/python/mgrspy/__pycache__/mgrs.cpython-36.pyc deleted file mode 100755 index a57cc30..0000000 Binary files a/python/mgrspy/__pycache__/mgrs.cpython-36.pyc and /dev/null differ diff --git a/python/mgrspy/mgrs.py b/python/mgrspy/mgrs.py deleted file mode 100755 index cbefa90..0000000 --- a/python/mgrspy/mgrs.py +++ /dev/null @@ -1,674 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - mgrs.py - --------------------- - Date : August 2016 - Copyright : (C) 2016 Boundless, http://boundlessgeo.com -*************************************************************************** -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -*************************************************************************** -""" -from builtins import str -from builtins import range - -__author__ = 'Alexander Bruy' -__date__ = 'August 2016' -__copyright__ = '(C) 2016 Boundless, http://boundlessgeo.com' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - - -import math -import itertools - -from osgeo import osr - - -ALPHABET = {l: c for c, l in enumerate('ABCDEFGHIJKLMNOPQRSTUVWXYZ')} - -ONEHT = 100000.0 -TWOMIL = 2000000.0 - -MAX_PRECISION = 5 # Maximum precision of easting & northing -MIN_EAST_NORTH = 0 -MAX_EAST_NORTH = 4000000 - -# letter, -# 2nd letter range - low, -# 2nd letter range - high, -# 3rd letter range - high (UPS), -# false easting based on 2nd letter, -# false northing based on 3rd letter -UPS_CONSTANTS = {0: (ALPHABET['A'], ALPHABET['J'], ALPHABET['Z'], ALPHABET['Z'], 800000.0, 800000.0), - 1: (ALPHABET['B'], ALPHABET['A'], ALPHABET['R'], ALPHABET['Z'], 2000000.0, 800000.0), - 2: (ALPHABET['Y'], ALPHABET['J'], ALPHABET['Z'], ALPHABET['P'], 800000.0, 1300000.0), - 3: (ALPHABET['Z'], ALPHABET['A'], ALPHABET['J'], ALPHABET['P'], 2000000.0, 1300000.0) - } - -# letter, minimum northing, upper latitude, lower latitude, northing offset -LATITUDE_BANDS = [(ALPHABET['C'], 1100000.0, -72.0, -80.5, 0.0), - (ALPHABET['D'], 2000000.0, -64.0, -72.0, 2000000.0), - (ALPHABET['E'], 2800000.0, -56.0, -64.0, 2000000.0), - (ALPHABET['F'], 3700000.0, -48.0, -56.0, 2000000.0), - (ALPHABET['G'], 4600000.0, -40.0, -48.0, 4000000.0), - (ALPHABET['H'], 5500000.0, -32.0, -40.0, 4000000.0), - (ALPHABET['J'], 6400000.0, -24.0, -32.0, 6000000.0), - (ALPHABET['K'], 7300000.0, -16.0, -24.0, 6000000.0), - (ALPHABET['L'], 8200000.0, -8.0, -16.0, 8000000.0), - (ALPHABET['M'], 9100000.0, 0.0, -8.0, 8000000.0), - (ALPHABET['N'], 0.0, 8.0, 0.0, 0.0), - (ALPHABET['P'], 800000.0, 16.0, 8.0, 0.0), - (ALPHABET['Q'], 1700000.0, 24.0, 16.0, 0.0), - (ALPHABET['R'], 2600000.0, 32.0, 24.0, 2000000.0), - (ALPHABET['S'], 3500000.0, 40.0, 32.0, 2000000.0), - (ALPHABET['T'], 4400000.0, 48.0, 40.0, 4000000.0), - (ALPHABET['U'], 5300000.0, 56.0, 48.0, 4000000.0), - (ALPHABET['V'], 6200000.0, 64.0, 56.0, 6000000.0), - (ALPHABET['W'], 7000000.0, 72.0, 64.0, 6000000.0), - (ALPHABET['X'], 7900000.0, 84.5, 72.0, 6000000.0)] - - -class MgrsException(Exception): - pass - - -def toMgrs(latitude, longitude, precision=5): - """ Converts geodetic (latitude and longitude) coordinates to an MGRS - coordinate string, according to the current ellipsoid parameters. - - @param latitude - latitude value - @param longitude - longitude value - @param precision - precision level of MGRS string - @returns - MGRS coordinate string - """ - if math.fabs(latitude) > 90: - raise MgrsException('Latitude outside of valid range (-90 to 90 degrees).') - - if (longitude < -180) or (longitude > 360): - raise MgrsException('Longitude outside of valid range (-180 to 360 degrees).') - - if (precision < 0) or (precision > MAX_PRECISION): - raise MgrsException('The precision must be between 0 and 5 inclusive.') - - hemisphere, zone, epsg = _epsgForWgs(latitude, longitude) - src = osr.SpatialReference() - src.ImportFromEPSG(4326) - dst = osr.SpatialReference() - dst.ImportFromEPSG(epsg) - ct = osr.CoordinateTransformation(src, dst) - x, y, z = ct.TransformPoint(longitude, latitude) - - if (latitude < -80) or (latitude > 84): - # Convert to UPS - mgrs = _upsToMgrs(hemisphere, x, y, precision) - else: - # Convert to UTM - mgrs = _utmToMgrs(zone, hemisphere, latitude, longitude, x, y, precision) - - return mgrs - - -def toWgs(mgrs): - """ Converts an MGRS coordinate string to geodetic (latitude and longitude) - coordinates - - @param mgrs - MGRS coordinate string - @returns - tuple containning latitude and longitude values - """ - if _checkZone(mgrs): - zone, hemisphere, easting, northing = _mgrsToUtm(mgrs) - else: - zone, hemisphere, easting, northing = _mgrsToUps(mgrs) - - epsg = _epsgForUtm(zone, hemisphere) - src = osr.SpatialReference() - src.ImportFromEPSG(epsg) - dst = osr.SpatialReference() - dst.ImportFromEPSG(4326) - ct = osr.CoordinateTransformation(src, dst) - longitude, latitude, z = ct.TransformPoint(easting, northing) - - return latitude, longitude - - -def _upsToMgrs(hemisphere, easting, northing, precision): - """ Converts UPS (hemisphere, easting, and northing) coordinates - to an MGRS coordinate string. - - @param hemisphere - hemisphere either 'N' or 'S' - @param easting - easting/X in meters - @param northing - northing/Y in meters - @param precision - precision level of MGRS string - @returns - MGRS coordinate string - """ - if hemisphere not in ['N', 'S']: - raise MgrsException('Invalid hemisphere ("N" or "S").') - - if (easting < MIN_EAST_NORTH) or (easting > MAX_EAST_NORTH): - raise MgrsException('Easting outside of valid range (100,000 to 900,000 meters for UTM, 0 to 4,000,000 meters for UPS).') - - if (northing < MIN_EAST_NORTH) or (northing > MAX_EAST_NORTH): - raise MgrsException('Northing outside of valid range (0 to 10,000,000 meters for UTM, 0 to 4,000,000 meters for UPS).') - - if (precision < 0) or (precision > MAX_PRECISION): - raise MgrsException('The precision must be between 0 and 5 inclusive.') - - letters = [None, None, None] - if hemisphere == 'N': - if easting >= TWOMIL: - letters[0] = ALPHABET['Z'] - else: - letters[0] = ALPHABET['Y'] - - idx = letters[0] - 22 - ltr2LowValue = UPS_CONSTANTS[idx][1] - falseEasting = UPS_CONSTANTS[idx][4] - falseNorthing = UPS_CONSTANTS[idx][5] - else: - if easting >= TWOMIL: - letters[0] = ALPHABET['B'] - else: - letters[0] = ALPHABET['A'] - - ltr2LowValue = UPS_CONSTANTS[letters[0]][1] - falseEasting = UPS_CONSTANTS[letters[0]][4] - falseNorthing = UPS_CONSTANTS[letters[0]][5] - - gridNorthing = northing - gridNorthing = gridNorthing - falseNorthing - - letters[2] = int(gridNorthing / ONEHT) - - if letters[2] > ALPHABET['H']: - letters[2] = letters[2] + 1 - - if letters[2] > ALPHABET['N']: - letters[2] = letters[2] + 1 - - gridEasting = easting - gridEasting = gridEasting - falseEasting; - letters[1] = ltr2LowValue + int(gridEasting / ONEHT) - - if easting < TWOMIL: - if letters[1] > ALPHABET['L']: - letters[1] = letters[1] + 3 - - if letters[1] > ALPHABET['U']: - letters[1] = letters[1] + 2 - else: - if letters[1] > ALPHABET['C']: - letters[1] = letters[1] + 2 - - if letters[1] > ALPHABET['H']: - letters[1] = letters[1] + 1 - - if letters[1] > ALPHABET['L']: - letters[1] = letters[1] + 3 - - return _mgrsString(0, letters, easting, northing, precision) - - -def _mgrsToUps(mgrs): - """ Converts an MGRS coordinate string to UTM projection (zone, hemisphere, - easting and northing) coordinates - - @param mgrs - MGRS coordinate string - @returns - tuple containing UTM zone, hemisphere, easting and northing - """ - zone, letters, easting, northing, precision = _breakMgrsString(mgrs) - - if zone != 0: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - if letters[0] >= ALPHABET['Y']: - hemisphere = 'N' - - idx = letters[0] - 22 - ltr2LowValue = UPS_CONSTANTS[idx][1] - ltr2HighValue = UPS_CONSTANTS[idx][2] - ltr3HighValue = UPS_CONSTANTS[idx][3] - falseEasting = UPS_CONSTANTS[idx][4] - falseNorthing = UPS_CONSTANTS[idx][5] - else: - hemisphere = 'S' - - ltr2LowValue = UPS_CONSTANTS[letters[0]][1] - ltr2HighValue = UPS_CONSTANTS[letters[0]][2] - ltr3HighValue = UPS_CONSTANTS[letters[0]][3] - falseEasting = UPS_CONSTANTS[letters[0]][4] - falseNorthing = UPS_CONSTANTS[letters[0]][5] - - # Check that the second letter of the MGRS string is within the range - # of valid second letter values. Also check that the third letter is valid - invalid = [ALPHABET['D'], ALPHABET['E'], ALPHABET['M'], ALPHABET['N'], ALPHABET['V'], ALPHABET['W']] - if (letters[1] < ltr2LowValue) or (letters[1] > ltr2HighValue) or (letters[1] in [invalid]) or (letters[2] > ltr3HighValue): - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - gridNorthing = float(letters[2] * ONEHT + falseNorthing) - if letters[2] > ALPHABET['I']: - gridNorthing = gridNorthing - ONEHT - - if letters[2] > ALPHABET['O']: - gridNorthing = gridNorthing - ONEHT - - gridEasting = float((letters[1] - ltr2LowValue) * ONEHT + falseEasting) - if ltr2LowValue != ALPHABET['A']: - if letters[1] > ALPHABET['L']: - gridEasting = gridEasting - 300000.0 - - if letters[1] > ALPHABET['U']: - gridEasting = gridEasting - 200000.0 - else: - if letters[1] > ALPHABET['C']: - gridEasting = gridEasting - 200000.0 - - if letters[1] > ALPHABET['I']: - gridEasting = gridEasting - ONEHT - - if letters[1] > ALPHABET['L']: - gridEasting = gridEasting - 300000.0 - - easting += gridEasting - northing += gridNorthing - - return zone, hemisphere, easting, northing - - -def _utmToMgrs(zone, hemisphere, latitude, longitude, easting, northing, precision): - """ Calculates an MGRS coordinate string based on the UTM zone, latitude, - easting and northing values. - - @param zone - UTM zone number - @param hemisphere - hemisphere either 'N' or 'S' - @param latitude - latitude value - @param longitude - longitude value - @param easting - easting/X in meters - @param northing - northing/Y in meters - @param precision - precision level of MGRS string - @returns - MGRS coordinate string - """ - # FIXME: do we really need this? - # Special check for rounding to (truncated) eastern edge of zone 31V - # if (zone == 31) and (((latitude >= 56.0) and (latitude < 64.0)) and ((longitude >= 3.0) or (easting >= 500000.0))): - # # Reconvert to UTM zone 32 - # override = 32 - # lat = int(latitude) - # lon = int(longitude) - # if zone == 1 and override == 60: - # zone = override - # elif zone == 60 and override == 1: - # zone = override - # elif (lat > 71) and (lon > -1) and (lon < 42): - # if (zone - 2 <= override) and (override <= zone + 2): - # zone = override - # else: - # raise MgrsException('Zone outside of valid range (1 to 60) and within 1 of "natural" zone') - # elif (zone - 1 <= override) and (override <= zone + 1): - # zone = override - # else: - # raise MgrsException('Zone outside of valid range (1 to 60) and within 1 of "natural" zone') - # - # epsg = _epsgForUtm(zone, hemisphere) - # - # src = osr.SpatialReference() - # src.ImportFromEPSG(4326) - # dst = osr.SpatialReference() - # dst.ImportFromEPSG(epsg) - # ct = osr.CoordinateTransformation(src, dst) - # x, y, z = ct.TransformPoint(longitude, latitude) - - if latitude <= 0.0 and northing == 1.0e7: - latitude = 0 - northing = 0 - - ltr2LowValue, ltr2HighValue, patternOffset = _gridValues(zone) - - letters = [_latitudeLetter(latitude), None, None] - - while northing >= TWOMIL: - northing = northing - TWOMIL - - northing += patternOffset - if northing >= TWOMIL: - northing = northing - TWOMIL - - letters[2] = int(northing / ONEHT) - if letters[2] > ALPHABET['H']: - letters[2] += 1 - - if letters[2] > ALPHABET['N']: - letters[2] += 1 - - if ((letters[0] == ALPHABET['V']) and (zone == 31)) and (easting == 500000.0): - easting = easting - 1.0 # Substract 1 meter - - letters[1] = ltr2LowValue + int((easting / ONEHT) - 1) - if ltr2LowValue == ALPHABET['J'] and letters[1] > ALPHABET['N']: - letters[1] += 1 - - return _mgrsString(zone, letters, easting, northing, precision) - - -def _mgrsToUtm(mgrs): - """ Converts an MGRS coordinate string to UTM projection (zone, hemisphere, - easting and northing) coordinates. - - @param mgrs - MGRS coordinate string - @returns - tuple containing UTM zone, hemisphere, easting, northing - """ - zone, letters, easting, northing, precision = _breakMgrsString(mgrs) - if zone == 0: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - if letters == ALPHABET['X'] and zone in [32, 34, 36]: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - if letters[0] < ALPHABET['N']: - hemisphere = 'S' - else: - hemisphere = 'N' - - ltr2LowValue, ltr2HighValue, patternOffset = _gridValues(zone) - - # Check that the second letter of the MGRS string is within the range - # of valid second letter values. Also check that the third letter is valid - if (letters[1] < ltr2LowValue) or (letters[1] > ltr2HighValue) or (letters[2] > ALPHABET['V']): - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - rowLetterNorthing = float(letters[2] * ONEHT) - gridEasting = float((letters[1] - ltr2LowValue + 1) * ONEHT) - if ltr2LowValue == ALPHABET['J'] and letters[1] > ALPHABET['O']: - gridEasting = gridEasting - ONEHT - - if letters[2] > ALPHABET['O']: - rowLetterNorthing = rowLetterNorthing - ONEHT - - if letters[2] > ALPHABET['I']: - rowLetterNorthing = rowLetterNorthing - ONEHT - - if rowLetterNorthing >= TWOMIL: - rowLetterNorthing = rowLetterNorthing - TWOMIL - - minNorthing, northingOffset = _latitudeBandMinNorthing(letters[0]) - - gridNorthing = rowLetterNorthing - patternOffset - if gridNorthing < 0: - gridNorthing += TWOMIL - - gridNorthing += northingOffset - - if gridNorthing < minNorthing: - gridNorthing += TWOMIL - - easting += gridEasting - northing += gridNorthing - - return zone, hemisphere, easting, northing - - -def _mgrsString(zone, letters, easting, northing, precision): - """ Constructs an MGRS string from its component parts - @param zone - UTM zone - @param letters - MGRS coordinate string letters - @param easting - easting value - @param northing - northing value - @param precision - precision level of MGRS string - @returns - MGRS coordinate string - """ - mrgs = '' - if zone: - tmp = str(zone) - mgrs = tmp.zfill(3 - len(tmp)) - else: - mgrs = ' ' - - for i in range(3): - mgrs += list(ALPHABET.keys())[list(ALPHABET.values()).index(letters[i])] - - easting = math.fmod(easting + 1e-8, 100000.0) - if easting >= 99999.5: - easting = 99999.0 - mgrs += str(int(easting)).rjust(5, '0')[:precision] - - northing = math.fmod(northing + 1e-8, 100000.0) - if northing >= 99999.5: - northing = 99999.0 - mgrs += str(int(northing)).rjust(5, '0')[:precision] - - return mgrs - - -def _epsgForWgs(latitude, longitude): - """ Returns corresponding UTM or UPS EPSG code from WGS84 coordinates - @param latitude - latitude value - @param longitude - longitude value - @returns - tuple containing hemisphere, UTM zone and EPSG code - """ - - if math.fabs(latitude) > 90: - raise MgrsException('Latitude outside of valid range (-90 to 90 degrees).') - - if longitude < -180 or longitude > 360: - return MgrsException('Longitude outside of valid range (-180 to 360 degrees).') - - # hemisphere - if latitude < 0: - hemisphere = 'S' - else: - hemisphere = 'N' - - # UTM zone - if latitude <= -80 or latitude >= 84: - # Coordinates falls under UPS system - zone = 61 - else: - # Coordinates falls under UTM system - if longitude < 180: - zone = int(31 + (longitude / 6.0)) - else: - zone = int((longitude / 6) - 29) - - if zone > 60: - zone = 1 - - # Handle UTM special cases - if latitude >= 56.0 and latitude < 64.0 and longitude >= 3.0 and longitude < 12.0: - zone = 32 - - if latitude >= 72.0 and latitude < 84.0: - if longitude >= 0.0 and longitude < 9.0: - zone = 31 - elif longitude >= 9.0 and longitude < 21.0: - zone = 33 - elif longitude >= 21.0 and longitude < 33.0: - zone = 35 - elif longitude >= 33.0 and longitude < 42.0: - zone = 37 - - # North or South hemisphere - if latitude >= 0: - ns = 600 - else: - ns = 700 - - return hemisphere, zone, 32000 + ns + zone - - -def _epsgForUtm(zone, hemisphere): - """ Returen EPSG code for given UTM zone and hemisphere - - @param zone - UTM zone - @param hemisphere - hemisphere either 'N' or 'S' - @returns - corresponding EPSG code - """ - if hemisphere not in ['N', 'S']: - raise MgrsException('Invalid hemisphere ("N" or "S").') - - if zone < 0 or zone > 60: - raise MgrsException('UTM zone ouside valid range.') - - if hemisphere == 'N': - ns = 600 - else: - ns = 700 - - if zone == 0: - zone = 61 - - return 32000 + ns + zone - - -def _gridValues(zone): - """ Sets the letter range used for the 2nd letter in the MGRS coordinate - string, based on the set number of the UTM zone. It also sets the pattern - offset using a value of A for the second letter of the grid square, based - on the grid pattern and set number of the UTM zone. - - @param zone - UTM zone number - @returns - tuple containing 2nd letter low number, 2nd letter high number - and pattern offset - """ - setNumber = zone % 6 - - if not setNumber: - setNumber = 6 - - if setNumber in [1, 4]: - ltr2LowValue = ALPHABET['A'] - ltr2HighValue = ALPHABET['H'] - elif setNumber in [2, 5]: - ltr2LowValue = ALPHABET['J'] - ltr2HighValue = ALPHABET['R'] - elif setNumber in [3, 6]: - ltr2LowValue = ALPHABET['S'] - ltr2HighValue = ALPHABET['Z'] - - if setNumber % 2: - patternOffset = 0.0 - else: - patternOffset = 500000.0 - - return ltr2LowValue, ltr2HighValue, patternOffset - - -def _latitudeLetter(latitude): - """ Returns the latitude band letter for given latitude - - @param latitude - latitude value - @returns - latitude band letter - """ - if latitude >= 72 and latitude < 84.5: - return ALPHABET['X'] - elif latitude > -80.5 and latitude < 72: - idx = int(((latitude + 80.0) / 8.0) + 1.0e-12) - return LATITUDE_BANDS[idx][0] - - -def _checkZone(mgrs): - """ Checks if MGRS coordinate string contains UTM zone definition - - @param mgrs - MGRS coordinate string - @returns - True if zone is given, False otherwise - """ - mgrs = mgrs.lstrip() - count = sum(1 for c in itertools.takewhile(str.isdigit, mgrs)) - if count <= 2: - return count > 0 - else: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - -def _breakMgrsString(mgrs): - """ Breaks down an MGRS coordinate string into its component parts. - - @param mgrs - MGRS coordinate string - @returns - tuple containing MGRS string componets: UTM zone, - MGRS coordinate string letters, easting, northing and precision - """ - mgrs = mgrs.lstrip() - # Number of zone digits - count = sum(1 for c in itertools.takewhile(str.isdigit, mgrs)) - if count <= 2: - if count > 0: - zone = int(mgrs[:2]) - if zone < 1 or zone > 60: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - else: - zone = 0 - else: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - idx = count - # MGRS letters - count = sum(1 for c in itertools.takewhile(str.isalpha, itertools.islice(mgrs, idx, None))) - if count == 3: - a = ord('A') - invalid = [ALPHABET['I'], ALPHABET['O']] - - letters = [] - ch = ord(mgrs[idx:idx + 1].upper()) - a - if ch in invalid: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - idx += 1 - letters.append(ch) - - ch = ord(mgrs[idx:idx + 1].upper()) - a - if ch in invalid: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - idx += 1 - letters.append(ch) - - ch = ord(mgrs[idx:idx + 1].upper()) - a - if ch in invalid: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - idx += 1 - letters.append(ch) - else: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - # Easting and Northing - count = sum(1 for c in itertools.takewhile(str.isdigit, itertools.islice(mgrs, idx, None))) - if count <= 10 and count % 2 == 0: - precision = int(count / 2) - if precision > 0: - easting = float(mgrs[idx:idx + precision]) - northing = float(mgrs[idx + precision:]) - else: - easting = 0 - northing = 0 - else: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - return zone, letters, easting, northing, precision - - -def _latitudeBandMinNorthing(letter): - """ Determines the minimum northing and northing offset - for given latitude band letter. - - @param letter - latitude band letter - @returns - tuple containing minimum northing and northing offset - for that letter - """ - if letter >= ALPHABET['C'] and letter <= ALPHABET['H']: - minNorthing = LATITUDE_BANDS[letter - 2][1] - northingOffset = LATITUDE_BANDS[letter - 2][4] - elif letter >= ALPHABET['J'] and letter <= ALPHABET['N']: - minNorthing = LATITUDE_BANDS[letter - 3][1] - northingOffset = LATITUDE_BANDS[letter - 3][4] - elif letter >= ALPHABET['P'] and letter <= ALPHABET['X']: - minNorthing = LATITUDE_BANDS[letter - 4][1] - northingOffset = LATITUDE_BANDS[letter - 4][4] - else: - raise MgrsException('An MGRS string error: string too long, too short, or badly formed') - - return minNorthing, northingOffset diff --git a/templates/Military/Example A0 Landscape.qpt b/templates/Military/Example A0 Landscape.qpt deleted file mode 100755 index e69de29..0000000 diff --git a/templates/Military/Example A4 Portrait.qpt b/templates/Military/Example A4 Portrait.qpt deleted file mode 100755 index e69de29..0000000 diff --git a/templates/Simple/A4L.qpt b/templates/Simple/A4L.qpt deleted file mode 100644 index 1fd9fe7..0000000 --- a/templates/Simple/A4L.qpt +++ /dev/null @@ -1,470 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +proj=longlat +a=6378137.0000 +rf=298.2572221010000 +units=m +nadgrids=@null +no_defs - 10051 - 210642000 - IGNF:WGS84G - World Geodetic System 1984 - longlat - IGNF:ELG037 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/templates/Simple/Example A0 Landscape.qpt b/templates/Simple/Example A0 Landscape.qpt deleted file mode 100755 index e69de29..0000000 diff --git a/templates/Simple/Example A4 Portrait.qpt b/templates/Simple/Example A4 Portrait.qpt deleted file mode 100755 index e69de29..0000000 diff --git a/templates/Simple/New Example map.qpt b/templates/Simple/New Example map.qpt deleted file mode 100755 index e69de29..0000000