kamelopard 0.0.14 → 0.0.15
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 +15 -0
- data/lib/kamelopard/classes.rb +69 -7
- data/lib/kamelopard/geocode.rb +57 -16
- data/lib/kamelopard/helpers.rb +834 -720
- data/lib/kamelopard/multicamify.rb +2 -0
- data/lib/kamelopard/spline.rb +99 -1
- data/spec/test.rb +2999 -0
- metadata +17 -15
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZTY5Y2M5MWMyYWE4MGUyNTgxM2VlNzljMzYzMTJlYjkzZmU0NWYxZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2Y2MmIwNDk4YzIwNGZkMjdjMDVhOTlmYzZlMGMyNzM4N2QxMTJhMg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OWNkNGFjMGU0NjY3ZTU2MzUxYTg3NWUzOGNiZmI0ZDhmYTY5MTM4NTM2ODhj
|
10
|
+
ZmJmNDRhZmYzNzA1OTdjOTMzYTYxZGY4Y2RlMmIzY2ZiMTRiNWVkNmQ4ODU1
|
11
|
+
NmYyMTUzODU4NzA0Zjc5NWNhMmU4ZGM5NWJiNmExODRkN2YwZGU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NGY5ZTE0NGQyNzA1OTg4NjRlZWIwNzgwMDRlYzNkZDc5ZTIyZWQ5YmE4NjUz
|
14
|
+
MWY4NjEwMWMzMGUyMzBlNDFhMzc3Yjc1ZTc5MWE0NjIwYjZmZjM0OTJhNTg5
|
15
|
+
ZjJmZGQxNDkzNTU3MmYzMDliZTg0ZGEwNmFhNmI5ZDIyMzcwYTE=
|
data/lib/kamelopard/classes.rb
CHANGED
@@ -2,11 +2,53 @@
|
|
2
2
|
#--
|
3
3
|
# vim:ts=4:sw=4:et:smartindent:nowrap
|
4
4
|
#++
|
5
|
-
# Classes to manage various KML objects. See
|
6
|
-
# http://code.google.com/apis/kml/documentation/kmlreference.html for a
|
7
|
-
# description of KML
|
8
5
|
|
9
|
-
#
|
6
|
+
# == Description
|
7
|
+
# Kamelopard is a gem to create and manipulate Keyhole Markup Language, or KML.
|
8
|
+
# See http://code.google.com/apis/kml/documentation/kmlreference.html for a
|
9
|
+
# reference on the subject. Within the Kamelopard module are several classes
|
10
|
+
# which represent KML objects. To use Kamelopard to create a KML document from
|
11
|
+
# scratch, you'll eventually want to create instances of these classes. You can
|
12
|
+
# manipulate these instances' attributes and connections to other classes, and
|
13
|
+
# in the end, write the result to a KML file. Here's a simple example which
|
14
|
+
# creates one placemark in a file called doc.kml:
|
15
|
+
#
|
16
|
+
# require 'rubygems'
|
17
|
+
# require 'kamelopard'
|
18
|
+
#
|
19
|
+
# f = Kamelopard::Folder.new('Some Folder Name')
|
20
|
+
# f << Kamelopard::Placemark('My placemark',
|
21
|
+
# :geometry => Kamelopard::Point(1, 2, 3))
|
22
|
+
# write_kml_to 'doc.kml'
|
23
|
+
#
|
24
|
+
# Kamelopard operates as a sort of state machine, with a concept of the
|
25
|
+
# "current" document. Newly created objects are appended to the current
|
26
|
+
# document. See the DocumentHolder class to learn about switching around
|
27
|
+
# between different documents. Note also that whereas tour elements such as
|
28
|
+
# FlyTo and Wait are always kept in the order in which they were created, other
|
29
|
+
# elements like Styles and Folders might show up in different orders. Since in
|
30
|
+
# the final output this doesn't matter (or shouldn't, anyway), this isn't
|
31
|
+
# considered a bug, and in fact it makes it easier sometimes, because you don't
|
32
|
+
# have to figure out the structure of your document in the proper order at run
|
33
|
+
# time.
|
34
|
+
#
|
35
|
+
# Kamelopard comes with a set of helper functions which it puts in the default
|
36
|
+
# namespace. Experienced users will probably choose use these functions to
|
37
|
+
# create Kamelopard objects rather than instantiating these classes directly.
|
38
|
+
#
|
39
|
+
# Objects' attributes are often undocumented, when they correspond directly to
|
40
|
+
# a similarly named attribute in the KML object they represent. Refer to the
|
41
|
+
# KML reference linked above for more details about these undocumented
|
42
|
+
# attributes. Most objects' constructors accept a hash of options you can use
|
43
|
+
# to set these attributes, such as the :geometry option used in the sample code
|
44
|
+
# above. Kamelopard will complain if you try to set an option it doesn't
|
45
|
+
# recognize.
|
46
|
+
#
|
47
|
+
# Most objects also include a to_kml() method, which returns an XML::Node
|
48
|
+
# containing the KML this object represents, including any other objects nested
|
49
|
+
# inside. The write_kml_to helper function used above, and other helper
|
50
|
+
# functions involved in KML output, generally wrap this method so it rarely
|
51
|
+
# gets called directly.
|
10
52
|
module Kamelopard
|
11
53
|
require 'bundler/setup'
|
12
54
|
require 'singleton'
|
@@ -58,7 +100,7 @@ module Kamelopard
|
|
58
100
|
@@logger.call(level, mod, msg) unless @@logger.nil? or @@log_level > LogLevels[level]
|
59
101
|
end
|
60
102
|
|
61
|
-
def Kamelopard.xml_to_hash(node, fields)
|
103
|
+
def Kamelopard.xml_to_hash(node, fields) # :nodoc:
|
62
104
|
result = {}
|
63
105
|
fields.each do |field|
|
64
106
|
begin
|
@@ -1061,7 +1103,7 @@ module Kamelopard
|
|
1061
1103
|
|
1062
1104
|
# Represents KML's Document class.
|
1063
1105
|
class Document < Container
|
1064
|
-
attr_accessor :flyto_mode, :folders, :tours, :uses_xal, :vsr_actions
|
1106
|
+
attr_accessor :flyto_mode, :folders, :tours, :uses_xal, :vsr_actions, :filename
|
1065
1107
|
|
1066
1108
|
# Is this KML destined for a master LG node, or a slave? True if this
|
1067
1109
|
# is a master node. This defaults to true, so tours that don't need
|
@@ -1073,11 +1115,20 @@ module Kamelopard
|
|
1073
1115
|
@folders = []
|
1074
1116
|
@vsr_actions = []
|
1075
1117
|
@master_mode = false
|
1118
|
+
@filename = 'doc.kml'
|
1076
1119
|
Kamelopard.log(:info, 'Document', "Adding myself to the document holder")
|
1077
1120
|
DocumentHolder.instance << self
|
1078
1121
|
super
|
1079
1122
|
end
|
1080
1123
|
|
1124
|
+
def make_current
|
1125
|
+
Kamelopard::DocumentHolder.instance.set_current self
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
def activate
|
1129
|
+
make_current
|
1130
|
+
end
|
1131
|
+
|
1081
1132
|
# Returns viewsyncrelay actions as a hash
|
1082
1133
|
def get_actions
|
1083
1134
|
{
|
@@ -1202,6 +1253,12 @@ module Kamelopard
|
|
1202
1253
|
#! These get printed out in the call to super, in Feature.to_kml()
|
1203
1254
|
#@styles.map do |a| d << a.to_kml unless a.attached? end
|
1204
1255
|
|
1256
|
+
# then misc
|
1257
|
+
@features.each do |f|
|
1258
|
+
next if f.is_a? Folder or f.is_a? Style or f.is_a? Tour
|
1259
|
+
f.to_kml d
|
1260
|
+
end
|
1261
|
+
|
1205
1262
|
# then folders
|
1206
1263
|
@folders.map do |a|
|
1207
1264
|
a.to_kml(d) unless a.has_parent?
|
@@ -1685,7 +1742,10 @@ module Kamelopard
|
|
1685
1742
|
end
|
1686
1743
|
|
1687
1744
|
# Corresponds to KML's Placemark objects. The geometry attribute requires a
|
1688
|
-
# descendant of Geometry
|
1745
|
+
# descendant of Geometry. *Note:* whereas most objects implicitly add
|
1746
|
+
# themselves to the end of the current Document, Placemarks do not. They
|
1747
|
+
# must be explicitly added to the Document or other Container they live in,
|
1748
|
+
# typically with the Container's << operator.
|
1689
1749
|
class Placemark < Feature
|
1690
1750
|
attr_accessor :name, :geometry, :balloonVisibility
|
1691
1751
|
|
@@ -2368,6 +2428,8 @@ module Kamelopard
|
|
2368
2428
|
}.each do |k, v|
|
2369
2429
|
d = XML::Node.new k.to_s
|
2370
2430
|
d << v.to_s
|
2431
|
+
# Don't escape links, because Earth doesn't like that.
|
2432
|
+
d.first.output_escaping = false
|
2371
2433
|
x << d
|
2372
2434
|
end
|
2373
2435
|
Kamelopard.kml_array(x, [
|
data/lib/kamelopard/geocode.rb
CHANGED
@@ -7,22 +7,53 @@ require 'uri'
|
|
7
7
|
require 'cgi'
|
8
8
|
require 'json'
|
9
9
|
|
10
|
-
# Geocoder base class
|
10
|
+
# Geocoder base class. You should use a subclass. It is your responsibility to
|
11
|
+
# ensure you comply with all API licensing and usage requirements. Kamelopard
|
12
|
+
# won't do it for you.
|
11
13
|
class Geocoder
|
12
14
|
attr_accessor :host, :path, :params
|
13
15
|
def initialize
|
14
16
|
@params = {}
|
15
17
|
end
|
16
18
|
|
19
|
+
def processParam(value, key = 'location')
|
20
|
+
return ["#{key}=#{value}"] if key == 'key'
|
21
|
+
if value.kind_of? Hash then
|
22
|
+
p = value.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }
|
23
|
+
else
|
24
|
+
p = ["#{CGI.escape(key)}=#{CGI.escape(value)}"]
|
25
|
+
end
|
26
|
+
return p
|
27
|
+
end
|
28
|
+
|
17
29
|
def parse_response(r)
|
18
30
|
raise "Unimplemented -- use a child of the Geocoder class"
|
19
31
|
end
|
20
32
|
end
|
21
33
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
34
|
+
class GoogleGeocoder < Geocoder
|
35
|
+
attr_reader :api_key, :response_format
|
36
|
+
|
37
|
+
def initialize(key, response_format = 'json')
|
38
|
+
super()
|
39
|
+
@proto = 'http'
|
40
|
+
@host = 'maps.googleapis.com'
|
41
|
+
@path = '/maps/api/geocode'
|
42
|
+
@api_key = key
|
43
|
+
@response_format = response_format
|
44
|
+
end
|
45
|
+
|
46
|
+
def getURL(params)
|
47
|
+
http = Net::HTTP.new(@host)
|
48
|
+
u = URI::HTTP.build([nil, @host, nil, "#{@path}/#{@response_format}", params, nil])
|
49
|
+
|
50
|
+
JSON.parse(Net::HTTP.get u)
|
51
|
+
end
|
52
|
+
|
53
|
+
def lookup(address)
|
54
|
+
getURL(processParam(address, 'address').join('&'))
|
55
|
+
end
|
56
|
+
end
|
26
57
|
|
27
58
|
class MapquestGeocoder < Geocoder
|
28
59
|
attr_reader :api_key, :response_format
|
@@ -31,28 +62,38 @@ class MapquestGeocoder < Geocoder
|
|
31
62
|
super()
|
32
63
|
@proto = 'http'
|
33
64
|
@host = 'www.mapquestapi.com'
|
34
|
-
@path =
|
65
|
+
@path = {
|
66
|
+
:address => '/geocoding/v1/address',
|
67
|
+
:batch => '/geocoding/v1/batch'
|
68
|
+
}
|
35
69
|
@api_key = key
|
36
70
|
@response_format = response_format
|
37
71
|
@params['key'] = @api_key
|
38
72
|
end
|
39
73
|
|
74
|
+
def getURL(args, type)
|
75
|
+
raise "Type (#{type}) must be one of #{ @path.keys.map { |a| ":#{a}" }.join(', ')}" unless @path.has_key? type
|
76
|
+
|
77
|
+
params = @params.map { |k, v| processParam(v, k) }.concat(args).join('&')
|
78
|
+
|
79
|
+
http = Net::HTTP.new(@host)
|
80
|
+
u = URI::HTTP.build([nil, @host, nil, @path[type], params, nil])
|
81
|
+
|
82
|
+
resp = Net::HTTP.get u
|
83
|
+
parse_response resp
|
84
|
+
end
|
85
|
+
|
40
86
|
# Returns an object built from the JSON result of the lookup, or an exception
|
41
87
|
def lookup(address)
|
42
88
|
# The argument can be a string, in which case PlaceFinder does the parsing
|
43
89
|
# The argument can also be a hash, with several possible keys. See the PlaceFinder documentation for details
|
44
90
|
# http://developer.yahoo.com/geo/placefinder/guide/requests.html
|
45
|
-
|
46
|
-
|
47
|
-
p = @params.merge address
|
48
|
-
else
|
49
|
-
p = @params.merge( { 'location' => address } )
|
50
|
-
end
|
51
|
-
q = p.map { |k,v| "#{ k == 'key' ? k : CGI.escape(k) }=#{ k == 'key' ? v : CGI.escape(v) }" }.join('&')
|
52
|
-
u = URI::HTTP.build([nil, @host, nil, @path, q, nil])
|
91
|
+
return getURL(processParam(address), :address)
|
92
|
+
end
|
53
93
|
|
54
|
-
|
55
|
-
|
94
|
+
def lookupBatch(addresses)
|
95
|
+
# The argument should be an array of the same sorts of values that can be fed to lookup()
|
96
|
+
return getURL(addresses.map { |k| processParam(k) }.flatten(1), :batch)
|
56
97
|
end
|
57
98
|
|
58
99
|
def parse_response(r)
|