diff --git a/README.html b/README.html deleted file mode 100644 index 886e7c9..0000000 --- a/README.html +++ /dev/null @@ -1,42 +0,0 @@ - -
-
-Your QGIS plugin directory is located at:
- /home/klakar/.local/share/QGIS/QGIS3/profiles/default/python/plugins
-
-
-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.
- 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 @@
-