motel 0.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|