motel 0.3 → 0.3.1
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/Rakefile +5 -3
- data/bin/motel-client +211 -0
- data/bin/motel-rage-client +80 -0
- data/bin/{server/main.rb → motel-server} +0 -3
- data/conf/motel-schema.xml +30 -5
- data/lib/motel.rb +3 -1
- data/lib/motel/callbacks.rb +139 -0
- data/lib/motel/location.rb +23 -4
- data/lib/motel/movement_strategies/elliptical.rb +1 -0
- data/lib/motel/movement_strategies/linear.rb +1 -0
- data/lib/motel/movement_strategy.rb +4 -3
- data/lib/motel/runner.rb +136 -38
- data/lib/motel/simrpc_adapter.rb +190 -0
- data/spec/callbacks_spec.rb +156 -0
- data/spec/dsl_spec.rb +5 -5
- data/spec/location_spec.rb +15 -10
- data/spec/runner_spec.rb +24 -10
- data/spec/simrpc_spec.rb +142 -21
- data/spec/spec_helper.rb +1 -0
- metadata +48 -13
- data/bin/clients/simple/main.rb +0 -131
- data/lib/motel/simrpc.rb +0 -131
- data/lib/motel/thread_pool.rb +0 -51
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ require 'rake/gempackagetask'
|
|
9
9
|
|
10
10
|
|
11
11
|
GEM_NAME="motel"
|
12
|
-
PKG_VERSION='0.3'
|
12
|
+
PKG_VERSION='0.3.1'
|
13
13
|
SIMRPC_SPEC='conf/motel-schema.xml'
|
14
14
|
|
15
15
|
desc "Run all specs"
|
@@ -23,20 +23,22 @@ Rake::RDocTask.new do |rd|
|
|
23
23
|
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
24
24
|
end
|
25
25
|
|
26
|
-
PKG_FILES = FileList['
|
26
|
+
PKG_FILES = FileList['conf/motel-schema.xml', 'lib/**/*.rb',
|
27
27
|
'COPYING', 'LICENSE', 'Rakefile', 'README.rdoc', 'spec/**/*.rb' ]
|
28
28
|
|
29
29
|
SPEC = Gem::Specification.new do |s|
|
30
30
|
s.name = GEM_NAME
|
31
31
|
s.version = PKG_VERSION
|
32
32
|
s.files = PKG_FILES
|
33
|
+
s.executables << 'motel-server' << 'motel-client' << 'motel-rage-client'
|
33
34
|
|
34
35
|
s.required_ruby_version = '>= 1.8.1'
|
35
36
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.3.3")
|
37
|
+
s.add_development_dependency('rspec', '~> 1.3.0')
|
36
38
|
|
37
39
|
s.author = "Mohammed Morsi"
|
38
40
|
s.email = "movitto@yahoo.com"
|
39
|
-
s.date = %q{2010-
|
41
|
+
s.date = %q{2010-09-05}
|
40
42
|
s.description = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
|
41
43
|
s.summary = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
|
42
44
|
s.homepage = %q{http://morsi.org/projects/motel}
|
data/bin/motel-client
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# A simple motel client executable
|
3
|
+
# Executable to use the motel library to perform operations on
|
4
|
+
# a remote location server, simply printing out results
|
5
|
+
#
|
6
|
+
# Flags: (see below)
|
7
|
+
#
|
8
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
9
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
10
|
+
|
11
|
+
require 'rubygems'
|
12
|
+
require 'optparse'
|
13
|
+
require 'motel'
|
14
|
+
|
15
|
+
include Motel
|
16
|
+
include Motel::MovementStrategies
|
17
|
+
|
18
|
+
######################
|
19
|
+
|
20
|
+
def main()
|
21
|
+
# command line parameters
|
22
|
+
schema_file = nil
|
23
|
+
location = {:parent_id => nil,
|
24
|
+
:x => nil,
|
25
|
+
:y => nil,
|
26
|
+
:z => nil}
|
27
|
+
other_location_id = nil
|
28
|
+
movement_strategy_type = nil
|
29
|
+
movement_strategy = { :step_delay => nil,
|
30
|
+
:speed => nil,
|
31
|
+
:direction_vector_x => nil,
|
32
|
+
:direction_vector_y => nil,
|
33
|
+
:direction_vector_z => nil,
|
34
|
+
:relative_to => nil,
|
35
|
+
:eccentricity => nil,
|
36
|
+
:semi_latus_rectum => nil,
|
37
|
+
:direction_major_x => nil,
|
38
|
+
:direction_major_y => nil,
|
39
|
+
:direction_major_z => nil,
|
40
|
+
:direction_minor_x => nil,
|
41
|
+
:direction_minor_y => nil,
|
42
|
+
:direction_minor_z => nil}
|
43
|
+
request_target = nil
|
44
|
+
|
45
|
+
# setup cmd line options
|
46
|
+
opts = OptionParser.new do |opts|
|
47
|
+
opts.banner = "Usage: main.rb [command] [options]"
|
48
|
+
|
49
|
+
opts.on("-h", "--help", "Print this help message") do
|
50
|
+
puts opts
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on("-s", "--schema [path]", "Motel Schema File") do |path|
|
55
|
+
schema_file = path
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.separator ""
|
59
|
+
opts.separator "Commands:"
|
60
|
+
opts.on("-g", "--get", "get location specified by id")do
|
61
|
+
request_target = :get_location
|
62
|
+
end
|
63
|
+
opts.on("-c", "--create", "create location w/ id")do
|
64
|
+
request_target = :create_location
|
65
|
+
end
|
66
|
+
opts.on("-u", "--update", "update location specified by id w/ specified options")do
|
67
|
+
request_target = :update_location
|
68
|
+
end
|
69
|
+
opts.on("-m", "--subscribe-to-movement", "subscribe to movement updates to location specified by id")do
|
70
|
+
request_target = :subscribe_to_location_movement
|
71
|
+
end
|
72
|
+
opts.on("-r", "--subscribe-to-proximity", "subscribe to locations proximity events")do
|
73
|
+
request_target = :subscribe_to_locations_proximity
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.separator ""
|
77
|
+
opts.separator "Location Options:"
|
78
|
+
opts.on("-i", "--id [location_id]", "Target location id") do |id|
|
79
|
+
location[:id] = id
|
80
|
+
end
|
81
|
+
opts.on("-o", "--other-id [location_id]", "Second location id for actions that require it") do |id|
|
82
|
+
other_location_id = id
|
83
|
+
end
|
84
|
+
opts.on("-p", "--parent-id [location_id]", "Target parent location id") do |id|
|
85
|
+
location[:parent_id] = id
|
86
|
+
end
|
87
|
+
opts.on("-x", "--xcoordinate [coordinate]", "Target location x coordinate") do |x|
|
88
|
+
location[:x] = x
|
89
|
+
end
|
90
|
+
opts.on("-y", "--ycoordinate [coordinate]", "Target location y coordinate") do |y|
|
91
|
+
location[:y] = y
|
92
|
+
end
|
93
|
+
opts.on("-z", "--zcoordinate [coordinate]", "Target location z coordinate") do |z|
|
94
|
+
location[:z] = z
|
95
|
+
end
|
96
|
+
|
97
|
+
opts.separator ""
|
98
|
+
opts.separator "Movement Strategy Options:"
|
99
|
+
opts.on("--movement-strategy-type [type]", "Movement strategy type") do |type|
|
100
|
+
movement_strategy_type = type
|
101
|
+
end
|
102
|
+
opts.on("--step-delay [delay]", "Movement strategy step delay") do |delay|
|
103
|
+
movement_strategy[:step_delay] = delay.to_f
|
104
|
+
end
|
105
|
+
opts.on("--speed [speed]", "Movement strategy speed") do |speed|
|
106
|
+
movement_strategy[:speed] = speed.to_f
|
107
|
+
end
|
108
|
+
opts.on("--direction-vector-x [x]", "Linear movement strategy direction vector x coordinate") do |x|
|
109
|
+
movement_strategy[:direction_vector_x] = x.to_f
|
110
|
+
end
|
111
|
+
opts.on("--direction-vector-y [y]", "Linear movement strategy direction vector y coordinate") do |y|
|
112
|
+
movement_strategy[:direction_vector_y] = y.to_f
|
113
|
+
end
|
114
|
+
opts.on("--direction-vector-z [z]", "Linear movement strategy direction vector z coordinate") do |z|
|
115
|
+
movement_strategy[:direction_vector_z] = z.to_f
|
116
|
+
end
|
117
|
+
opts.on("--relative-to [relative]", "Elliptical movement strategy relative to") do |relative|
|
118
|
+
movement_strategy[:relative_to] = relative
|
119
|
+
end
|
120
|
+
opts.on("--eccentricity [e]", "Elliptical movement strategy eccentricity") do |e|
|
121
|
+
movement_strategy[:eccentricity] = e
|
122
|
+
end
|
123
|
+
opts.on("--semi-latus-rectum [l]", "Elliptical movement strategy semi-latus-rectum") do |l|
|
124
|
+
movement_strategy[:semi_latus_rectum] = l
|
125
|
+
end
|
126
|
+
opts.on("--direction-major-x [x]", "Elliptical movement strategy major direction vector x coordinate") do |x|
|
127
|
+
movement_strategy[:direction_major_x] = x.to_f
|
128
|
+
end
|
129
|
+
opts.on("--direction-major-y [y]", "Elliptical movement strategy major direction vector y coordinate") do |y|
|
130
|
+
movement_strategy[:direction_major_y] = y.to_f
|
131
|
+
end
|
132
|
+
opts.on("--direction-major-z [z]", "Elliptical movement strategy major direction vector z coordinate") do |z|
|
133
|
+
movement_strategy[:direction_major_z] = z.to_f
|
134
|
+
end
|
135
|
+
opts.on("--direction-minor-x [x]", "Elliptical movement strategy minor direction vector x coordinate") do |x|
|
136
|
+
movement_strategy[:direction_minor_x] = x.to_f
|
137
|
+
end
|
138
|
+
opts.on("--direction-minor-y [y]", "Elliptical movement strategy minor direction vector y coordinate") do |y|
|
139
|
+
movement_strategy[:direction_minor_y] = y.to_f
|
140
|
+
end
|
141
|
+
opts.on("--direction-minor-z [z]", "Elliptical movement strategy minor direction vector z coordinate") do |z|
|
142
|
+
movement_strategy[:direction_minor_z] = z.to_f
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
# parse cmd line
|
148
|
+
begin
|
149
|
+
opts.parse!(ARGV)
|
150
|
+
rescue OptionParser::InvalidOption => e
|
151
|
+
puts opts
|
152
|
+
puts e.to_s
|
153
|
+
exit
|
154
|
+
end
|
155
|
+
|
156
|
+
if request_target.nil? || location[:id].nil? || schema_file.nil? #||
|
157
|
+
#request_target == :update && location[:x].nil? && location[:y].nil? && location[:z].nil? && location[:parent_id].nil?
|
158
|
+
puts opts
|
159
|
+
puts "must specify schema, a command to perform, a location id, and other required options"
|
160
|
+
exit
|
161
|
+
end
|
162
|
+
|
163
|
+
lid = location[:id]
|
164
|
+
location = Motel::Location.new :id => location[:id],
|
165
|
+
:parent_id => location[:parent_id],
|
166
|
+
:x => location[:x],
|
167
|
+
:y => location[:y],
|
168
|
+
:z => location[:z]
|
169
|
+
|
170
|
+
unless movement_strategy_type.nil?
|
171
|
+
movement_strategy = movement_strategy_type.camelize.constantize.new movement_strategy
|
172
|
+
location.movement_strategy = movement_strategy
|
173
|
+
end
|
174
|
+
|
175
|
+
args = []
|
176
|
+
case(request_target)
|
177
|
+
when :get_location
|
178
|
+
args.push location.id
|
179
|
+
when :create_location
|
180
|
+
args.push location
|
181
|
+
when :update_location
|
182
|
+
args.push location
|
183
|
+
when :subscribe_to_location_movement
|
184
|
+
args.push location.id
|
185
|
+
when :subscribe_to_locations_proximity
|
186
|
+
args.push location.id, other_location_id
|
187
|
+
end
|
188
|
+
|
189
|
+
# FIXME need configurable amqp broker ip/port
|
190
|
+
client = Motel::Client.new :schema_file => schema_file
|
191
|
+
result = client.request request_target, *args
|
192
|
+
|
193
|
+
if request_target == :subscribe_to_location_movement
|
194
|
+
client.on_location_moved = lambda { |loc|
|
195
|
+
puts "location moved:"
|
196
|
+
puts "#{loc}"
|
197
|
+
}
|
198
|
+
client.join
|
199
|
+
|
200
|
+
elsif request_target == :subscribe_to_locations_proximity
|
201
|
+
client.on_locations_proximity = lambda { |loc1, loc2|
|
202
|
+
puts "locations proximity:"
|
203
|
+
puts "#{loc1}/#{loc2}"
|
204
|
+
}
|
205
|
+
client.join
|
206
|
+
end
|
207
|
+
|
208
|
+
puts "server returned #{result}"
|
209
|
+
end
|
210
|
+
|
211
|
+
main()
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# A motel client using the Ruby Advanced Gaming Engine library to display location
|
3
|
+
#
|
4
|
+
# Flags: (see below)
|
5
|
+
#
|
6
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
7
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'optparse'
|
11
|
+
require 'rage'
|
12
|
+
require 'motel'
|
13
|
+
|
14
|
+
include Motel
|
15
|
+
include Motel::MovementStrategies
|
16
|
+
|
17
|
+
|
18
|
+
######################
|
19
|
+
|
20
|
+
def main()
|
21
|
+
# command line parameters
|
22
|
+
schema_file = nil
|
23
|
+
mesh_file = nil
|
24
|
+
location_id = nil
|
25
|
+
|
26
|
+
# setup cmd line options
|
27
|
+
opts = OptionParser.new do |opts|
|
28
|
+
opts.banner = "Usage: main.rb [command] [options]"
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Print this help message") do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-s", "--schema [path]", "Motel Schema File") do |path|
|
36
|
+
schema_file = path
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-i", "--id [id]", "ID of location to display") do |id|
|
40
|
+
location_id = id
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-m", "--mesh [uri]", "Mesh to display at location") do |uri|
|
44
|
+
mesh_file = uri
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# parse cmd line
|
49
|
+
begin
|
50
|
+
opts.parse!(ARGV)
|
51
|
+
rescue OptionParser::InvalidOption => e
|
52
|
+
puts opts
|
53
|
+
puts e.to_s
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
if schema_file.nil? || mesh_file.nil? || location_id.nil?
|
58
|
+
puts "must specify motel schema, location id, and mesh to display"
|
59
|
+
puts opts
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
mesh = resource :type => :mesh, :uri => mesh_file
|
64
|
+
|
65
|
+
client = Motel::Client.new :schema_file => schema_file
|
66
|
+
result = client.request :subscribe_to_location_movement, location_id
|
67
|
+
client.on_location_moved = lambda { |loc, d, dx, dy, dz|
|
68
|
+
mesh.show_at :x => loc.x, :y => loc.y, :z => loc.z
|
69
|
+
}
|
70
|
+
|
71
|
+
window(:width => 512, :height => 512) { |win|
|
72
|
+
win.create_viewport
|
73
|
+
}.show
|
74
|
+
|
75
|
+
game.run
|
76
|
+
|
77
|
+
#client.join
|
78
|
+
end
|
79
|
+
|
80
|
+
main()
|
@@ -10,9 +10,6 @@
|
|
10
10
|
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
11
11
|
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
12
12
|
|
13
|
-
CURRENT_DIR=File.dirname(__FILE__)
|
14
|
-
$: << File.expand_path(CURRENT_DIR + "/../../lib")
|
15
|
-
|
16
13
|
require 'rubygems'
|
17
14
|
require 'optparse'
|
18
15
|
require 'motel'
|
data/conf/motel-schema.xml
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
<member name="parent_id" type="int" desc="location id of parent, null if this is a root location" ignore_null="true" />
|
39
39
|
<member name="parent" type="obj" associated="Location" desc="parent location"/>
|
40
40
|
<member name="children" type="array" associated="Location" desc="children locations"/>
|
41
|
-
<member name="movement_strategy" type="obj" desc="associated movement strategy"/>
|
41
|
+
<member name="movement_strategy" type="obj" default="" desc="associated movement strategy"/>
|
42
42
|
<member name="entity_id" type="int" desc="id of entity represented by this location" />
|
43
43
|
<member name="entity_type" type="str" desc="type of entity represented by this location" />
|
44
44
|
</class>
|
@@ -48,9 +48,9 @@
|
|
48
48
|
<return_value name="location" type="obj" associated="Location" desc="Location corresponding to id or nil"/>
|
49
49
|
</method>
|
50
50
|
|
51
|
-
<method name="create_location" desc="create new location
|
52
|
-
<param name="
|
53
|
-
<return_value name="
|
51
|
+
<method name="create_location" desc="create new location">
|
52
|
+
<param name="location" type="obj" associated="Location" desc="Location to create"/>
|
53
|
+
<return_value name="location" type="obj" associated="Location" desc="Location create or nil"/>
|
54
54
|
</method>
|
55
55
|
|
56
56
|
<method name="update_location" desc="update running location w/ new location sharing the same id">
|
@@ -60,13 +60,38 @@
|
|
60
60
|
|
61
61
|
<!-- TODO delete_location -->
|
62
62
|
|
63
|
-
<method name="
|
63
|
+
<method name="subscribe_to_location_movement" desc="subscribe simrpc endpoint to location movement updates">
|
64
|
+
<param name="node_id" type="str" desc="Node identifier which to update of location movements"/>
|
64
65
|
<param name="location_id" type="int" desc="Location identifier"/>
|
66
|
+
<param name="min_distance" type="float" default="0" desc="Min distance the location needs to have moved before notifying node"/>
|
67
|
+
<param name="min_x" type="float" default="0" desc="Min x-axis-distance the location needs to have moved before notifying node"/>
|
68
|
+
<param name="min_y" type="float" default="0" desc="Min y-axis-distance the location needs to have moved before notifying node"/>
|
69
|
+
<param name="min_z" type="float" default="0" desc="Min z-axis-distance the location needs to have moved before notifying node"/>
|
70
|
+
<return_value name="success" type="bool" desc="bool success"/>
|
71
|
+
</method>
|
72
|
+
|
73
|
+
<method name="subscribe_to_locations_proximity" desc="subscribe simrpc endpoint to location proximity events">
|
65
74
|
<param name="node_id" type="str" desc="Node identifier which to update of location movements"/>
|
75
|
+
<param name="location_id1" type="int" desc="First location identifier"/>
|
76
|
+
<param name="location_id2" type="int" desc="Second location identifier"/>
|
77
|
+
<param name="event" type="str" default="proximity" desc="Proximity event to subscribe to, should be proximity, entered_proxity, or left_proximity" />
|
78
|
+
<param name="max_distance" type="float" default="0" desc="Max distance the locations need to be apart before notifying node"/>
|
79
|
+
<param name="max_x" type="float" default="0" desc="Max x-axis-distance the locations need to be apart before notifying node"/>
|
80
|
+
<param name="max_y" type="float" default="0" desc="Max y-axis-distance the locations need to be apart before notifying node"/>
|
81
|
+
<param name="max_z" type="float" default="0" desc="Max z-axis-distance the locations need to be apart before notifying node"/>
|
66
82
|
<return_value name="success" type="bool" desc="bool success"/>
|
67
83
|
</method>
|
68
84
|
|
69
85
|
<method name="location_moved" desc="inform simrpc endpoint that location was moved">
|
70
86
|
<param name="location" type="obj" associated="Location" desc="Location that was moved with new coordinates and original id"/>
|
87
|
+
<param name="distance" type="float" desc="Total distance location moved"/>
|
88
|
+
<param name="x_distance" type="float" desc="Distance location moved along the x axis"/>
|
89
|
+
<param name="y_distance" type="float" desc="Distance location moved along the y axis"/>
|
90
|
+
<param name="z_distance" type="float" desc="Distance location moved along the z axis"/>
|
91
|
+
</method>
|
92
|
+
|
93
|
+
<method name="locations_proximity" desc="inform simrpc endpoint of location proximity event">
|
94
|
+
<param name="location1" type="obj" associated="Location" desc="First location in proximity"/>
|
95
|
+
<param name="location2" type="obj" associated="Location" desc="Second location in proximity"/>
|
71
96
|
</method>
|
72
97
|
</schema>
|
data/lib/motel.rb
CHANGED
@@ -4,10 +4,12 @@
|
|
4
4
|
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
5
5
|
|
6
6
|
lib = File.dirname(__FILE__)
|
7
|
+
$: << lib + '/motel/'
|
7
8
|
|
8
9
|
require lib + '/motel/exceptions'
|
10
|
+
require lib + '/motel/callbacks'
|
9
11
|
require lib + '/motel/runner'
|
10
|
-
require lib + '/motel/
|
12
|
+
require lib + '/motel/simrpc_adapter'
|
11
13
|
|
12
14
|
require lib + '/motel/dsl'
|
13
15
|
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# Motel callback definitions
|
2
|
+
#
|
3
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
4
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
5
|
+
|
6
|
+
require 'motel/common'
|
7
|
+
require 'motel/location'
|
8
|
+
|
9
|
+
module Motel
|
10
|
+
|
11
|
+
module Callbacks
|
12
|
+
|
13
|
+
# TODO implement callbacks via callback conditions, optional conditions
|
14
|
+
# which may be added to a callback which all or some must be true to
|
15
|
+
# invoke callback (eg min movement, max proximity, min time passed, etc)
|
16
|
+
|
17
|
+
# Base Motel callback interface, provides access to invocable handler
|
18
|
+
class Base
|
19
|
+
# Accessor which will be invoked upon callback event
|
20
|
+
attr_accessor :handler
|
21
|
+
|
22
|
+
def initialize(args = {}, &block)
|
23
|
+
@handler = args[:handler] if args.has_key?(:handler)
|
24
|
+
@handler = block if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
# FIXME XXX this should be *args instead of args = [] (remove [] around super calls below)
|
28
|
+
def invoke(args = [])
|
29
|
+
handler.call *args
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
# Invoked upon specified minimum location movement
|
35
|
+
class Movement < Base
|
36
|
+
# Minimum distance the location needs to move to trigger event
|
37
|
+
attr_accessor :min_distance
|
38
|
+
|
39
|
+
# Minimum x,y,z distance the location needs to move to trigger the event
|
40
|
+
attr_accessor :min_x, :min_y, :min_z
|
41
|
+
|
42
|
+
def initialize(args = {}, &block)
|
43
|
+
@min_distance = 0
|
44
|
+
@min_x = 0
|
45
|
+
@min_y = 0
|
46
|
+
@min_z = 0
|
47
|
+
|
48
|
+
@min_distance = args[:min_distance] if args.has_key?(:min_distance)
|
49
|
+
@min_x = args[:min_x] if args.has_key?(:min_x)
|
50
|
+
@min_y = args[:min_y] if args.has_key?(:min_y)
|
51
|
+
@min_z = args[:min_z] if args.has_key?(:min_z)
|
52
|
+
|
53
|
+
# store original coordinates internally,
|
54
|
+
# until minimum distances are satified
|
55
|
+
# and callback is invoked, then clear
|
56
|
+
@orig_x = @orig_y = @orig_z = nil
|
57
|
+
|
58
|
+
super(args, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Calculate distance between location and old coordinates, invoke handler w/ location if minimums are true
|
62
|
+
def invoke(new_location, old_x, old_y, old_z)
|
63
|
+
# unless original coordinates is nil, ignore old coordinates passed in
|
64
|
+
if @orig_x.nil?
|
65
|
+
@orig_x = old_x
|
66
|
+
@orig_y = old_y
|
67
|
+
@orig_z = old_z
|
68
|
+
end
|
69
|
+
|
70
|
+
dx = new_location.x - @orig_x
|
71
|
+
dy = new_location.y - @orig_y
|
72
|
+
dz = new_location.z - @orig_z
|
73
|
+
d = Math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)
|
74
|
+
|
75
|
+
if d >= @min_distance && dx.abs >= @min_x && dy.abs >= @min_y && dz.abs >= @min_z
|
76
|
+
super([new_location, d, dx, dy, dz])
|
77
|
+
@orig_x = @orig_y = @orig_z = nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end # class Movement
|
81
|
+
|
82
|
+
# Invoked upon specified maximum distance between locations
|
83
|
+
class Proximity < Base
|
84
|
+
# location which to compare to
|
85
|
+
attr_accessor :to_location
|
86
|
+
|
87
|
+
# proximity event which to trigger on
|
88
|
+
attr_accessor :event
|
89
|
+
|
90
|
+
# Max distance the locations needs to be apart to trigger event
|
91
|
+
attr_accessor :max_distance
|
92
|
+
|
93
|
+
# Max x,y,z distance the locations need to be to trigger the event
|
94
|
+
attr_accessor :max_x, :max_y, :max_z
|
95
|
+
|
96
|
+
def initialize(args = {}, &block)
|
97
|
+
@max_distance = 0
|
98
|
+
@max_x = 0
|
99
|
+
@max_y = 0
|
100
|
+
@max_z = 0
|
101
|
+
@to_location = nil
|
102
|
+
@event = :proximity
|
103
|
+
|
104
|
+
@max_distance = args[:max_distance] if args.has_key?(:max_distance)
|
105
|
+
@max_x = args[:max_x] if args.has_key?(:max_x)
|
106
|
+
@max_y = args[:max_y] if args.has_key?(:max_y)
|
107
|
+
@max_z = args[:max_z] if args.has_key?(:max_z)
|
108
|
+
@to_location = args[:to_location] if args.has_key?(:to_location)
|
109
|
+
@event = args[:event].intern if args.has_key?(:event)
|
110
|
+
|
111
|
+
# keep track of proximity state internally for different event types
|
112
|
+
@locations_in_proximity = false
|
113
|
+
|
114
|
+
super(args, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Calculate distance between specified location and stored one,
|
118
|
+
# invoke handler w/ specified location if they are within proximity
|
119
|
+
def invoke(location)
|
120
|
+
dx = (location.x - to_location.x).abs
|
121
|
+
dy = (location.y - to_location.y).abs
|
122
|
+
dz = (location.z - to_location.z).abs
|
123
|
+
d = Math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)
|
124
|
+
|
125
|
+
currently_in_proximity = (d <= @max_distance) || (dx <= @max_x && dy <= @max_y && dz <= @max_z)
|
126
|
+
trigger_callback = (currently_in_proximity && (@event == :proximity ||
|
127
|
+
(@event == :entered_proximity &&
|
128
|
+
!@locations_in_proximity))) ||
|
129
|
+
(!currently_in_proximity && (@event == :left_proximity &&
|
130
|
+
@locations_in_proximity))
|
131
|
+
|
132
|
+
@locations_in_proximity = currently_in_proximity
|
133
|
+
|
134
|
+
super([location, to_location]) if trigger_callback
|
135
|
+
end
|
136
|
+
end # class Proximity
|
137
|
+
|
138
|
+
end # module Callbacks
|
139
|
+
end # module Motel
|