Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Commit 1f7f43d

Browse files
committed
Merge branch 'develop'
Conflicts: README.md
2 parents fef1823 + 6ffadaf commit 1f7f43d

16 files changed

+346
-218
lines changed

README.md

+47-9
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,64 @@ and usage of hexagonal raster grids. These tools rely on the
2929
Future work includes the development of a Graphical User Interface (GUI) for
3030
these tools on QGIS, making the usage of hexagonal grids even simpler.
3131

32+
3233
This tool suite can be installed from the [PyPi repository](https://pypi.python.org/pypi/hex-utils).
3334

3435

3536

36-
Software dependencies
37+
38+
Installation Requirements
3739
-------------------------------------------------------------------------------
3840

39-
The `hasc2gml` script requires the GDAL library. On Debian based systems it can
40-
be installed with the following command:
41+
The `hasc2gml` script requires the Python GDAL library; the `asc2hasc` script
42+
requires the `scipy` library. At this moment there are no functional universal
43+
Python packages available for these libraries. Therefore system specific
44+
packages are required in these cases. On Debian based systems they can be
45+
installed with the following command:
46+
47+
`sudo apt install python3-gdal python3-scipy`
48+
49+
The Python package manager is required to install dependencies; on Debian based
50+
systems it can be obtained like:
51+
52+
`sudo apt install python3-pip`
53+
54+
Installing from PyPi
55+
-------------------------------------------------------------------------------
56+
57+
The easiest way to install `hex-utils` is through the universal package
58+
available from the Python Package Index (PyPi); an example again on Debian
59+
based systems:
60+
61+
`sudo pip3 install hex-utils`
62+
63+
Installing from GitHub
64+
-------------------------------------------------------------------------------
65+
66+
Start by cloning the repository to your system:
67+
68+
`git clone [email protected]:ldesousa/hex-utils.git`
69+
70+
Change to the new folder:
71+
72+
`cd hex-utils.git`
73+
74+
It is possible to install directly from the `master` branch, but it is more
75+
advisable to use of the [tagged releases](https://github.com/ldesousa/hex-utils/releases),
76+
*e.g.*:
77+
78+
`git checkout tags/v2.2`
4179

42-
`apt install python-gdal`
80+
Then install the scripts system wide:
4381

44-
It can also be installed from the PyPi repository (the best option for virtual
45-
environments):
82+
`sudo python3 setup.py install`
4683

47-
`pip instal GDAL`
84+
Finally, install the remaining dependencies:
4885

86+
`sudo pip3 install -r requirements.txt`
4987

5088
Licence
5189
-------------------------------------------------------------------------------
5290

53-
This suite of programmes is released under the EUPL 1.1 licence. For further
54-
details please consult the LICENCE file.
91+
This suite of programmes is released under the [EUPL 1.1 licence](https://joinup.ec.europa.eu/community/eupl/og_page/introduction-eupl-licence).
92+
For full details please consult the LICENCE file.

hex_utils/asc.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def _getNeighbourhoodGridCoords(self, i, j):
8888
ii.append(i-1)
8989
jj.append(j)
9090

91-
if j < self.nrows - 1:
91+
if j < self._nrows - 1:
9292
ii.append(i-1)
9393
jj.append(j+1)
9494

@@ -99,11 +99,11 @@ def _getNeighbourhoodGridCoords(self, i, j):
9999
ii.append(i)
100100
jj.append(j)
101101

102-
if j < self.nrows - 1:
102+
if j < self._nrows - 1:
103103
ii.append(i)
104104
jj.append(j+1)
105105

106-
if i < self.ncols - 1:
106+
if i < self._ncols - 1:
107107

108108
if j > 0:
109109
ii.append(i+1)
@@ -112,7 +112,7 @@ def _getNeighbourhoodGridCoords(self, i, j):
112112
ii.append(i+1)
113113
jj.append(j)
114114

115-
if j < self.nrows - 1:
115+
if j < self._nrows - 1:
116116
ii.append(i+1)
117117
jj.append(j+1)
118118

hex_utils/hasc.py

+58-23
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,21 @@ def init(self, ncols, nrows, xll, yll, side, nodata = "", angle = None):
5858
def _loadHeader(self):
5959

6060
# Mandatory header
61-
self._set_ncols(self._loadHeaderLine(self._file.readline(), self._key_ncols, type(1)))
62-
self._set_nrows(self._loadHeaderLine(self._file.readline(), self._key_nrows, type(1)))
63-
self._xll = self._loadHeaderLine(self._file.readline(), self._key_xll, type(1.0))
64-
self._yll = self._loadHeaderLine(self._file.readline(), self._key_yll, type(1.0))
65-
self._set_side( self._loadHeaderLine(self._file.readline(), self._key_side, type(1.0)))
61+
ncols = self._loadHeaderLine(self._file.readline(), self._key_ncols, type(1))
62+
nrows = self._loadHeaderLine(self._file.readline(), self._key_nrows, type(1))
63+
xll = self._loadHeaderLine(self._file.readline(), self._key_xll, type(1.0))
64+
yll = self._loadHeaderLine(self._file.readline(), self._key_yll, type(1.0))
65+
side = self._loadHeaderLine(self._file.readline(), self._key_side, type(1.0))
6666
# Optional headers
6767
self._nextLine = self._file.readline()
68-
self._nodata = self._loadHeaderLine(self._nextLine, self._key_nodata, type("a"), True)
69-
if self._nodata != "" :
68+
nodata = self._loadHeaderLine(self._nextLine, self._key_nodata, type("a"), True)
69+
if nodata != "" :
7070
self._nextLine = self._file.readline()
71-
self._angle = self._loadHeaderLine(self._nextLine, self._key_angle, type(1.0), True)
72-
if self._angle != None :
71+
angle = self._loadHeaderLine(self._nextLine, self._key_angle, type(1.0), True)
72+
if angle != None :
7373
self._nextLine = self._file.readline()
74+
75+
self.init(ncols, nrows, xll, yll, side, nodata, angle)
7476

7577

7678
def _saveHeader(self, f):
@@ -111,11 +113,8 @@ def saveAsGML(self, outputFilePath):
111113

112114
newField = ogr.FieldDefn("value", ogr.OFTReal)
113115
outLayer.GetLayerDefn().AddFieldDefn(newField)
114-
115-
# The perpendicular distance from cell center to cell edge
116-
perp = math.sqrt(3) * self._side / 2
117116

118-
# Edge coordinates of an hexagon centered in (x,y) and a side of d:
117+
# Edge coordinates of an hexagon centered in (x,y) having a side of d:
119118
#
120119
# [x-d/2, y+sqrt(3)*d/2] [x+d/2, y+sqrt(3)*d/2]
121120
#
@@ -125,23 +124,59 @@ def saveAsGML(self, outputFilePath):
125124

126125
for j in range(self._nrows):
127126
for i in range(self._ncols):
127+
128128
x = self._xll + i * 3 * self._side / 2
129-
y = self._yll + j * 2 * perp
129+
y = self._yll + j * 2 * self._hexPerp
130130
if (i % 2) != 0:
131-
y += perp
131+
y += self._hexPerp
132132

133133
polygon = ogr.CreateGeometryFromWkt("POLYGON ((" +
134-
str(x - self._side) + " " + str(y) + ", " +
135-
str(x - self._side / 2) + " " + str(y - perp) + ", " +
136-
str(x + self._side / 2) + " " + str(y - perp) + ", " +
137-
str(x + self._side) + " " + str(y) + ", " +
138-
str(x + self._side / 2) + " " + str(y + perp) + ", " +
139-
str(x - self._side / 2) + " " + str(y + perp) + ", " +
140-
str(x - self._side) + " " + str(y) + "))")
134+
str(x - self._side) + " " + str(y) + ", " +
135+
str(x - self._side / 2) + " " + str(y - self._hexPerp) + ", " +
136+
str(x + self._side / 2) + " " + str(y - self._hexPerp) + ", " +
137+
str(x + self._side) + " " + str(y) + ", " +
138+
str(x + self._side / 2) + " " + str(y + self._hexPerp) + ", " +
139+
str(x - self._side / 2) + " " + str(y + self._hexPerp) + ", " +
140+
str(x - self._side) + " " + str(y) + "))")
141141

142142
outFeature = ogr.Feature(feature_def=outLayer.GetLayerDefn())
143143
outFeature.SetGeometryDirectly(polygon)
144144
outFeature.SetField("value", self._grid[i][self._nrows - j - 1])
145145
outLayer.CreateFeature(outFeature)
146+
146147

147-
148+
def saveAsGeoJSON(self, outputFilePath):
149+
150+
try:
151+
from geojson import Feature, Polygon, FeatureCollection, dump
152+
except ImportError:
153+
raise ImportError(""" ERROR: Could not find the GeoJSON Python library.""")
154+
155+
collection = FeatureCollection([])
156+
157+
for j in range(self._nrows):
158+
for i in range(self._ncols):
159+
160+
x,y = self.getCellCentroidCoords(i, j)
161+
162+
collection.features.append(
163+
Feature(
164+
geometry = Polygon([[
165+
(x - self._side, y ),
166+
(x - self._side / 2, y - self._hexPerp ),
167+
(x + self._side / 2, y - self._hexPerp ),
168+
(x + self._side, y ),
169+
(x + self._side / 2, y + self._hexPerp ),
170+
(x - self._side / 2, y + self._hexPerp ),
171+
(x - self._side, y )
172+
]]),
173+
properties = {"value": self._grid[i][self._nrows - j - 1]}))
174+
175+
with open(outputFilePath, 'w') as fp:
176+
dump(collection, fp)
177+
178+
179+
180+
181+
182+

hex_utils/hasc2geojson.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/python3
2+
# coding=utf8
3+
#
4+
# Copyright (c) 2016 - Luís Moreira de Sousa
5+
#
6+
# Transforms ASCII encoded cartographic hexagonal grids [0] into GeoJSON.
7+
# A geometric hexagon is generated for each grid cell and encoded as a feature
8+
# in the output JSON file. The cell value is saved in the 'value' attribute of
9+
# the new feature.
10+
#
11+
# Author: Luís Moreira de Sousa (luis.de.sousa[@]protonmail.ch)
12+
# Date: 11-10-2016
13+
#
14+
# [0] https://github.com/ldesousa/HexAsciiBNF
15+
16+
import sys
17+
from hex_utils.hasc import HASC
18+
19+
def wrongUsage():
20+
21+
print("This programme requires two arguments:\n" +
22+
" - path to an input HASC file \n" +
23+
" - path to the output GeoJSON file \n" +
24+
"Usage example: \n"
25+
" hasc2gml /path/to/input.hasc /path/to/output.json")
26+
sys.exit()
27+
28+
29+
def processArguments(args):
30+
31+
global inputFile
32+
global outputFile
33+
34+
if len(args) < 3:
35+
wrongUsage()
36+
else:
37+
inputFile = str(args[1])
38+
outputFile = str(args[2])
39+
40+
41+
# ----- Main ----- #
42+
def main():
43+
44+
processArguments(sys.argv)
45+
46+
hexGrid = HASC()
47+
48+
try:
49+
hexGrid.loadFromFile(inputFile)
50+
except (ValueError, IOError) as ex:
51+
print("Error loading the grid %s: %s" % (inputFile, ex))
52+
sys.exit()
53+
print ("Loaded input HASC, converting...")
54+
55+
try:
56+
hexGrid.saveAsGeoJSON(outputFile)
57+
except (ImportError, IOError) as ex:
58+
print("Error saving the grid %s: %s" % (inputFile, ex))
59+
sys.exit()
60+
print ("Conversion successfully completed.")
61+
62+
main()
63+

hex_utils/surface2asc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# Creates a rectangular ESRI ASCII grid by sampling a a given surface.
77
# Usage example:
8-
# surface2asc -x 0 -y 0 -X 2000 -Y 2000 -s 20 -m surfaces.surfaceGaussian -f fun -o output.asc
8+
# surface2asc -x 0 -y 0 -X 2000 -Y 2000 -s 20 -m surfaces.eat2Gaussian -f fun -o output.asc
99
#
1010
# Author: Luís Moreira de Sousa (luis.de.sousa[@]protonmail.ch)
1111
# Date: 03-06-2016

hex_utils/surface2hasc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
#
66
# Creates an hexagonal ASCII grid [0] by sampling a a given surface.
77
# Usage examples:
8-
# surface2hasc -x 0 -y 0 -X 2001 -Y 2001 -s 12.4080647880 -m surfaces.surfaceGaussian -f fun -o output.hasc
9-
# surface2hasc -x 0 -y 0 -X 2001 -Y 2001 -s 13.2191028998 -m surfaces.surfaceGaussian -f fun -o output.hasc
8+
# surface2hasc -x 0 -y 0 -X 2001 -Y 2001 -s 12.4080647880 -m surfaces.eat2Gaussian -f fun -o output.hasc
9+
# surface2hasc -x 0 -y 0 -X 2001 -Y 2001 -s 13.2191028998 -m surfaces.eat2Gaussian -f fun -o output.hasc
1010
#
1111
# [0] https://github.com/ldesousa/HexAsciiBNF
1212
#

setup.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55

66
setup(
77
name = "hex-utils",
8-
version = "0.2",
8+
version = "0.2.2.3",
99
packages = find_packages(),#['utils'],
10-
install_requires=[],
10+
install_requires=[
11+
'cycler',
12+
'numpy',
13+
'pyparsing',
14+
'python-dateutil',
15+
'pytz',
16+
'six',
17+
],
1118
entry_points={
1219
'console_scripts': [
1320
'hasc2gml=hex_utils.hasc2gml:main',

surfaces/channel.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'''
2+
Created on 12 Oct 2016
3+
4+
@author: desouslu
5+
'''
6+
7+
import math
8+
import numpy as np
9+
from mpl_toolkits.mplot3d import Axes3D
10+
import matplotlib.pyplot as plt
11+
from surfaces.surface import Surface
12+
13+
class Channel(Surface):
14+
15+
angle = 30
16+
slope = 0.25
17+
centre_x = 5
18+
centre_y = 5
19+
centre_z = 5
20+
radius = 0.5
21+
depth = 1
22+
23+
24+
def __init__(self, slope = None):
25+
26+
if slope != None:
27+
self.slope = slope
28+
29+
30+
def fun(self, x, y):
31+
32+
plane = ((self.centre_x - x) * self.slope + self.centre_z) * math.cos(math.radians(self.angle)) + \
33+
((self.centre_y - y) * self.slope + self.centre_z) * math.sin(math.radians(self.angle))
34+
35+
centre = (x - self.centre_x) / math.sin(math.radians(90 - self.angle)) * \
36+
math.sin(math.radians(self.angle))
37+
38+
if (y - self.centre_y) >= (centre - self.radius) and \
39+
(y - self.centre_y) <= (centre + self.radius):
40+
return plane - self.depth
41+
else:
42+
return plane
43+
44+
45+
# Uncomment these lines to test a single pit.
46+
c = Channel()
47+
c.plotWireFrame()
48+

0 commit comments

Comments
 (0)