mapwkt 1.0.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.
- data/lib/mapwkt/gmap/map.rb +140 -0
- data/lib/mapwkt/gmap/marker.rb +7 -0
- data/lib/mapwkt/gmap/overlay.rb +20 -0
- data/lib/mapwkt/gmap/polygon.rb +12 -0
- data/lib/mapwkt/gmap/polyline.rb +10 -0
- data/lib/mapwkt/wkt/geometry.rb +77 -0
- data/lib/mapwkt/wkt/line_string.rb +97 -0
- data/lib/mapwkt/wkt/point.rb +123 -0
- data/lib/mapwkt/wkt/polygon.rb +42 -0
- data/lib/mapwkt-safe.rb +17 -0
- data/lib/mapwkt.rb +44 -0
- metadata +56 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Map
|
4
|
+
def center
|
5
|
+
return @center if @center
|
6
|
+
return if self.overlays.empty?
|
7
|
+
|
8
|
+
n, s, e, w = nil
|
9
|
+
|
10
|
+
self.overlays.each do |o|
|
11
|
+
n = o.center.y if !n || o.center.y > n
|
12
|
+
s = o.center.y if !s || o.center.y < s
|
13
|
+
e = o.center.x if !e || o.center.x > e
|
14
|
+
w = o.center.x if !w || o.center.x < w
|
15
|
+
end
|
16
|
+
|
17
|
+
x = (e + w) / 2
|
18
|
+
y = (n + s) / 2
|
19
|
+
|
20
|
+
@center = MapWKT::Geometry::Point.new(y, x)
|
21
|
+
end
|
22
|
+
|
23
|
+
def center= (center)
|
24
|
+
return unless MapWKT::Geometry::Point === center
|
25
|
+
@center = center
|
26
|
+
end
|
27
|
+
|
28
|
+
def id
|
29
|
+
@id
|
30
|
+
end
|
31
|
+
|
32
|
+
def id= (id)
|
33
|
+
return unless id
|
34
|
+
raise(ArgumentError, "invalid HTML id: #{id.to_json}") unless id =~ /^[a-zA-Z][\w\d.:-]*$/
|
35
|
+
@id = id
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize (arg = {})
|
39
|
+
@overlays = []
|
40
|
+
|
41
|
+
self.options = case arg
|
42
|
+
when String then { id: arg }
|
43
|
+
when Hash then arg
|
44
|
+
else {}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def js_initialize
|
49
|
+
"mapwkt_#{self.object_id}_initialize()"
|
50
|
+
end
|
51
|
+
|
52
|
+
def js_output (arg = {})
|
53
|
+
self.options = case arg
|
54
|
+
when String then { id: arg }
|
55
|
+
when Hash then arg
|
56
|
+
else {}
|
57
|
+
end
|
58
|
+
|
59
|
+
raise(ArgumentError, "HMTL id is required") unless self.id
|
60
|
+
|
61
|
+
<<-JAVASCRIPT.gsub('new google.maps.LatLng','new p')
|
62
|
+
function mapwkt_#{self.object_id}_initialize ()
|
63
|
+
{
|
64
|
+
var p = google.maps.LatLng
|
65
|
+
var element = document.getElementById('#{self.id}')
|
66
|
+
var options = { center: new google.maps.LatLng(#{self.center.latitude_f},#{self.center.longitude_f}), mapTypeId: google.maps.MapTypeId.#{self.map_type_id}, zoom: #{self.zoom} }
|
67
|
+
var map = new google.maps.Map(element, options)
|
68
|
+
#{self.overlays.map {|obj| obj.js_output('map') }.join("\n ")}
|
69
|
+
}
|
70
|
+
JAVASCRIPT
|
71
|
+
end
|
72
|
+
|
73
|
+
def map_type_id
|
74
|
+
@map_type_id ||= 'ROADMAP'
|
75
|
+
end
|
76
|
+
|
77
|
+
def map_type_id= (map_type_id)
|
78
|
+
return unless map_type_id
|
79
|
+
@map_type_id = ([map_type_id.to_s.upcase] & %w:HYBRID ROADMAP SATELLITE TERRAIN:).first || 'ROADMAP'
|
80
|
+
end
|
81
|
+
|
82
|
+
def options
|
83
|
+
{
|
84
|
+
center: self.center,
|
85
|
+
id: self.id,
|
86
|
+
map_type_id: self.map_type_id,
|
87
|
+
zoom: self.zoom
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def options= (options)
|
92
|
+
options.symbolize_keys!
|
93
|
+
self.center = options[:center] || self.center
|
94
|
+
self.id = options[:id] || self.id
|
95
|
+
self.map_type_id = options[:map_type_id] || options[:mapTypeId] || self.map_type_id
|
96
|
+
self.zoom = options[:zoom] || self.zoom || 10
|
97
|
+
end
|
98
|
+
|
99
|
+
def overlays
|
100
|
+
self.refresh!
|
101
|
+
@overlays
|
102
|
+
end
|
103
|
+
|
104
|
+
def refresh!
|
105
|
+
return self if @refreshed
|
106
|
+
@refreshed = true
|
107
|
+
|
108
|
+
self.overlays.select! {|p| MapWKT::Overlay === p }
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def zoom
|
113
|
+
@zoom ||= 10
|
114
|
+
end
|
115
|
+
|
116
|
+
def zoom= (zoom)
|
117
|
+
return unless zoom
|
118
|
+
@zoom = [0,[zoom.to_i, 25].min].max
|
119
|
+
end
|
120
|
+
|
121
|
+
def << (obj)
|
122
|
+
overlays = case obj
|
123
|
+
when MapWKT::Geometry then [MapWKT::Overlay.new(obj)]
|
124
|
+
when MapWKT::Overlay then [obj]
|
125
|
+
else
|
126
|
+
raise(TypeError, "method `wkt' is not defined for #{obj.inspect}") unless obj.respond_to?(:wkt)
|
127
|
+
|
128
|
+
MapWKT::Geometry.parse_wkt(obj.wkt).map do |g|
|
129
|
+
{
|
130
|
+
MapWKT::Geometry::Point => MapWKT::Overlay::Marker,
|
131
|
+
MapWKT::Geometry::LineString => MapWKT::Overlay::Polyline,
|
132
|
+
MapWKT::Geometry::Polygon => MapWKT::Overlay::Polygon
|
133
|
+
}[g.class].new(g, obj)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
self.overlays.push(*overlays)
|
138
|
+
self
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Overlay::Marker < MapWKT::Overlay
|
4
|
+
def js_output (map_name = nil)
|
5
|
+
"new google.maps.Marker({#{" map: #{map_name}," if map_name} position: new google.maps.LatLng(#{self.geometry.latitude_f},#{self.geometry.longitude_f}) })"
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Overlay
|
4
|
+
def center
|
5
|
+
self.geometry.center
|
6
|
+
end
|
7
|
+
|
8
|
+
def geometry
|
9
|
+
@geometry
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize (geometry, source)
|
13
|
+
@geometry = geometry
|
14
|
+
@source = source
|
15
|
+
end
|
16
|
+
|
17
|
+
def source
|
18
|
+
@source
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Overlay::Polygon < MapWKT::Overlay
|
4
|
+
def js_output (map_name = nil)
|
5
|
+
paths = [self.geometry.perimeter, *self.geometry.lacunae].map do |g|
|
6
|
+
points = [*g.points, g.points.first]
|
7
|
+
"[#{points.map {|p| "new google.maps.LatLng(#{p.latitude_f},#{p.longitude_f})" }.join(?,)}]"
|
8
|
+
end.join(?,)
|
9
|
+
|
10
|
+
"new google.maps.Polygon({#{" map: #{map_name}," if map_name} paths: [#{paths}] })"
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Overlay::Polyline < MapWKT::Overlay
|
4
|
+
def js_output (map_name = nil)
|
5
|
+
points = self.geometry.open? ? self.geometry.points : [*self.geometry.points, self.geometry.points.first]
|
6
|
+
path = "[#{points.map {|p| "new google.maps.LatLng(#{p.latitude_f},#{p.longitude_f})" }.join(?,)}]"
|
7
|
+
|
8
|
+
"new google.maps.Polyline({#{" map: #{map_name}," if map_name} path: #{path} })"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Geometry
|
4
|
+
def self.parse_wkt (wkt_string)
|
5
|
+
# Remove extraneous whitespace.
|
6
|
+
s = wkt_string.to_s.upcase.strip.gsub(/\s*([),(])\s*/,'\1').gsub(/\s+/,' ')
|
7
|
+
|
8
|
+
case s
|
9
|
+
when /^POINT\(([\d\s.-]*?)\)$/
|
10
|
+
x, y = self.parse_x_y $1
|
11
|
+
[MapWKT::Geometry::Point.new(y,x)]
|
12
|
+
|
13
|
+
when /^LINESTRING\(([\d\s,.-]*?)\)$/
|
14
|
+
points = self.parse_points $1
|
15
|
+
[MapWKT::Geometry::LineString.new(*points)]
|
16
|
+
|
17
|
+
when /^POLYGON\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
|
18
|
+
perimeter, lacunae = self.parse_linestrings $1
|
19
|
+
[MapWKT::Geometry::Polygon.new(perimeter, *lacunae)]
|
20
|
+
|
21
|
+
when /^MULTIPOINT\(([\d\s,.-]*?)\)$/
|
22
|
+
self.parse_points $1
|
23
|
+
|
24
|
+
when /^MULTIPOINT\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
|
25
|
+
points_string = $1.gsub(/[()]/,'')
|
26
|
+
self.parse_points(points_string)
|
27
|
+
|
28
|
+
when /^MULTILINESTRING\((\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*)\)$/
|
29
|
+
self.parse_linestrings $1
|
30
|
+
|
31
|
+
when /^MULTIPOLYGON\((\(\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*\)(?:,\(\([\d\s,.-]*?\)(?:,\([\d\s,.-]*?\))*\))*)\)$/
|
32
|
+
self.parse_polygons $1
|
33
|
+
|
34
|
+
when /^GEOMETRYCOLLECTION\((.*?)\)$/
|
35
|
+
wkt_strings = $1.scan(/([A-Z]+\(.*?\))(?=,[A-Z]|$)/).flatten
|
36
|
+
wkt_strings.map {|wkt_string| self.parse_wkt(wkt_string) }.flatten
|
37
|
+
|
38
|
+
else
|
39
|
+
raise SyntaxError
|
40
|
+
end
|
41
|
+
|
42
|
+
rescue SyntaxError
|
43
|
+
raise SyntaxError, "not a valid WKT string: #{wkt_string.inspect}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.parse_polygons (polygons_string)
|
47
|
+
# Create Polygons from each "((x y, …), (x y, …))" in the polygons string.
|
48
|
+
polygons_string.scan(/\((\(.*?\))\)/).flatten.map do |linestrings_string|
|
49
|
+
perimeter, lacunae = self.parse_linestrings(linestrings_string)
|
50
|
+
MapWKT::Geometry::Polygon.new(perimeter, *lacunae)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.parse_linestrings (linestrings_string)
|
55
|
+
# Create LineStrings from each "(x y, …)" in the linestrings string.
|
56
|
+
linestrings_string.scan(/\((.*?)\)/).flatten.map do |points_string|
|
57
|
+
points = self.parse_points(points_string)
|
58
|
+
MapWKT::Geometry::LineString.new(*points)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.parse_points (points_string)
|
63
|
+
# Create Points from each "x y" in the points string.
|
64
|
+
points_string.split(?,).map do |x_y_string|
|
65
|
+
x, y = self.parse_x_y(x_y_string)
|
66
|
+
MapWKT::Geometry::Point.new(y,x)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.parse_x_y (x_y_string)
|
71
|
+
# Check the string.
|
72
|
+
raise SyntaxError unless x_y_string =~ /^(-?\d+(?:\.\d+)?)\s(-?\d+(?:\.\d+)?)$/
|
73
|
+
|
74
|
+
# Return the x and y values.
|
75
|
+
[$1, $2].map(&:to_f)
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Geometry::LineString < MapWKT::Geometry
|
4
|
+
# Returns a Point midway between the N/S- & E/W-most Points in the LineString.
|
5
|
+
def center
|
6
|
+
return if self.points.empty?
|
7
|
+
n, s, e, w = nil
|
8
|
+
|
9
|
+
self.points.each do |p|
|
10
|
+
n = p.y if !n || p.y > n
|
11
|
+
s = p.y if !s || p.y < s
|
12
|
+
e = p.x if !e || p.x > e
|
13
|
+
w = p.x if !w || p.x < w
|
14
|
+
end
|
15
|
+
|
16
|
+
x = (e + w) / 2
|
17
|
+
y = (n + s) / 2
|
18
|
+
|
19
|
+
Point.new(y, x)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns this LineString after closing its endpoints.
|
23
|
+
def close!
|
24
|
+
self.refresh! unless @refreshed
|
25
|
+
@closed = true
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns true if this LineString is closed, false otherwise.
|
30
|
+
def closed?
|
31
|
+
self.refresh!
|
32
|
+
@closed ||= false
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a new LineString with the same geographic Points as this LineString.
|
36
|
+
def dup
|
37
|
+
points = self.points.map(&:dup)
|
38
|
+
LineString(*points).tap {|ls| ls.close! if self.closed? }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a new LineString containing the given Points.
|
42
|
+
def initialize (*points)
|
43
|
+
@points = points
|
44
|
+
self.refresh!
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns false if this LineString is closed, true otherwise.
|
48
|
+
def open?
|
49
|
+
!self.closed?
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns this LineString after opening its endpoints.
|
53
|
+
def open!
|
54
|
+
self.refresh!
|
55
|
+
@closed = false
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the array of Points in this LineString.
|
60
|
+
def points
|
61
|
+
self.refresh!
|
62
|
+
@points
|
63
|
+
end
|
64
|
+
|
65
|
+
# Removes any non-Point objects from this LineString's #points array. If the
|
66
|
+
# first Point has been added to the end of the #points array, closes the
|
67
|
+
# LineString and removes the Point. Returns this LineString.
|
68
|
+
def refresh!
|
69
|
+
return self if @refreshed
|
70
|
+
@refreshed = true
|
71
|
+
|
72
|
+
self.points.select! {|p| MapWKT::Geometry::Point === p }
|
73
|
+
|
74
|
+
while (self.points.many?) && (self.points.last == self.points.first)
|
75
|
+
self.points.pop
|
76
|
+
@closed = true
|
77
|
+
end
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns a string representation of this LineString. ⤿ indicates an open
|
83
|
+
# LineString, while ⟲ indicates a closed LineString.
|
84
|
+
def to_s
|
85
|
+
points = self.points.join(", ")
|
86
|
+
marker = self.closed? ? ?⟲ : ?⤿
|
87
|
+
|
88
|
+
"#{marker} #{points} #{marker} "
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns this LineString's WKT representation, with latitudes and longitudes
|
92
|
+
# rounded to 7 decimal places.
|
93
|
+
def wkt
|
94
|
+
points = self.open? ? self.points : [*self.points, self.points.first]
|
95
|
+
"LINESTRING(#{points.map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})"
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Geometry::Point < MapWKT::Geometry
|
4
|
+
# Returns a new Point with the same latitude and longitude as this Point.
|
5
|
+
def center
|
6
|
+
self.dup
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns true if this Point lies in the eastern hemisphere, false otherwise.
|
10
|
+
def east?
|
11
|
+
self.longitude > 0
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if this Point lies on the equator, false otherwise.
|
15
|
+
def equator?
|
16
|
+
self.latitude == 0
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a new MapWKT::Geometry::Point with latitude and longitude normalized
|
20
|
+
# to fit within the range [-90,90] for latitude and (-180,180] for longitude.
|
21
|
+
def initialize (φ, λ)
|
22
|
+
# Check arguments.
|
23
|
+
if [φ, λ].all? {|arg| arg.respond_to?(:to_f) }
|
24
|
+
φ = φ.to_f
|
25
|
+
λ = λ.to_f
|
26
|
+
else
|
27
|
+
raise ArgumentError, "expected (latitude, longitude), got (#{φ.inspect}, #{λ.inspect})"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Normalize latitude (-90..90) and longitude (-179..180).
|
31
|
+
λ += 180 * (((φ / 90 + 1).floor / 2) % 2)
|
32
|
+
@y = 90 - (((90 + φ) % 360) - 180).abs
|
33
|
+
@x = self.pole? ? 0 : (λ - 180) % -360 + 180
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns this Point's latitude as a float, rounded to 7 decimal places.
|
37
|
+
def latitude
|
38
|
+
self.y.round(7)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns this Point's latitude as a string, rounded to 7 decimal places.
|
42
|
+
def latitude_f
|
43
|
+
sprintf("%.7f", self.latitude).gsub(/\.?0*$/,'')
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns this Point's latitude in degrees N/S, rounded to 7 decimal places.
|
47
|
+
def latitude_°
|
48
|
+
φ = self.latitude
|
49
|
+
direction = (φ == 0) ? "" : (φ > 0) ? "N" : "S"
|
50
|
+
|
51
|
+
sprintf("%.7f°%s", φ.abs, direction).gsub(/\.?0*(?=°)/,'')
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns this Point's longitude as a float, rounded to 7 decimal places.
|
55
|
+
def longitude
|
56
|
+
self.x.round(7)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns this Point's longitude as a string, rounded to 7 decimal places.
|
60
|
+
def longitude_f
|
61
|
+
sprintf("%.7f", self.longitude).gsub(/\.?0*$/,'')
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns this Point's longitude in degrees E/W, rounded to 7 decimal places.
|
65
|
+
def longitude_°
|
66
|
+
λ = self.longitude
|
67
|
+
direction = [0, 180].include?(λ) ? "" : (λ > 0) ? "E" : "W"
|
68
|
+
|
69
|
+
sprintf("%.7f°%s", λ.abs, direction).gsub(/\.?0*(?=°)/,'')
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns 1 if this Point is the north pole, -1 if it is the south pole, or nil
|
73
|
+
# if it is neither.
|
74
|
+
def pole?
|
75
|
+
return 1 if self.north_pole?
|
76
|
+
return -1 if self.south_pole?
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns true if this Point is the north pole.
|
80
|
+
def north_pole?
|
81
|
+
self.latitude == 90
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns true if this Point is the south pole.
|
85
|
+
def south_pole?
|
86
|
+
self.latitude == -90
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a string representation of this Point.
|
90
|
+
def to_s
|
91
|
+
"#{self.latitude_°} #{self.longitude_°}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns true if this Point lies in the western hemisphere, false otherwise.
|
95
|
+
def west?
|
96
|
+
self.longitude < 0
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns this Point's WKT representation, rounded to 7 decimal places.
|
100
|
+
def wkt
|
101
|
+
"POINT(#{self.longitude_f} #{self.latitude_f})"
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns this Point's longitude as a float.
|
105
|
+
def x
|
106
|
+
@x
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns this Point's latitude as a float.
|
110
|
+
def y
|
111
|
+
@y
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns true if this Point matches the other Point, within 7 decimal places.
|
115
|
+
def == (other)
|
116
|
+
[self.latitude, self.longitude] == [other.latitude, other.longitude]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns true if this Point matches the other Point exactly.
|
120
|
+
def === (other)
|
121
|
+
[self.x, self.y] == [other.x, other.y]
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MapWKT::Geometry::Polygon < MapWKT::Geometry
|
4
|
+
# Returns a Point midway between the N/S- & E/W-most Points in the perimeter.
|
5
|
+
def center
|
6
|
+
self.perimeter.center
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns a new MapWKT::Geometry::Polygon with the given outer perimeter and
|
10
|
+
# internal lacunae. If the given LineStrings were unclosed, closes them for
|
11
|
+
# use in the Polygon, but leaves the original LineStrings unchanged.
|
12
|
+
def initialize (perimeter, *lacunae)
|
13
|
+
@perimeter = perimeter.dup.close!
|
14
|
+
@lacunae = lacunae.map {|lacuna| lacuna.dup.close! }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns an array of LineStrings representing the geographical areas treated
|
18
|
+
# as lacunae in this Polygon's enclosed area. Does not return the objects
|
19
|
+
# themselves, nor the actual array containing them.
|
20
|
+
def lacunae
|
21
|
+
@lacunae.map(&:dup)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a LineString representing the geographical area treated as the
|
25
|
+
# outer perimeter of this Polygon's enclosed area. Does not return the actual
|
26
|
+
# LineString object used in this Polygon.
|
27
|
+
def perimeter
|
28
|
+
@perimeter.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a string representation of this Polygon. ⭓ indicates the perimeter
|
32
|
+
# LineString, while ⬠ indicates a lacuna LineString.
|
33
|
+
def to_s
|
34
|
+
"⭓ #{@perimeter.points.join(", ")} ⭓#{@lacunae.map {|lacuna| " | ⬠ #{lacuna.points.join(", ")} ⬠" }.join} "
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns this Polygon's WKT representation, with latitudes and longitudes
|
38
|
+
# rounded to 7 decimal places.
|
39
|
+
def wkt
|
40
|
+
"POLYGON((#{[*@perimeter.points, @perimeter.points.first].map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})#{@lacunae.map {|lacuna| ", (#{[*lacuna.points, lacuna.points.first].map {|p| "#{p.longitude_f} #{p.latitude_f}" }.join(", ")})" }.join })"
|
41
|
+
end
|
42
|
+
end
|
data/lib/mapwkt-safe.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module MapWKT
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'active_support/all'
|
6
|
+
|
7
|
+
require_relative 'mapwkt/gmap/overlay'
|
8
|
+
require_relative 'mapwkt/gmap/map'
|
9
|
+
require_relative 'mapwkt/gmap/marker'
|
10
|
+
require_relative 'mapwkt/gmap/polygon'
|
11
|
+
require_relative 'mapwkt/gmap/polyline'
|
12
|
+
|
13
|
+
require_relative 'mapwkt/wkt/geometry'
|
14
|
+
require_relative 'mapwkt/wkt/line_string'
|
15
|
+
require_relative 'mapwkt/wkt/point'
|
16
|
+
require_relative 'mapwkt/wkt/polygon'
|
17
|
+
end
|
data/lib/mapwkt.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
Geometry = Class.new
|
4
|
+
Map = Class.new
|
5
|
+
Overlay = Class.new
|
6
|
+
|
7
|
+
LineString = Class.new(Geometry)
|
8
|
+
Point = Class.new(Geometry)
|
9
|
+
Polygon = Class.new(Geometry)
|
10
|
+
|
11
|
+
Marker = Class.new(Overlay)
|
12
|
+
PolygonOverlay = Class.new(Overlay)
|
13
|
+
Polyline = Class.new(Overlay)
|
14
|
+
|
15
|
+
# Register the class names in the top-level namespace.
|
16
|
+
[
|
17
|
+
Geometry, LineString, Map, Marker, Overlay,
|
18
|
+
Point, Polygon, PolygonOverlay, Polyline
|
19
|
+
].map(&:name)
|
20
|
+
|
21
|
+
# Create the namespaced constants pointing to the classes.
|
22
|
+
module MapWKT
|
23
|
+
Geometry = ::Geometry
|
24
|
+
Map = ::Map
|
25
|
+
Overlay = ::Overlay
|
26
|
+
|
27
|
+
class Geometry
|
28
|
+
LineString = ::LineString
|
29
|
+
Point = ::Point
|
30
|
+
Polygon = ::Polygon
|
31
|
+
end
|
32
|
+
|
33
|
+
class Overlay
|
34
|
+
Marker = ::Marker
|
35
|
+
Polygon = ::PolygonOverlay
|
36
|
+
Polyline = ::Polyline
|
37
|
+
end
|
38
|
+
|
39
|
+
require_relative 'mapwkt-safe'
|
40
|
+
end
|
41
|
+
|
42
|
+
def Point (*args) Point.new(*args) end
|
43
|
+
def LineString (*args) LineString.new(*args) end
|
44
|
+
def Polygon (*args) Polygon.new(*args) end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mapwkt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jesse Sielaff
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: .
|
15
|
+
email: jesse.sielaff@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ./lib/mapwkt/gmap/map.rb
|
21
|
+
- ./lib/mapwkt/gmap/marker.rb
|
22
|
+
- ./lib/mapwkt/gmap/overlay.rb
|
23
|
+
- ./lib/mapwkt/gmap/polygon.rb
|
24
|
+
- ./lib/mapwkt/gmap/polyline.rb
|
25
|
+
- ./lib/mapwkt/wkt/geometry.rb
|
26
|
+
- ./lib/mapwkt/wkt/line_string.rb
|
27
|
+
- ./lib/mapwkt/wkt/point.rb
|
28
|
+
- ./lib/mapwkt/wkt/polygon.rb
|
29
|
+
- ./lib/mapwkt-safe.rb
|
30
|
+
- ./lib/mapwkt.rb
|
31
|
+
homepage:
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.23
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: An object library for converting Ruby objects with WKT to JavaScript for
|
55
|
+
Google Maps.
|
56
|
+
test_files: []
|