libgd-gis 0.2.6 → 0.2.8
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/lib/gd/gis/color_helpers.rb +65 -0
- data/lib/gd/gis/crs_normalizer.rb +57 -0
- data/lib/gd/gis/feature.rb +3 -2
- data/lib/gd/gis/geometry.rb +211 -16
- data/lib/gd/gis/input/detector.rb +34 -0
- data/lib/gd/gis/input/geojson.rb +0 -0
- data/lib/gd/gis/input/kml.rb +0 -0
- data/lib/gd/gis/input/shapefile.rb +0 -0
- data/lib/gd/gis/layer_geojson.rb +53 -3
- data/lib/gd/gis/layer_lines.rb +27 -19
- data/lib/gd/gis/layer_points.rb +3 -6
- data/lib/gd/gis/layer_polygons.rb +22 -6
- data/lib/gd/gis/map.rb +215 -69
- data/lib/gd/gis/middleware.rb +89 -0
- data/lib/gd/gis/ontology.rb +26 -0
- data/lib/gd/gis/ontology.yml +28 -0
- data/lib/gd/gis.rb +1 -0
- metadata +19 -10
- data/lib/gd/gis/style/dark.rb +0 -49
- data/lib/gd/gis/style/light.rb +0 -49
- data/lib/gd/gis/style/solarized.rb +0 -49
data/lib/gd/gis/map.rb
CHANGED
|
@@ -8,57 +8,151 @@ require_relative "layer_polygons"
|
|
|
8
8
|
|
|
9
9
|
module GD
|
|
10
10
|
module GIS
|
|
11
|
+
attr_accessor :debug
|
|
12
|
+
|
|
11
13
|
class Map
|
|
12
14
|
TILE_SIZE = 256
|
|
13
15
|
|
|
14
16
|
attr_reader :image
|
|
17
|
+
attr_reader :layers
|
|
15
18
|
attr_accessor :style
|
|
16
19
|
|
|
17
|
-
def initialize(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def initialize(
|
|
21
|
+
bbox:,
|
|
22
|
+
zoom:,
|
|
23
|
+
basemap:,
|
|
24
|
+
width: nil,
|
|
25
|
+
height: nil,
|
|
26
|
+
crs: nil,
|
|
27
|
+
fitted_bbox: false
|
|
28
|
+
)
|
|
29
|
+
# --------------------------------------------------
|
|
30
|
+
# 1. Basic input validation
|
|
31
|
+
# --------------------------------------------------
|
|
32
|
+
raise ArgumentError, "bbox must be [min_lng, min_lat, max_lng, max_lat]" unless
|
|
33
|
+
bbox.is_a?(Array) && bbox.size == 4
|
|
34
|
+
|
|
35
|
+
raise ArgumentError, "zoom must be an Integer" unless zoom.is_a?(Integer)
|
|
36
|
+
|
|
37
|
+
if (width && !height) || (!width && height)
|
|
38
|
+
raise ArgumentError, "width and height must be provided together"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@zoom = zoom
|
|
42
|
+
@width = width
|
|
43
|
+
@height = height
|
|
44
|
+
|
|
45
|
+
# --------------------------------------------------
|
|
46
|
+
# 2. CRS normalization (input → WGS84 lon/lat)
|
|
47
|
+
# --------------------------------------------------
|
|
48
|
+
if crs
|
|
49
|
+
normalizer = GD::GIS::CRS::Normalizer.new(crs)
|
|
50
|
+
|
|
51
|
+
min_lng, min_lat = normalizer.normalize(bbox[0], bbox[1])
|
|
52
|
+
max_lng, max_lat = normalizer.normalize(bbox[2], bbox[3])
|
|
53
|
+
|
|
54
|
+
bbox = [min_lng, min_lat, max_lng, max_lat]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# --------------------------------------------------
|
|
58
|
+
# 3. Final bbox (viewport-aware if width/height)
|
|
59
|
+
# --------------------------------------------------
|
|
60
|
+
@bbox =
|
|
61
|
+
if width && height && !fitted_bbox
|
|
62
|
+
GD::GIS::Geometry.viewport_bbox(
|
|
63
|
+
bbox: bbox,
|
|
64
|
+
zoom: zoom,
|
|
65
|
+
width: width,
|
|
66
|
+
height: height
|
|
67
|
+
)
|
|
68
|
+
else
|
|
69
|
+
bbox
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# --------------------------------------------------
|
|
73
|
+
# 4. Basemap (uses FINAL bbox)
|
|
74
|
+
# --------------------------------------------------
|
|
75
|
+
@basemap = GD::GIS::Basemap.new(zoom, @bbox, basemap)
|
|
21
76
|
|
|
22
|
-
#
|
|
77
|
+
# --------------------------------------------------
|
|
78
|
+
# 5. Legacy semantic layers (REQUIRED by render)
|
|
79
|
+
# --------------------------------------------------
|
|
23
80
|
@layers = {
|
|
24
|
-
motorway:
|
|
25
|
-
primary:
|
|
81
|
+
motorway: [],
|
|
82
|
+
primary: [],
|
|
26
83
|
secondary: [],
|
|
27
|
-
street:
|
|
28
|
-
minor:
|
|
29
|
-
rail:
|
|
30
|
-
water:
|
|
31
|
-
park:
|
|
84
|
+
street: [],
|
|
85
|
+
minor: [],
|
|
86
|
+
rail: [],
|
|
87
|
+
water: [],
|
|
88
|
+
park: []
|
|
32
89
|
}
|
|
33
90
|
|
|
34
|
-
#
|
|
91
|
+
# Optional alias (semantic clarity, no behavior change)
|
|
92
|
+
@road_layers = @layers
|
|
93
|
+
|
|
94
|
+
# --------------------------------------------------
|
|
95
|
+
# 6. Overlay layers (generic)
|
|
96
|
+
# --------------------------------------------------
|
|
35
97
|
@points_layers = []
|
|
36
98
|
@lines_layers = []
|
|
37
99
|
@polygons_layers = []
|
|
38
100
|
|
|
101
|
+
# --------------------------------------------------
|
|
102
|
+
# 7. Style
|
|
103
|
+
# --------------------------------------------------
|
|
39
104
|
@style = nil
|
|
105
|
+
|
|
106
|
+
@debug = false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def features_by_layer(layer)
|
|
110
|
+
return [] unless @layers[layer]
|
|
111
|
+
|
|
112
|
+
@layers[layer].map do |item|
|
|
113
|
+
item.is_a?(Array) ? item.last : item
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def features
|
|
118
|
+
@layers.values.flatten.map do |item|
|
|
119
|
+
item.is_a?(Array) ? item.last : item
|
|
120
|
+
end
|
|
40
121
|
end
|
|
41
122
|
|
|
42
123
|
# -----------------------------------
|
|
43
|
-
# GeoJSON input (unchanged)
|
|
124
|
+
# GeoJSON input (unchanged behavior)
|
|
44
125
|
# -----------------------------------
|
|
45
|
-
|
|
46
126
|
def add_geojson(path)
|
|
47
127
|
features = LayerGeoJSON.load(path)
|
|
48
128
|
|
|
49
129
|
features.each do |feature|
|
|
50
|
-
|
|
51
|
-
|
|
130
|
+
case feature.layer
|
|
131
|
+
when :water
|
|
132
|
+
kind =
|
|
133
|
+
case (feature.properties["objeto"] || feature.properties["waterway"]).to_s.downcase
|
|
134
|
+
when /river|río/ then :river
|
|
135
|
+
when /stream|arroyo/ then :stream
|
|
136
|
+
else :minor
|
|
137
|
+
end
|
|
138
|
+
|
|
52
139
|
@layers[:water] << [kind, feature]
|
|
53
140
|
|
|
54
|
-
|
|
55
|
-
@layers[:
|
|
141
|
+
when :roads
|
|
142
|
+
@layers[:street] << feature
|
|
56
143
|
|
|
57
|
-
|
|
58
|
-
@layers[:
|
|
144
|
+
when :parks
|
|
145
|
+
@layers[:park] << feature
|
|
59
146
|
|
|
60
|
-
|
|
61
|
-
|
|
147
|
+
when :track
|
|
148
|
+
# elegí una:
|
|
149
|
+
@layers[:minor] << feature
|
|
150
|
+
# o @layers[:street] << feature
|
|
151
|
+
else
|
|
152
|
+
geom_type = feature.geometry["type"]
|
|
153
|
+
if geom_type == "LineString" || geom_type == "MultiLineString"
|
|
154
|
+
@layers[:minor] << feature
|
|
155
|
+
end
|
|
62
156
|
end
|
|
63
157
|
end
|
|
64
158
|
end
|
|
@@ -66,35 +160,12 @@ module GD
|
|
|
66
160
|
# -----------------------------------
|
|
67
161
|
# Overlay layers
|
|
68
162
|
# -----------------------------------
|
|
69
|
-
|
|
70
163
|
def add_points(data, **opts)
|
|
71
164
|
@points_layers << GD::GIS::PointsLayer.new(data, **opts)
|
|
72
165
|
end
|
|
73
166
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
"type" => "Feature",
|
|
77
|
-
"geometry" => {
|
|
78
|
-
"type" => "LineString",
|
|
79
|
-
"coordinates" => coords
|
|
80
|
-
},
|
|
81
|
-
"properties" => {}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
add_lines([feature], **opts)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def add_multiline(lines, **opts)
|
|
88
|
-
feature = {
|
|
89
|
-
"type" => "Feature",
|
|
90
|
-
"geometry" => {
|
|
91
|
-
"type" => "MultiLineString",
|
|
92
|
-
"coordinates" => lines
|
|
93
|
-
},
|
|
94
|
-
"properties" => []
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
add_lines([feature], **opts)
|
|
167
|
+
def add_lines(features, **opts)
|
|
168
|
+
@lines_layers << GD::GIS::LinesLayer.new(features, **opts)
|
|
98
169
|
end
|
|
99
170
|
|
|
100
171
|
def add_polygons(polygons, **opts)
|
|
@@ -102,12 +173,21 @@ module GD
|
|
|
102
173
|
end
|
|
103
174
|
|
|
104
175
|
# -----------------------------------
|
|
105
|
-
# Rendering
|
|
176
|
+
# Rendering (LEGACY, UNCHANGED)
|
|
106
177
|
# -----------------------------------
|
|
107
|
-
|
|
108
178
|
def render
|
|
109
179
|
raise "map.style must be set" unless @style
|
|
110
180
|
|
|
181
|
+
if @width && @height
|
|
182
|
+
render_viewport
|
|
183
|
+
else
|
|
184
|
+
render_tiles
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def render_tiles
|
|
189
|
+
raise "map.style must be set" unless @style
|
|
190
|
+
|
|
111
191
|
tiles, x_min, y_min = @basemap.fetch_tiles
|
|
112
192
|
|
|
113
193
|
xs = tiles.map { |t| t[0] }
|
|
@@ -141,7 +221,7 @@ module GD
|
|
|
141
221
|
[(x - origin_x).round, (y - origin_y).round]
|
|
142
222
|
end
|
|
143
223
|
|
|
144
|
-
# 1️⃣
|
|
224
|
+
# 1️⃣ GeoJSON semantic layers
|
|
145
225
|
@style.order.each do |kind|
|
|
146
226
|
draw_layer(kind, projection)
|
|
147
227
|
end
|
|
@@ -152,6 +232,75 @@ module GD
|
|
|
152
232
|
@points_layers.each { |l| l.render!(@image, projection) }
|
|
153
233
|
end
|
|
154
234
|
|
|
235
|
+
def render_viewport
|
|
236
|
+
raise "map.style must be set" unless @style
|
|
237
|
+
|
|
238
|
+
@image = GD::Image.new(@width, @height)
|
|
239
|
+
@image.antialias = false
|
|
240
|
+
|
|
241
|
+
# --------------------------------------------------
|
|
242
|
+
# 1. Compute global pixel bbox
|
|
243
|
+
# --------------------------------------------------
|
|
244
|
+
min_lng, min_lat, max_lng, max_lat = @bbox
|
|
245
|
+
|
|
246
|
+
x1, y1 = GD::GIS::Projection.lonlat_to_global_px(min_lng, max_lat, @zoom)
|
|
247
|
+
x2, y2 = GD::GIS::Projection.lonlat_to_global_px(max_lng, min_lat, @zoom)
|
|
248
|
+
|
|
249
|
+
# --------------------------------------------------
|
|
250
|
+
# 2. Fetch tiles
|
|
251
|
+
# --------------------------------------------------
|
|
252
|
+
tiles, = @basemap.fetch_tiles
|
|
253
|
+
|
|
254
|
+
# --------------------------------------------------
|
|
255
|
+
# 3. Draw tiles clipped to viewport
|
|
256
|
+
# --------------------------------------------------
|
|
257
|
+
tiles.each do |x, y, file|
|
|
258
|
+
tile = GD::Image.open(file)
|
|
259
|
+
|
|
260
|
+
tile_x = x * TILE_SIZE
|
|
261
|
+
tile_y = y * TILE_SIZE
|
|
262
|
+
|
|
263
|
+
dst_x = tile_x - x1
|
|
264
|
+
dst_y = tile_y - y1
|
|
265
|
+
|
|
266
|
+
src_x = [0, -dst_x].max
|
|
267
|
+
src_y = [0, -dst_y].max
|
|
268
|
+
|
|
269
|
+
draw_w = [TILE_SIZE - src_x, @width - dst_x - src_x].min
|
|
270
|
+
draw_h = [TILE_SIZE - src_y, @height - dst_y - src_y].min
|
|
271
|
+
|
|
272
|
+
next if draw_w <= 0 || draw_h <= 0
|
|
273
|
+
|
|
274
|
+
@image.copy(
|
|
275
|
+
tile,
|
|
276
|
+
dst_x + src_x,
|
|
277
|
+
dst_y + src_y,
|
|
278
|
+
src_x,
|
|
279
|
+
src_y,
|
|
280
|
+
draw_w,
|
|
281
|
+
draw_h
|
|
282
|
+
)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# --------------------------------------------------
|
|
286
|
+
# 4. Projection (viewport version)
|
|
287
|
+
# --------------------------------------------------
|
|
288
|
+
projection = lambda do |lon, lat|
|
|
289
|
+
GD::GIS::Geometry.project(lon, lat, @bbox, @zoom)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# --------------------------------------------------
|
|
293
|
+
# 5. REUSE the same render pipeline
|
|
294
|
+
# --------------------------------------------------
|
|
295
|
+
@style.order.each do |kind|
|
|
296
|
+
draw_layer(kind, projection)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
@polygons_layers.each { |l| l.render!(@image, projection) }
|
|
300
|
+
@lines_layers.each { |l| l.render!(@image, projection) }
|
|
301
|
+
@points_layers.each { |l| l.render!(@image, projection) }
|
|
302
|
+
end
|
|
303
|
+
|
|
155
304
|
def save(path)
|
|
156
305
|
@image.save(path)
|
|
157
306
|
end
|
|
@@ -164,9 +313,12 @@ module GD
|
|
|
164
313
|
case kind
|
|
165
314
|
when :street, :primary, :motorway, :secondary, :minor
|
|
166
315
|
@style.roads[kind]
|
|
167
|
-
when :rail
|
|
168
|
-
|
|
169
|
-
when :
|
|
316
|
+
when :rail
|
|
317
|
+
@style.rails
|
|
318
|
+
when :water
|
|
319
|
+
@style.water
|
|
320
|
+
when :park
|
|
321
|
+
@style.parks
|
|
170
322
|
else
|
|
171
323
|
@style.extra[kind] if @style.respond_to?(:extra)
|
|
172
324
|
end
|
|
@@ -186,20 +338,25 @@ module GD
|
|
|
186
338
|
|
|
187
339
|
if style[:stroke]
|
|
188
340
|
color = GD::Color.rgb(*style[:stroke])
|
|
341
|
+
|
|
342
|
+
color = GD::GIS::ColorHelpers.random_vivid if @debug
|
|
343
|
+
|
|
189
344
|
f.draw(@image, projection, color, width, :water)
|
|
190
345
|
end
|
|
191
|
-
|
|
192
346
|
else
|
|
193
347
|
f = item
|
|
194
348
|
geom = f.geometry["type"]
|
|
195
349
|
|
|
196
350
|
if geom == "Polygon" || geom == "MultiPolygon"
|
|
197
|
-
# THIS is the critical fix
|
|
198
351
|
f.draw(@image, projection, nil, nil, style)
|
|
199
352
|
else
|
|
200
353
|
if style[:stroke]
|
|
201
354
|
color = GD::Color.rgb(*style[:stroke])
|
|
202
|
-
|
|
355
|
+
|
|
356
|
+
color = GD::GIS::ColorHelpers.random_vivid if @debug
|
|
357
|
+
|
|
358
|
+
width = style[:stroke_width] ? style[:stroke_width].round : 1
|
|
359
|
+
width = 1 if width < 1
|
|
203
360
|
f.draw(@image, projection, color, width)
|
|
204
361
|
end
|
|
205
362
|
end
|
|
@@ -207,18 +364,7 @@ module GD
|
|
|
207
364
|
end
|
|
208
365
|
end
|
|
209
366
|
|
|
210
|
-
private
|
|
211
|
-
|
|
212
|
-
def add_lines(features, **opts)
|
|
213
|
-
stroke = opts.delete(:color) || opts.delete(:stroke)
|
|
214
|
-
width = opts.delete(:width) || opts.delete(:stroke_width)
|
|
215
|
-
|
|
216
|
-
raise ArgumentError, "missing :color or :stroke" unless stroke
|
|
217
|
-
raise ArgumentError, "missing :width" unless width
|
|
218
|
-
|
|
219
|
-
@lines_layers << GD::GIS::LinesLayer.new(features, :stroke => stroke, :width => width)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
367
|
end
|
|
223
368
|
end
|
|
224
369
|
end
|
|
370
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module GD
|
|
2
|
+
module GIS
|
|
3
|
+
module CRS
|
|
4
|
+
CRS84 = "urn:ogc:def:crs:OGC:1.3:CRS84"
|
|
5
|
+
EPSG4326 = "EPSG:4326"
|
|
6
|
+
EPSG3857 = "EPSG:3857"
|
|
7
|
+
GK_ARGENTINA = "EPSG:22195" # Gauss–Krüger Argentina (zone 5 example)
|
|
8
|
+
|
|
9
|
+
# Normalize any CRS → CRS84 (lon,lat in degrees)
|
|
10
|
+
class Normalizer
|
|
11
|
+
def initialize(crs)
|
|
12
|
+
@crs = normalize_name(crs)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def normalize(lon, lat)
|
|
16
|
+
case @crs
|
|
17
|
+
when CRS84
|
|
18
|
+
[lon, lat]
|
|
19
|
+
|
|
20
|
+
when EPSG4326
|
|
21
|
+
# EPSG:4326 uses (lat, lon)
|
|
22
|
+
[lat, lon]
|
|
23
|
+
|
|
24
|
+
when GK_ARGENTINA
|
|
25
|
+
gk_to_wgs84(lon, lat)
|
|
26
|
+
|
|
27
|
+
when EPSG3857
|
|
28
|
+
mercator_to_wgs84(lon, lat)
|
|
29
|
+
|
|
30
|
+
else
|
|
31
|
+
raise "Unsupported CRS: #{@crs}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def normalize_name(name)
|
|
38
|
+
return CRS84 if name.nil?
|
|
39
|
+
name.to_s.strip
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Web Mercator → WGS84
|
|
43
|
+
def mercator_to_wgs84(x, y)
|
|
44
|
+
r = 6378137.0
|
|
45
|
+
lon = (x / r) * 180.0 / Math::PI
|
|
46
|
+
lat = (2 * Math.atan(Math.exp(y / r)) - Math::PI / 2) * 180.0 / Math::PI
|
|
47
|
+
[lon, lat]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Gauss–Krüger Argentina (Zone 5) → WGS84
|
|
51
|
+
# This is enough precision for mapping
|
|
52
|
+
def gk_to_wgs84(easting, northing)
|
|
53
|
+
# Parameters for Argentina GK Zone 5
|
|
54
|
+
a = 6378137.0
|
|
55
|
+
f = 1 / 298.257223563
|
|
56
|
+
e2 = 2*f - f*f
|
|
57
|
+
lon0 = -60.0 * Math::PI / 180.0 # central meridian zone 5
|
|
58
|
+
|
|
59
|
+
x = easting - 500000.0
|
|
60
|
+
y = northing
|
|
61
|
+
|
|
62
|
+
m = y
|
|
63
|
+
mu = m / (a * (1 - e2/4 - 3*e2*e2/64))
|
|
64
|
+
|
|
65
|
+
e1 = (1 - Math.sqrt(1 - e2)) / (1 + Math.sqrt(1 - e2))
|
|
66
|
+
|
|
67
|
+
j1 = 3*e1/2 - 27*e1**3/32
|
|
68
|
+
j2 = 21*e1**2/16 - 55*e1**4/32
|
|
69
|
+
|
|
70
|
+
fp = mu + j1*Math.sin(2*mu) + j2*Math.sin(4*mu)
|
|
71
|
+
|
|
72
|
+
c1 = e2 * Math.cos(fp)**2
|
|
73
|
+
t1 = Math.tan(fp)**2
|
|
74
|
+
r1 = a * (1 - e2) / (1 - e2 * Math.sin(fp)**2)**1.5
|
|
75
|
+
n1 = a / Math.sqrt(1 - e2 * Math.sin(fp)**2)
|
|
76
|
+
|
|
77
|
+
d = x / n1
|
|
78
|
+
|
|
79
|
+
lat = fp - (n1*Math.tan(fp)/r1) *
|
|
80
|
+
(d**2/2 - (5 + 3*t1 + 10*c1)*d**4/24)
|
|
81
|
+
|
|
82
|
+
lon = lon0 + (d - (1 + 2*t1 + c1)*d**3/6) / Math.cos(fp)
|
|
83
|
+
|
|
84
|
+
[lon * 180.0 / Math::PI, lat * 180.0 / Math::PI]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module GD
|
|
4
|
+
module GIS
|
|
5
|
+
class Ontology
|
|
6
|
+
def initialize(path = nil)
|
|
7
|
+
path ||= File.expand_path("ontology.yml", __dir__)
|
|
8
|
+
@rules = YAML.load_file(path)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def classify(properties)
|
|
12
|
+
@rules.each do |layer, sources|
|
|
13
|
+
sources.each do |source, rules|
|
|
14
|
+
rules.each do |key, values|
|
|
15
|
+
v = (properties[key.to_s] || properties[key.to_sym]).to_s.strip.downcase
|
|
16
|
+
values = values.map { |x| x.to_s.downcase }
|
|
17
|
+
|
|
18
|
+
return layer.to_sym if values.any? { |x| v.include?(x) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
water:
|
|
2
|
+
ign:
|
|
3
|
+
objeto:
|
|
4
|
+
- canal
|
|
5
|
+
- río
|
|
6
|
+
- arroyo
|
|
7
|
+
- embalse
|
|
8
|
+
- laguna
|
|
9
|
+
- dique
|
|
10
|
+
- represa
|
|
11
|
+
gna:
|
|
12
|
+
- canal
|
|
13
|
+
- río
|
|
14
|
+
- arroyo
|
|
15
|
+
- embalse
|
|
16
|
+
- laguna
|
|
17
|
+
|
|
18
|
+
natural_earth:
|
|
19
|
+
featurecla:
|
|
20
|
+
- river
|
|
21
|
+
- lake
|
|
22
|
+
- reservoir
|
|
23
|
+
- riverbank
|
|
24
|
+
|
|
25
|
+
track:
|
|
26
|
+
gps:
|
|
27
|
+
name:
|
|
28
|
+
- track
|
data/lib/gd/gis.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: libgd-gis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Germán Alberto Giménez Silva
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-01-19 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: ruby-libgd
|
|
@@ -15,20 +16,20 @@ dependencies:
|
|
|
15
16
|
requirements:
|
|
16
17
|
- - "~>"
|
|
17
18
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.2.
|
|
19
|
+
version: 0.2.3
|
|
19
20
|
- - ">="
|
|
20
21
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.2.
|
|
22
|
+
version: 0.2.3
|
|
22
23
|
type: :runtime
|
|
23
24
|
prerelease: false
|
|
24
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
26
|
requirements:
|
|
26
27
|
- - "~>"
|
|
27
28
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: 0.2.
|
|
29
|
+
version: 0.2.3
|
|
29
30
|
- - ">="
|
|
30
31
|
- !ruby/object:Gem::Version
|
|
31
|
-
version: 0.2.
|
|
32
|
+
version: 0.2.3
|
|
32
33
|
description: A native GIS raster engine for Ruby built on libgd. Render maps, GeoJSON,
|
|
33
34
|
heatmaps and tiles.
|
|
34
35
|
email:
|
|
@@ -41,23 +42,30 @@ files:
|
|
|
41
42
|
- lib/gd/gis.rb
|
|
42
43
|
- lib/gd/gis/basemap.rb
|
|
43
44
|
- lib/gd/gis/classifier.rb
|
|
45
|
+
- lib/gd/gis/color_helpers.rb
|
|
46
|
+
- lib/gd/gis/crs_normalizer.rb
|
|
44
47
|
- lib/gd/gis/feature.rb
|
|
45
48
|
- lib/gd/gis/geometry.rb
|
|
49
|
+
- lib/gd/gis/input/detector.rb
|
|
50
|
+
- lib/gd/gis/input/geojson.rb
|
|
51
|
+
- lib/gd/gis/input/kml.rb
|
|
52
|
+
- lib/gd/gis/input/shapefile.rb
|
|
46
53
|
- lib/gd/gis/layer_geojson.rb
|
|
47
54
|
- lib/gd/gis/layer_lines.rb
|
|
48
55
|
- lib/gd/gis/layer_points.rb
|
|
49
56
|
- lib/gd/gis/layer_polygons.rb
|
|
50
57
|
- lib/gd/gis/map.rb
|
|
58
|
+
- lib/gd/gis/middleware.rb
|
|
59
|
+
- lib/gd/gis/ontology.rb
|
|
60
|
+
- lib/gd/gis/ontology.yml
|
|
51
61
|
- lib/gd/gis/projection.rb
|
|
52
62
|
- lib/gd/gis/style.rb
|
|
53
|
-
- lib/gd/gis/style/dark.rb
|
|
54
|
-
- lib/gd/gis/style/light.rb
|
|
55
|
-
- lib/gd/gis/style/solarized.rb
|
|
56
63
|
- lib/libgd_gis.rb
|
|
57
64
|
homepage: https://github.com/ggerman/libgd-gis
|
|
58
65
|
licenses:
|
|
59
66
|
- MIT
|
|
60
67
|
metadata: {}
|
|
68
|
+
post_install_message:
|
|
61
69
|
rdoc_options: []
|
|
62
70
|
require_paths:
|
|
63
71
|
- lib
|
|
@@ -72,7 +80,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
72
80
|
- !ruby/object:Gem::Version
|
|
73
81
|
version: '0'
|
|
74
82
|
requirements: []
|
|
75
|
-
rubygems_version:
|
|
83
|
+
rubygems_version: 3.5.22
|
|
84
|
+
signing_key:
|
|
76
85
|
specification_version: 4
|
|
77
86
|
summary: Geospatial raster rendering for Ruby using libgd
|
|
78
87
|
test_files: []
|
data/lib/gd/gis/style/dark.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
module GD
|
|
2
|
-
module GIS
|
|
3
|
-
class Style
|
|
4
|
-
DARK = Style.new(
|
|
5
|
-
roads: {
|
|
6
|
-
motorway: {
|
|
7
|
-
stroke: [255,255,255],
|
|
8
|
-
stroke_width: 10,
|
|
9
|
-
fill: [60,60,60],
|
|
10
|
-
fill_width: 6
|
|
11
|
-
},
|
|
12
|
-
primary: {
|
|
13
|
-
stroke: [200,200,200],
|
|
14
|
-
stroke_width: 7,
|
|
15
|
-
fill: [80,80,80],
|
|
16
|
-
fill_width: 4
|
|
17
|
-
},
|
|
18
|
-
street: {
|
|
19
|
-
stroke: [120,120,120],
|
|
20
|
-
stroke_width: 1
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
rail: {
|
|
24
|
-
stroke: [255,255,255],
|
|
25
|
-
stroke_width: 6,
|
|
26
|
-
fill: [220,50,50],
|
|
27
|
-
fill_width: 4,
|
|
28
|
-
center: [255,255,255],
|
|
29
|
-
center_width: 1
|
|
30
|
-
},
|
|
31
|
-
water: {
|
|
32
|
-
fill: [40,80,120],
|
|
33
|
-
stroke: [100,160,220]
|
|
34
|
-
},
|
|
35
|
-
park: {
|
|
36
|
-
fill: [40,80,40]
|
|
37
|
-
},
|
|
38
|
-
order: [
|
|
39
|
-
:water,
|
|
40
|
-
:park,
|
|
41
|
-
:street,
|
|
42
|
-
:primary,
|
|
43
|
-
:motorway,
|
|
44
|
-
:rail
|
|
45
|
-
]
|
|
46
|
-
)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|