schleyfox-ruby_kml 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ module KML #:nodoc:
2
+ # Specifies where the top, bottom, right, and left sides of a bounding box for the ground overlay are aligned. Values for
3
+ # +north+, +south+, +east+, and +west+ are required.
4
+ #
5
+ # * +north+ (required) Specifies the latitude of the north edge of the bounding box, in decimal degrees from 0 to ±90.
6
+ # * +south+ (required) Specifies the latitude of the south edge of the bounding box, in decimal degrees from 0 to ±90.
7
+ # * +east+ (required) Specifies the longitude of the east edge of the bounding box, in decimal degrees from 0 to ±180.
8
+ # (For overlays that overlap the meridian of 180° longitude, values can extend beyond that range.)
9
+ # * +west+ (required) Specifies the longitude of the west edge of the bounding box, in decimal degrees from 0 to ±180.
10
+ # (For overlays that overlap the meridian of 180° longitude, values can extend beyond that range.)
11
+ # * +rotation+ (optional) specifies a rotation of the overlay about its center, in degrees. Values can be ±180. The
12
+ # default is 0 (north). Rotations are specified in a clockwise direction.
13
+
14
+ class LatLonBox < KML::Object
15
+ attr_accessor :north
16
+ attr_accessor :south
17
+ attr_accessor :east
18
+ attr_accessor :west
19
+ attr_accessor :rotation
20
+
21
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
22
+ raise InvalidKMLError, "LatLonBox.north is required" if north.nil?
23
+ raise InvalidKMLError, "LatLonBox.south is required" if south.nil?
24
+ raise InvalidKMLError, "LatLonBox.east is required" if east.nil?
25
+ raise InvalidKMLError, "LatLonBox.west is required" if west.nil?
26
+
27
+ xm.LatLonBox {
28
+ xm.north(north)
29
+ xm.south(south)
30
+ xm.east(east)
31
+ xm.west(west)
32
+ xm.rotation unless rotation.nil?
33
+ }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module KML #:nodoc:
2
+ # Defines a connected set of line segments. Use LineStyle to specify the color, color mode, and width of the line.
3
+ # When a LineString is extruded, the line is extended to the ground, forming a polygon that looks somewhat like a wall.
4
+ # For extruded LineStrings, the line itself uses the current LineStyle, and the extrusion uses the current PolyStyle.
5
+ # See the <a href="http://earth.google.com/kml/kml_tut.html">KML Tutorial</a> for examples of LineStrings (or paths).
6
+ class LineString < Geometry
7
+
8
+ # Two or more coordinate tuples, each consisting of floating point values for longitude, latitude, and altitude.
9
+ # The altitude component is optional.
10
+ def coordinates
11
+ @coordinates
12
+ end
13
+
14
+ # Set the coordinates. When specifying as a String, insert a space or linebreak between tuples. Do not include spaces
15
+ # within a tuple.
16
+ def coordinates=(c)
17
+ case c
18
+ when String
19
+ @coordinates = c.split(/\s+/).collect { |coord| coord.split(',') }
20
+ when Array
21
+ c.each do |coord_array|
22
+ unless coord_array.is_a?(Array)
23
+ raise ArgumentError, "If set with an array, coordinates must be specified as an array of arrays"
24
+ end
25
+ end
26
+ @coordinates = c
27
+ else
28
+ raise ArgumentError, "Coordinates must either be a String or an Array of Arrays"
29
+ end
30
+ end
31
+
32
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
33
+ raise ArgumentError, "Coordinates required" if coordinates.nil?
34
+ xm.LineString {
35
+ super
36
+ xm.coordinates(coordinates.collect { |c| c.join(',') }.join(" "))
37
+ }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module KML
2
+ # Specifies the drawing style (color, color mode, and line width) for all line geometry. Line geometry includes the
3
+ # outlines of outlined polygons and the extruded "tether" of Placemark icons (if extrusion is enabled).
4
+ class LineStyle < ColorStyle
5
+ # Width of the line, in pixels.
6
+ attr_accessor :width
7
+
8
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
9
+ xm.LineStyle {
10
+ super
11
+ xm.width(width) unless width.nil?
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,49 @@
1
+ # Source code for producing a LinearRing element:
2
+ #
3
+ # <LinearRing id="ID">
4
+ # <!-- specific to LinearRing -->
5
+ # <extrude>0</extrude> <!-- boolean -->
6
+ # <tessellate>0</tessellate> <!-- boolean -->
7
+ # <altitudeMode>clampToGround</altitudeMode>
8
+ # <!-- kml:altitudeModeEnum: clampToGround, relativeToGround, or absolute -->
9
+ # <coordinates>...</coordinates> <!-- lon,lat[,alt] tuples -->
10
+ # </LinearRing>
11
+
12
+ module KML #:nodoc:
13
+ # Defines a closed line string, typically the outer boundary of a Polygon. Optionally, a LinearRing can also
14
+ # be used as the inner boundary of a Polygon to create holes in the Polygon. A Polygon can contain multiple
15
+ # LinearRing instances used as inner boundaries.
16
+ class LinearRing < Geometry
17
+ # Four or more tuples, each consisting of floating point values for longitude, latitude, and altitude.
18
+ # The altitude component is optional. Do not include spaces within a tuple. The last coordinate must be
19
+ # the same as the first coordinate. Coordinates are expressed in decimal degrees only.
20
+ def coordinates
21
+ @coordinates
22
+ end
23
+
24
+ # Set the coordinates
25
+ def coordinates=(c)
26
+ case c
27
+ when String
28
+ @coordinates = c.split(/\s+/).collect { |coord| coord.split(',') }
29
+ when Array
30
+ c.each do |coord_array|
31
+ unless coord_array.is_a?(Array)
32
+ raise ArgumentError, "If set with an array, coordinates must be specified as an array of arrays"
33
+ end
34
+ end
35
+ @coordinates = c
36
+ else
37
+ raise ArgumentError, "Coordinates must either be a String or an Array of Arrays"
38
+ end
39
+ end
40
+
41
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
42
+ raise ArgumentError, "Coordinates required" if coordinates.nil?
43
+ xm.LinearRing {
44
+ super
45
+ xm.coordinates(coordinates.collect { |c| c.join(',') }.join(" "))
46
+ }
47
+ end
48
+ end
49
+ end
data/lib/kml/link.rb ADDED
@@ -0,0 +1,51 @@
1
+ module KML #:nodoc:
2
+ # Link specifies the location of any of the following:
3
+ #
4
+ # * KML files fetched by network links
5
+ # * Image files used by icons in icon styles, ground overlays, and screen overlays
6
+ # * Model files used in the Model element
7
+ #
8
+ # The file is conditionally loaded and refreshed, depending on the refresh parameters supplied here.
9
+ # Two different sets of refresh parameters can be specified: one set is based on time (+refresh_mode+ and
10
+ # +refresh_interval+) and one is based on the current "camera" view (+view_refresh_mode+ and
11
+ # +view_refresh_time+). In addition, Link specifies whether to scale the bounding box parameters that
12
+ # are sent to the server (+view_bound_scale+ and provides a set of optional viewing parameters that can
13
+ # be sent to the server (+view_format+) as well as a set of optional parameters containing version and
14
+ # language information.
15
+ #
16
+ # When a file is fetched, the URL that is sent to the server is composed of three pieces of information:
17
+ #
18
+ # * the +href+ (Hypertext Reference) that specifies the file to load.
19
+ # * an arbitrary format string that is created from (a) parameters that you specify in +view_format+ or
20
+ # (b) bounding box parameters (this is the default and is used if no +view_format+ is specified).
21
+ # * a second format string that is specified in +http_query+.
22
+ #
23
+ # If the file specified in +href+ is a local file, +view_format+ and +http_query+ are not used.
24
+ class Link < KML::Object
25
+ attr_accessor :href
26
+ attr_accessor :refresh_mode
27
+ attr_accessor :refresh_interval
28
+ attr_accessor :view_refresh_mode
29
+ attr_accessor :view_refresh_time
30
+ attr_accessor :view_bound_scale
31
+ attr_accessor :view_format
32
+ attr_accessor :http_query
33
+
34
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
35
+ raise InvalidKMLError, "Link.href must be specified" if href.nil?
36
+ xm.Link {
37
+ self.elements.each do |a|
38
+ xm.__send__(a, self.__send__(a)) unless self.__send__(a).nil?
39
+ end
40
+ }
41
+ end
42
+
43
+ protected
44
+ def elements
45
+ [
46
+ :href, :refresh_mode, :refresh_interval, :view_refresh_mode, :view_refresh_time,
47
+ :view_bound_scale, :view_format, :http_query
48
+ ]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # <LookAt id="ID">
2
+ # <longitude></longitude> <!-- kml:angle180 -->
3
+ # <latitude></latitude> <!-- kml:angle90 -->
4
+ # <altitude>0</altitude> <!-- double -->
5
+ # <range></range> <!-- double -->
6
+ # <tilt>0</tilt> <!-- float -->
7
+ # <heading>0</heading> <!-- float -->
8
+ # <altitudeMode>clampToGround</altitudeMode>
9
+ # <!--kml:altitudeModeEnum:clampToGround, relativeToGround, absolute -->
10
+ # </LookAt>
11
+ module KML
12
+ class LookAt < KML::Object
13
+ attr_accessor :longitude
14
+ attr_accessor :latitude
15
+ attr_accessor :altitude
16
+ attr_accessor :range
17
+ attr_accessor :tilt
18
+ attr_accessor :heading
19
+ attr_accessor :altitude_mode
20
+ end
21
+ end
data/lib/kml/model.rb ADDED
@@ -0,0 +1,4 @@
1
+ module KML
2
+ class Model < Geometry
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module KML
2
+ class MultiGeometry < Geometry
3
+
4
+ end
5
+ end
data/lib/kml/object.rb ADDED
@@ -0,0 +1,29 @@
1
+ module KML #:nodoc:
2
+ # Base class for all KML objects
3
+ class Object
4
+ # The KML object ID
5
+ attr_accessor :id
6
+
7
+ # Initialize the object, optionally passing a Hash of attributes to set.
8
+ def initialize(attributes=nil)
9
+ if attributes
10
+ case attributes
11
+ when Hash
12
+ attributes.each do |name, value|
13
+ self.__send__("#{name}=".to_sym, value)
14
+ end
15
+ else
16
+ raise ArgumentError, "Attributes must be specified as a Hash"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'kml/feature'
24
+ require 'kml/geometry'
25
+ require 'kml/color_style'
26
+ require 'kml/style_selector'
27
+ require 'kml/link'
28
+ require 'kml/icon'
29
+ require 'kml/lat_lon_box'
@@ -0,0 +1,20 @@
1
+ module KML
2
+ # Overlay is the base type for image overlays drawn on the planet surface or on the screen. +icon+ specifies the
3
+ # image to use and can be configured to reload images based on a timer or by camera changes. This element also
4
+ # includes specifications for stacking order of multiple overlays and for adding color and transparency values to
5
+ # the base image.
6
+ class Overlay < Feature
7
+ attr_accessor :color
8
+ attr_accessor :draw_order
9
+ attr_accessor :icon
10
+
11
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
12
+ super
13
+ xm.color(color) unless color.nil?
14
+ xm.drawOrder(drawOrder) unless draw_order.nil?
15
+ icon.render(xm) unless icon.nil?
16
+ end
17
+ end
18
+ end
19
+
20
+ require 'kml/ground_overlay'
@@ -0,0 +1,36 @@
1
+ # Basic XML Structure:
2
+ #
3
+ # <Placemark id="ID">
4
+ # <!-- inherited from Feature element -->
5
+ # <name>...</name> <!-- string -->
6
+ # <visibility>1</visibility> <!-- boolean -->
7
+ # <open>1</open> <!-- boolean -->
8
+ # <address>...</address> <!-- string -->
9
+ # <AddressDetails xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">...
10
+ # </AddressDetails> <!-- string -->
11
+ # <phoneNumber>...</phoneNumber> <!-- string -->
12
+ # <Snippet maxLines="2">...</Snippet> <!-- string -->
13
+ # <description>...</description> <!-- string -->
14
+ # <LookAt>...</LookAt>
15
+ # <TimePrimitive>...</TimePrimitive>
16
+ # <styleUrl>...</styleUrl> <!-- anyURI -->
17
+ # <StyleSelector>...</StyleSelector>
18
+ # <Region>...</Region>
19
+ # <Metadata>...</Metadata>
20
+ #
21
+ # <!-- specific to Placemark element -->
22
+ # <Geometry>...</Geometry>
23
+ # </Placemark>
24
+
25
+ module KML
26
+ class Placemark < Feature
27
+ attr_accessor :geometry
28
+
29
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
30
+ xm.Placemark {
31
+ super
32
+ geometry.render(xm) unless geometry.nil?
33
+ }
34
+ end
35
+ end
36
+ end
data/lib/kml/point.rb ADDED
@@ -0,0 +1,47 @@
1
+ # <Point id="ID">
2
+ # <!-- specific to Point -->
3
+ # <extrude>0</extrude> <!-- boolean -->
4
+ # <tessellate>0</tessellate> <!-- boolean -->
5
+ # <altitudeMode>clampToGround</altitudeMode>
6
+ # <!-- kml:altitudeModeEnum: clampToGround, relativeToGround, or absolute -->
7
+ # <coordinates>...</coordinates> <!-- lon,lat[,alt] -->
8
+ # </Point>
9
+ module KML
10
+ class Point < Geometry
11
+
12
+ # A single tuple consisting of floating point values for longitude, latitude, and altitude (in that order).
13
+ # Longitude and latitude values are in degrees, where:
14
+ #
15
+ # * longitude >= -180 and <= 180
16
+ # * latitude >= -90 and <= 90
17
+ # * altitude values (optional) are in meters above sea level
18
+ def coordinates
19
+ @coordinates
20
+ end
21
+
22
+ # Set the coordinates
23
+ def coordinates=(c)
24
+ case c
25
+ when String
26
+ @coordinates = c.split(',')
27
+ unless @coordinates.length == 2 || @coordinates.length == 3
28
+ raise "Coordinates string may only have 2 parts (indicating lat and long) or 3 parts (lat, long and altitude)"
29
+ end
30
+ when Array
31
+ @coordinates = c
32
+ when Hash
33
+ @coordinates = [:lng, :lat, :alt].collect {|attr| c[attr]}.compact
34
+ else
35
+ raise ArgumentError, "Coordinates must be either a String, Hash or an Array"
36
+ end
37
+ end
38
+
39
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
40
+ xm.Point {
41
+ super
42
+ xm.coordinates(coordinates.join(","))
43
+ }
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ module KML
2
+ # Specifies the drawing style for all polygons, including polygon extrusions (which look like the walls of buildings)
3
+ # and line extrusions (which look like solid fences).
4
+ class PolyStyle < ColorStyle
5
+ attr_accessor :fill
6
+ attr_accessor :outline
7
+
8
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
9
+ xm.PolyStyle {
10
+ super
11
+ xm.fill(fill) unless fill.nil?
12
+ xm.outline(outline) unless outline.nil?
13
+ }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ # Source file which generates a Polygon element.
2
+ #
3
+ # <Polygon id="ID">
4
+ # <!-- specific to Polygon -->
5
+ # <extrude>0</extrude> <!-- boolean -->
6
+ # <tessellate>0</tessellate> <!-- boolean -->
7
+ # <altitudeMode>clampToGround</altitudeMode>
8
+ # <!-- kml:altitudeModeEnum: clampToGround, relativeToGround, or absolute -->
9
+ # <outerBoundaryIs>
10
+ # <LinearRing>
11
+ # <coordinates>...</coordinates> <!-- lon,lat[,alt] -->
12
+ # </LinearRing>
13
+ # </outerBoundaryIs>
14
+ # <innerBoundaryIs>
15
+ # <LinearRing>
16
+ # <coordinates>...</coordinates> <!-- lon,lat[,alt] -->
17
+ # </LinearRing>
18
+ # </innerBoundaryIs>
19
+ # </Polygon>
20
+
21
+ module KML #:nodoc:
22
+ # A Polygon is defined by an outer boundary and 0 or more inner boundaries. The boundaries, in turn, are defined
23
+ # by LinearRings. When a Polygon is extruded, its boundaries are connected to the ground to form additional polygons,
24
+ # which gives the appearance of a building. When a Polygon is extruded, each point is extruded individually.
25
+ # Extruded Polygons use PolyStyle for their color, color mode, and fill.
26
+ class Polygon < Geometry
27
+ attr_accessor :inner_boundary_is
28
+ attr_accessor :outer_boundary_is
29
+
30
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
31
+ xm.Polygon {
32
+ super
33
+ xm.outerBoundaryIs {
34
+ outer_boundary_is.render(xm)
35
+ }
36
+ unless inner_boundary_is.nil?
37
+ xm.innerBoundaryIs {
38
+ inner_boundary_is.render(xm)
39
+ }
40
+ end
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ module KML #:nodoc:
2
+ # A short description of a feature. In Google Earth, this description is displayed in the Places panel
3
+ # under the name of the feature. If a Snippet is not supplied, the first two lines of the description are
4
+ # used. In Google Earth, if a Placemark contains both a description and a Snippet, the Snippet appears
5
+ # beneath the Placemark in the Places panel, and the description appears in the Placemark's description
6
+ # balloon. This object does not support HTML markup.
7
+ class Snippet
8
+ # The maximum number of lines to display.
9
+ attr_accessor :max_lines
10
+
11
+ # The text that is displayed (HTML not supported)
12
+ attr_accessor :text
13
+
14
+ # Initialize the snippet with the given text and optionally with the given max_lines value.
15
+ def initialize(text, max_lines=nil)
16
+ @text = text
17
+ @max_lines = max_lines
18
+ end
19
+
20
+ # The maximum number of lines to display. Default is 2
21
+ def max_lines
22
+ @max_lines ||= 2
23
+ end
24
+ end
25
+ end
data/lib/kml/style.rb ADDED
@@ -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 = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/kml.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+
4
+ require 'kml_file'
5
+
6
+ class InvalidKMLError < StandardError
7
+ end
data/lib/kml_file.rb ADDED
@@ -0,0 +1,28 @@
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
+ attr_accessor :objects
13
+
14
+ # The objects in the KML file
15
+ def objects
16
+ @objects ||= []
17
+ end
18
+
19
+ # Render the KML file.
20
+ def render(xm=Builder::XmlMarkup.new(:indent => 2))
21
+ xm.instruct!
22
+ xm.kml(:xmlns => 'http://earth.google.com/kml/2.1'){
23
+ objects.each { |o| o.render(xm) }
24
+ }
25
+ end
26
+ end
27
+
28
+ require 'kml/object'
@@ -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