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.
- checksums.yaml +4 -4
- data/README.md +132 -98
- data/lib/gd/gis/basemap.rb +69 -16
- data/lib/gd/gis/classifier.rb +48 -9
- data/lib/gd/gis/color_helpers.rb +39 -17
- data/lib/gd/gis/crs_normalizer.rb +53 -7
- data/lib/gd/gis/feature.rb +119 -36
- data/lib/gd/gis/font_helper.rb +33 -0
- data/lib/gd/gis/geometry.rb +116 -42
- data/lib/gd/gis/layer_geojson.rb +28 -4
- data/lib/gd/gis/layer_lines.rb +27 -0
- data/lib/gd/gis/layer_points.rb +69 -21
- data/lib/gd/gis/layer_polygons.rb +43 -8
- data/lib/gd/gis/map.rb +160 -66
- data/lib/gd/gis/middleware.rb +81 -18
- data/lib/gd/gis/ontology.rb +45 -2
- data/lib/gd/gis/ontology.yml +8 -0
- data/lib/gd/gis/projection.rb +55 -5
- data/lib/gd/gis/style.rb +66 -3
- data/lib/gd/gis.rb +28 -0
- data/lib/libgd_gis.rb +60 -30
- metadata +31 -6
- data/lib/gd/gis/input/detector.rb +0 -34
- data/lib/gd/gis/input/geojson.rb +0 -0
- data/lib/gd/gis/input/kml.rb +0 -0
- data/lib/gd/gis/input/shapefile.rb +0 -0
data/lib/gd/gis/layer_lines.rb
CHANGED
|
@@ -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 &&
|
data/lib/gd/gis/layer_points.rb
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
74
|
+
if idx.zero?
|
|
39
75
|
# ring exterior
|
|
40
76
|
img.filled_polygon(pts, @fill)
|
|
41
77
|
end
|
|
42
78
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|