kamelopard 0.0.3

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.
@@ -0,0 +1,119 @@
1
+ # vim:ts=4:sw=4:et:smartindent:nowrap
2
+ def fly_to(p, d = 0, r = 100, m = nil)
3
+ m = Document.instance.flyto_mode if m.nil?
4
+ FlyTo.new(p, r, d, m)
5
+ end
6
+
7
+ def set_flyto_mode_to(a)
8
+ Document.instance.flyto_mode = a
9
+ end
10
+
11
+ def mod_popup_for(p, v)
12
+ a = AnimatedUpdate.new
13
+ if ! p.is_a? Placemark then
14
+ raise "Can't show popups for things that aren't placemarks"
15
+ end
16
+ a << "<Change><Placemark targetId=\"#{p.id}\"><visibility>#{v}</visibility></Placemark></Change>"
17
+ a
18
+ end
19
+
20
+ def hide_popup_for(p)
21
+ mod_popup_for(p, 0)
22
+ end
23
+
24
+ def show_popup_for(p)
25
+ mod_popup_for(p, 1)
26
+ end
27
+
28
+ def point(lo, la, alt=0, mode=nil, extrude = false)
29
+ KMLPoint.new(lo, la, alt, mode.nil? ? :clampToGround : mode, extrude)
30
+ end
31
+
32
+ # Returns the KML that makes up the current Document, as a string.
33
+ def get_kml
34
+ Document.instance.to_kml
35
+ end
36
+
37
+ def pause(p)
38
+ Wait.new p
39
+ end
40
+
41
+ def name_tour(a)
42
+ Document.instance.tour.name = a
43
+ end
44
+
45
+ def new_folder(name)
46
+ Folder.new(name)
47
+ end
48
+
49
+ def name_folder(a)
50
+ Document.instance.folder.name = a
51
+ end
52
+
53
+ def zoom_out(dist = 1000, dur = 0, mode = nil)
54
+ l = Document.instance.tour.last_abs_view
55
+ raise "No current position to zoom out from\n" if l.nil?
56
+ l.range += dist
57
+ FlyTo.new(l, nil, dur, mode)
58
+ end
59
+
60
+ # Creates a list of FlyTo elements to orbit and look at a given point (center),
61
+ # at a given range (in meters), starting and ending at given angles (in
62
+ # degrees) from the center, where 0 and 360 (and -360, and 720, and -980, etc.)
63
+ # are north. To orbit clockwise, make startHeading less than endHeading.
64
+ # Otherwise, it will orbit counter-clockwise. To orbit multiple times, add or
65
+ # subtract 360 from the endHeading. The tilt argument matches the KML LookAt
66
+ # tilt argument
67
+ def orbit(center, range = 100, tilt = 0, startHeading = 0, endHeading = 360)
68
+ fly_to LookAt.new(center, startHeading, tilt, range), 2, nil
69
+
70
+ # We want at least 5 points (arbitrarily chosen value), plus at least 5 for
71
+ # each full revolution
72
+
73
+ # When I tried this all in one step, ruby told me 360 / 10 = 1805. I'm sure
74
+ # there's some reason why this is a feature and not a bug, but I'd rather
75
+ # not look it up right now.
76
+ num = (endHeading - startHeading).abs
77
+ den = ((endHeading - startHeading) / 360.0).to_i.abs * 5 + 5
78
+ step = num / den
79
+ step = 1 if step < 1
80
+ step = step * -1 if startHeading > endHeading
81
+
82
+ lastval = startHeading
83
+ startHeading.step(endHeading, step) do |theta|
84
+ lastval = theta
85
+ fly_to LookAt.new(center, theta, tilt, range), 2, nil, 'smooth'
86
+ end
87
+ if lastval != endHeading then
88
+ fly_to LookAt.new(center, endHeading, tilt, range), 2, nil, 'smooth'
89
+ end
90
+ end
91
+
92
+ def sound_cue(href, ds = nil)
93
+ SoundCue.new href, ds
94
+ end
95
+
96
+ # XXX This implementation of orbit is trying to do things the hard way, but the code might be useful for other situations where the hard way is the only possible one
97
+ # def orbit(center, range = 100, startHeading = 0, endHeading = 360)
98
+ # p = ThreeDPointList.new()
99
+ #
100
+ # # Figure out how far we're going, and d
101
+ # dist = endHeading - startHeading
102
+ #
103
+ # # We want at least 5 points (arbitrarily chosen value), plus at least 5 for each full revolution
104
+ # step = (endHeading - startHeading) / ((endHeading - startHeading) / 360.0).to_i * 5 + 5
105
+ # startHeading.step(endHeading, step) do |theta|
106
+ # p << KMLPoint.new(
107
+ # center.longitude + Math.cos(theta),
108
+ # center.latitude + Math.sin(theta),
109
+ # center.altitude, center.altitudeMode)
110
+ # end
111
+ # p << KMLPoint.new(
112
+ # center.longitude + Math.cos(endHeading),
113
+ # center.latitude + Math.sin(endHeading),
114
+ # center.altitude, center.altitudeMode)
115
+ #
116
+ # p.interpolate.each do |a|
117
+ # fly_to
118
+ # end
119
+ # end
@@ -0,0 +1,62 @@
1
+ # vim:ts=4:sw=4:et:smartindent:nowrap
2
+
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'cgi'
6
+ require 'json'
7
+
8
+ # Geocoder base class
9
+ class Geocoder
10
+ def initialize
11
+ raise "Unimplemented -- some other class should extend Geocoder and replace this initialize method"
12
+ end
13
+
14
+ def lookup(address)
15
+ raise "Unimplemented -- some other class should extend Geocoder and replace this lookup method"
16
+ end
17
+ end
18
+
19
+ # Uses Yahoo's PlaceFinder geocoding service: http://developer.yahoo.com/geo/placefinder/guide/requests.html
20
+ # Google's would seem most obvious, but since it requires you to display
21
+ # results on a map, ... I didn't want to have to evaluate other possible
22
+ # restrictions. The argument to the constructor is a PlaceFinder API key, but
23
+ # testing suggests it's actually unnecessary
24
+ class YahooGeocoder < Geocoder
25
+ def initialize(key)
26
+ @api_key = key
27
+ @proto = 'http'
28
+ @host = 'where.yahooapis.com'
29
+ @path = '/geocode'
30
+ @params = { 'appid' => @api_key, 'flags' => 'J' }
31
+ end
32
+
33
+ # Returns an object built from the JSON result of the lookup, or an exception
34
+ def lookup(address)
35
+ # The argument can be a string, in which case PlaceFinder does the parsing
36
+ # The argument can also be a hash, with several possible keys. See the PlaceFinder documentation for details
37
+ # http://developer.yahoo.com/geo/placefinder/guide/requests.html
38
+ http = Net::HTTP.new(@host)
39
+ if address.kind_of? Hash then
40
+ p = @params.merge address
41
+ else
42
+ p = @params.merge( { 'q' => address } )
43
+ end
44
+ q = p.map { |k,v| "#{ CGI.escape(k) }=#{ CGI.escape(v) }" }.join('&')
45
+ u = URI::HTTP.build([nil, @host, nil, @path, q, nil])
46
+
47
+ resp = Net::HTTP.get u
48
+ parse_response resp
49
+ end
50
+
51
+ def parse_response(resp)
52
+ d = JSON.parse(resp)
53
+ raise d['ErrorMessage'] if d['Error'].to_i != 0
54
+ d
55
+ end
56
+ end
57
+
58
+ # EXAMPLE
59
+ # require 'rubygems'
60
+ # require 'kamelopard'
61
+ # g = YahooGeocoder.new('some-api-key')
62
+ # puts g.lookup({ 'city' => 'Springfield', 'count' => '100' })
@@ -0,0 +1,127 @@
1
+ # vim:ts=4:sw=4:et:smartindent:nowrap
2
+ require 'matrix'
3
+ #require 'kamelopard_classes'
4
+
5
+ class NDPointList
6
+ # Contains a list of N-dimensional numeric arrays
7
+
8
+ attr_reader :dim
9
+
10
+ def initialize(num)
11
+ raise "Can't have an NDPointList with #{num} dimensions -- must be 1 or more" if num < 1
12
+ @dim = num
13
+ @points = []
14
+ end
15
+
16
+ def size
17
+ return @points.size
18
+ end
19
+
20
+ def <<(a)
21
+ # Append points to our list
22
+ if a.kind_of? KMLPoint then
23
+ if self.dim == 3 then
24
+ @points << [a.longitude, a.latitude, a.altitude]
25
+ else
26
+ @points << [a.longitude, a.latitude]
27
+ end
28
+ elsif a.respond_to? 'dim' and @dim != a.dim then
29
+ raise "Argument's dimension #{a.dim} must agree with our dimension #{@dim} to append to an NDPointList"
30
+ else
31
+ @points << a
32
+ end
33
+ end
34
+
35
+ def last
36
+ @points.last
37
+ end
38
+
39
+ def [](i)
40
+ @points[i]
41
+ end
42
+
43
+ def x
44
+ @points.collect do |a| a[0] end
45
+ end
46
+
47
+ def y
48
+ if @dim >= 2 then
49
+ @points.collect do |a| a[1] end
50
+ else
51
+ raise "NDPointList of size #{@dim} has no Y element"
52
+ end
53
+ end
54
+
55
+ def z
56
+ if @dim >= 2 then
57
+ @points.collect do |a| a[2] end
58
+ else
59
+ raise "NDPointList of size #{@dim} has no Z element"
60
+ end
61
+ end
62
+
63
+ def each(&blk)
64
+ @points.each(&blk)
65
+ end
66
+
67
+ def interpolate(resolution = nil)
68
+ # XXX Figure out how to implement the "resolution" argument
69
+ STDERR.puts "resolution argument to NDPointList.interpolate is ignored" if resolution.nil?
70
+ # Ruby implementation of Catmull-Rom splines (http://www.cubic.org/docs/hermite.htm)
71
+ # Return NDPointList interpolating a path along all points in this list
72
+
73
+ h = Matrix[
74
+ [ 2, -2, 1, 1 ],
75
+ [-3, 3, -2, -1 ],
76
+ [ 0, 0, 1, 0 ],
77
+ [ 1, 0, 0, 0 ],
78
+ ]
79
+
80
+ result = NDPointList.new(@dim)
81
+
82
+ # Calculate spline between every two points
83
+ (0..(self.size-2)).each do |i|
84
+ p1 = self[i]
85
+ p2 = self[i+1]
86
+
87
+ # Get surrounding points for calculating tangents
88
+ if i <= 0 then pt1 = p1 else pt1 = self[i-1] end
89
+ if i == self.size - 2 then pt2 = p2 else pt2 = self[i+2] end
90
+
91
+ # Build tangent points into matrices to calculate tangents.
92
+ t1 = 0.5 * ( Matrix[p2] - Matrix[pt1] )
93
+ t2 = 0.5 * ( Matrix[pt2] - Matrix[p1] )
94
+
95
+ # Build matrix of Hermite parameters
96
+ c = Matrix[p1, p2, t1.row(0), t2.row(0)]
97
+
98
+ # Make a set of points
99
+ (0..10).each do |t|
100
+ r = t/10.0
101
+ s = Matrix[[r**3, r**2, r, 1]]
102
+ tmp = s * h
103
+ p = tmp * c
104
+ result << p.row(0).to_a
105
+ end
106
+ end
107
+ result
108
+ end
109
+ end
110
+
111
+ class OneDPointList < NDPointList
112
+ def initialize
113
+ super 1
114
+ end
115
+ end
116
+
117
+ class TwoDPointList < NDPointList
118
+ def initialize
119
+ super 2
120
+ end
121
+ end
122
+
123
+ class ThreeDPointList < NDPointList
124
+ def initialize
125
+ super 3
126
+ end
127
+ end
data/lib/kamelopard.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'kamelopard/classes'
2
+ require 'kamelopard/functions'
3
+ require 'kamelopard/geocode'
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kamelopard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joshua Tolley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-24 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Various classes and functions used to ease development of KML files,
15
+ in particular for development of Google Earth tours
16
+ email: josh@endpoint.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/kamelopard/geocode.rb
22
+ - lib/kamelopard/classes.rb
23
+ - lib/kamelopard/functions.rb
24
+ - lib/kamelopard/pointlist.rb
25
+ - lib/kamelopard.rb
26
+ homepage: http://www.endpoint.com/services/liquid_galaxy
27
+ licenses: []
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 1.8.9
47
+ signing_key:
48
+ specification_version: 3
49
+ summary: Tools for building KML
50
+ test_files: []