libgd-gis 0.3.1 → 0.3.3

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: adcbc0b0d92182bc12b431152cb1f79b202786ef999e3571f42c9ec27e999561
4
- data.tar.gz: 50cb494d8e9b2fdf94f9ac126c22f14cb39335c4f1d0289df554f88159b5d389
3
+ metadata.gz: 853349ea776badb5542429302596948e10214ccd5dd3eb75c31e075bfde0e45e
4
+ data.tar.gz: 51a6d88d8f49e6e14a363c68fbd9a0837aae91aef028b456f4df20865831fce8
5
5
  SHA512:
6
- metadata.gz: 704ce58b27ab6ea1096390ad63daa926627f8b4d6b2a7613a0517949129d66850bac74f7860d090b4fd3a8aeb2c1ec58148b6cddce35e6e5a5d90d72e866e2e9
7
- data.tar.gz: eb62734dbf1d2168918e958ac4a432ea621eb263c9c17e1f36dad7f9f008e9a3e4499eaa3767daad5f8291017c2d316731cab2c3df3873c47c99c251c7d7ba69
6
+ metadata.gz: e3430de5b4a01574ccb741d0948de4458b07cae11e196835282c71c88edf2e69f3f6a53f5d35cdaa3195423f0e9bf845324919b233f3aeec68af5719da752173
7
+ data.tar.gz: e2a9b4e8149839b5b9d7b834757e304979a81e3879a4332f97159e75236be79ea4c4e179a54ed3efd94231c24d290edc83812793b2962ffdbd40ae12549bf40a
@@ -38,27 +38,35 @@ module GD
38
38
  label: nil,
39
39
  font: nil,
40
40
  size: 12,
41
- color: [0, 0, 0]
41
+ color: [0, 0, 0],
42
+ font_color: nil,
43
+ symbol: 0
42
44
  )
43
45
  @data = data
44
46
  @lon = lon
45
47
  @lat = lat
48
+ @color = color
49
+ @font_color = font_color
46
50
 
47
51
  if icon.is_a?(Array) || icon.nil?
48
52
  fill, stroke = icon || [GD::GIS::ColorHelpers.random_rgb, GD::GIS::ColorHelpers.random_rgb]
49
53
  @icon = build_default_marker(fill, stroke)
54
+ elsif %w[numeric alphabetic symbol].include?(icon)
55
+ @icon = icon
50
56
  else
51
57
  @icon = GD::Image.open(icon)
58
+ @icon.alpha_blending = true
59
+ @icon.save_alpha = true
52
60
  end
53
61
 
54
62
  @label = label
55
63
  @font = font
56
64
  @size = size
65
+
57
66
  @r, @g, @b, @a = color
58
67
  @a = 0 if @a.nil?
59
68
 
60
- @icon.alpha_blending = true
61
- @icon.save_alpha = true
69
+ @symbol = symbol
62
70
  end
63
71
 
64
72
  # Builds a default circular marker icon.
@@ -93,8 +101,23 @@ module GD
93
101
  #
94
102
  # @return [void]
95
103
  def render!(img, projector)
96
- w = @icon.width
97
- h = @icon.height
104
+ value = case @icon
105
+ when "numeric"
106
+ @symbol
107
+ when "alphabetic"
108
+ (@symbol + 96).chr
109
+ when "symbol"
110
+ @symbol
111
+ else
112
+ @icon
113
+ end
114
+
115
+ if @icon.is_a?(GD::Image)
116
+ w = @icon.width
117
+ h = @icon.height
118
+ else
119
+ w = radius_from_text(img, value, font: @font, size: @size) * 2
120
+ end
98
121
 
99
122
  @data.each do |row|
100
123
  lon = @lon.call(row)
@@ -102,10 +125,6 @@ module GD
102
125
 
103
126
  x, y = projector.call(lon, lat)
104
127
 
105
- # icono
106
- img.copy(@icon, x - (w / 2), y - (h / 2), 0, 0, w, h)
107
-
108
- # etiqueta opcional
109
128
  next unless @label && @font
110
129
 
111
130
  text = @label.call(row)
@@ -113,14 +132,80 @@ module GD
113
132
 
114
133
  font_h = @size * 1.1
115
134
 
135
+ if @icon == "numeric" || @icon == "alphabetic" || @icon == "symbol"
136
+ draw_symbol_circle!(
137
+ img: img,
138
+ x: x,
139
+ y: y,
140
+ symbol: value,
141
+ bg_color: @color,
142
+ font_color: @font_color,
143
+ font: @font,
144
+ font_size: @size
145
+ )
146
+ else
147
+ img.copy(@icon, x - (w / 2), y - (h / 2), 0, 0, w, h)
148
+ end
149
+
116
150
  img.text(text,
117
151
  x: x + (w / 2) + 4,
118
152
  y: y + (font_h / 2),
119
153
  size: @size,
120
- color: GD::Color.rgba(@r, @g, @b, @a),
154
+ color: @font_color,
121
155
  font: @font)
122
156
  end
123
157
  end
158
+
159
+ # Draws a filled circle (bullet) with a centered numeric label.
160
+ #
161
+ # - x, y: circle center in pixels
162
+ # - y for text() is BASELINE (not top). We compute baseline to center the text.
163
+ def draw_symbol_circle!(img:, x:, y:, symbol:, bg_color:, font_color:, font:, font_size:, angle: 0.0)
164
+ diameter = radius_from_text(img, symbol, font: font, size: font_size) * 2
165
+
166
+ # 1) Bullet background
167
+ img.filled_ellipse(x, y, diameter, diameter, bg_color)
168
+
169
+ # 2) Measure text in pixels (matches rendering)
170
+ text = symbol.to_s
171
+ w, h = img.text_bbox(text, font: font, size: font_size, angle: angle)
172
+
173
+ # 3) Compute centered position:
174
+ # text() uses baseline Y, so:
175
+ # top_y = y - h/2
176
+ # baseline = top_y + h = y + h/2
177
+ text_x = (x - (w / 2.0)).round
178
+ text_y = (y + (h / 2.0)).round
179
+
180
+ # 4) Draw number
181
+ img.text(
182
+ text,
183
+ x: text_x,
184
+ y: text_y,
185
+ font: font,
186
+ size: font_size,
187
+ color: font_color
188
+ )
189
+ end
190
+
191
+ # Calculates a circle radius that fully contains the rendered text.
192
+ #
193
+ # img : GD::Image
194
+ # text : String (number, letters, etc.)
195
+ # font : path to .ttf
196
+ # size : font size in points
197
+ # padding : extra pixels around text (visual breathing room)
198
+ #
199
+ def radius_from_text(img, text, font:, size:, padding: 4)
200
+ w, h = img.text_bbox(
201
+ text.to_s,
202
+ font: font,
203
+ size: size
204
+ )
205
+
206
+ # Use the larger dimension to ensure the text fits
207
+ ([w, h].max / 2.0).ceil + padding
208
+ end
124
209
  end
125
210
  end
126
211
  end
data/lib/gd/gis/map.rb CHANGED
@@ -133,6 +133,7 @@ module GD
133
133
 
134
134
  @debug = false
135
135
  @used_labels = {}
136
+ @count = 1
136
137
  end
137
138
 
138
139
  # Returns all features belonging to a given semantic layer.
@@ -258,20 +259,20 @@ module GD
258
259
  warn "Style error: missing 'points' section"
259
260
  end
260
261
 
261
- font = points_style[:font] || begin
262
+ font = @style.points[:font] || begin
262
263
  warn "[libgd-gis] points.font not defined in style, using random system font"
263
264
  GD::GIS::FontHelper.random
264
265
  end
265
266
 
266
- size = points_style[:size] || begin
267
+ size = @style.points[:size] || begin
267
268
  warn "[libgd-gis] points.font size not defined in style, using random system font size"
268
269
  (6..14).to_a.sample
269
270
  end
270
271
 
271
- raw_color = points_style[:color]
272
- color = @style.normalize_color(raw_color)
272
+ color = @style.points[:color] ? @style.normalize_color(@style.points[:color]) : GD::GIS::ColorHelpers.random_vivid
273
+ font_color = @style.points[:font_color] ? @style.normalize_color(@style.points[:font_color]) : [250, 250, 250, 0]
273
274
 
274
- icon = if points_style.key?(:icon_fill) && points_style.key?(:icon_stroke)
275
+ icon = if @style.points.key?(:icon_fill) && @style.points.key?(:icon_stroke)
275
276
  [points_style[:icon_stroke],
276
277
  points_style[:icon_stroke]]
277
278
  end
@@ -285,8 +286,11 @@ module GD
285
286
  label: ->(f) { f.properties["name"] },
286
287
  font: font,
287
288
  size: size,
288
- color: color
289
+ color: color,
290
+ font_color: font_color,
291
+ symbol: @count
289
292
  )
293
+ @count += 1
290
294
  elsif LINE_GEOMS.include?(geom_type)
291
295
  @layers[:minor] << feature
292
296
  end
@@ -294,6 +298,96 @@ module GD
294
298
  end
295
299
  end
296
300
 
301
+ # Adds a single point (marker) to the map.
302
+ #
303
+ # This is a convenience helper for the most common use case: rendering
304
+ # one point with an optional label and icon, without having to build
305
+ # a full collection or manually configure a PointsLayer.
306
+ #
307
+ # Internally, this method wraps the given coordinates into a one-element
308
+ # data collection and delegates rendering to {GD::GIS::PointsLayer},
309
+ # preserving the same rendering behavior and options.
310
+ #
311
+ # This method is intended for annotations, markers, alerts, cities,
312
+ # or any scenario where only one point needs to be rendered.
313
+ #
314
+ # @param lon [Numeric]
315
+ # Longitude of the point.
316
+ # @param lat [Numeric]
317
+ # Latitude of the point.
318
+ # @param label [String, nil]
319
+ # Optional text label rendered next to the point.
320
+ # @param icon [String, Array<GD::Color>, nil]
321
+ # Marker representation. Can be:
322
+ # - a path to an image file
323
+ # - :numeric or :alphabetic symbol styles
324
+ # - an array of [fill, stroke] colors
325
+ # - nil to generate a default marker
326
+ # @param font [String, nil]
327
+ # Font path used to render the label or symbol.
328
+ # @param size [Integer]
329
+ # Font size in pixels (default: 12).
330
+ # @param color [Array<Integer>]
331
+ # Label or symbol background color as an RGB(A) array.
332
+ # @param font_color [GD::Color, nil]
333
+ # Text color for numeric or alphabetic symbols.
334
+ #
335
+ # @return [void]
336
+ #
337
+ # @example Render a simple point
338
+ # map.add_point(
339
+ # lon: -58.3816,
340
+ # lat: -34.6037
341
+ # )
342
+ #
343
+ # @example Point with label
344
+ # map.add_point(
345
+ # lon: -58.3816,
346
+ # lat: -34.6037,
347
+ # label: "Buenos Aires"
348
+ # )
349
+ #
350
+ # @example Point with numeric marker
351
+ # map.add_point(
352
+ # lon: -58.3816,
353
+ # lat: -34.6037,
354
+ # icon: "numeric",
355
+ # label: "1",
356
+ # font: "/usr/share/fonts/DejaVuSans.ttf"
357
+ # )
358
+ #
359
+
360
+ def add_point(
361
+ lon:,
362
+ lat:,
363
+ label: nil,
364
+ icon: nil,
365
+ font: nil,
366
+ size: nil,
367
+ color: nil,
368
+ font_color: nil,
369
+ symbol: nil
370
+ )
371
+ row = {
372
+ lon: lon,
373
+ lat: lat,
374
+ label: label
375
+ }
376
+
377
+ @points_layers << GD::GIS::PointsLayer.new(
378
+ [row],
379
+ lon: -> r { r[:lon] },
380
+ lat: -> r { r[:lat] },
381
+ icon: icon || @style.point[:icon],
382
+ label: label ? -> r { r[:label] } : nil,
383
+ font: font || @style.point[:font],
384
+ size: size || @style.point[:size],
385
+ color: color || @style.point[:color],
386
+ font_color: font_color || @style.point[:font_color],
387
+ symbol: symbol
388
+ )
389
+ end
390
+
297
391
  # Adds a generic points overlay layer.
298
392
  #
299
393
  # @param data [Enumerable]
data/lib/gd/gis/style.rb CHANGED
@@ -17,6 +17,9 @@ module GD
17
17
  # @return [Hash] global styling rules
18
18
  attr_reader :global
19
19
 
20
+ # @return [Hash] point styling rules
21
+ attr_reader :point
22
+
20
23
  # @return [Hash] road styling rules
21
24
  attr_reader :roads
22
25
 
@@ -45,6 +48,7 @@ module GD
45
48
  # :global, :roads, :rails, :water, :parks, :points, :order, :track
46
49
  def initialize(definition)
47
50
  @global = definition[:global] || {}
51
+ @point = definition[:point] || {}
48
52
  @roads = definition[:roads] || {}
49
53
  @rails = definition[:rails] || {}
50
54
  @water = definition[:water] || {}
@@ -79,6 +83,7 @@ module GD
79
83
 
80
84
  new(
81
85
  global: data[:global],
86
+ point: data[:point],
82
87
  roads: data[:roads],
83
88
  rails: data[:rail] || data[:rails],
84
89
  track: data[:track],
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.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Germán Alberto Giménez Silva
@@ -57,7 +57,6 @@ files:
57
57
  - lib/gd/gis/projection.rb
58
58
  - lib/gd/gis/style.rb
59
59
  - lib/libgd_gis.rb
60
- - lib/test.rb
61
60
  homepage: https://github.com/ggerman/libgd-gis
62
61
  licenses:
63
62
  - MIT
@@ -77,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
76
  - !ruby/object:Gem::Version
78
77
  version: '0'
79
78
  requirements: []
80
- rubygems_version: 4.0.4
79
+ rubygems_version: 4.0.5
81
80
  specification_version: 4
82
81
  summary: Geospatial raster rendering for Ruby using libgd
83
82
  test_files: []
data/lib/test.rb DELETED
@@ -1,4 +0,0 @@
1
- def foo
2
- end
3
-
4
- foo(1, 2)