nswtopo 2.0.0.pre.beta1 → 3.0
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.
- checksums.yaml +4 -4
- data/COPYING +70 -83
- data/bin/nswtopo +227 -116
- data/docs/README.md +1 -12
- data/docs/add.md +1 -1
- data/docs/config.md +1 -1
- data/docs/contours.md +3 -1
- data/docs/init.md +8 -0
- data/docs/inspect.md +103 -0
- data/docs/move.md +9 -0
- data/docs/render.md +16 -7
- data/docs/scrape.md +67 -0
- data/docs/spot-heights.md +6 -2
- data/lib/nswtopo/archive.rb +50 -41
- data/lib/nswtopo/chrome.rb +227 -0
- data/lib/nswtopo/commands/add.rb +106 -0
- data/lib/nswtopo/commands/config.rb +38 -0
- data/lib/nswtopo/commands/inspect.rb +74 -0
- data/lib/nswtopo/commands/layers.rb +22 -0
- data/lib/nswtopo/commands/scrape.rb +79 -0
- data/lib/nswtopo/commands.rb +57 -0
- data/lib/nswtopo/dither.rb +5 -3
- data/lib/nswtopo/font.rb +46 -21
- data/lib/nswtopo/formats/gemf.rb +42 -0
- data/lib/nswtopo/formats/kmz.rb +26 -24
- data/lib/nswtopo/formats/mbtiles.rb +5 -41
- data/lib/nswtopo/formats/pdf.rb +82 -17
- data/lib/nswtopo/formats/svg.rb +114 -45
- data/lib/nswtopo/formats/svgz.rb +2 -2
- data/lib/nswtopo/formats/zip.rb +33 -23
- data/lib/nswtopo/formats.rb +77 -32
- data/lib/nswtopo/geometry/overlap.rb +1 -32
- data/lib/nswtopo/geometry/r_tree.rb +16 -10
- data/lib/nswtopo/geometry/segment.rb +3 -3
- data/lib/nswtopo/geometry/straight_skeleton/nodes.rb +5 -6
- data/lib/nswtopo/geometry/vector_sequence.rb +7 -6
- data/lib/nswtopo/gis/arcgis/connection.rb +56 -0
- data/lib/nswtopo/gis/arcgis/layer/map.rb +163 -0
- data/lib/nswtopo/gis/arcgis/layer/query.rb +87 -0
- data/lib/nswtopo/gis/arcgis/layer/renderer.rb +66 -0
- data/lib/nswtopo/gis/arcgis/layer/statistics.rb +15 -0
- data/lib/nswtopo/gis/arcgis/layer.rb +201 -0
- data/lib/nswtopo/gis/arcgis/service.rb +57 -0
- data/lib/nswtopo/gis/arcgis.rb +3 -0
- data/lib/nswtopo/gis/dem.rb +13 -12
- data/lib/nswtopo/gis/esri_hdr.rb +8 -2
- data/lib/nswtopo/gis/geojson/collection.rb +45 -21
- data/lib/nswtopo/gis/geojson/multi_line_string.rb +2 -24
- data/lib/nswtopo/gis/geojson/multi_polygon.rb +2 -53
- data/lib/nswtopo/gis/geojson/polygon.rb +15 -0
- data/lib/nswtopo/gis/geojson.rb +12 -3
- data/lib/nswtopo/gis/gps/kml.rb +25 -19
- data/lib/nswtopo/gis/gps.rb +2 -0
- data/lib/nswtopo/gis/projection.rb +35 -24
- data/lib/nswtopo/gis/shapefile.rb +89 -16
- data/lib/nswtopo/gis.rb +1 -2
- data/lib/nswtopo/helpers/array.rb +0 -11
- data/lib/nswtopo/helpers/colour.rb +34 -14
- data/lib/nswtopo/layer/arcgis_raster.rb +44 -48
- data/lib/nswtopo/layer/colour_mask.rb +5 -0
- data/lib/nswtopo/layer/contour.rb +35 -28
- data/lib/nswtopo/layer/control.rb +2 -7
- data/lib/nswtopo/layer/declination.rb +9 -9
- data/lib/nswtopo/layer/feature.rb +36 -22
- data/lib/nswtopo/layer/grid.rb +30 -27
- data/lib/nswtopo/layer/import.rb +1 -21
- data/lib/nswtopo/layer/labels/barrier.rb +39 -0
- data/lib/nswtopo/layer/labels.rb +551 -383
- data/lib/nswtopo/layer/mask_render.rb +37 -0
- data/lib/nswtopo/layer/overlay.rb +2 -2
- data/lib/nswtopo/layer/raster.rb +31 -41
- data/lib/nswtopo/layer/raster_import.rb +17 -0
- data/lib/nswtopo/layer/raster_render.rb +15 -0
- data/lib/nswtopo/layer/relief.rb +27 -95
- data/lib/nswtopo/layer/spot.rb +63 -62
- data/lib/nswtopo/layer/vector/cutout.rb +15 -0
- data/lib/nswtopo/layer/vector/knockout.rb +16 -0
- data/lib/nswtopo/layer/vector.rb +121 -89
- data/lib/nswtopo/layer/vegetation.rb +39 -34
- data/lib/nswtopo/layer.rb +30 -16
- data/lib/nswtopo/map.rb +202 -109
- data/lib/nswtopo/os.rb +5 -27
- data/lib/nswtopo/tiled_web_map.rb +54 -0
- data/lib/nswtopo/tree_indenter.rb +27 -0
- data/lib/nswtopo/version.rb +27 -2
- data/lib/nswtopo.rb +6 -199
- metadata +41 -22
- data/lib/nswtopo/font/chrome.rb +0 -59
- data/lib/nswtopo/font/generic.rb +0 -25
- data/lib/nswtopo/gis/arcgis_server/connection.rb +0 -52
- data/lib/nswtopo/gis/arcgis_server.rb +0 -155
- data/lib/nswtopo/gis/geojson/multi_point.rb +0 -12
- data/lib/nswtopo/gis/world_file.rb +0 -19
- data/lib/nswtopo/layer/labels/fence.rb +0 -20
data/bin/nswtopo
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
# Copyright 2011-
|
|
3
|
+
# Copyright 2011-2022 Matthew Hollingworth
|
|
4
4
|
#
|
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
|
6
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
7
|
# the Free Software Foundation, either version 3 of the License, or
|
|
8
8
|
# (at your option) any later version.
|
|
9
9
|
#
|
|
10
10
|
# This program is distributed in the hope that it will be useful,
|
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
-
# GNU General Public License for more details.
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
14
|
#
|
|
15
|
-
# You should have received a copy of the GNU General Public License
|
|
16
|
-
# along with this program. If not, see <
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
begin
|
|
19
19
|
require 'open3'
|
|
@@ -30,75 +30,80 @@ begin
|
|
|
30
30
|
|
|
31
31
|
GDAL_VERSION = begin
|
|
32
32
|
stdout, * = Open3.capture3 "gdalinfo", "--version"
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/^GDAL (?<version>\d+(?:\.\d+){1,2})/ =~ stdout
|
|
34
|
+
version || raise
|
|
35
|
+
rescue Errno::ENOENT, RuntimeError
|
|
35
36
|
log_abort "GDAL not installed"
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
case
|
|
39
|
-
when (RUBY_VERSION.split(/\D+/).take(3).map(&:to_i) <=> [
|
|
40
|
-
log_abort "ruby
|
|
40
|
+
when (RUBY_VERSION.split(/\D+/).take(3).map(&:to_i) <=> [3,0,4]) < 0
|
|
41
|
+
log_abort "ruby 3.0.4 or greater required"
|
|
41
42
|
when !Zlib.const_defined?(:GzipFile)
|
|
42
43
|
log_abort "ruby with GZIP_SUPPORT required"
|
|
43
|
-
when (GDAL_VERSION.split(/\D+/).take(3).map(&:to_i) <=> [
|
|
44
|
-
log_abort "GDAL
|
|
44
|
+
when (GDAL_VERSION.split(/\D+/).take(3).map(&:to_i) <=> [3,4]) < 0
|
|
45
|
+
log_abort "GDAL 3.4 or greater required"
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
digits = '\d+(?:_\d+)*'
|
|
48
49
|
float = "[-+]?(?:#{digits}(?=(.)?)(?:\\.(?:#{digits})?)?|\\.#{digits})(?:[eE][-+]?#{digits})?"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
pair = "#{float},#{float}"
|
|
51
|
+
quad = "#{float},#{float},#{float},#{float}"
|
|
52
|
+
field = '[^\s",]+'
|
|
53
|
+
|
|
54
|
+
PositiveInt = Class.new
|
|
55
|
+
PositiveFloat = Class.new
|
|
56
|
+
NonNegFloat = Class.new
|
|
57
|
+
Dimensions = Class.new
|
|
58
|
+
Inset = Class.new
|
|
59
|
+
Margins = Class.new
|
|
60
|
+
CoordList = Class.new
|
|
61
|
+
Rotation = Class.new
|
|
62
|
+
Opacity = Class.new
|
|
63
|
+
DashArray = Class.new
|
|
64
|
+
Zoom = Class.new
|
|
65
|
+
ZlibLevel = Class.new
|
|
66
|
+
FieldList = Class.new
|
|
67
|
+
|
|
68
|
+
OptionParser.accept PositiveInt, /\A#{digits}\z/ do |string|
|
|
63
69
|
raise OptionParser::InvalidArgument, string unless string.to_i.positive?
|
|
64
70
|
string.to_i
|
|
65
71
|
end
|
|
66
72
|
|
|
67
|
-
OptionParser.accept PositiveFloat,
|
|
73
|
+
OptionParser.accept PositiveFloat, /\A#{float}\z/ do |string|
|
|
68
74
|
raise OptionParser::InvalidArgument, string unless string.to_f.positive?
|
|
69
75
|
string.to_f
|
|
70
76
|
end
|
|
71
77
|
|
|
72
|
-
OptionParser.accept NonNegFloat,
|
|
78
|
+
OptionParser.accept NonNegFloat, /\A#{float}\z/ do |string|
|
|
73
79
|
raise OptionParser::InvalidArgument, string if string.to_f.negative?
|
|
74
80
|
string.to_f
|
|
75
81
|
end
|
|
76
82
|
|
|
77
|
-
OptionParser.accept Dimensions,
|
|
83
|
+
OptionParser.accept Dimensions, /\A#{pair}\z/ do |string|
|
|
78
84
|
dimensions = string.split(?,).map(&:to_f)
|
|
79
85
|
raise OptionParser::InvalidArgument, string unless dimensions.all?(&:positive?)
|
|
80
86
|
dimensions
|
|
81
87
|
end
|
|
82
88
|
|
|
83
|
-
OptionParser.accept
|
|
89
|
+
OptionParser.accept Inset, /\A#{quad}(?:,#{quad})*\z/ do |string|
|
|
90
|
+
string.split(?,).map(&:to_f).each_slice(4).entries
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
OptionParser.accept Margins, /\A#{float}(?:,#{float})?\z/ do |string|
|
|
84
94
|
margins = string.split(?,).map(&:to_f)
|
|
85
95
|
raise OptionParser::InvalidArgument, string if margins.any?(&:negative?)
|
|
86
96
|
margins.one? ? margins * 2 : margins
|
|
87
97
|
end
|
|
88
98
|
|
|
89
|
-
OptionParser.accept CoordList,
|
|
99
|
+
OptionParser.accept CoordList, /\A#{pair}(?:,#{pair})*\z/ do |string|
|
|
90
100
|
string.split(?,).map(&:to_f).each_slice(2).to_a
|
|
91
101
|
end
|
|
92
102
|
|
|
93
|
-
OptionParser.accept Rotation,
|
|
103
|
+
OptionParser.accept Rotation, /\A(?:#{float}|magnetic|auto)\z/ do |string|
|
|
94
104
|
"magnetic" == string ? string : "auto" == string ? string : string.to_f
|
|
95
105
|
end
|
|
96
106
|
|
|
97
|
-
OptionParser.accept AltitudeAngle, PositiveFloat do |string|
|
|
98
|
-
raise OptionParser::InvalidArgument, string unless AltitudeAngle === string.to_f
|
|
99
|
-
string.to_f
|
|
100
|
-
end
|
|
101
|
-
|
|
102
107
|
OptionParser.accept Pathname do |string|
|
|
103
108
|
path = Pathname(string).expand_path
|
|
104
109
|
raise OptionParser::InvalidArgument, string unless path.exist?
|
|
@@ -106,23 +111,37 @@ begin
|
|
|
106
111
|
end
|
|
107
112
|
|
|
108
113
|
OptionParser.accept Colour do |string|
|
|
109
|
-
string == "none" ? string : Colour.new(string.downcase)
|
|
114
|
+
string == "none" ? string : Colour.new(string.downcase)
|
|
110
115
|
rescue Colour::Error
|
|
111
116
|
raise OptionParser::InvalidArgument, string
|
|
112
117
|
end
|
|
113
118
|
|
|
114
|
-
OptionParser.accept Opacity,
|
|
119
|
+
OptionParser.accept Opacity, /\A#{float}%?\z/ do |string|
|
|
115
120
|
opacity = string.end_with?(?%) ? Float(string.chomp ?%) * 0.01 : Float(string)
|
|
116
121
|
raise OptionParser::InvalidArgument, string unless (0..1) === opacity
|
|
117
122
|
opacity
|
|
118
123
|
end
|
|
119
124
|
|
|
120
|
-
OptionParser.accept DashArray,
|
|
125
|
+
OptionParser.accept DashArray, /\A#{float}(?:(?:,#{float})*|(?: #{float})*)\z/ do |string|
|
|
121
126
|
values = string.split(/[, ]/).map(&:to_f)
|
|
122
127
|
raise OptionParser::InvalidArgument, string if values.any?(&:negative?)
|
|
123
128
|
values.join ?\s
|
|
124
129
|
end
|
|
125
130
|
|
|
131
|
+
OptionParser.accept Zoom, /\A(?:#{digits},)?#{digits}\z/ do |string|
|
|
132
|
+
values = string.split(?,).map(&:to_i)
|
|
133
|
+
raise OptionParser::InvalidArgument, string unless values.all?(10..20)
|
|
134
|
+
values
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
OptionParser.accept ZlibLevel, /\A\d\z/ do |string|
|
|
138
|
+
Integer(string)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
OptionParser.accept FieldList, /\A#{field}(?:,#{field})*\z/ do |string|
|
|
142
|
+
string.split ?,
|
|
143
|
+
end
|
|
144
|
+
|
|
126
145
|
ansi = lambda do |string|
|
|
127
146
|
string.to_s.gsub(/\*([-a-zA-Z0-9]+)\*/) do
|
|
128
147
|
"\e[1m%s\e[0m" % $1
|
|
@@ -130,7 +149,7 @@ begin
|
|
|
130
149
|
"\e[4m%s\e[0m" % $1
|
|
131
150
|
end.gsub(/~([-a-zA-Z0-9]+)~/) do
|
|
132
151
|
"\e[3m%s\e[0m" % $1
|
|
133
|
-
end
|
|
152
|
+
end.prepend("\r\e[K")
|
|
134
153
|
end
|
|
135
154
|
|
|
136
155
|
plain = lambda do |string|
|
|
@@ -154,6 +173,7 @@ begin
|
|
|
154
173
|
controls add rogaine control markers
|
|
155
174
|
overlay add KML or GPX overlay
|
|
156
175
|
delete delete map layer
|
|
176
|
+
move move map layer
|
|
157
177
|
render render map in various formats
|
|
158
178
|
layers list available map layers
|
|
159
179
|
config configure nswtopo
|
|
@@ -188,15 +208,16 @@ begin
|
|
|
188
208
|
*nswtopo* *init* - initialise map bounds and scale
|
|
189
209
|
usage: _nswtopo_ _init_ [~options~] <map.tgz>
|
|
190
210
|
EOF
|
|
191
|
-
parser.on "-s", "--scale <scale>", PositiveInt,
|
|
192
|
-
parser.on "-b", "--bounds <bounds.kml>", Pathname,
|
|
193
|
-
parser.on "-c", "--coords <x1,y1,...>", CoordList,
|
|
194
|
-
|
|
195
|
-
parser.on "-d", "--dimensions <width,height>", Dimensions,
|
|
196
|
-
parser.on "-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
parser.on "-
|
|
211
|
+
parser.on "-s", "--scale <scale>", PositiveInt, "scale of map (default 25000)"
|
|
212
|
+
parser.on "-b", "--bounds <bounds.kml>", Pathname, "bounds for map as KML or GPX file"
|
|
213
|
+
parser.on "-c", "--coords <x1,y1,...>", CoordList, "bounds for map as one or more WGS84",
|
|
214
|
+
"longitude/latitude pairs"
|
|
215
|
+
parser.on "-d", "--dimensions <width,height>", Dimensions, "map dimensions in mm"
|
|
216
|
+
parser.on "-r", "--rotation <rotation>", Rotation, "map rotation angle in clockwise",
|
|
217
|
+
"degrees, 'auto' or 'magnetic'"
|
|
218
|
+
parser.on "-m", "--margins <x[,y]>", Margins, "map margins in mm"
|
|
219
|
+
parser.on "-i", "--inset <x1,y1,x2,y2>", Inset, "map inset coordinates in mm"
|
|
220
|
+
parser.on "-o", "--overwrite", "overwrite existing map file"
|
|
200
221
|
|
|
201
222
|
when "info"
|
|
202
223
|
parser.banner = <<~EOF
|
|
@@ -204,72 +225,84 @@ begin
|
|
|
204
225
|
usage: _nswtopo_ _info_ [~options~] <map.tgz>
|
|
205
226
|
EOF
|
|
206
227
|
parser.on "-e", "--empty", "show empty layers"
|
|
228
|
+
parser.on "-j", "--json", "show map bounds as GeoJSON string"
|
|
229
|
+
parser.on "-p", "--proj", "show map projection as a proj string"
|
|
230
|
+
parser.on "-w", "--wkt", "show map projection as a WKT2 string"
|
|
207
231
|
|
|
208
232
|
when "add"
|
|
209
233
|
parser.banner = <<~EOF
|
|
210
234
|
*nswtopo* *add* - add named map layer
|
|
211
235
|
usage: _nswtopo_ _add_ [~options~] <map.tgz> <layer> [<layer> ...]
|
|
212
236
|
EOF
|
|
213
|
-
parser.on "-r", "--resolution <resolution>", PositiveFloat, "raster
|
|
237
|
+
parser.on "-r", "--resolution <resolution>", PositiveFloat, "raster resolution in metres per pixel"
|
|
238
|
+
parser.on "--ppi <ppi>", PositiveFloat, "raster resolution in pixels per inch"
|
|
239
|
+
parser.on "-o", "--opacity <opacity>", Opacity, "layer opacity (between 0 and 1)"
|
|
214
240
|
parser.on "-p", "--path <path>", Pathname, "source data path for layer"
|
|
215
241
|
parser.on "-a", "--after <layer>", "insert after specified layer"
|
|
216
242
|
parser.on "-b", "--before <layer>", "insert before specified layer"
|
|
217
243
|
parser.on "-c", "--replace <layer>", "replace specified layer"
|
|
218
244
|
parser.on "-o", "--overwrite", "overwrite layer if it already exists"
|
|
245
|
+
parser.on "-s", "--strict", "don't continue if a layer fails"
|
|
219
246
|
|
|
220
247
|
when "contours"
|
|
221
248
|
parser.banner = <<~EOF
|
|
222
249
|
*nswtopo* *contours* - add contours from elevation data
|
|
223
250
|
usage: _nswtopo_ _contours_ [~options~] <map.tgz> <dem.zip>
|
|
224
251
|
EOF
|
|
225
|
-
parser.on "-i", "--interval
|
|
226
|
-
parser.on "-x", "--index
|
|
227
|
-
parser.on "-
|
|
228
|
-
parser.on "-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
parser.on
|
|
232
|
-
parser.on
|
|
233
|
-
parser.on "-
|
|
234
|
-
parser.on "-
|
|
235
|
-
parser.on "-
|
|
236
|
-
parser.on
|
|
237
|
-
parser.on "--stroke
|
|
238
|
-
parser.on "--
|
|
252
|
+
parser.on "-i", "--interval <interval>", PositiveInt, "contour interval in metres (default %s)" % NSWTopo::Contour::DEFAULTS["interval"]
|
|
253
|
+
parser.on "-x", "--index <index>", PositiveInt, "index interval in metres"
|
|
254
|
+
parser.on "-a", "--auxiliary", "show auxiliary contours"
|
|
255
|
+
parser.on "-s", "--smooth <radius>", NonNegFloat, "DEM smoothing radius in mm (default %s)" % NSWTopo::Contour::DEFAULTS["smooth"]
|
|
256
|
+
parser.on "-t", "--thin", "thin intermediate contours in steep areas"
|
|
257
|
+
parser.on "-d", "--density <density>", PositiveFloat, "thinning threshold (default %s lines/mm)" % NSWTopo::Contour::DEFAULTS["density"]
|
|
258
|
+
# parser.on "-m", "--min-length <length>", PositiveFloat, "minimum length before contour thinning in mm"
|
|
259
|
+
parser.on "--no-depression", "don't show or clean depression contours"
|
|
260
|
+
parser.on "-k", "--knolls <size>", NonNegFloat, "minimum knoll size in mm (default %s)" % NSWTopo::Contour::DEFAULTS["knolls"]
|
|
261
|
+
parser.on "-a", "--after <layer>", "insert after specified layer"
|
|
262
|
+
parser.on "-b", "--before <layer>", "insert before specified layer"
|
|
263
|
+
parser.on "-c", "--replace <layer>", "replace specified layer"
|
|
264
|
+
parser.on "--stroke <colour>", Colour, "stroke colour (name or RGB triplet)"
|
|
265
|
+
parser.on "--stroke-width <width>", PositiveFloat, "stroke width in mm (default %s)" % NSWTopo::Contour::DEFAULTS["stroke-width"]
|
|
266
|
+
parser.on "--fill <colour>", Colour, "label colour (defaults to stroke colour)"
|
|
267
|
+
parser.on "-r", "--resolution <resolution>", PositiveFloat, "DEM processing resolution in metres"
|
|
239
268
|
|
|
240
269
|
when "spot-heights"
|
|
241
270
|
parser.banner = <<~EOF
|
|
242
271
|
*nswtopo* *spot-heights* - add spot heights from elevation data
|
|
243
272
|
usage: _nswtopo_ _spot-heights_ [~options~] <map.tgz> <dem.zip>
|
|
244
273
|
EOF
|
|
245
|
-
parser.on "-s", "--smooth
|
|
246
|
-
parser.on "--spacing
|
|
247
|
-
parser.on "-p", "--prefer
|
|
248
|
-
parser.on "-
|
|
249
|
-
parser.on "-
|
|
250
|
-
parser.on "-
|
|
274
|
+
parser.on "-s", "--smooth <radius>", NonNegFloat, "DEM smoothing radius in mm (default %s)" % NSWTopo::Spot::DEFAULTS["smooth"]
|
|
275
|
+
parser.on "--spacing <spacing>", PositiveFloat, "minimum spot spacing in mm (default %i)" % NSWTopo::Spot::DEFAULTS["spacing"]
|
|
276
|
+
parser.on "-p", "--prefer <knolls|saddles>", %w[knolls saddles], "preferred spot locations"
|
|
277
|
+
parser.on "-e", "--extent <extent>", PositiveFloat, "minimum feature extent in mm (default %i)" % NSWTopo::Spot::DEFAULTS["extent"]
|
|
278
|
+
parser.on "-a", "--after <layer>", "insert after specified layer"
|
|
279
|
+
parser.on "-b", "--before <layer>", "insert before specified layer"
|
|
280
|
+
parser.on "-c", "--replace <layer>", "replace specified layer"
|
|
281
|
+
parser.on "-r", "--resolution <resolution>", PositiveFloat, "DEM processing resolution in metres"
|
|
251
282
|
|
|
252
283
|
when "relief"
|
|
253
284
|
parser.banner = <<~EOF
|
|
254
285
|
*nswtopo* *relief* - add shaded relief
|
|
255
286
|
usage: _nswtopo_ _relief_ [~options~] <map.tgz> <dem.zip>
|
|
256
287
|
EOF
|
|
257
|
-
parser.on "-r", "--resolution
|
|
258
|
-
parser.on "-
|
|
259
|
-
parser.on "-
|
|
260
|
-
parser.on
|
|
261
|
-
parser.on "-
|
|
262
|
-
parser.on "-
|
|
263
|
-
|
|
264
|
-
parser.on "-f", "--factor <factor>", PositiveFloat, "exaggeration factor (default %s)" % NSWTopo::Relief::DEFAULTS["factor"]
|
|
288
|
+
parser.on "-r", "--resolution <resolution>", PositiveFloat, "resolution in metres per pixel"
|
|
289
|
+
parser.on "-p", "--ppi <ppi>", PositiveFloat, "resolution in pixels per inch"
|
|
290
|
+
parser.on "-o", "--opacity <opacity>", Opacity, "opacity (default %s)" % NSWTopo::Relief::DEFAULTS["opacity"]
|
|
291
|
+
parser.on "--shade <colour>", Colour, "shade colour (default %s)" % NSWTopo::Relief::DEFAULTS["shade"]
|
|
292
|
+
parser.on "-m", "--method <igor|combined>", %w[igor combined], "relief shading method (default %s)" % NSWTopo::Relief::DEFAULTS["method"]
|
|
293
|
+
parser.on "-z", "--azimuth <azimuth>", Float, "azimuth in degrees (default %i)" % NSWTopo::Relief::DEFAULTS["azimuth"]
|
|
294
|
+
parser.on "-f", "--factor <factor>", PositiveFloat, "exaggeration factor (default %s)" % NSWTopo::Relief::DEFAULTS["factor"]
|
|
265
295
|
|
|
266
296
|
when "grid"
|
|
267
297
|
parser.banner = <<~EOF
|
|
268
298
|
*nswtopo* *grid* - add UTM grid
|
|
269
299
|
usage: _nswtopo_ _grid_ [~options~] <map.tgz>
|
|
270
300
|
EOF
|
|
271
|
-
parser.on "-i", "--interval
|
|
272
|
-
|
|
301
|
+
parser.on "-i", "--interval <interval>", PositiveFloat, "interval between grid lines in",
|
|
302
|
+
"metres (default %i)" % NSWTopo::Grid::DEFAULTS["interval"]
|
|
303
|
+
parser.on "-u", "--unlabeled", "don't add grid labels"
|
|
304
|
+
parser.on "-b", "--border", "add map border"
|
|
305
|
+
parser.on "--stroke-width <width>", PositiveFloat, "stroke width in mm (default %s)" % NSWTopo::Grid::DEFAULTS["stroke-width"]
|
|
273
306
|
|
|
274
307
|
when "declination"
|
|
275
308
|
parser.banner = <<~EOF
|
|
@@ -292,6 +325,7 @@ begin
|
|
|
292
325
|
parser.on "-s", "--spot", "add spots at centres"
|
|
293
326
|
parser.on "-c", "--colour <colour>", Colour, "colour of markers and labels",
|
|
294
327
|
"(name or RGB triplet)"
|
|
328
|
+
parser.on "-k", "--knockout <width>", NonNegFloat, "symbol knockout width in mm (default %s)" % NSWTopo::Control::DEFAULTS["knockout"]
|
|
295
329
|
parser.on "-f", "--font-size <font-size>", PositiveFloat, "font size for labels in mm"
|
|
296
330
|
|
|
297
331
|
when "overlay"
|
|
@@ -321,22 +355,30 @@ begin
|
|
|
321
355
|
usage: _nswtopo_ _delete_ [~options~] <map.tgz> <layer> [<layer> ...]
|
|
322
356
|
EOF
|
|
323
357
|
|
|
358
|
+
when "move"
|
|
359
|
+
parser.banner = <<~EOF
|
|
360
|
+
*nswtopo* *move* - move map layer
|
|
361
|
+
usage: _nswtopo_ _move_ [~options~] <map.tgz> <layer>
|
|
362
|
+
EOF
|
|
363
|
+
parser.on "-a", "--after <layer>", "insert after specified layer"
|
|
364
|
+
parser.on "-b", "--before <layer>", "insert before specified layer"
|
|
365
|
+
|
|
324
366
|
when "render"
|
|
325
367
|
parser.banner = <<~EOF
|
|
326
368
|
*nswtopo* *render* - render map in various formats
|
|
327
|
-
usage: _nswtopo_ _render_ [~options~] <map.tgz> [<format-or-path> ...]
|
|
369
|
+
usage: _nswtopo_ _render_ [~options~] <map.tgz|map.svg> [<format-or-path> ...]
|
|
328
370
|
formats: #{NSWTopo::Formats.extensions.sort.join ?\s}
|
|
329
371
|
default: svg
|
|
330
372
|
EOF
|
|
331
|
-
parser.on "-p", "--ppi
|
|
332
|
-
|
|
333
|
-
parser.on "-z", "--zoom
|
|
334
|
-
parser.on "-
|
|
335
|
-
parser.on "-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
parser.on "-
|
|
339
|
-
parser.on "-f", "--force",
|
|
373
|
+
parser.on "-p", "--ppi <ppi>", PositiveInt, "resolution for raster formats in pixels",
|
|
374
|
+
"per inch (default %i)" % NSWTopo::Formats::PPI
|
|
375
|
+
parser.on "-z", "--zoom <zoom>", Zoom, "maximum tile zoom (10-20, default %i)" % NSWTopo::TiledWebMap::DEFAULT_ZOOM
|
|
376
|
+
parser.on "-b", "--background <colour>", Colour, "background colour (name or RGB triplet)"
|
|
377
|
+
parser.on "-d", "--dither", "use indexed colour for raster formats"
|
|
378
|
+
parser.on "-w", "--worldfile", "save additional projection (.prj) and",
|
|
379
|
+
"world file (.wld) for raster formats"
|
|
380
|
+
parser.on "-o", "--overwrite", "overwrite existing output files"
|
|
381
|
+
parser.on "-f", "--force", "force regeneration of cached SVG"
|
|
340
382
|
|
|
341
383
|
when "layers"
|
|
342
384
|
parser.banner = <<~EOF
|
|
@@ -351,11 +393,46 @@ begin
|
|
|
351
393
|
EOF
|
|
352
394
|
parser.on "-d", "--delete <name>", "delete configuration setting"
|
|
353
395
|
parser.on "-c", "--chrome <path>", Pathname, "set path for Google Chrome"
|
|
354
|
-
parser.on "-f", "--firefox <path>", Pathname, "set path for Firefox"
|
|
355
396
|
parser.on "-p", "--path <path>", Pathname, "set path for given layer"
|
|
356
397
|
parser.on "-r", "--resolution <resolution>", PositiveFloat, "set resolution for given layer"
|
|
357
398
|
parser.on "--layer-dir <path>", Pathname, "set an extra layer directory"
|
|
358
399
|
parser.on "--[no-]labelling", "enable or disable map labelling"
|
|
400
|
+
parser.on "--[no-]debug", "enable or disable label debuging"
|
|
401
|
+
parser.on "--[no-]gpu", "enable or disable Chrome GPU usage"
|
|
402
|
+
parser.on "--[no-]versioning", "enable or disable map version checking"
|
|
403
|
+
parser.on "-z", "--zlib-level <0-9>", ZlibLevel, "set zlib compression level"
|
|
404
|
+
parser.on "-k", "--knockout <width>", NonNegFloat, "set label knockout width in mm"
|
|
405
|
+
|
|
406
|
+
when "scrape"
|
|
407
|
+
parser.banner = <<~EOF
|
|
408
|
+
*nswtopo* *scrape* - scrape data from an ArcGIS REST endpoint
|
|
409
|
+
usage: _nswtopo_ _scrape_ [~options~] <url> <path>
|
|
410
|
+
EOF
|
|
411
|
+
parser.on "-l", "--layer <layer>", String, "name of ArcGIS service layer"
|
|
412
|
+
parser.on "-i", "--id <id>", Integer, "id number of layer"
|
|
413
|
+
parser.on "-w", "--where <where>", String, "filtering clause"
|
|
414
|
+
parser.on "-c", "--coords <x0,y0,x1,y1>", CoordList, "WGS84 coordinates of bounding box corners"
|
|
415
|
+
parser.on "-n", "--name <name>", /^\w+$/, "name of saved layer"
|
|
416
|
+
parser.on "-f", "--fields <field,...>", FieldList, "comma-separated list of fields"
|
|
417
|
+
parser.on "-d", "--decode", "convert coded values where possible"
|
|
418
|
+
parser.on "-e", "--epsg <number>", PositiveInt, "EPSG number for reprojection"
|
|
419
|
+
parser.on "-p", "--paginate <number>", PositiveInt, "number of records per request"
|
|
420
|
+
parser.on "--concat", "collect all features before saving"
|
|
421
|
+
parser.on "-u", "--unique <field>", String, "field for counting map-only features"
|
|
422
|
+
|
|
423
|
+
when "inspect"
|
|
424
|
+
parser.banner = <<~EOF
|
|
425
|
+
*nswtopo* *inspect* - inspect data from an ArcGIS REST endpoint or local data source
|
|
426
|
+
usage: _nswtopo_ inspect [~options~] <url-or-path>
|
|
427
|
+
EOF
|
|
428
|
+
parser.on "-l", "--layer <layer>", String, "name of layer"
|
|
429
|
+
parser.on "-i", "--id <id>", Integer, "id number of layer"
|
|
430
|
+
parser.on "-w", "--where <where>", String, "filtering clause"
|
|
431
|
+
parser.on "-c", "--coords <x0,y0,x1,y1>", CoordList, "WGS84 coordinates of bounding box corners"
|
|
432
|
+
parser.on "-f", "--fields <field,...>", FieldList, "comma-separated list of fields"
|
|
433
|
+
parser.on "-d", "--decode", "convert coded values where possible"
|
|
434
|
+
parser.on "--codes", "show coded values for an ArcGIS Layer"
|
|
435
|
+
parser.on "--countwise", "sort fields by count instead of value"
|
|
359
436
|
|
|
360
437
|
when nil
|
|
361
438
|
raise OptionParser::MissingArgument, "no command specified"
|
|
@@ -381,50 +458,84 @@ begin
|
|
|
381
458
|
case command
|
|
382
459
|
when "layers"
|
|
383
460
|
raise OptionParser::NeedlessArgument, ARGV if ARGV.any?
|
|
384
|
-
NSWTopo.layers options
|
|
461
|
+
NSWTopo.layers **options
|
|
385
462
|
exit
|
|
386
463
|
when "config"
|
|
387
464
|
layer = ARGV.shift
|
|
388
465
|
raise OptionParser::NeedlessArgument, ARGV if ARGV.any?
|
|
389
466
|
NSWTopo.config *layer, **options
|
|
390
467
|
exit
|
|
468
|
+
when "scrape"
|
|
469
|
+
url, path = ARGV.shift, ARGV.shift
|
|
470
|
+
raise OptionParser::MissingArgument, "no URL specified" unless url
|
|
471
|
+
raise OptionParser::MissingArgument, "no path specified" unless path
|
|
472
|
+
raise OptionParser::NeedlessArgument, ARGV if ARGV.any?
|
|
473
|
+
path = Pathname(path).expand_path
|
|
474
|
+
raise OptionParser::InvalidArgument, "invalid path: #{path}" unless path.parent.directory?
|
|
475
|
+
raise OptionParser::InvalidOption, "can't specify both --id and --layer" if options[:id] && options[:layer]
|
|
476
|
+
NSWTopo.scrape url, path, **options
|
|
477
|
+
exit
|
|
478
|
+
when "inspect"
|
|
479
|
+
url_or_path = ARGV.shift
|
|
480
|
+
raise OptionParser::MissingArgument, "no URL or path specified" unless url_or_path
|
|
481
|
+
raise OptionParser::NeedlessArgument, ARGV if ARGV.any?
|
|
482
|
+
[%i[where codes], %i[fields codes], %i[decode codes], %i[id layer]].each do |flags|
|
|
483
|
+
raise OptionParser::InvalidOption, "can't have --%s with --%s" % flags if options.values_at(*flags).all?
|
|
484
|
+
end
|
|
485
|
+
raise OptionParser::InvalidOption, "--countwise requires --fields" if options[:countwise] && !options[:fields]
|
|
486
|
+
raise OptionParser::InvalidOption, "--decode requires --fields" if options[:decode] && !options[:fields]
|
|
487
|
+
NSWTopo.inspect url_or_path, **options
|
|
488
|
+
exit
|
|
489
|
+
when "add", "relief"
|
|
490
|
+
raise OptionParser::InvalidOption, "can't specify both --resolution and --ppi" if options[:resolution] && options[:ppi]
|
|
391
491
|
end
|
|
392
492
|
|
|
393
493
|
raise OptionParser::MissingArgument, "no map path specified" if ARGV.empty?
|
|
394
494
|
tgz_path = Pathname(ARGV.shift)
|
|
395
495
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
command = command.tr ?-, ?_
|
|
407
|
-
arity, error = NSWTopo.method(command).arity, nil
|
|
496
|
+
in_path = case command
|
|
497
|
+
when "init"
|
|
498
|
+
raise "already a directory: #{tgz_path}" if tgz_path.directory?
|
|
499
|
+
raise "file already exists: #{tgz_path}" if !options.delete(:overwrite) && tgz_path.exist?
|
|
500
|
+
raise "no such directory: #{tgz_path.parent}" unless tgz_path.parent.directory?
|
|
501
|
+
else
|
|
502
|
+
raise "no such file: #{tgz_path}" unless tgz_path.exist?
|
|
503
|
+
raise "not a file: #{tgz_path}" unless tgz_path.file?
|
|
504
|
+
tgz_path
|
|
505
|
+
end
|
|
408
506
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
507
|
+
command = command.tr ?-, ?_
|
|
508
|
+
ARGV.prepend in_path.basename(".tgz").basename(".tar.gz").basename(".svg") if "render" == command
|
|
509
|
+
|
|
510
|
+
nil.tap do |partial_failure|
|
|
511
|
+
NSWTopo::Archive.open(in_path: in_path, out_path: tgz_path) do |archive|
|
|
512
|
+
NSWTopo.method(command).parameters.group_by(&:first).inject [archive] do |args, (type, params)|
|
|
513
|
+
case type
|
|
514
|
+
when :req
|
|
515
|
+
raise OptionParser::MissingArgument if ARGV.length < params.length - args.length
|
|
516
|
+
args.concat ARGV.shift(params.length - args.length)
|
|
517
|
+
when :rest
|
|
518
|
+
args.concat ARGV.shift(ARGV.length)
|
|
519
|
+
else args
|
|
520
|
+
end
|
|
521
|
+
end.tap do |args|
|
|
522
|
+
raise OptionParser::NeedlessArgument, ARGV.join(?\s) if ARGV.any?
|
|
523
|
+
NSWTopo.send command, *args, **options
|
|
524
|
+
rescue NSWTopo::PartialFailureError => partial_failure
|
|
416
525
|
end
|
|
417
|
-
|
|
418
|
-
NSWTopo.send command, *args
|
|
419
|
-
rescue NSWTopo::PartialFailureError => error
|
|
420
526
|
end
|
|
421
|
-
raise
|
|
527
|
+
raise partial_failure if partial_failure
|
|
528
|
+
rescue NSWTopo::Archive::Invalid
|
|
529
|
+
raise "unrecognised map file: #{in_path}" unless "render" == command
|
|
530
|
+
raise OptionParser::InvalidOption, "can't specify --force without a map file" if options[:force]
|
|
531
|
+
in_path, tgz_path, options = nil, nil, options.merge(svg_path: in_path)
|
|
532
|
+
retry
|
|
422
533
|
end
|
|
423
534
|
rescue OptionParser::ParseError => error
|
|
424
535
|
warn ansi[command_parser] if $stderr.tty?
|
|
425
536
|
log_abort error.message
|
|
426
537
|
rescue Interrupt
|
|
427
|
-
|
|
538
|
+
log_abort "interrupted"
|
|
428
539
|
rescue RuntimeError => error
|
|
429
540
|
log_abort error.message
|
|
430
541
|
end
|
data/docs/README.md
CHANGED
|
@@ -10,20 +10,9 @@ Help screens are available describing usage for each commands. Use the `--help`
|
|
|
10
10
|
$ nswtopo init --help
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
# Configuration
|
|
14
|
-
|
|
15
|
-
An important initial step is to configure the location of *Google Chrome* on your PC. Chrome is required for rendering the map in most formats. Use the *configure* command to set the path:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
$ nswtopo config --chrome "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
19
|
-
nswtopo: configuration updated
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Use forward slashes for paths, even on Windows.
|
|
23
|
-
|
|
24
13
|
# Map Files
|
|
25
14
|
|
|
26
|
-
Most commands need a map file to work on. Name this file anything you want. A `.tgz` extension is suggested, as the file is in *gzipped tar* archive format. All map contents are contained within the file
|
|
15
|
+
Most commands need a map file to work on. Name this file anything you want. A `.tgz` extension is suggested, as the file is in *gzipped tar* archive format. All map contents are contained within the file.
|
|
27
16
|
|
|
28
17
|
# Example
|
|
29
18
|
|
data/docs/add.md
CHANGED
|
@@ -10,7 +10,7 @@ The forward-slash character is used indicate the nested folder structure of thes
|
|
|
10
10
|
|
|
11
11
|
Some layers, such as vegetation layers, require a dataset to be present on your computer. Specify the location of the dataset with the `--path` option. The path can be absolute, or relative to the working directory.
|
|
12
12
|
|
|
13
|
-
Raster layers (vegetation, shaded relief) typically
|
|
13
|
+
Raster layers (vegetation, shaded relief) are typically imported at the data's native resolution. If desired, you can choose a different value using the `--resolution` option, for a data resolution in metres per pixel, or the `--ppi` option for output resolution in pixels per inch.
|
|
14
14
|
|
|
15
15
|
For repeated use, it's easier to set the path or resolution for a layer in a permanent configuration file. Use the *config* command for this task.
|
|
16
16
|
|
data/docs/config.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Description
|
|
2
2
|
|
|
3
|
-
Configure and view permanent *nswtopo* settings using the *config* command. For example, to set the *Google Chrome* path
|
|
3
|
+
Configure and view permanent *nswtopo* settings using the *config* command. For example, to manually set the *Google Chrome* path:
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
$ nswtopo config --chrome "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
data/docs/contours.md
CHANGED
|
@@ -12,6 +12,8 @@ Choose a contour interval in metres using the `--interval` option. A five metre
|
|
|
12
12
|
|
|
13
13
|
Noise in raw elevation data usually produces unsuitably rough contour lines. Some smoothing of the DEM removes most such artefacts. A default smoothing radius of 0.2mm is applied, configurable with the `--smooth` option. Increase the radius to produce smoother contours at the expense of detail.
|
|
14
14
|
|
|
15
|
+
DEM tiles are normally processed at their maximumum native resolution. Change this using the `--resolution` option. A reduced resolution (say 5 metres) can markedly improve processing speed for 1- and 2-metre tiles.
|
|
16
|
+
|
|
15
17
|
# Layer Position
|
|
16
18
|
|
|
17
19
|
Use an `--after`, `--before` or `--replace` option to insert the contours in an appropriate layer position. You will most likely want to replace an existing contour layer:
|
|
@@ -21,7 +23,7 @@ $ nswtopo contours --replace nsw.topographic.contours map.tgz DATA_25994.zip
|
|
|
21
23
|
```
|
|
22
24
|
# Style
|
|
23
25
|
|
|
24
|
-
Contours are rendered in brown at a thickness of 0.08mm. Change line colour with `--stroke`, thickness with `--stroke-width` and label colour with `--fill`. Colour can be an *RGB triplet* (e.g.
|
|
26
|
+
Contours are rendered in brown at a thickness of 0.08mm. Change line colour with `--stroke`, thickness with `--stroke-width` and label colour with `--fill`. Colour can be an *RGB triplet* (e.g. *#800080*) or *web colour* name (e.g. *purple*).
|
|
25
27
|
|
|
26
28
|
# Contour Thinning
|
|
27
29
|
A small contour interval can produce very dense contours in steep terrain. An advanced `--thin` option is available to selectively remove contours in steep areas such as cliffsides. It emulates a manual contour thinning technique. An index multiple of eight (e.g. 5m contours with 40m index contours) produces the most aesthetic results.
|
data/docs/init.md
CHANGED
|
@@ -36,3 +36,11 @@ $ nswtopo init --dimensions 210,297 --coords 148.387,-36.148 map.tgz
|
|
|
36
36
|
# Map Scale
|
|
37
37
|
|
|
38
38
|
A 1:25000 scale is conventional and should work well for most purposes. Change to a smaller or larger scale using the `--scale` option.
|
|
39
|
+
|
|
40
|
+
# Map Inset
|
|
41
|
+
|
|
42
|
+
Use the `--inset` option to remove a rectangular inset from the map. Specify the inset location as two opposing corner coordinates in millimetres. For example, to remove a 50mm × 100mm inset from the map's top-left corner:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
$ nswtopo init --bounds bounds.kml --inset 0,0,50,100 map.tgz
|
|
46
|
+
```
|