libgd-gis 0.2.9 → 0.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.
@@ -1,8 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GD
2
4
  module GIS
5
+ # Renders collections of line geometries onto a GD image.
6
+ #
7
+ # A LinesLayer draws simple line strings using a fixed stroke
8
+ # color and width. Coordinates are expected to be in
9
+ # [longitude, latitude] order and are projected at render time.
10
+ #
3
11
  class LinesLayer
12
+ # @return [Boolean] enables debug rendering
4
13
  attr_accessor :debug
5
14
 
15
+ # Creates a new lines layer.
16
+ #
17
+ # @param lines [Array<Array<Array<Float>>>]
18
+ # array of line strings ([[lng, lat], ...])
19
+ # @param stroke [GD::Color] line color
20
+ # @param width [Integer] stroke width in pixels
6
21
  def initialize(lines, stroke:, width:)
7
22
  @lines = lines
8
23
  @stroke = stroke
@@ -10,6 +25,14 @@ module GD
10
25
  @debug = false
11
26
  end
12
27
 
28
+ # Renders the lines onto the given image.
29
+ #
30
+ # @param img [GD::Image] target image
31
+ # @param projection [#call]
32
+ # callable converting (lng, lat) → (x, y)
33
+ #
34
+ # @raise [RuntimeError] if a line is invalid
35
+ # @return [void]
13
36
  def render!(img, projection)
14
37
  @lines.each do |line|
15
38
  raise "Invalid line: #{line.inspect}" unless valid_line?(line)
@@ -33,6 +56,10 @@ module GD
33
56
 
34
57
  private
35
58
 
59
+ # Validates a line string.
60
+ #
61
+ # @param line [Object]
62
+ # @return [Boolean]
36
63
  def valid_line?(line)
37
64
  line.is_a?(Array) &&
38
65
  line.size >= 2 &&
@@ -1,13 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GD
2
4
  module GIS
5
+ # Renders point data as icons (markers) with optional labels.
6
+ #
7
+ # A PointsLayer draws markers for arbitrary data records.
8
+ # Longitude and latitude values are extracted using callables,
9
+ # allowing the layer to work with any data structure.
10
+ #
11
+ # Optionally, text labels can be rendered next to each marker.
12
+ #
3
13
  class PointsLayer
4
-
5
- def initialize(data, lon:, lat:, icon:, label: nil, font: nil, size: 12, color: [0,0,0])
14
+ # Creates a new points layer.
15
+ #
16
+ # @param data [Enumerable]
17
+ # collection of data records
18
+ # @param lon [#call]
19
+ # callable extracting longitude from a data record
20
+ # @param lat [#call]
21
+ # callable extracting latitude from a data record
22
+ # @param icon [String, Array<GD::Color>, nil]
23
+ # path to an icon image, or [fill, stroke] colors,
24
+ # or nil to generate a random marker
25
+ # @param label [#call, nil]
26
+ # callable extracting label text from a data record
27
+ # @param font [String, nil]
28
+ # font path used for labels
29
+ # @param size [Integer]
30
+ # font size in pixels
31
+ # @param color [Array<Integer>]
32
+ # label color as RGB array
33
+ def initialize(
34
+ data,
35
+ lon:,
36
+ lat:,
37
+ icon:,
38
+ label: nil,
39
+ font: nil,
40
+ size: 12,
41
+ color: [0, 0, 0]
42
+ )
6
43
  @data = data
7
44
  @lon = lon
8
45
  @lat = lat
9
46
 
10
- if icon.kind_of?(Array) || icon.nil?
47
+ if icon.is_a?(Array) || icon.nil?
11
48
  fill, stroke = icon || [GD::GIS::ColorHelpers.random_rgb, GD::GIS::ColorHelpers.random_rgb]
12
49
  @icon = build_default_marker(fill, stroke)
13
50
  else
@@ -23,6 +60,11 @@ module GD
23
60
  @icon.save_alpha = true
24
61
  end
25
62
 
63
+ # Builds a default circular marker icon.
64
+ #
65
+ # @param fill [GD::Color]
66
+ # @param stroke [GD::Color]
67
+ # @return [GD::Image]
26
68
  def build_default_marker(fill, stroke)
27
69
  size = 32
28
70
 
@@ -34,14 +76,21 @@ module GD
34
76
  r = 5
35
77
 
36
78
  # stroke
37
- img.arc(cx, cy, r*2+4, r*2+4, 0, 360, stroke)
79
+ img.arc(cx, cy, (r * 2) + 4, (r * 2) + 4, 0, 360, stroke)
38
80
 
39
81
  # fill
40
- img.filled_arc(cx, cy, r*2, r*2, 0, 360, fill)
82
+ img.filled_arc(cx, cy, r * 2, r * 2, 0, 360, fill)
41
83
 
42
84
  img
43
85
  end
44
86
 
87
+ # Renders all points onto the image.
88
+ #
89
+ # @param img [GD::Image] target image
90
+ # @param projector [#call]
91
+ # callable converting (lon, lat) → (x, y)
92
+ #
93
+ # @return [void]
45
94
  def render!(img, projector)
46
95
  w = @icon.width
47
96
  h = @icon.height
@@ -50,26 +99,25 @@ module GD
50
99
  lon = @lon.call(row)
51
100
  lat = @lat.call(row)
52
101
 
53
- x,y = projector.call(lon,lat)
102
+ x, y = projector.call(lon, lat)
54
103
 
55
104
  # icono
56
- img.copy(@icon, x - w/2, y - h/2, 0,0,w,h)
105
+ img.copy(@icon, x - (w / 2), y - (h / 2), 0, 0, w, h)
57
106
 
58
107
  # etiqueta opcional
59
- if @label && @font
60
- text = @label.call(row)
61
- unless text.nil? || text.strip.empty?
62
- font_h = @size * 1.1
63
-
64
- img.text(text,
65
- x: x + w/2 + 4,
66
- y: y + font_h/2,
67
- size: @size,
68
- color: @color,
69
- font: @font
70
- )
71
- end
72
- end
108
+ next unless @label && @font
109
+
110
+ text = @label.call(row)
111
+ next if text.nil? || text.strip.empty?
112
+
113
+ font_h = @size * 1.1
114
+
115
+ img.text(text,
116
+ x: x + (w / 2) + 4,
117
+ y: y + (font_h / 2),
118
+ size: @size,
119
+ color: @color,
120
+ font: @font)
73
121
  end
74
122
  end
75
123
  end
@@ -1,17 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GD
2
4
  module GIS
5
+ # Renders polygon geometries onto a GD image.
6
+ #
7
+ # A PolygonsLayer draws filled polygons with optional
8
+ # stroke outlines. Polygons are expected to be provided
9
+ # as arrays of rings in [longitude, latitude] order.
10
+ #
3
11
  class PolygonsLayer
12
+ # @return [Boolean] enables debug rendering
4
13
  attr_accessor :debug
5
14
 
15
+ # Creates a new polygons layer.
16
+ #
17
+ # @param polygons [Array<Array<Array<Array<Float>>>>]
18
+ # array of polygons, each consisting of one or more rings
19
+ # @param fill [GD::Color] fill color
20
+ # @param stroke [GD::Color, nil] stroke color
21
+ # @param width [Integer, nil] stroke width in pixels
6
22
  def initialize(polygons, fill:, stroke: nil, width: nil)
7
23
  @polygons = polygons
8
24
  @fill = fill
9
25
  @stroke = stroke
10
26
  @width = width
11
-
12
- @debug = false
27
+ @debug = false
13
28
  end
14
29
 
30
+ # Builds a polygon layer by buffering line features.
31
+ #
32
+ # This is a convenience constructor that converts
33
+ # line geometries into polygon buffers using a naive
34
+ # geometric approximation.
35
+ #
36
+ # @param features [Array<Hash>]
37
+ # GeoJSON-like features with LineString geometries
38
+ # @param stroke [GD::Color]
39
+ # @param fill [GD::Color]
40
+ # @param width [Numeric]
41
+ # buffer width (approximate)
42
+ #
43
+ # @return [PolygonsLayer]
15
44
  def self.from_lines(features, stroke:, fill:, width:)
16
45
  polys = []
17
46
 
@@ -24,6 +53,13 @@ module GD
24
53
  new(polys, fill: fill, stroke: stroke)
25
54
  end
26
55
 
56
+ # Renders all polygons onto the image.
57
+ #
58
+ # @param img [GD::Image] target image
59
+ # @param projection [#call]
60
+ # callable converting (lng, lat) → (x, y)
61
+ #
62
+ # @return [void]
27
63
  def render!(img, projection)
28
64
  @polygons.each do |polygon|
29
65
  # polygon = [ ring, ring, ... ]
@@ -35,20 +71,19 @@ module GD
35
71
  @stroke = GD::GIS::ColorHelpers.random_vivid if @debug
36
72
  @fill = GD::GIS::ColorHelpers.random_vivid if @debug
37
73
 
38
- if idx == 0
74
+ if idx.zero?
39
75
  # ring exterior
40
76
  img.filled_polygon(pts, @fill)
41
77
  end
42
78
 
43
- if @stroke
44
- pts.each_cons(2) do |a, b|
45
- img.line(a[0], a[1], b[0], b[1], @stroke, thickness: (@width || 1))
46
- end
79
+ next unless @stroke
80
+
81
+ pts.each_cons(2) do |a, b|
82
+ img.line(a[0], a[1], b[0], b[1], @stroke, thickness: @width || 1)
47
83
  end
48
84
  end
49
85
  end
50
86
  end
51
-
52
87
  end
53
88
  end
54
89
  end