Class: GD::GIS::Feature

Inherits:
Object
  • Object
show all
Defined in:
lib/gd/gis/feature.rb

Overview

Represents a single geographic feature with geometry and properties.

A Feature acts as the rendering bridge between:

  • GeoJSON-like geometry data

  • Attribute properties

  • GD drawing primitives

Features are responsible for drawing themselves onto a GD image using a provided projection and styling information.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(geometry, properties, layer = nil) ⇒ Feature

Creates a new feature.

Parameters:

  • geometry (Hash)

    GeoJSON-like geometry hash (type + coordinates)

  • properties (Hash, nil)

    feature attributes / tags

  • layer (Symbol, nil) (defaults to: nil)

    optional logical layer identifier



33
34
35
36
37
# File 'lib/gd/gis/feature.rb', line 33

def initialize(geometry, properties, layer = nil)
  @geometry   = geometry
  @properties = properties || {}
  @layer      = layer
end

Instance Attribute Details

#geometryHash (readonly)

Returns GeoJSON geometry object.

Returns:

  • (Hash)

    GeoJSON geometry object



17
18
19
# File 'lib/gd/gis/feature.rb', line 17

def geometry
  @geometry
end

#layerSymbol? (readonly)

Returns logical layer identifier.

Returns:

  • (Symbol, nil)

    logical layer identifier



23
24
25
# File 'lib/gd/gis/feature.rb', line 23

def layer
  @layer
end

#propertiesHash (readonly)

Returns feature properties (tags).

Returns:

  • (Hash)

    feature properties (tags)



20
21
22
# File 'lib/gd/gis/feature.rb', line 20

def properties
  @properties
end

Instance Method Details

#centroidArray<Float>?

Computes a simple centroid for line-based geometries.

Returns:

  • (Array<Float>, nil)
    lon, lat

    or nil



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/gd/gis/feature.rb', line 217

def centroid
  pts = []

  case geometry["type"]
  when "LineString"
    pts = geometry["coordinates"]
  when "MultiLineString"
    pts = geometry["coordinates"].flatten(1)
  end

  return nil if pts.empty?

  lon = pts.sum(&:first) / pts.size
  lat = pts.sum(&:last) / pts.size

  [lon, lat]
end

#draw(img, projection, color, width, layer = nil) ⇒ void

This method returns an undefined value.

Draws the feature onto a GD image.

This is the main rendering entry point and dispatches to the appropriate drawing method based on geometry type and layer styling.

Supported geometry types:

  • Polygon

  • MultiPolygon

  • LineString

  • MultiLineString

Parameters:

  • img (GD::Image)

    target image

  • projection (#call)

    callable object converting (lon, lat) → (x, y)

  • color (GD::Color, nil)

    base color

  • width (Integer)

    stroke width

  • layer (Symbol, Hash, nil) (defaults to: nil)

    layer identifier or style hash



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/gd/gis/feature.rb', line 60

def draw(img, projection, color, width, layer = nil)
  case geometry["type"]
  when "Polygon"
    if layer == :water
      draw_polygon_outline(img, projection, geometry["coordinates"], color, width)
    elsif layer.is_a?(Hash)
      draw_polygon_styled(img, projection, geometry["coordinates"], layer)
    else
      draw_polygon(img, projection, geometry["coordinates"], color)
    end
  when "MultiPolygon"
    geometry["coordinates"].each do |poly|
      if layer == :water
        draw_polygon_outline(img, projection, poly, color, width)
      elsif layer.is_a?(Hash)
        draw_polygon_styled(img, projection, poly, layer)
      else
        draw_polygon(img, projection, poly, color)
      end
    end
  when "LineString", "MultiLineString"
    draw_lines(img, projection, geometry["coordinates"], color, width)
  end
end

#draw_line(img, projection, coords, color, width) ⇒ void

This method returns an undefined value.

Draws a single line geometry.

Parameters:

  • img (GD::Image)
  • projection (#call)
  • coords (Array)
  • color (GD::Color)
  • width (Integer)


195
196
197
198
199
200
201
202
203
# File 'lib/gd/gis/feature.rb', line 195

def draw_line(img, projection, coords, color, width)
  return if color.nil?

  coords.each_cons(2) do |(lon1, lat1), (lon2, lat2)|
    x1, y1 = projection.call(lon1, lat1)
    x2, y2 = projection.call(lon2, lat2)
    img.line(x1, y1, x2, y2, color, thickness: width)
  end
end

#draw_lines(img, projection, coords, color, width) ⇒ void

This method returns an undefined value.

Draws line or multiline geometries.

Parameters:

  • img (GD::Image)
  • projection (#call)
  • coords (Array)
  • color (GD::Color)
  • width (Integer)


177
178
179
180
181
182
183
184
185
# File 'lib/gd/gis/feature.rb', line 177

def draw_lines(img, projection, coords, color, width)
  return if color.nil?

  if coords.first.is_a?(Array) && coords.first.first.is_a?(Array)
    coords.each { |line| draw_line(img, projection, line, color, width) }
  else
    draw_line(img, projection, coords, color, width)
  end
end

#draw_polygon(img, projection, rings, color) ⇒ void

This method returns an undefined value.

Draws a filled polygon using a single color.

Parameters:

  • img (GD::Image)
  • projection (#call)
  • rings (Array)
  • color (GD::Color)


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/gd/gis/feature.rb', line 151

def draw_polygon(img, projection, rings, color)
  return if color.nil?

  rings.each do |ring|
    pts = ring.filter_map do |lon, lat|
      x, y = projection.call(lon, lat)
      next if x.nil? || y.nil?

      [x.to_i, y.to_i]
    end

    pts = pts.chunk_while { |a, b| a == b }.map(&:first)
    next if pts.length < 3

    img.filled_polygon(pts, color)
  end
end

#draw_polygon_outline(img, projection, rings, color, width) ⇒ void

This method returns an undefined value.

Draws only the outline of a polygon.

Used primarily for water bodies.

Parameters:

  • img (GD::Image)
  • projection (#call)
  • rings (Array)
  • color (GD::Color)
  • width (Integer)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/gd/gis/feature.rb', line 129

def draw_polygon_outline(img, projection, rings, color, width)
  return if color.nil?

  rings.each do |ring|
    pts = ring.filter_map do |lon, lat|
      x, y = projection.call(lon, lat)
      [x.to_i, y.to_i] if x && y
    end

    next if pts.size < 2

    img.lines(pts, color, width)
  end
end

#draw_polygon_styled(img, projection, rings, style) ⇒ void

This method returns an undefined value.

Draws a polygon with fill and stroke styling.

Parameters:

  • img (GD::Image)
  • projection (#call)
  • rings (Array)

    polygon rings (GeoJSON format)

  • style (Hash)

    style hash with :fill and/or :stroke RGB arrays



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/gd/gis/feature.rb', line 95

def draw_polygon_styled(img, projection, rings, style)
  fill   = style[:fill]   ? GD::Color.rgb(*style[:fill])   : nil
  stroke = style[:stroke] ? GD::Color.rgb(*style[:stroke]) : nil

  rings.each do |ring|
    pts = ring.filter_map do |lon, lat|
      x, y = projection.call(lon, lat)
      next if x.nil? || y.nil?

      [x.to_i, y.to_i]
    end

    pts = pts.chunk_while { |a, b| a == b }.map(&:first)
    next if pts.length < 3

    img.filled_polygon(pts, fill) if fill

    if stroke
      pts.each_cons(2) { |a, b| img.line(a[0], a[1], b[0], b[1], stroke) }
      img.line(pts.last[0], pts.last[1], pts.first[0], pts.first[1], stroke)
    end
  end
end

#labelString?

Returns the display label for the feature.

Prefers Japanese names if present.

Returns:

  • (String, nil)


210
211
212
# File 'lib/gd/gis/feature.rb', line 210

def label
  properties["name:ja"] || properties["name"]
end