ruby_kml 0.1.7

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.
Files changed (49) hide show
  1. data/LICENSE +7 -0
  2. data/README.md +34 -0
  3. data/Rakefile +52 -0
  4. data/examples/melbourne-stations.kml +18 -0
  5. data/lib/kml/color_style.rb +34 -0
  6. data/lib/kml/container.rb +42 -0
  7. data/lib/kml/document.rb +46 -0
  8. data/lib/kml/feature.rb +185 -0
  9. data/lib/kml/folder.rb +29 -0
  10. data/lib/kml/geometry.rb +102 -0
  11. data/lib/kml/ground_overlay.rb +18 -0
  12. data/lib/kml/hot_spot.rb +31 -0
  13. data/lib/kml/icon.rb +15 -0
  14. data/lib/kml/icon_style.rb +52 -0
  15. data/lib/kml/lat_lon_box.rb +36 -0
  16. data/lib/kml/line_string.rb +40 -0
  17. data/lib/kml/line_style.rb +15 -0
  18. data/lib/kml/linear_ring.rb +67 -0
  19. data/lib/kml/link.rb +51 -0
  20. data/lib/kml/look_at.rb +28 -0
  21. data/lib/kml/model.rb +40 -0
  22. data/lib/kml/multi_geometry.rb +26 -0
  23. data/lib/kml/object.rb +37 -0
  24. data/lib/kml/overlay.rb +21 -0
  25. data/lib/kml/placemark.rb +60 -0
  26. data/lib/kml/point.rb +65 -0
  27. data/lib/kml/poly_style.rb +16 -0
  28. data/lib/kml/polygon.rb +91 -0
  29. data/lib/kml/screen_overlay.rb +61 -0
  30. data/lib/kml/snippet.rb +25 -0
  31. data/lib/kml/style.rb +23 -0
  32. data/lib/kml/style_map.rb +39 -0
  33. data/lib/kml/style_selector.rb +7 -0
  34. data/lib/kml/version.rb +9 -0
  35. data/lib/kml_file.rb +55 -0
  36. data/lib/ruby_kml.rb +8 -0
  37. data/ruby_kml.gemspec +14 -0
  38. data/test/cdata_and_snippet.kml +21 -0
  39. data/test/ground_overlays.kml +25 -0
  40. data/test/kml/point_test.rb +10 -0
  41. data/test/kml_file_test.rb +255 -0
  42. data/test/paths.kml +33 -0
  43. data/test/polygon.kml +20 -0
  44. data/test/polygon_inner.kml +25 -0
  45. data/test/polygon_style.kml +24 -0
  46. data/test/simple_placemark.kml +12 -0
  47. data/test/style_map.kml +40 -0
  48. data/test/test_helper.rb +11 -0
  49. metadata +124 -0
@@ -0,0 +1,23 @@
1
+ module KML
2
+ # A Style defines an addressable style group that can be referenced by StyleMaps and Features. Styles affect
3
+ # how Geometry is presented in the 3D viewer and how Features appear in the Places panel of the List view.
4
+ # Shared styles are collected in a Document and must have an id defined for them so that they can be referenced
5
+ # by the individual Features that use them.
6
+ class Style < StyleSelector
7
+ attr_accessor :icon_style
8
+ attr_accessor :label_style
9
+ attr_accessor :line_style
10
+ attr_accessor :poly_style
11
+ attr_accessor :balloon_style
12
+ attr_accessor :list_style
13
+
14
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
15
+ xm.Style(:id => id) {
16
+ %w(Icon Label Line Poly Balloon List).each do |name|
17
+ field = "#{name.downcase}_style".to_sym
18
+ self.__send__(field).render(xm) unless self.__send__(field).nil?
19
+ end
20
+ }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ # Source file that defines a StyleMap element
2
+ #
3
+ # <StyleMap id="ID">
4
+ # <!-- extends StyleSelector -->
5
+ # <!-- elements specific to StyleMap -->
6
+ # <Pair id="ID">
7
+ # <key>normal</key> <!-- kml:styleStateEnum: normal or highlight
8
+ # <styleUrl>...</styleUrl> <!-- anyURI -->
9
+ # </Pair>
10
+ # </StyeMap>
11
+
12
+ module KML #:nodoc:
13
+ # A StyleMap maps between two different icon styles. Typically a StyleMap element is used to provide
14
+ # separate normal and highlighted styles for a placemark, so that the highlighted version appears when
15
+ # the user mouses over the icon in Google Earth.
16
+ class StyleMap < StyleSelector
17
+ # Key/styleUrl pairs
18
+ attr_accessor :pairs
19
+
20
+ # Get the pairs Hash. Each key/value pair maps a mode (normal or highlight) to the predefined style URL.
21
+ # Each pair contains a key and a value which references the style. For referenced style elements that
22
+ # are local to the KML document, a simple # referencing is used. For styles that are contained in
23
+ # external files, use a full URL along with # referencing.
24
+ def pairs
25
+ @pairs ||= {}
26
+ end
27
+
28
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
29
+ xm.StyleMap(:id => id) {
30
+ pairs.each do |key, value|
31
+ xm.Pair {
32
+ xm.key(key)
33
+ xm.styleUrl(value)
34
+ }
35
+ end
36
+ }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ module KML
2
+ class StyleSelector < KML::Object
3
+ end
4
+ end
5
+
6
+ require 'kml/style'
7
+ require 'kml/style_map'
@@ -0,0 +1,9 @@
1
+ module KML#:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 7
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ # The KMLFile class is the top level class for constructing KML files. To create a new KML file
2
+ # create a KMLFile instance and add KML objects to its objects. For example:
3
+ #
4
+ # f = KMLFile.new
5
+ # f.objects << Placemark.new(
6
+ # :name => 'Simple placemark',
7
+ # :description => 'Attached to the ground. Intelligently places itself at the height of the underlying terrain.',
8
+ # :geometry => Point.new(:coordinates=>'-122.0822035425683,37.42228990140251,0')
9
+ # )
10
+ # puts f.render
11
+ class KMLFile
12
+ # The objects in the KML file
13
+ def objects
14
+ @objects ||= []
15
+ end
16
+ alias :features :objects
17
+
18
+ # Render the KML file
19
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
20
+ xm.instruct!
21
+ xm.kml(:xmlns => 'http://earth.google.com/kml/2.1'){
22
+ objects.each { |o| o.render(xm) }
23
+ }
24
+ end
25
+
26
+ def save filename
27
+ File.open(filename, 'w') { |f| f.write render }
28
+ end
29
+
30
+ # Parse the KML file using nokogiri
31
+ # <kml xmlns="http://www.opengis.net/kml/2.2">
32
+ # <NetworkLinkControl> ... </NetworkLinkControl>
33
+ # <!-- 0 or 1 Feature elements -->
34
+ # </kml>
35
+ def self.parse(io)
36
+ kml = self.new
37
+ doc = Nokogiri::XML::Document.parse(io)
38
+ doc.root.element_children.each do |cld|
39
+ case cld.name
40
+ when 'Document'
41
+ kml.features << KML::Document.parse(cld)
42
+ when 'Folder'
43
+ when 'NetworkLink'
44
+ when 'Placemark'
45
+ when 'GroundOverlay'
46
+ when 'PhotoOverlay'
47
+ when 'ScreenOverlay'
48
+ end
49
+ end
50
+ kml
51
+ end
52
+
53
+ end
54
+
55
+ require 'kml/object'
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+ require 'nokogiri'
4
+
5
+ require 'kml_file'
6
+
7
+ class InvalidKMLError < StandardError
8
+ end
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.version = "0.1.7"
3
+ s.date = "2012-05-07"
4
+ s.name = "ruby_kml"
5
+ s.summary = "Generate KML files with ruby"
6
+ s.email = ""
7
+ s.homepage = "http://github.com/schleyfox/ruby_kml"
8
+ s.description = "Generate KML files with ruby"
9
+ s.has_rdoc = false
10
+ s.authors = ["aeden, schleyfox, xaviershay, andykram, IanVaughan"]
11
+ s.files = Dir['**/**']
12
+ s.add_dependency('nokogiri')
13
+ s.add_dependency('builder')
14
+ end
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <kml xmlns="http://earth.google.com/kml/2.1">
3
+ <Document>
4
+ <name>Document with CDATA example</name>
5
+ <Snippet>Document level snippet2</Snippet>
6
+ <Placemark>
7
+ <name>CDATA example</name>
8
+ <description>
9
+ <![CDATA[<h1>CDATA Tags are useful!</h1>
10
+ <p><font color="red">Text is <i>more readable</i> and
11
+ <b>easier to write</b> when you can avoid using entity
12
+ references.</font></p>
13
+ ]]>
14
+ </description>
15
+ <Snippet>Example of a snippet2</Snippet>
16
+ <Point>
17
+ <coordinates>-122.0822035425683,37.4228,0</coordinates>
18
+ </Point>
19
+ </Placemark>
20
+ </Document>
21
+ </kml>
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <kml xmlns="http://earth.google.com/kml/2.1">
3
+ <Folder>
4
+ <name>Ground Overlays</name>
5
+ <description>
6
+ <![CDATA[Examples of ground overlays]]>
7
+ </description>
8
+ <GroundOverlay>
9
+ <name>Large-scale overlay on terrain</name>
10
+ <description>
11
+ <![CDATA[Overlay shows Mount Etna erupting on July 13th, 2001.]]>
12
+ </description>
13
+ <Icon>
14
+ <href>http://code.google.com/apis/kml/documentation/etna.jpg</href>
15
+ </Icon>
16
+ <LatLonBox>
17
+ <north>37.91904192681665</north>
18
+ <south>37.46543388598137</south>
19
+ <east>15.35832653742206</east>
20
+ <west>14.60128369746704</west>
21
+ <rotation/>
22
+ </LatLonBox>
23
+ </GroundOverlay>
24
+ </Folder>
25
+ </kml>
@@ -0,0 +1,10 @@
1
+ require "#{File.dirname(__FILE__)}/../test_helper"
2
+
3
+ class KML::PointTest < Test::Unit::TestCase
4
+ include KML
5
+
6
+ def test_allows_coordinates_to_be_specified_with_a_hash
7
+ point = Point.new(:coordinates => {:lat => 10, :lng => 20, :alt => 30})
8
+ assert_equal [20, 10, 30], point.coordinates
9
+ end
10
+ end
@@ -0,0 +1,255 @@
1
+ require './test/test_helper'
2
+
3
+ class KMLFileTest < Test::Unit::TestCase
4
+ include KML
5
+
6
+ # This also tests the stripping of coordinates
7
+ def test_placemark
8
+ kml = KMLFile.new
9
+ kml.objects << Placemark.new(
10
+ :name => 'Simple placemark',
11
+ :description => 'Attached to the ground. Intelligently places itself at the height of the underlying terrain.',
12
+ :geometry => Point.new(:coordinates=>' -122.0822035425683,37.42228990140251,0 ')
13
+ )
14
+ assert_equal File.read('test/simple_placemark.kml'), kml.render
15
+ end
16
+
17
+ def test_cdata_description
18
+ description = <<-DESC
19
+ <h1>CDATA Tags are useful!</h1>
20
+ <p><font color="red">Text is <i>more readable</i> and
21
+ <b>easier to write</b> when you can avoid using entity
22
+ references.</font></p>
23
+ DESC
24
+
25
+ kml = KMLFile.new
26
+ document = Document.new(
27
+ :name => 'Document with CDATA example',
28
+ :snippet => Snippet.new("Document level snippet")
29
+ )
30
+ document.features << Placemark.new(
31
+ :name => 'CDATA example',
32
+ :description => description,
33
+ :snippet => Snippet.new("Example of a snippet"),
34
+ :geometry => Point.new(:coordinates=>'-122.0822035425683,37.4228,0')
35
+ )
36
+ kml.objects << document
37
+ assert_equal File.read('test/cdata_and_snippet.kml'), kml.render
38
+ end
39
+
40
+ def test_ground_overlays
41
+ kml = KMLFile.new
42
+ folder = Folder.new(
43
+ :name => 'Ground Overlays',
44
+ :description => 'Examples of ground overlays'
45
+ )
46
+ folder.features << GroundOverlay.new(
47
+ :name => 'Large-scale overlay on terrain',
48
+ :description => 'Overlay shows Mount Etna erupting on July 13th, 2001.',
49
+ :icon => Icon.new(:href => 'http://code.google.com/apis/kml/documentation/etna.jpg'),
50
+ :lat_lon_box => LatLonBox.new(
51
+ :north => 37.91904192681665,
52
+ :south => 37.46543388598137,
53
+ :east => 15.35832653742206,
54
+ :west => 14.60128369746704,
55
+ :rotation => -0.1556640799496235
56
+ )
57
+ )
58
+ kml.objects << folder
59
+ assert_equal File.read('test/ground_overlays.kml'), kml.render
60
+ end
61
+
62
+ def test_paths
63
+ kml = KMLFile.new
64
+ kml.objects << Document.new(
65
+ :name => 'Paths',
66
+ :description => 'Examples of paths. Note that the tessellate tag is by default
67
+ set to 0. If you want to create tessellated lines, they must be authored
68
+ (or edited) directly in KML.',
69
+ :styles => [
70
+ Style.new(
71
+ :id => 'yellowLineGreenPoly',
72
+ :line_style => LineStyle.new(:color => '7f00ffff', :width => 4),
73
+ :poly_style => PolyStyle.new(:color => '7f00ff00')
74
+ )
75
+ ],
76
+ :features => [
77
+ Placemark.new(
78
+ :name => 'Absolute Extruded',
79
+ :description => 'Transparent green wall with yellow outlines',
80
+ :style_url => '#yellowLineGreenPoly',
81
+ :geometry => LineString.new(
82
+ :extrude => true,
83
+ :tessellate => true,
84
+ :altitude_mode => 'absolute',
85
+ :coordinates => '-112.2550785337791,36.07954952145647,2357
86
+ -112.2549277039738,36.08117083492122,2357
87
+ -112.2552505069063,36.08260761307279,2357
88
+ -112.2564540158376,36.08395660588506,2357
89
+ -112.2580238976449,36.08511401044813,2357
90
+ -112.2595218489022,36.08584355239394,2357
91
+ -112.2608216347552,36.08612634548589,2357
92
+ -112.262073428656,36.08626019085147,2357
93
+ -112.2633204928495,36.08621519860091,2357
94
+ -112.2644963846444,36.08627897945274,2357
95
+ -112.2656969554589,36.08649599090644,2357'
96
+ )
97
+ )
98
+ ]
99
+ )
100
+ assert_equal File.read('test/paths.kml'), kml.render
101
+ end
102
+
103
+ def test_polygon
104
+ kml = KMLFile.new
105
+ kml.objects << Placemark.new(
106
+ :name => 'The Pentagon',
107
+ :geometry => Polygon.new(
108
+ :extrude => true,
109
+ :altitude_mode => 'relativeToGround',
110
+ :outer_boundary_is => LinearRing.new(
111
+ :coordinates => '-77.05788457660967,38.87253259892824,100
112
+ -77.05465973756702,38.87291016281703,100
113
+ -77.05315536854791,38.87053267794386,100
114
+ -77.05552622493516,38.868757801256,100
115
+ -77.05844056290393,38.86996206506943,100
116
+ -77.05788457660967,38.87253259892824,100'
117
+ ),
118
+ :inner_boundary_is => LinearRing.new(
119
+ :coordinates => '-77.05668055019126,38.87154239798456,100
120
+ -77.05542625960818,38.87167890344077,100
121
+ -77.05485125901024,38.87076535397792,100
122
+ -77.05577677433152,38.87008686581446,100
123
+ -77.05691162017543,38.87054446963351,100
124
+ -77.05668055019126,38.87154239798456,100'
125
+ )
126
+ )
127
+ )
128
+ assert_equal File.read('test/polygon.kml'), kml.render
129
+ end
130
+
131
+ def test_polygon_with_multiple_inner_boundaries
132
+ kml = KMLFile.new
133
+ kml.objects << Placemark.new(
134
+ :name => 'The Pentagon',
135
+ :geometry => Polygon.new(
136
+ :extrude => true,
137
+ :altitude_mode => 'relativeToGround',
138
+ :outer_boundary_is => LinearRing.new(
139
+ :coordinates => '-77.05788457660967,38.87253259892824,100
140
+ -77.05465973756702,38.87291016281703,100
141
+ -77.05315536854791,38.87053267794386,100
142
+ -77.05552622493516,38.868757801256,100
143
+ -77.05844056290393,38.86996206506943,100
144
+ -77.05788457660967,38.87253259892824,100'
145
+ ),
146
+ :inner_boundary_is => [
147
+ LinearRing.new(
148
+ :coordinates => '-77.05668055019126,38.87154239798456,100
149
+ -77.05542625960818,38.87167890344077,100
150
+ -77.05485125901024,38.87076535397792,100
151
+ -77.05577677433152,38.87008686581446,100
152
+ -77.05691162017543,38.87054446963351,100
153
+ -77.05668055019126,38.87154239798456,100'
154
+ ),
155
+ LinearRing.new(
156
+ :coordinates => '-77.05668055019126,38.87154239798456,100
157
+ -77.05542625960818,38.87167890344077,100
158
+ -77.05485125901024,38.87076535397792,100
159
+ -77.05577677433152,38.87008686581446,100
160
+ -77.05691162017543,38.87054446963351,100
161
+ -77.05668055019126,38.87154239798456,100'
162
+ )
163
+ ]
164
+ )
165
+ )
166
+ assert_equal File.read('test/polygon_inner.kml'), kml.render
167
+ end
168
+
169
+ def test_geometry_styles
170
+ kml = KMLFile.new
171
+ kml.objects << Style.new(
172
+ :id => "transBluePoly",
173
+ :line_style => LineStyle.new(
174
+ :width => 1.5
175
+ ),
176
+ :poly_style => PolyStyle.new(
177
+ :color => '7dff0000'
178
+ )
179
+ )
180
+ kml.objects << Placemark.new(
181
+ :name => 'Building 41',
182
+ :style_url => '#transBluePoly',
183
+ :geometry => Polygon.new(
184
+ :extrude => true,
185
+ :altitude_mode => 'relativeToGround',
186
+ :outer_boundary_is => LinearRing.new(
187
+ :coordinates => '-122.0857412771483,37.42227033155257,17
188
+ -122.0858169768481,37.42231408832346,17
189
+ -122.085852582875,37.42230337469744,17
190
+ -122.0858799945639,37.42225686138789,17
191
+ -122.0858860101409,37.4222311076138,17
192
+ -122.0858069157288,37.42220250173855,17
193
+ -122.0858379542653,37.42214027058678,17
194
+ -122.0856732640519,37.42208690214408,17
195
+ -122.0856022926407,37.42214885429042,17
196
+ -122.0855902778436,37.422128290487,17
197
+ -122.0855841672237,37.42208171967246,17
198
+ -122.0854852065741,37.42210455874995,17
199
+ -122.0855067264352,37.42214267949824,17
200
+ -122.0854430712915,37.42212783846172,17
201
+ -122.0850990714904,37.42251282407603,17
202
+ -122.0856769818632,37.42281815323651,17
203
+ -122.0860162273783,37.42244918858722,17
204
+ -122.0857260327004,37.42229239604253,17
205
+ -122.0857412771483,37.42227033155257,17'
206
+ )
207
+ )
208
+ )
209
+
210
+ assert_equal File.read('test/polygon_style.kml'), kml.render
211
+ end
212
+
213
+ def test_style_map
214
+ kml = KMLFile.new
215
+ kml.objects << Document.new(
216
+ :name => 'Highlighted Icon',
217
+ :description => 'Place your mouse over the icon to see it display the new icon',
218
+ :styles => [
219
+ Style.new(
220
+ :id => "highlightPlacemark",
221
+ :icon_style => IconStyle.new(
222
+ :icon => Icon.new(
223
+ :href => "http://maps.google.com/mapfiles/kml/paddle/red-stars.png"
224
+ )
225
+ )
226
+ ),
227
+ Style.new(
228
+ :id => "normalPlacemark",
229
+ :icon_style => IconStyle.new(
230
+ :icon => Icon.new(
231
+ :href => "http://maps.google.com/mapfiles/kml/paddle/wht-blank.png"
232
+ )
233
+ )
234
+ ),
235
+ StyleMap.new(
236
+ :id => 'exampleStyleMap',
237
+ :pairs => {
238
+ 'normal' => '#normalPlacemark',
239
+ 'highlight' => '#highlightPlacemark'
240
+ }
241
+ )
242
+ ],
243
+ :features => [
244
+ Placemark.new(
245
+ :name => 'Roll over this icon',
246
+ :style_url => '#exampleStyleMap',
247
+ :geometry => Point.new(
248
+ :coordinates => '-122.0856545755255,37.42243077405461,0'
249
+ )
250
+ )
251
+ ]
252
+ )
253
+ assert_equal File.read('test/style_map.kml'), kml.render
254
+ end
255
+ end