BERATools 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. beratools/__init__.py +1 -7
  2. beratools/core/algo_centerline.py +491 -351
  3. beratools/core/algo_common.py +497 -0
  4. beratools/core/algo_cost.py +192 -0
  5. beratools/core/{dijkstra_algorithm.py → algo_dijkstra.py} +503 -460
  6. beratools/core/algo_footprint_rel.py +577 -0
  7. beratools/core/algo_line_grouping.py +944 -0
  8. beratools/core/algo_merge_lines.py +214 -0
  9. beratools/core/algo_split_with_lines.py +304 -0
  10. beratools/core/algo_tiler.py +428 -0
  11. beratools/core/algo_vertex_optimization.py +469 -0
  12. beratools/core/constants.py +52 -86
  13. beratools/core/logger.py +76 -85
  14. beratools/core/tool_base.py +196 -133
  15. beratools/gui/__init__.py +11 -15
  16. beratools/gui/{beratools.json → assets/beratools.json} +2185 -2300
  17. beratools/gui/batch_processing_dlg.py +513 -463
  18. beratools/gui/bt_data.py +481 -487
  19. beratools/gui/bt_gui_main.py +710 -691
  20. beratools/gui/main.py +26 -0
  21. beratools/gui/map_window.py +162 -146
  22. beratools/gui/tool_widgets.py +725 -493
  23. beratools/tools/Beratools_r_script.r +1120 -1120
  24. beratools/tools/Ht_metrics.py +116 -116
  25. beratools/tools/__init__.py +7 -7
  26. beratools/tools/batch_processing.py +136 -132
  27. beratools/tools/canopy_threshold_relative.py +672 -670
  28. beratools/tools/canopycostraster.py +222 -222
  29. beratools/tools/centerline.py +136 -176
  30. beratools/tools/common.py +857 -885
  31. beratools/tools/fl_regen_csf.py +428 -428
  32. beratools/tools/forest_line_attributes.py +408 -408
  33. beratools/tools/line_footprint_absolute.py +213 -363
  34. beratools/tools/line_footprint_fixed.py +436 -282
  35. beratools/tools/line_footprint_functions.py +733 -720
  36. beratools/tools/line_footprint_relative.py +73 -64
  37. beratools/tools/line_grouping.py +45 -0
  38. beratools/tools/ln_relative_metrics.py +615 -615
  39. beratools/tools/r_cal_lpi_elai.r +24 -24
  40. beratools/tools/r_generate_pd_focalraster.r +100 -100
  41. beratools/tools/r_interface.py +79 -79
  42. beratools/tools/r_point_density.r +8 -8
  43. beratools/tools/rpy_chm2trees.py +86 -86
  44. beratools/tools/rpy_dsm_chm_by.py +81 -81
  45. beratools/tools/rpy_dtm_by.py +63 -63
  46. beratools/tools/rpy_find_cellsize.py +43 -43
  47. beratools/tools/rpy_gnd_csf.py +74 -74
  48. beratools/tools/rpy_hummock_hollow.py +85 -85
  49. beratools/tools/rpy_hummock_hollow_raster.py +71 -71
  50. beratools/tools/rpy_las_info.py +51 -51
  51. beratools/tools/rpy_laz2las.py +40 -40
  52. beratools/tools/rpy_lpi_elai_lascat.py +466 -466
  53. beratools/tools/rpy_normalized_lidar_by.py +56 -56
  54. beratools/tools/rpy_percent_above_dbh.py +80 -80
  55. beratools/tools/rpy_points2trees.py +88 -88
  56. beratools/tools/rpy_vegcoverage.py +94 -94
  57. beratools/tools/tiler.py +48 -206
  58. beratools/tools/tool_template.py +69 -54
  59. beratools/tools/vertex_optimization.py +61 -620
  60. beratools/tools/zonal_threshold.py +144 -144
  61. beratools-0.2.2.dist-info/METADATA +108 -0
  62. beratools-0.2.2.dist-info/RECORD +74 -0
  63. {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/WHEEL +1 -1
  64. {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/licenses/LICENSE +22 -22
  65. beratools/gui/cli.py +0 -18
  66. beratools/gui/gui.json +0 -8
  67. beratools/gui_tk/ASCII Banners.txt +0 -248
  68. beratools/gui_tk/__init__.py +0 -20
  69. beratools/gui_tk/beratools_main.py +0 -515
  70. beratools/gui_tk/bt_widgets.py +0 -442
  71. beratools/gui_tk/cli.py +0 -18
  72. beratools/gui_tk/img/BERALogo.png +0 -0
  73. beratools/gui_tk/img/closed.gif +0 -0
  74. beratools/gui_tk/img/closed.png +0 -0
  75. beratools/gui_tk/img/open.gif +0 -0
  76. beratools/gui_tk/img/open.png +0 -0
  77. beratools/gui_tk/img/tool.gif +0 -0
  78. beratools/gui_tk/img/tool.png +0 -0
  79. beratools/gui_tk/main.py +0 -14
  80. beratools/gui_tk/map_window.py +0 -144
  81. beratools/gui_tk/runner.py +0 -1481
  82. beratools/gui_tk/tooltip.py +0 -55
  83. beratools/third_party/pyqtlet2/__init__.py +0 -9
  84. beratools/third_party/pyqtlet2/leaflet/__init__.py +0 -26
  85. beratools/third_party/pyqtlet2/leaflet/control/__init__.py +0 -6
  86. beratools/third_party/pyqtlet2/leaflet/control/control.py +0 -59
  87. beratools/third_party/pyqtlet2/leaflet/control/draw.py +0 -52
  88. beratools/third_party/pyqtlet2/leaflet/control/layers.py +0 -20
  89. beratools/third_party/pyqtlet2/leaflet/core/Parser.py +0 -24
  90. beratools/third_party/pyqtlet2/leaflet/core/__init__.py +0 -2
  91. beratools/third_party/pyqtlet2/leaflet/core/evented.py +0 -180
  92. beratools/third_party/pyqtlet2/leaflet/layer/__init__.py +0 -5
  93. beratools/third_party/pyqtlet2/leaflet/layer/featuregroup.py +0 -34
  94. beratools/third_party/pyqtlet2/leaflet/layer/icon/__init__.py +0 -1
  95. beratools/third_party/pyqtlet2/leaflet/layer/icon/icon.py +0 -30
  96. beratools/third_party/pyqtlet2/leaflet/layer/imageoverlay.py +0 -18
  97. beratools/third_party/pyqtlet2/leaflet/layer/layer.py +0 -105
  98. beratools/third_party/pyqtlet2/leaflet/layer/layergroup.py +0 -45
  99. beratools/third_party/pyqtlet2/leaflet/layer/marker/__init__.py +0 -1
  100. beratools/third_party/pyqtlet2/leaflet/layer/marker/marker.py +0 -91
  101. beratools/third_party/pyqtlet2/leaflet/layer/tile/__init__.py +0 -2
  102. beratools/third_party/pyqtlet2/leaflet/layer/tile/gridlayer.py +0 -4
  103. beratools/third_party/pyqtlet2/leaflet/layer/tile/tilelayer.py +0 -16
  104. beratools/third_party/pyqtlet2/leaflet/layer/vector/__init__.py +0 -5
  105. beratools/third_party/pyqtlet2/leaflet/layer/vector/circle.py +0 -15
  106. beratools/third_party/pyqtlet2/leaflet/layer/vector/circlemarker.py +0 -18
  107. beratools/third_party/pyqtlet2/leaflet/layer/vector/path.py +0 -5
  108. beratools/third_party/pyqtlet2/leaflet/layer/vector/polygon.py +0 -14
  109. beratools/third_party/pyqtlet2/leaflet/layer/vector/polyline.py +0 -18
  110. beratools/third_party/pyqtlet2/leaflet/layer/vector/rectangle.py +0 -14
  111. beratools/third_party/pyqtlet2/leaflet/map/__init__.py +0 -1
  112. beratools/third_party/pyqtlet2/leaflet/map/map.py +0 -220
  113. beratools/third_party/pyqtlet2/mapwidget.py +0 -45
  114. beratools/third_party/pyqtlet2/web/custom.js +0 -43
  115. beratools/third_party/pyqtlet2/web/map.html +0 -23
  116. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers-2x.png +0 -0
  117. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers.png +0 -0
  118. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon-2x.png +0 -0
  119. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon.png +0 -0
  120. beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-shadow.png +0 -0
  121. beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.css +0 -656
  122. beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.js +0 -6
  123. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.codeclimate.yml +0 -14
  124. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.editorconfig +0 -4
  125. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.gitattributes +0 -22
  126. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.travis.yml +0 -43
  127. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/LICENSE +0 -20
  128. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers-2x.png +0 -0
  129. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers.png +0 -0
  130. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon-2x.png +0 -0
  131. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon.png +0 -0
  132. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-shadow.png +0 -0
  133. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet-2x.png +0 -0
  134. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.png +0 -0
  135. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.svg +0 -156
  136. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.css +0 -10
  137. beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.js +0 -10
  138. beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/LICENSE +0 -22
  139. beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/leaflet.rotatedMarker.js +0 -57
  140. beratools/tools/forest_line_ecosite.py +0 -216
  141. beratools/tools/lapis_all.py +0 -103
  142. beratools/tools/least_cost_path_from_chm.py +0 -152
  143. beratools-0.2.0.dist-info/METADATA +0 -63
  144. beratools-0.2.0.dist-info/RECORD +0 -142
  145. /beratools/gui/{img → assets}/BERALogo.png +0 -0
  146. /beratools/gui/{img → assets}/closed.gif +0 -0
  147. /beratools/gui/{img → assets}/closed.png +0 -0
  148. /beratools/{gui_tk → gui/assets}/gui.json +0 -0
  149. /beratools/gui/{img → assets}/open.gif +0 -0
  150. /beratools/gui/{img → assets}/open.png +0 -0
  151. /beratools/gui/{img → assets}/tool.gif +0 -0
  152. /beratools/gui/{img → assets}/tool.png +0 -0
  153. {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/entry_points.txt +0 -0
@@ -1,55 +0,0 @@
1
- # ---------------------------------------------------------------------------
2
- #
3
- # Tooltip.py
4
- # Script Author: SquareRoot17, retrieved at 01/01/2020 from
5
- # https://stackoverflow.com/questions/20399243/display-message-when-hovering-over-something-with-mouse-cursor-in-python
6
- # Modified by Gustavo Lopes Queiroz
7
- # Date: 2020-Jan-22
8
- #
9
- # Purpose: Allows for GUI tooltips when user hovers the cursor over elements
10
- #
11
- # ---------------------------------------------------------------------------
12
- try:
13
- from tkinter import *
14
- except ImportError:
15
- from Tkinter import *
16
-
17
- class ToolTip(object):
18
-
19
- def __init__(self, widget, wraplength = 0):
20
- self.widget = widget
21
- self.tipwindow = None
22
- self.id = None
23
- self.x = self.y = 0
24
- self.wraplength = wraplength
25
-
26
- def showtip(self, text):
27
- "Display text in tooltip window"
28
- self.text = text
29
- if self.tipwindow or not self.text:
30
- return
31
- x, y, cx, cy = self.widget.bbox("insert")
32
- x = x + self.widget.winfo_rootx() + 57
33
- y = y + cy + self.widget.winfo_rooty() +27
34
- self.tipwindow = tw = Toplevel(self.widget)
35
- tw.wm_overrideredirect(1)
36
- tw.wm_geometry("+%d+%d" % (x, y))
37
- label = Label(tw, text=self.text, justify=LEFT,
38
- background="#ffffe0", relief=SOLID, borderwidth=1, wraplength = self.wraplength,
39
- font=("tahoma", "8", "normal"))
40
- label.pack(ipadx=1)
41
-
42
- def hidetip(self):
43
- tw = self.tipwindow
44
- self.tipwindow = None
45
- if tw:
46
- tw.destroy()
47
-
48
- def CreateToolTip(widget, text, wraplength = 500):
49
- toolTip = ToolTip(widget, wraplength)
50
- def enter(event):
51
- toolTip.showtip(text)
52
- def leave(event):
53
- toolTip.hidetip()
54
- widget.bind('<Enter>', enter)
55
- widget.bind('<Leave>', leave)
@@ -1,9 +0,0 @@
1
- """
2
- Bringing Leaflet maps to PyQt.
3
- """
4
-
5
- __author__ = 'Leon Friedmann <leon.friedmann@tum.de>'
6
- __version__ = '0.9.3'
7
-
8
- from .mapwidget import MapWidget
9
- from .leaflet import L
@@ -1,26 +0,0 @@
1
- from .map import Map
2
- from .layer import LayerGroup, FeatureGroup, imageOverlay
3
- from .layer.tile import TileLayer
4
- from .layer.marker import Marker
5
- from .layer.icon import Icon
6
- from .layer.vector import Circle, CircleMarker, Polygon, Polyline, Rectangle
7
- from .control import Control
8
-
9
- class L:
10
- """
11
- Leaflet namespace that holds reference to all the leaflet objects
12
- """
13
- map = Map
14
- tileLayer = TileLayer
15
- imageOverlay = imageOverlay
16
- marker = Marker
17
- icon = Icon
18
- circleMarker = CircleMarker
19
- polyline = Polyline
20
- polygon = Polygon
21
- rectangle = Rectangle
22
- circle = Circle
23
- layerGroup = LayerGroup
24
- featureGroup = FeatureGroup
25
- control = Control
26
-
@@ -1,6 +0,0 @@
1
- from .layers import Layers
2
- from .draw import Draw
3
-
4
- class Control:
5
- layers = Layers
6
- draw = Draw
@@ -1,59 +0,0 @@
1
- import json
2
- import logging
3
- import os
4
- import time
5
-
6
- from qtpy.QtCore import Slot, Signal
7
- from ..core import Evented
8
-
9
- class Control(Evented):
10
-
11
- # controlId is a static variable shared between all controls
12
- # It is used to give unique names to controls
13
- controlId = 0
14
- # addedToMap and removedFromMap are signals for controls to
15
- # know when they're added and removed from maps
16
- addedToMap = Signal()
17
- removedFromMap = Signal()
18
-
19
- @property
20
- def map(self):
21
- return self._map
22
-
23
- @map.setter
24
- def map(self, map_):
25
- self._map = map_
26
- if map_ is None:
27
- self.removedFromMap.emit()
28
- else:
29
- self.addedToMap.emit()
30
-
31
- @property
32
- def jsName(self):
33
- return self._controlName
34
-
35
- @property
36
- def controlName(self):
37
- return self._controlName
38
-
39
- @controlName.setter
40
- def controlName(self, name):
41
- self._controlName = name
42
-
43
- def __init__(self):
44
- super().__init__()
45
- self._map = None
46
- self._controlName = self._getNewControlName()
47
-
48
- def addTo(self, map_):
49
- map_.addControl(self)
50
- return self
51
-
52
- def removeFrom(self, map_):
53
- map_.removeControl(self)
54
-
55
- def _getNewControlName(self):
56
- controlName = 'c{}'.format(self.controlId)
57
- Control.controlId += 1
58
- return controlName
59
-
@@ -1,52 +0,0 @@
1
- from .control import Control
2
- # NOTE: Importing FeatureGroup here may not be the best idea
3
- from ..layer.featuregroup import FeatureGroup
4
-
5
- DEFAULT_POSITION = 'topleft'
6
- DEFAULT_CIRCLE = False
7
- DEFAULT_RECTANGLE = False
8
-
9
- class Draw(Control):
10
-
11
- def __init__(self, options={}, handleFeatureGroup=True):
12
- super().__init__()
13
- self.options = options
14
- self.handleFeatureGroup = handleFeatureGroup
15
- self.featureGroup = None
16
- self._handleOptions()
17
- if self._map:
18
- self._initJs()
19
- if handleFeatureGroup:
20
- self.addedToMap.connect(self.addDrawnToFeatureGroup)
21
-
22
- def _initJs(self):
23
- jsObject = 'new L.Control.Draw('
24
- if self.options:
25
- jsObject += '{options}'.format(options=self._stringifyForJs(self.options))
26
- jsObject += ')'
27
- self._createJsObject(jsObject, self._map.mapWidgetIndex)
28
-
29
- def _handleOptions(self):
30
- # If there are no options, then we want to set the default options
31
- self.options['position'] = self.options.get('position', DEFAULT_POSITION)
32
- draw = self.options.get('draw', {})
33
- if draw is not False:
34
- # We want to make sure the user wants draw functionality
35
- draw['circle'] = draw.get('circle', DEFAULT_CIRCLE)
36
- draw['rectangle'] = draw.get('rectangle', DEFAULT_RECTANGLE)
37
- self.options['draw'] = draw
38
- edit = self.options.get('edit', {})
39
- if edit is not False:
40
- # We want to make sure the user wants edit functionality
41
- featureGroup = edit.get('featureGroup', None)
42
- if featureGroup is None and self.handleFeatureGroup:
43
- # If a feature group has not been set, create one and add it
44
- featureGroup = FeatureGroup()
45
- edit['featureGroup'] = featureGroup
46
- self.featureGroup = featureGroup
47
- self.options['edit'] = edit
48
-
49
- def addDrawnToFeatureGroup(self):
50
- self.map.addLayer(self.featureGroup)
51
- self.map.drawCreated.connect(self.featureGroup.createAndAddDrawnLayer)
52
-
@@ -1,20 +0,0 @@
1
- from .control import Control
2
-
3
- class Layers(Control):
4
-
5
- def __init__(self, layers=[], overlays={}, options=None):
6
- super().__init__()
7
- self.layers = layers
8
- self.overlays = overlays
9
- self.options = options
10
- self._initJs()
11
-
12
- def _initJs(self):
13
- jsObject = 'L.control.layers({layers}'.format(layers=self._stringifyForJs(self.layers))
14
- if self.overlays is not None:
15
- jsObject += ', {overlays}'.format(overlays=self._stringifyForJs(self.overlays))
16
- if self.options is not None:
17
- jsObject += ', {options}'.format(options=self._stringifyForJs(self.options))
18
- jsObject += ')'
19
- self._createJsObject(jsObject)
20
-
@@ -1,24 +0,0 @@
1
- class Parser:
2
- @staticmethod
3
- def dict_for_js(object_to_parse: dict) -> dict:
4
- return_dict = {}
5
- for key, value in object_to_parse.items():
6
- if isinstance(value, bool):
7
- return_dict[key] = str(value).lower()
8
- continue
9
-
10
- return_dict[key] = value
11
- return return_dict
12
-
13
- @staticmethod
14
- def js_for_dict(object_to_parse: dict) -> dict:
15
- return_dict = {}
16
- for key, value in object_to_parse.items():
17
- if isinstance(value, str):
18
- value: str
19
- if value.lower() in ["true", "false"]:
20
- return_dict[key] = True if value.lower() == "true" else False
21
- continue
22
-
23
- return_dict[key] = value
24
- return return_dict
@@ -1,2 +0,0 @@
1
- from .evented import Evented
2
-
@@ -1,180 +0,0 @@
1
- import logging
2
-
3
- from ... import mapwidget
4
-
5
- from qtpy.QtCore import QObject, QJsonValue
6
-
7
-
8
- class Evented(QObject):
9
- '''
10
- Base class for all pyqtlet2 objects.
11
- Handles initiation, as well as all python<->js communication
12
- '''
13
- mapWidgets = []
14
-
15
- def __init__(self, mapWidget=None, mapWidgetIndex=None):
16
- '''
17
- Base class for all pyqtlet2 objects
18
- Handles initiation, as well as python-Js communication
19
- The first pyqtlet2 object to be initiated should be pyqtlet2.L.map
20
- This will allow all the pyqtlet2 objects to have access to the
21
- widget and thus the ability to implement leaflet via python.
22
-
23
- :param pyqtlet2.MapWidget mapWidget: The mapwidget object
24
- Should only be sent once, when the first object is being
25
- initialised.
26
- '''
27
- super().__init__()
28
- self._logger = logging.getLogger(__name__)
29
- self.response = None
30
-
31
- if isinstance(mapWidgetIndex, type(None)):
32
- return
33
-
34
- if mapWidget is None:
35
- raise RuntimeError('L.map must be initialised before other pyqtlet2 objects')
36
- if not issubclass(type(mapWidget), mapwidget.MapWidget):
37
- raise TypeError(('Expected mapWidget of type pyqtlet2.MapWidget, '
38
- 'received {type_}'.format(type_=type(mapWidget))))
39
- self.mapWidgets.append(mapWidget)
40
- js = ('var channelObjects = null;'
41
- 'new QWebChannel(qt.webChannelTransport, function(channel) {'
42
- ' channelObjects = channel.objects;'
43
- '});')
44
- self.runJavaScript(js, mapWidgetIndex)
45
- if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
46
- mapWidget.page.titleChanged.connect(lambda: print('title changed'))
47
-
48
- def getMapWidgetAtIndex(self, mapWidgetIndex):
49
- if len(self.mapWidgets) > mapWidgetIndex:
50
- return self.mapWidgets[mapWidgetIndex]
51
- self._logger.error("No")
52
- return None
53
-
54
- def getJsResponse(self, js, mapWidgetIndex, callback):
55
- '''
56
- Runs javascript code in the mapWidget and triggers callback.
57
-
58
- Can be used for custom use cases where information is required
59
- from the mapwidget, and the existing code does not cover the
60
- requirement
61
-
62
- :param str js: The javascript code
63
- :param function callback: The function that will consume the
64
- javascript response
65
-
66
- .. note::
67
- Qt runs runJavaScript function asynchronously. So if we want
68
- to get a response from leaflet, we need to force it to be sync
69
- In all that I have tried, I was unable to get the response from
70
- the same function, so I am converting it to a method with callback
71
- '''
72
- self._logger.debug('Running JS with callback: {js}=>{callback}'.format(
73
- js=js, callback=callback.__name__))
74
- if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
75
- mapWidget.page.runJavaScript(js, callback)
76
- else:
77
- self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
78
-
79
- def runJavaScript(self, js, mapWidgetIndex: int):
80
- '''
81
- Runs javascript code in the mapWidget.
82
-
83
- Can be used for custom use cases where the existing code,
84
- methods etc. do not cover the requirements.
85
-
86
- :param str js: The javascript code
87
- '''
88
- self._logger.debug('Running JS: {js}'.format(js=js))
89
- if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
90
- mapWidget.page.runJavaScript(js)
91
- else:
92
- self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
93
-
94
- def _createJsObject(self, leafletJsObject, mapWidgetIndex):
95
- '''
96
- Function to create variables/objects in leaflet in the
97
- javascript "engine", and registers the object so that it can
98
- be called in the webchannel.
99
-
100
- :param str leafletJsObject: javascript code that creates the
101
- leaflet object
102
- '''
103
- # Creates the js object on the mapWidget page
104
- js = 'var {name} = {jsObject}'.format(name=self.jsName,
105
- jsObject=leafletJsObject)
106
- self.runJavaScript(js, mapWidgetIndex)
107
- # register the object in the channel
108
- if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
109
- mapWidget.channel.registerObject(
110
- '{name}Object'.format(name=self.jsName), self)
111
- else:
112
- self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
113
-
114
- def _connectEventToSignal(self, event, signalEmitter, mapWidgetIndex):
115
- # We need to delete some keys as they are causing circular structures
116
- js = '{name}.on("{event}", function(e) {{\
117
- delete e.target;\
118
- delete e.sourceTarget;\
119
- e = copyWithoutCircularReferences([e], e);\
120
- channelObjects.{name}Object.{signalEmitter}(e)}})'.format(
121
- name=self.jsName, event=event, signalEmitter=signalEmitter)
122
- self.runJavaScript(js, mapWidgetIndex)
123
-
124
- def _stringifyForJs(self, object_):
125
- # When passing options to JS, sometimes we need to pass in objects
126
- # this method and _handleObject take care of that
127
- # Some arguments are strings and some are objects. We also make sure
128
- # that the objects are not sent as strings. Similarly, we also convert
129
- # python bool to js bool etc.
130
- jsString = str(self._handleObject(object_))
131
- jsString = jsString.replace('\'__pyqtletObjectStart__', '')
132
- jsString = jsString.replace('\"__pyqtletObjectStart__', '')
133
- jsString = jsString.replace('__pyqtletObjectEnd__\'', '')
134
- jsString = jsString.replace('__pyqtletObjectEnd__\"', '')
135
- return jsString
136
-
137
- def _handleObject(self, object_):
138
- if type(object_) is list:
139
- return [self._handleObject(item) for item in object_]
140
- if type(object_) is dict:
141
- return {key: self._handleObject(object_[key]) for key in object_}
142
- if issubclass(object_.__class__, Evented):
143
- return '__pyqtletObjectStart__{name}__pyqtletObjectEnd__'.format(name=object_.jsName)
144
- if object_ is True:
145
- return '__pyqtletObjectStart__true__pyqtletObjectEnd__'
146
- if object_ is False:
147
- return '__pyqtletObjectStart__false__pyqtletObjectEnd__'
148
- if object_ is None:
149
- return '__pyqtletObjectStart__null__pyqtletObjectEnd__'
150
- return object_
151
-
152
- def _qJsonValueToDict(self, object_):
153
- # Qt returns QJsonValue from within the QChannel. Converting
154
- # that into a dict is a small recursive function.
155
- if type(object_) is QJsonValue:
156
- return self._qJsonValueToDict(self._qJsonToRespectiveType(object_))
157
- if type(object_) is list:
158
- return [self._qJsonValueToDict(item) for item in object_]
159
- if type(object_) is dict:
160
- return {key: self._qJsonValueToDict(object_[key]) for key in object_}
161
- return object_
162
-
163
- def _qJsonToRespectiveType(self, object_):
164
- # A QJsonValue can be one of many types. This function just
165
- # converts into the correct type
166
- if object_.isArray():
167
- return object_.toArray()
168
- if object_.isBool():
169
- return object_.toBool()
170
- if object_.isDouble():
171
- return object_.toDouble()
172
- if object_.isNull():
173
- return None
174
- if object_.isObject():
175
- return object_.toObject()
176
- if object_.isString():
177
- return object_.toString()
178
- if object_.isUndefined():
179
- return None
180
-
@@ -1,5 +0,0 @@
1
- from .featuregroup import FeatureGroup
2
- from .layer import Layer
3
- from .layergroup import LayerGroup
4
- from .imageoverlay import imageOverlay
5
-
@@ -1,34 +0,0 @@
1
- from .layergroup import LayerGroup
2
- from ..layer import marker, vector
3
-
4
- class FeatureGroup(LayerGroup):
5
- """
6
- Used to group several layers and handle them as one. If you add it to the map, any layers added or removed from the group will be added/removed on the map as well.
7
- """
8
-
9
- def _initJs(self):
10
- leafletJsObject = 'new L.featureGroup()'
11
- self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
12
-
13
- def createAndAddDrawnLayer(self, drawnLayer, options=None):
14
- layerType = drawnLayer['layerType']
15
- if layerType == 'polygon':
16
- coords = drawnLayer['layer']['_latlngs']['0']
17
- coords = [coords[p] for p in coords]
18
- self.addLayer(vector.Polygon(coords, options))
19
- elif layerType == 'marker':
20
- coords = drawnLayer['layer']['_latlng']
21
- self.addLayer(marker.Marker(coords, options))
22
- elif layerType == 'polyline':
23
- coords = drawnLayer['layer']['_latlngs']
24
- coords = [coords[p] for p in coords]
25
- self.addLayer(vector.Polyline(coords, options))
26
- elif layerType == 'rectangle':
27
- coords = drawnLayer['layer']['_latlngs']['0']
28
- coords = [coords[p] for p in coords]
29
- self.addLayer(vector.Rectangle(coords, options))
30
- elif layerType == 'circle':
31
- coords = drawnLayer['layer']['_latlng']
32
- radius = drawnLayer['layer']['options']['radius']
33
- self.addLayer(vector.Circle([coords['lat'], coords['lng']], radius))
34
-
@@ -1 +0,0 @@
1
- from .icon import Icon
@@ -1,30 +0,0 @@
1
- from ..layer import Layer
2
- from ...core.Parser import Parser
3
- import os
4
-
5
-
6
- class Icon(Layer):
7
- def __init__(self, iconUrl: str, options=None):
8
- super().__init__()
9
- if isinstance(options, type(None)):
10
- options = {}
11
- self.iconUrl = iconUrl
12
- self.icon_found = False
13
- self.options = options
14
- self._check_icon_url()
15
- if self._map:
16
- self._initJs()
17
-
18
- def _check_icon_url(self):
19
- if "http" in self.iconUrl:
20
- self._log.info("Can't check if icon exists at url!")
21
- return
22
- if not os.path.isfile(self.iconUrl):
23
- self._log.error(f"Can't locate file at path: '{self.iconUrl}'. Current working directory is '{os.getcwd()}'")
24
- return
25
- self.icon_found = True
26
-
27
- def _initJs(self):
28
- leafletJsObject = 'L.icon({options});'.format(options=Parser.dict_for_js({"iconUrl": self.iconUrl,
29
- **self.options}))
30
- self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
@@ -1,18 +0,0 @@
1
- from .layer import Layer
2
-
3
- class imageOverlay(Layer):
4
- def __init__(self, imageURL, bounds, options=None):
5
- super().__init__()
6
- self.imageURL = imageURL
7
- self.bounds = bounds
8
- self.options = options
9
- if self._map:
10
- self._initJs()
11
-
12
- def _initJs(self):
13
- leafletJsObject = 'L.imageOverlay("{imageURL}",{bounds}'.format(imageURL=self.imageURL,bounds=self.bounds)
14
- if self.options:
15
- leafletJsObject += ', {options}'.format(options=self.options)
16
- leafletJsObject += ')'
17
- self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
18
-
@@ -1,105 +0,0 @@
1
- from ..core import Evented
2
- import logging
3
- from abc import abstractmethod
4
-
5
- class Layer(Evented):
6
-
7
- # layerId is a static variable shared between all layers
8
- # It is used to give unique names to layers
9
- layerId = 0
10
-
11
- @property
12
- def layerName(self):
13
- return self._layerName
14
-
15
- @layerName.setter
16
- def layerName(self, name):
17
- self._layerName = name
18
-
19
- @property
20
- def jsName(self):
21
- return self._layerName
22
-
23
- @property
24
- def map(self):
25
- return self._map
26
-
27
- @map.setter
28
- def map(self, map_):
29
- self._map = map_
30
-
31
- @abstractmethod
32
- def _initJs(self):
33
- raise NotImplemented
34
-
35
- def runJavaScriptForMapIndex(self, js):
36
- if self._map is not None:
37
- self.runJavaScript(js, self._map.mapWidgetIndex)
38
-
39
- def getJsResponseForMapIndex(self, js, callback):
40
- if self._map is not None:
41
- self.getJsResponse(js, self._map.mapWidgetIndex, callback)
42
-
43
- def __init__(self):
44
- super().__init__()
45
- self._map = None
46
- self._layerName = self._getNewLayerName()
47
- self._log = logging.getLogger(f"layer_{self._layerName}")
48
- self._popup = None
49
- self._popupOptions = None
50
- self._tooltip = None
51
- self._tooltipOptions = None
52
-
53
- def _initPopupAndTooltip(self):
54
- if self._popup is not None:
55
- self._bindPopupOrTooltip("Popup", self._popup, self._popupOptions)
56
- if self._tooltip is not None:
57
- self._bindPopupOrTooltip("Tooltip", self._tooltip, self._tooltipOptions)
58
-
59
- def _bindPopupOrTooltip(self, kind, content, options):
60
- js = f'{self._layerName}.bind{kind}("{content}"'
61
- if options is not None:
62
- js += f', {self._stringifyForJs(options)}'
63
- js += ')'
64
- self.runJavaScriptForMapIndex(js)
65
-
66
- def _getNewLayerName(self):
67
- layerName = 'l{}'.format(self.layerId)
68
- Layer.layerId += 1
69
- return layerName
70
-
71
- def addTo(self, map_):
72
- map_.addLayer(self)
73
- return self
74
-
75
- def removeFrom(self, map_):
76
- map_.removeLayer(self)
77
- return self
78
-
79
- def bindPopup(self, content, options=None):
80
- self._popup = content
81
- self._popupOptions = options
82
- self._bindPopupOrTooltip("Popup", self._popup, self._popupOptions)
83
- return self
84
-
85
- def unbindPopup(self):
86
- self._popup = None
87
- self._popupOptions = None
88
- js = '{layerName}.unbindPopup()'.format(layerName=self._layerName)
89
- self.runJavaScriptForMapIndex(js)
90
- return self
91
-
92
- def bindTooltip(self, content, options=None):
93
- self._tooltip = content
94
- self._tooltipOptions = options
95
- self._bindPopupOrTooltip("Tooltip", self._tooltip, self._tooltipOptions)
96
- return self
97
-
98
- def unbindTooltip(self):
99
- self._tooltip = None
100
- self._tooltipOptions = None
101
- js = '{layerName}.unbindTooltip()'.format(layerName=self._layerName)
102
- self.runJavaScriptForMapIndex(js)
103
- return self
104
-
105
-