libgd-gis 0.3.0 → 0.3.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: 72c8b1d43f60ad8615302e22054c3d5e00be6bd746c757f00d980e781f760b0c
4
- data.tar.gz: 74d09fb46fe02d7d53c75f4c2a9acb6bbab24383b51ef9bd9ec3ad8c89e0253f
3
+ metadata.gz: adcbc0b0d92182bc12b431152cb1f79b202786ef999e3571f42c9ec27e999561
4
+ data.tar.gz: 50cb494d8e9b2fdf94f9ac126c22f14cb39335c4f1d0289df554f88159b5d389
5
5
  SHA512:
6
- metadata.gz: e09c62bf8ee7218019a2e69676cc9b7461982568842bb8afac861f38f290d7fec658ee15269915ec5a3ad925de4d5ef4e6dcdce0415d7b97d438d91795d022a5
7
- data.tar.gz: e7a1a6f47da4bbf9db7e18de9c3184e4af3498f636f51ba8b8ee9aa25b1c57c9532be24e71ee76e2201f5f7a240cddc62e33f16d886a1673062d845163831664
6
+ metadata.gz: 704ce58b27ab6ea1096390ad63daa926627f8b4d6b2a7613a0517949129d66850bac74f7860d090b4fd3a8aeb2c1ec58148b6cddce35e6e5a5d90d72e866e2e9
7
+ data.tar.gz: eb62734dbf1d2168918e958ac4a432ea621eb263c9c17e1f36dad7f9f008e9a3e4499eaa3767daad5f8291017c2d316731cab2c3df3873c47c99c251c7d7ba69
@@ -1,5 +1,30 @@
1
1
  module GD
2
2
  module GIS
3
+ # Provides helper methods for discovering and selecting font files
4
+ # available on the local system.
5
+ #
6
+ # This module is primarily used to supply font paths to text-rendering
7
+ # components (such as PointsLayer labels) in environments where font
8
+ # availability is system-dependent.
9
+ #
10
+ # Font discovery is performed by scanning a set of well-known directories
11
+ # for TrueType and OpenType font files. The results are cached for the
12
+ # lifetime of the process.
13
+ #
14
+ # Supported font formats:
15
+ # - TrueType (.ttf)
16
+ # - OpenType (.otf)
17
+ # - TrueType Collection (.ttc)
18
+ #
19
+ # @example Select a random system font
20
+ # font_path = GD::GIS::FontHelper.random
21
+ #
22
+ # @example Find a font by name fragment
23
+ # font_path = GD::GIS::FontHelper.find("Noto")
24
+ #
25
+ # @note
26
+ # This helper does not validate glyph coverage (e.g. CJK support).
27
+ # It only locates font files present on the system.
3
28
  module FontHelper
4
29
  PATHS = [
5
30
  "/usr/share/fonts",
@@ -9,6 +34,16 @@ module GD
9
34
 
10
35
  EXTENSIONS = %w[ttf otf ttc].freeze
11
36
 
37
+ # Returns the list of all font files discovered on the system.
38
+ #
39
+ # The search is performed once and cached. Subsequent calls return
40
+ # the cached result.
41
+ #
42
+ # Font files are discovered by recursively scanning the directories
43
+ # defined in {PATHS} for files matching the extensions in {EXTENSIONS}.
44
+ #
45
+ # @return [Array<String>]
46
+ # An array of absolute file paths to font files.
12
47
  def self.all
13
48
  @all ||= PATHS.flat_map do |path|
14
49
  next [] unless Dir.exist?(path)
@@ -19,10 +54,34 @@ module GD
19
54
  end.compact.uniq
20
55
  end
21
56
 
57
+ # Returns a randomly selected font file from the system.
58
+ #
59
+ # This is primarily intended as a fallback mechanism when no explicit
60
+ # font is configured by the caller.
61
+ #
62
+ # @return [String]
63
+ # Absolute path to a font file.
64
+ #
65
+ # @raise [RuntimeError]
66
+ # If no font files are found on the system.
67
+ #
68
+ # @note
69
+ # The selected font is not guaranteed to support any particular
70
+ # character set.
22
71
  def self.random
23
72
  all.sample or raise "GD::GIS::FontHelper: no fonts found on system"
24
73
  end
25
74
 
75
+ # Finds a font file whose filename includes the given name fragment.
76
+ #
77
+ # The match is case-insensitive and performed against the basename
78
+ # of each discovered font file.
79
+ #
80
+ # @param name [String]
81
+ # A substring to search for in font filenames (e.g. "Noto", "DejaVu").
82
+ #
83
+ # @return [String, nil]
84
+ # The path to the first matching font file, or nil if no match is found.
26
85
  def self.find(name)
27
86
  all.find do |f|
28
87
  File.basename(f).downcase.include?(name.downcase)
@@ -54,7 +54,8 @@ module GD
54
54
  @label = label
55
55
  @font = font
56
56
  @size = size
57
- @color = color
57
+ @r, @g, @b, @a = color
58
+ @a = 0 if @a.nil?
58
59
 
59
60
  @icon.alpha_blending = true
60
61
  @icon.save_alpha = true
@@ -116,7 +117,7 @@ module GD
116
117
  x: x + (w / 2) + 4,
117
118
  y: y + (font_h / 2),
118
119
  size: @size,
119
- color: @color,
120
+ color: GD::Color.rgba(@r, @g, @b, @a),
120
121
  font: @font)
121
122
  end
122
123
  end
data/lib/gd/gis/map.rb CHANGED
@@ -113,6 +113,7 @@ module GD
113
113
  primary: [],
114
114
  secondary: [],
115
115
  street: [],
116
+ track: [],
116
117
  minor: [],
117
118
  rail: [],
118
119
  water: [],
@@ -155,7 +156,37 @@ module GD
155
156
  end
156
157
  end
157
158
 
159
+ # Creates a single text label for a named linear feature (LineString or
160
+ # MultiLineString), avoiding duplicate labels for the same named entity.
161
+ #
162
+ # Many datasets (especially OSM) split a single logical entity
163
+ # (rivers, streets, railways, etc.) into multiple line features that
164
+ # all share the same name. This method ensures that:
165
+ #
166
+ # - Only one label is created per unique entity name
167
+ # - The label is placed on a representative segment of the geometry
168
+ # - The logic is independent of the feature's semantic layer (water, road, rail)
169
+ #
170
+ # Labels are rendered using a PointsLayer because libgd-gis does not
171
+ # support text rendering directly on line geometries.
172
+ #
173
+ # The label position is chosen as the midpoint of the line coordinates.
174
+ # This is a simple heuristic that provides a reasonable placement without
175
+ # requiring geometry merging or topological analysis.
176
+ #
177
+ # @param feature [GD::GIS::Feature]
178
+ # A feature with a linear geometry and a "name" property.
179
+ #
180
+ # @return [void]
181
+ # Adds a PointsLayer to @points_layers if a label is created.
182
+ #
183
+ # @note
184
+ # This method must be called during feature loading (add_geojson),
185
+ # before rendering. It intentionally does not depend on map style
186
+ # configuration, which is applied later during rendering.
158
187
  def maybe_create_line_label(feature)
188
+ return true if @style.global[:label] == false || @style.global[:label].nil?
189
+
159
190
  geom = feature.geometry
160
191
  return unless LINE_GEOMS.include?(geom["type"])
161
192
 
@@ -171,17 +202,15 @@ module GD
171
202
 
172
203
  lon, lat = coords[coords.size / 2]
173
204
 
174
- puts @style
175
-
176
205
  @points_layers << GD::GIS::PointsLayer.new(
177
206
  [feature],
178
207
  lon: ->(_) { lon },
179
208
  lat: ->(_) { lat },
180
- icon: nil,
209
+ icon: @style.global[:label][:icon],
181
210
  label: ->(_) { name },
182
- font: GD::GIS::FontHelper.random,
183
- size: 10,
184
- color: GD::Color.rgb(0, 0, 0)
211
+ font: @style.global[:label][:font] || GD::GIS::FontHelper.random,
212
+ size: @style.global[:label][:size] || (6..20).to_a.sample,
213
+ color: @style.global[:label][:color] || GD::GIS::ColorHelpers.random_rgba
185
214
  )
186
215
 
187
216
  @used_labels[key] = true
@@ -207,7 +236,7 @@ module GD
207
236
  kind =
208
237
  case (feature.properties["objeto"] || feature.properties["waterway"]).to_s.downcase
209
238
  when /river|río|canal/ then :river
210
- when /stream|arroyo/ then :stream
239
+ when /stream|arroyo/ then :stream
211
240
  else :minor
212
241
  end
213
242
 
@@ -220,9 +249,7 @@ module GD
220
249
  @layers[:park] << feature
221
250
 
222
251
  when :track
223
- # elegí una:
224
- @layers[:minor] << feature
225
- # o @layers[:street] << feature
252
+ @layers[:track] << feature
226
253
  else
227
254
  geom_type = feature.geometry["type"]
228
255
 
@@ -272,8 +299,8 @@ module GD
272
299
  # @param data [Enumerable]
273
300
  # @param opts [Hash]
274
301
  # @return [void]
275
- def add_points(data, **opts)
276
- @points_layers << GD::GIS::PointsLayer.new(data, **opts)
302
+ def add_points(data, **)
303
+ @points_layers << GD::GIS::PointsLayer.new(data, **)
277
304
  end
278
305
 
279
306
  # Adds a generic lines overlay layer.
@@ -281,8 +308,8 @@ module GD
281
308
  # @param features [Array]
282
309
  # @param opts [Hash]
283
310
  # @return [void]
284
- def add_lines(features, **opts)
285
- @lines_layers << GD::GIS::LinesLayer.new(features, **opts)
311
+ def add_lines(features, **)
312
+ @lines_layers << GD::GIS::LinesLayer.new(features, **)
286
313
  end
287
314
 
288
315
  # Adds a generic polygons overlay layer.
@@ -290,8 +317,8 @@ module GD
290
317
  # @param polygons [Array]
291
318
  # @param opts [Hash]
292
319
  # @return [void]
293
- def add_polygons(polygons, **opts)
294
- @polygons_layers << GD::GIS::PolygonsLayer.new(polygons, **opts)
320
+ def add_polygons(polygons, **)
321
+ @polygons_layers << GD::GIS::PolygonsLayer.new(polygons, **)
295
322
  end
296
323
 
297
324
  # Renders the map.
@@ -438,6 +465,8 @@ module GD
438
465
  case kind
439
466
  when :street, :primary, :motorway, :secondary, :minor
440
467
  @style.roads[kind]
468
+ when :track
469
+ @style.track[kind]
441
470
  when :rail
442
471
  @style.rails
443
472
  when :water
@@ -475,7 +504,9 @@ module GD
475
504
  if POLY_GEOMS.include?(geom)
476
505
  f.draw(@image, projection, nil, nil, style)
477
506
  elsif style[:stroke]
478
- color = GD::Color.rgb(*style[:stroke])
507
+ r, g, b, a = style[:stroke]
508
+ a = 0 if a.nil?
509
+ color = GD::Color.rgba(r, g, b, a)
479
510
 
480
511
  color = GD::GIS::ColorHelpers.random_vivid if @debug
481
512
 
@@ -32,5 +32,4 @@ track:
32
32
  gps:
33
33
  name:
34
34
  - track
35
-
36
-
35
+ - Track
data/lib/gd/gis/style.rb CHANGED
@@ -14,6 +14,9 @@ module GD
14
14
  # to a {GD::GIS::Map} instance before rendering.
15
15
  #
16
16
  class Style
17
+ # @return [Hash] global styling rules
18
+ attr_reader :global
19
+
17
20
  # @return [Hash] road styling rules
18
21
  attr_reader :roads
19
22
 
@@ -29,6 +32,9 @@ module GD
29
32
  # @return [Hash] point styling rules
30
33
  attr_reader :points
31
34
 
35
+ # @return [Hash] track styling rules
36
+ attr_reader :track
37
+
32
38
  # @return [Array<Symbol>] drawing order of semantic layers
33
39
  attr_reader :order
34
40
 
@@ -36,13 +42,15 @@ module GD
36
42
  #
37
43
  # @param definition [Hash]
38
44
  # style definition with optional sections:
39
- # :roads, :rails, :water, :parks, :points, :order
45
+ # :global, :roads, :rails, :water, :parks, :points, :order, :track
40
46
  def initialize(definition)
47
+ @global = definition[:global] || {}
41
48
  @roads = definition[:roads] || {}
42
49
  @rails = definition[:rails] || {}
43
50
  @water = definition[:water] || {}
44
51
  @parks = definition[:parks] || {}
45
52
  @points = definition[:points] || {}
53
+ @track = definition[:track] || {}
46
54
  @order = definition[:order] || []
47
55
  end
48
56
 
@@ -70,8 +78,10 @@ module GD
70
78
  data = deep_symbolize(data)
71
79
 
72
80
  new(
81
+ global: data[:global],
73
82
  roads: data[:roads],
74
83
  rails: data[:rail] || data[:rails],
84
+ track: data[:track],
75
85
  water: data[:water],
76
86
  parks: data[:park] || data[:parks],
77
87
  points: data[:points],
data/lib/test.rb ADDED
@@ -0,0 +1,4 @@
1
+ def foo
2
+ end
3
+
4
+ foo(1, 2)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libgd-gis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Germán Alberto Giménez Silva
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-01-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ruby-libgd
@@ -30,34 +29,6 @@ dependencies:
30
29
  - - ">="
31
30
  - !ruby/object:Gem::Version
32
31
  version: 0.2.3
33
- - !ruby/object:Gem::Dependency
34
- name: rubocop
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '1.60'
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '1.60'
47
- - !ruby/object:Gem::Dependency
48
- name: rubocop-performance
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '1.20'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.20'
61
32
  description: A native GIS raster engine for Ruby built on libgd. Render maps, GeoJSON,
62
33
  heatmaps and tiles.
63
34
  email:
@@ -86,11 +57,12 @@ files:
86
57
  - lib/gd/gis/projection.rb
87
58
  - lib/gd/gis/style.rb
88
59
  - lib/libgd_gis.rb
60
+ - lib/test.rb
89
61
  homepage: https://github.com/ggerman/libgd-gis
90
62
  licenses:
91
63
  - MIT
92
- metadata: {}
93
- post_install_message:
64
+ metadata:
65
+ rubygems_mfa_required: 'true'
94
66
  rdoc_options: []
95
67
  require_paths:
96
68
  - lib
@@ -105,8 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
77
  - !ruby/object:Gem::Version
106
78
  version: '0'
107
79
  requirements: []
108
- rubygems_version: 3.5.22
109
- signing_key:
80
+ rubygems_version: 4.0.4
110
81
  specification_version: 4
111
82
  summary: Geospatial raster rendering for Ruby using libgd
112
83
  test_files: []