libgd-gis 0.2.6 → 0.2.7.pre.alpha.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c36a99210906574c046daffe2120213b027d92fdd22dec0b27861df22f88029
4
- data.tar.gz: bd991fd3290c3bfb82f5640dad84c8e6486368285539774eed1b942acd7848b6
3
+ metadata.gz: 6559ec92e07ae18e0a783d5d822c676437c68896928d7e2a59143ffd0ef9bb7e
4
+ data.tar.gz: d1d343b32dbef5a5093746577db4b61d678a27d42949737079f3ba8e4c840a9a
5
5
  SHA512:
6
- metadata.gz: 6bed27a3930a9512b0f5fff46fdfe2f76fe76932ddf263cc2d219cdaafd754d5161ede878f1b0d929e5a7b00b9c4b546c6905d9ee27d9bc478d5e7914ebc1784
7
- data.tar.gz: ee203f7b9dc6f0a2669bbbedcde1e6fe31678c3a847c79a14d975c75cee1cc0a7f2784398acbef9b821943cce9124bdb5b41f0194070ff020fa39824f699a56a
6
+ metadata.gz: 40cdba7a5707db6afde50b1358e6ae65eb936e34880d4ba2d593acfa72945cb09dc25661bab3dfdf7eefc6ea7f260171f9c38bc396dbeb2c42c83fc573964bd7
7
+ data.tar.gz: ac76fd31a7b28acae6067ed56ed4783d2dabb97992d19c841af25459204caf9e3180cd5bea9e74b9de8c583741ab187044ccbdcabd45ce1b2523438faf5c1b5b
@@ -0,0 +1,57 @@
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
+
8
+ class Normalizer
9
+ def initialize(crs)
10
+ @crs = normalize_name(crs)
11
+ end
12
+
13
+ # Accepts:
14
+ # normalize(lon,lat)
15
+ # normalize(lon,lat,z)
16
+ # normalize([lon,lat])
17
+ # normalize([lon,lat,z])
18
+ def normalize(*args)
19
+ lon, lat = args.flatten
20
+ return nil if lon.nil? || lat.nil?
21
+
22
+ lon = lon.to_f
23
+ lat = lat.to_f
24
+
25
+ case @crs
26
+ when CRS84, nil
27
+ [lon, lat]
28
+
29
+ when EPSG4326
30
+ # axis order lat,lon → lon,lat
31
+ [lat, lon]
32
+
33
+ when EPSG3857
34
+ mercator_to_wgs84(lon, lat)
35
+
36
+ else
37
+ [lon, lat]
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def normalize_name(name)
44
+ return nil if name.nil?
45
+ name.to_s.strip
46
+ end
47
+
48
+ def mercator_to_wgs84(x, y)
49
+ r = 6378137.0
50
+ lon = (x / r) * 180.0 / Math::PI
51
+ lat = (2 * Math.atan(Math.exp(y / r)) - Math::PI / 2) * 180.0 / Math::PI
52
+ [lon, lat]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,11 +1,12 @@
1
1
  module GD
2
2
  module GIS
3
3
  class Feature
4
- attr_reader :geometry, :properties
4
+ attr_reader :geometry, :properties, :layer
5
5
 
6
- def initialize(geometry, properties)
6
+ def initialize(geometry, properties, layer = nil)
7
7
  @geometry = geometry
8
8
  @properties = properties || {}
9
+ @layer = layer
9
10
  end
10
11
 
11
12
  # -------------------------------------------------
@@ -0,0 +1,34 @@
1
+ module GD
2
+ module GIS
3
+ module Input
4
+ module Detector
5
+ def self.detect(path)
6
+ return :geojson if geojson?(path)
7
+ return :kml if kml?(path)
8
+ return :shapefile if shapefile?(path)
9
+ return :osm_pbf if pbf?(path)
10
+ :unknown
11
+ end
12
+
13
+ def self.geojson?(path)
14
+ File.open(path) do |f|
15
+ head = f.read(2048)
16
+ head.include?('"FeatureCollection"') || head.include?('"GeometryCollection"')
17
+ end
18
+ end
19
+
20
+ def self.kml?(path)
21
+ File.open(path) { |f| f.read(512).include?("<kml") }
22
+ end
23
+
24
+ def self.shapefile?(path)
25
+ File.open(path, "rb") { |f| f.read(4) == "\x00\x00\x27\x0A" }
26
+ end
27
+
28
+ def self.pbf?(path)
29
+ File.open(path, "rb") { |f| f.read(2) == "\x1f\x8b" }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
File without changes
File without changes
File without changes
File without changes
@@ -1,16 +1,66 @@
1
1
  require "json"
2
2
  require_relative "feature"
3
+ require_relative "crs_normalizer"
4
+ require_relative "ontology"
3
5
 
4
6
  module GD
5
7
  module GIS
6
8
  class LayerGeoJSON
9
+
7
10
  def self.load(path)
8
11
  data = JSON.parse(File.read(path))
9
- features = data["features"]
10
- features.map do |f|
11
- Feature.new(f["geometry"], f["properties"])
12
+
13
+ # 1) Detect CRS
14
+ crs_name = data["crs"]&.dig("properties", "name")
15
+ normalizer = CRS::Normalizer.new(crs_name)
16
+
17
+ # 2) Load ontology
18
+ ontology = Ontology.new
19
+
20
+ # 3) Normalize geometries + classify
21
+ data["features"].map do |f|
22
+ normalize_geometry!(f["geometry"], normalizer)
23
+ layer = ontology.classify(f["properties"] || {})
24
+ Feature.new(f["geometry"], f["properties"], layer)
12
25
  end
13
26
  end
27
+
28
+ # --------------------------------------------
29
+ # CRS normalization (2D + 3D safe)
30
+ # --------------------------------------------
31
+ def self.normalize_geometry!(geometry, normalizer)
32
+ case geometry["type"]
33
+
34
+ when "Point"
35
+ geometry["coordinates"] =
36
+ normalizer.normalize(geometry["coordinates"])
37
+
38
+ when "LineString"
39
+ geometry["coordinates"] =
40
+ geometry["coordinates"].map { |c| normalizer.normalize(c) }
41
+
42
+ when "MultiLineString"
43
+ geometry["coordinates"] =
44
+ geometry["coordinates"].map do |line|
45
+ line.map { |c| normalizer.normalize(c) }
46
+ end
47
+
48
+ when "Polygon"
49
+ geometry["coordinates"] =
50
+ geometry["coordinates"].map do |ring|
51
+ ring.map { |c| normalizer.normalize(c) }
52
+ end
53
+
54
+ when "MultiPolygon"
55
+ geometry["coordinates"] =
56
+ geometry["coordinates"].map do |poly|
57
+ poly.map do |ring|
58
+ ring.map { |c| normalizer.normalize(c) }
59
+ end
60
+ end
61
+ end
62
+ end
63
+
14
64
  end
15
65
  end
16
66
  end
@@ -1,6 +1,8 @@
1
1
  module GD
2
2
  module GIS
3
3
  class PointsLayer
4
+ attr_accessor :data, :size
5
+
4
6
  def initialize(data, lon:, lat:, icon:, label: nil, font: nil, size: 12, color: [0,0,0])
5
7
  @data = data
6
8
  @lon = lon
@@ -15,6 +17,7 @@ module GD
15
17
  @label = label
16
18
  @font = font
17
19
  @size = size
20
+ @data = data
18
21
  @color = color
19
22
 
20
23
  @icon.alpha_blending = true
data/lib/gd/gis/map.rb CHANGED
@@ -36,6 +36,10 @@ module GD
36
36
  @lines_layers = []
37
37
  @polygons_layers = []
38
38
 
39
+ @dynamic_points = []
40
+ @dynamic_lines = []
41
+ @dynamic_polys = []
42
+
39
43
  @style = nil
40
44
  end
41
45
 
@@ -47,18 +51,27 @@ module GD
47
51
  features = LayerGeoJSON.load(path)
48
52
 
49
53
  features.each do |feature|
50
- if Classifier.water?(feature)
51
- kind = Classifier.water_kind(feature)
54
+ case feature.layer
55
+ when :water
56
+ # optional: detect river vs canal from properties
57
+ kind =
58
+ case (feature.properties["objeto"] || feature.properties["waterway"]).to_s.downcase
59
+ when /river|río/ then :river
60
+ when /stream|arroyo/ then :stream
61
+ else :minor
62
+ end
63
+
52
64
  @layers[:water] << [kind, feature]
53
65
 
54
- elsif Classifier.park?(feature)
55
- @layers[:park] << feature
66
+ when :roads
67
+ # map to style categories if you want later
68
+ @layers[:street] << feature
56
69
 
57
- elsif Classifier.rail?(feature)
58
- @layers[:rail] << feature
70
+ when :parks
71
+ @layers[:park] << feature
59
72
 
60
- elsif type = Classifier.road(feature)
61
- @layers[type] << feature
73
+ else
74
+ # ignore unclassified for now
62
75
  end
63
76
  end
64
77
  end
@@ -68,7 +81,9 @@ module GD
68
81
  # -----------------------------------
69
82
 
70
83
  def add_points(data, **opts)
71
- @points_layers << GD::GIS::PointsLayer.new(data, **opts)
84
+ layer = GD::GIS::PointsLayer.new(data, **opts)
85
+ @points_layers << layer
86
+ layer
72
87
  end
73
88
 
74
89
  def add_line(coords, **opts)
@@ -136,20 +151,26 @@ module GD
136
151
  )
137
152
  end
138
153
 
139
- projection = lambda do |lon, lat|
154
+ @projection = lambda do |lon, lat|
140
155
  x, y = GD::GIS::Projection.lonlat_to_global_px(lon, lat, @zoom)
141
156
  [(x - origin_x).round, (y - origin_y).round]
142
157
  end
143
158
 
144
159
  # 1️⃣ Semantic GeoJSON layers (this is what was working)
145
160
  @style.order.each do |kind|
146
- draw_layer(kind, projection)
161
+ draw_layer(kind, @projection)
147
162
  end
148
163
 
149
164
  # 2️⃣ Generic overlays
150
- @polygons_layers.each { |l| l.render!(@image, projection) }
151
- @lines_layers.each { |l| l.render!(@image, projection) }
152
- @points_layers.each { |l| l.render!(@image, projection) }
165
+ @polygons_layers.each { |l| l.render!(@image, @projection) }
166
+ @lines_layers.each { |l| l.render!(@image, @projection) }
167
+ @points_layers.each { |l| l.render!(@image, @projection) }
168
+
169
+ @dynamic_polys.each { |l| l.render!(@image, @projection) }
170
+ @dynamic_lines.each { |l| l.render!(@image, @projection) }
171
+ @dynamic_points.each { |l| l.render!(@image, @projection) }
172
+
173
+ @image
153
174
  end
154
175
 
155
176
  def save(path)
@@ -186,7 +207,7 @@ module GD
186
207
 
187
208
  if style[:stroke]
188
209
  color = GD::Color.rgb(*style[:stroke])
189
- f.draw(@image, projection, color, width, :water)
210
+ f.draw(@image, @projection, color, width, :water)
190
211
  end
191
212
 
192
213
  else
@@ -195,18 +216,56 @@ module GD
195
216
 
196
217
  if geom == "Polygon" || geom == "MultiPolygon"
197
218
  # THIS is the critical fix
198
- f.draw(@image, projection, nil, nil, style)
219
+ f.draw(@image, @projection, nil, nil, style)
199
220
  else
200
221
  if style[:stroke]
201
222
  color = GD::Color.rgb(*style[:stroke])
202
223
  width = style[:stroke_width] || 1
203
- f.draw(@image, projection, color, width)
224
+ f.draw(@image, @projection, color, width)
204
225
  end
205
226
  end
206
227
  end
207
228
  end
208
229
  end
209
230
 
231
+ def clear_dynamic_layers
232
+ @dynamic_points.clear
233
+ @dynamic_lines.clear
234
+ @dynamic_polys.clear
235
+ end
236
+
237
+ def add_dynamic_point(data, **opts)
238
+ @dynamic_points << GD::GIS::PointsLayer.new(data, **opts)
239
+ end
240
+
241
+ def add_dynamic_line(coords, **opts)
242
+ feature = {
243
+ "type" => "Feature",
244
+ "geometry" => {
245
+ "type" => "LineString",
246
+ "coordinates" => coords
247
+ },
248
+ "properties" => {}
249
+ }
250
+ @dynamic_lines << GD::GIS::LinesLayer.new([feature], **opts)
251
+ end
252
+
253
+ def render_base
254
+ render
255
+ @base_image = @image
256
+ end
257
+
258
+ def render_with_base
259
+ img = GD::Image.new(@base_image.width, @base_image.height)
260
+ img.copy(@base_image, 0,0, 0,0, @base_image.width, @base_image.height)
261
+
262
+ @points_layers.each { |l| l.render!(img, @projection) }
263
+ @lines_layers.each { |l| l.render!(img, @projection) }
264
+ @polygons_layers.each{ |l| l.render!(img, @projection) }
265
+
266
+ img
267
+ end
268
+
210
269
  private
211
270
 
212
271
  def add_lines(features, **opts)
@@ -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,267 @@
1
+ # ============================================================
2
+ # WATER
3
+ # ============================================================
4
+
5
+ water:
6
+ ign:
7
+ objeto:
8
+ - canal
9
+ - río
10
+ - arroyo
11
+ - embalse
12
+ - laguna
13
+ - dique
14
+ - represa
15
+ gna:
16
+ - canal
17
+ - río
18
+ - arroyo
19
+ - embalse
20
+ - laguna
21
+
22
+ natural_earth:
23
+ featurecla:
24
+ - river
25
+ - lake
26
+ - reservoir
27
+ - riverbank
28
+
29
+ osm:
30
+ waterway:
31
+ - river
32
+ - stream
33
+ - canal
34
+ - drain
35
+ - ditch
36
+ natural:
37
+ - water
38
+ - lake
39
+ - reservoir
40
+ - wetland
41
+ - bay
42
+ - strait
43
+
44
+ # ============================================================
45
+ # ROADS
46
+ # ============================================================
47
+
48
+ roads:
49
+ ign:
50
+ objeto:
51
+ - autopista
52
+ - ruta
53
+ - camino
54
+ - calle
55
+ - avenida
56
+
57
+ natural_earth:
58
+ featurecla:
59
+ - road
60
+ - highway
61
+
62
+ osm:
63
+ highway:
64
+ - motorway
65
+ - motorway_link
66
+ - trunk
67
+ - trunk_link
68
+ - primary
69
+ - primary_link
70
+ - secondary
71
+ - secondary_link
72
+ - tertiary
73
+ - tertiary_link
74
+ - residential
75
+ - unclassified
76
+ - service
77
+ - living_street
78
+ - pedestrian
79
+ - road
80
+ - busway
81
+ - track
82
+
83
+ # ============================================================
84
+ # RAIL
85
+ # ============================================================
86
+
87
+ rail:
88
+ osm:
89
+ railway:
90
+ - rail
91
+ - subway
92
+ - light_rail
93
+ - tram
94
+ - monorail
95
+ - funicular
96
+
97
+ # ============================================================
98
+ # PARKS & GREEN
99
+ # ============================================================
100
+
101
+ park:
102
+ ign:
103
+ objeto:
104
+ - parque
105
+ - plaza
106
+ - reserva
107
+
108
+ natural_earth:
109
+ featurecla:
110
+ - park
111
+ - protected_area
112
+
113
+ osm:
114
+ leisure:
115
+ - park
116
+ - garden
117
+ - pitch
118
+ - playground
119
+ - recreation_ground
120
+ - golf_course
121
+ landuse:
122
+ - grass
123
+ - meadow
124
+ - forest
125
+ natural:
126
+ - wood
127
+ - scrub
128
+ - heath
129
+ - grassland
130
+
131
+ # ============================================================
132
+ # BUILDINGS
133
+ # ============================================================
134
+
135
+ buildings:
136
+ ign:
137
+ objeto:
138
+ - edificio
139
+ - hospital
140
+ - escuela
141
+
142
+ osm:
143
+ building:
144
+ - yes
145
+ - residential
146
+ - commercial
147
+ - industrial
148
+ - retail
149
+ - hospital
150
+ - school
151
+ - church
152
+ - cathedral
153
+ - university
154
+ - public
155
+ - civic
156
+ - apartments
157
+
158
+ # ============================================================
159
+ # POI (Points of Interest)
160
+ # ============================================================
161
+
162
+ poi:
163
+ osm:
164
+ amenity:
165
+ - hospital
166
+ - school
167
+ - university
168
+ - cafe
169
+ - restaurant
170
+ - bar
171
+ - pharmacy
172
+ - bank
173
+ - atm
174
+ - police
175
+ - fire_station
176
+ - library
177
+ - cinema
178
+ - theatre
179
+ - post_office
180
+ - fuel
181
+ shop:
182
+ - supermarket
183
+ - bakery
184
+ - convenience
185
+ - clothes
186
+ - mall
187
+ - department_store
188
+ - butcher
189
+ - greengrocer
190
+ - fast_food
191
+
192
+ # ============================================================
193
+ # TRANSPORT
194
+ # ============================================================
195
+
196
+ transport:
197
+ osm:
198
+ aeroway:
199
+ - aerodrome
200
+ - runway
201
+ - taxiway
202
+ - apron
203
+ - terminal
204
+ public_transport:
205
+ - station
206
+ - stop_position
207
+ - platform
208
+
209
+ # ============================================================
210
+ # NATURAL FEATURES
211
+ # ============================================================
212
+
213
+ natural:
214
+ natural_earth:
215
+ featurecla:
216
+ - mountain
217
+ - peak
218
+ - hill
219
+ - volcano
220
+
221
+ osm:
222
+ natural:
223
+ - peak
224
+ - hill
225
+ - volcano
226
+ - ridge
227
+ - cliff
228
+ - dune
229
+
230
+ # ============================================================
231
+ # LANDUSE
232
+ # ============================================================
233
+
234
+ landuse:
235
+ osm:
236
+ landuse:
237
+ - residential
238
+ - commercial
239
+ - industrial
240
+ - retail
241
+ - farmland
242
+ - forest
243
+ - grass
244
+ - meadow
245
+ - quarry
246
+ - cemetery
247
+ - landfill
248
+ - recreation_ground
249
+ roads:
250
+ osm_geofabrik:
251
+ fclass:
252
+ - motorway
253
+ - motorway_link
254
+ - trunk
255
+ - trunk_link
256
+ - primary
257
+ - primary_link
258
+ - secondary
259
+ - secondary_link
260
+ - tertiary
261
+ - tertiary_link
262
+ - residential
263
+ - unclassified
264
+ - service
265
+ - living_street
266
+ - pedestrian
267
+ - road
@@ -0,0 +1,68 @@
1
+ require "json"
2
+
3
+ module GD
4
+ module GIS
5
+ class PathSampler
6
+ def initialize(coords)
7
+ @coords = coords
8
+ @segments = []
9
+ @total = 0.0
10
+
11
+ coords.each_cons(2) do |a,b|
12
+ d = haversine(a[0],a[1], b[0],b[1])
13
+ @segments << [a,b,d]
14
+ @total += d
15
+ end
16
+ end
17
+
18
+ def point_at(t)
19
+ target = t * @total
20
+ acc = 0.0
21
+
22
+ @segments.each do |a,b,d|
23
+ return interpolate(a,b,(target-acc)/d) if acc + d >= target
24
+ acc += d
25
+ end
26
+
27
+ @coords.last
28
+ end
29
+
30
+ def interpolate(a,b,t)
31
+ [
32
+ a[0] + (b[0]-a[0])*t,
33
+ a[1] + (b[1]-a[1])*t
34
+ ]
35
+ end
36
+
37
+ def haversine(lon1,lat1,lon2,lat2)
38
+ r = 6371000
39
+ dlat = (lat2-lat1) * Math::PI/180
40
+ dlon = (lon2-lon1) * Math::PI/180
41
+ a = Math.sin(dlat/2)**2 +
42
+ Math.cos(lat1*Math::PI/180)*Math.cos(lat2*Math::PI/180)*
43
+ Math.sin(dlon/2)**2
44
+ 2 * r * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
45
+ end
46
+
47
+ def self.from_geojson(path)
48
+ data = JSON.parse(File.read(path))
49
+
50
+ coords =
51
+ if data["features"]
52
+ data["features"][0]["geometry"]["coordinates"]
53
+
54
+ elsif data["paths"]
55
+ data["paths"][0]["points"]["coordinates"]
56
+
57
+ elsif data["routes"]
58
+ data["routes"][0]["geometry"]["coordinates"]
59
+
60
+ else
61
+ raise "Formato de ruta desconocido en #{path}"
62
+ end
63
+
64
+ new(coords)
65
+ end
66
+ end
67
+ end
68
+ end
data/lib/gd/gis.rb CHANGED
@@ -12,3 +12,4 @@ require_relative "gis/layer_points"
12
12
  require_relative "gis/layer_lines"
13
13
  require_relative "gis/layer_polygons"
14
14
  require_relative "gis/layer_geojson"
15
+ require_relative "gis/path_sampler"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libgd-gis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.7.pre.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Germán Alberto Giménez Silva
@@ -15,20 +15,20 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.1
18
+ version: 0.2.3
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.2.1
21
+ version: 0.2.3
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: 0.2.1
28
+ version: 0.2.3
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.2.1
31
+ version: 0.2.3
32
32
  description: A native GIS raster engine for Ruby built on libgd. Render maps, GeoJSON,
33
33
  heatmaps and tiles.
34
34
  email:
@@ -41,13 +41,22 @@ files:
41
41
  - lib/gd/gis.rb
42
42
  - lib/gd/gis/basemap.rb
43
43
  - lib/gd/gis/classifier.rb
44
+ - lib/gd/gis/crs_normalizer.rb
44
45
  - lib/gd/gis/feature.rb
45
46
  - lib/gd/gis/geometry.rb
47
+ - lib/gd/gis/input.rb
48
+ - lib/gd/gis/input/detector.rb
49
+ - lib/gd/gis/input/geojson.rb
50
+ - lib/gd/gis/input/kml.rb
51
+ - lib/gd/gis/input/shapefile.rb
46
52
  - lib/gd/gis/layer_geojson.rb
47
53
  - lib/gd/gis/layer_lines.rb
48
54
  - lib/gd/gis/layer_points.rb
49
55
  - lib/gd/gis/layer_polygons.rb
50
56
  - lib/gd/gis/map.rb
57
+ - lib/gd/gis/ontology.rb
58
+ - lib/gd/gis/ontology.yml
59
+ - lib/gd/gis/path_sampler.rb
51
60
  - lib/gd/gis/projection.rb
52
61
  - lib/gd/gis/style.rb
53
62
  - lib/gd/gis/style/dark.rb
@@ -72,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
81
  - !ruby/object:Gem::Version
73
82
  version: '0'
74
83
  requirements: []
75
- rubygems_version: 4.0.3
84
+ rubygems_version: 4.0.4
76
85
  specification_version: 4
77
86
  summary: Geospatial raster rendering for Ruby using libgd
78
87
  test_files: []