motel 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +35 -0
- data/Rakefile +48 -0
- data/bin/clients/simple/main.rb +131 -0
- data/bin/server/main.rb +61 -0
- data/conf/motel-schema.xml +72 -0
- data/lib/motel/common.rb +35 -11
- data/lib/motel/dsl.rb +12 -0
- data/lib/motel/exceptions.rb +14 -0
- data/lib/motel/location.rb +100 -0
- data/lib/motel/{models → movement_strategies}/elliptical.rb +51 -89
- data/lib/motel/movement_strategies/linear.rb +54 -0
- data/lib/motel/movement_strategies/stopped.rb +18 -0
- data/lib/motel/movement_strategy.rb +29 -0
- data/lib/motel/runner.rb +94 -108
- data/lib/motel/simrpc.rb +131 -0
- data/lib/motel/thread_pool.rb +51 -0
- data/lib/motel.rb +9 -5
- data/spec/common_spec.rb +77 -0
- data/spec/dsl_spec.rb +27 -0
- data/spec/location_spec.rb +109 -0
- data/spec/movement_strategies/elliptical_spec.rb +90 -0
- data/spec/movement_strategies/linear_spec.rb +51 -0
- data/spec/movement_strategies/stopped_spec.rb +39 -0
- data/spec/movement_strategy_spec.rb +24 -0
- data/spec/runner_spec.rb +45 -0
- data/spec/simrpc_spec.rb +85 -0
- data/spec/spec_helper.rb +26 -0
- metadata +36 -34
- data/README +0 -0
- data/conf/amqp.yml +0 -13
- data/conf/database.yml +0 -41
- data/db/migrate/001_create_locations_and_movement_strategies.rb +0 -45
- data/db/migrate/002_create_linear_movement_strategy.rb +0 -23
- data/db/migrate/003_create_elliptical_movement_strategy.rb +0 -52
- data/lib/motel/loader.rb +0 -47
- data/lib/motel/models/linear.rb +0 -76
- data/lib/motel/models/location.rb +0 -109
- data/lib/motel/models/movement_strategy.rb +0 -82
- data/lib/motel/models/stopped.rb +0 -16
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
== Motel - Movable Object Tracking Encopassing Locations
|
2
|
+
|
3
|
+
Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
4
|
+
|
5
|
+
Motel is made available under the GNU AFFERO GENERAL PUBLIC LICENSE
|
6
|
+
as published by the Free Software Foundation, either version 3
|
7
|
+
of the License, or (at your option) any later version.
|
8
|
+
|
9
|
+
=== Intro
|
10
|
+
Motel is a simple framework for tracking 3d location written in Ruby.
|
11
|
+
A simple server is provider which handles requests which the provided client
|
12
|
+
can issue, altering heirarchies of locations and updating their coordinates
|
13
|
+
and movement strategies.
|
14
|
+
|
15
|
+
Each location is associated with a movement stategy which is used to move the location
|
16
|
+
(eg update its coordinates) in accordance to a set of rules / variables specific to each
|
17
|
+
strategy.
|
18
|
+
|
19
|
+
Multiple clients can connect to a motel server simutaneously and query for locations and
|
20
|
+
subscribe handlers to be invoked on updates.
|
21
|
+
|
22
|
+
To install motel simply run:
|
23
|
+
gem install motel
|
24
|
+
|
25
|
+
Source code is available via:
|
26
|
+
git clone http://github.com/movitto/motel
|
27
|
+
|
28
|
+
=== Using
|
29
|
+
Generate documentation via
|
30
|
+
rake rdoc
|
31
|
+
|
32
|
+
Also see specs for detailed usage.
|
33
|
+
|
34
|
+
=== Authors
|
35
|
+
Mohammed Morsi <movitto@yahoo.com>
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# motel project Rakefile
|
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 'rake/rdoctask'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'rake/gempackagetask'
|
9
|
+
|
10
|
+
|
11
|
+
GEM_NAME="motel"
|
12
|
+
PKG_VERSION='0.3'
|
13
|
+
SIMRPC_SPEC='conf/motel-schema.xml'
|
14
|
+
|
15
|
+
desc "Run all specs"
|
16
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
17
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::RDocTask.new do |rd|
|
21
|
+
rd.main = "README.rdoc"
|
22
|
+
rd.rdoc_dir = "doc/site/api"
|
23
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
24
|
+
end
|
25
|
+
|
26
|
+
PKG_FILES = FileList['bin/**/*', 'conf/motel-schema.xml', 'lib/**/*.rb',
|
27
|
+
'COPYING', 'LICENSE', 'Rakefile', 'README.rdoc', 'spec/**/*.rb' ]
|
28
|
+
|
29
|
+
SPEC = Gem::Specification.new do |s|
|
30
|
+
s.name = GEM_NAME
|
31
|
+
s.version = PKG_VERSION
|
32
|
+
s.files = PKG_FILES
|
33
|
+
|
34
|
+
s.required_ruby_version = '>= 1.8.1'
|
35
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.3.3")
|
36
|
+
|
37
|
+
s.author = "Mohammed Morsi"
|
38
|
+
s.email = "movitto@yahoo.com"
|
39
|
+
s.date = %q{2010-03-14}
|
40
|
+
s.description = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
|
41
|
+
s.summary = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
|
42
|
+
s.homepage = %q{http://morsi.org/projects/motel}
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::GemPackageTask.new(SPEC) do |pkg|
|
46
|
+
pkg.need_tar = true
|
47
|
+
pkg.need_zip = true
|
48
|
+
end
|
@@ -0,0 +1,131 @@
|
|
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
|
+
CURRENT_DIR=File.dirname(__FILE__)
|
12
|
+
$: << File.expand_path(CURRENT_DIR + "/../../../lib")
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'optparse'
|
16
|
+
require 'motel'
|
17
|
+
|
18
|
+
include Motel
|
19
|
+
include Motel::MovementStrategies
|
20
|
+
|
21
|
+
######################
|
22
|
+
|
23
|
+
# TODO movement strategy support
|
24
|
+
|
25
|
+
def main()
|
26
|
+
# command line parameters
|
27
|
+
schema_file = nil
|
28
|
+
location = {:parent_id => nil,
|
29
|
+
:x => nil,
|
30
|
+
:y => nil,
|
31
|
+
:z => nil}
|
32
|
+
request_target = nil
|
33
|
+
|
34
|
+
# setup cmd line options
|
35
|
+
opts = OptionParser.new do |opts|
|
36
|
+
opts.banner = "Usage: main.rb [command] [options]"
|
37
|
+
|
38
|
+
opts.on("-h", "--help", "Print this help message") do
|
39
|
+
puts opts
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-s", "--schema [path]", "Motel Schema File") do |path|
|
44
|
+
schema_file = path
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.separator ""
|
48
|
+
opts.separator "Commands:"
|
49
|
+
opts.on("-g", "--get", "get location specified by id")do
|
50
|
+
request_target = :get_location
|
51
|
+
end
|
52
|
+
opts.on("-c", "--create", "create location w/ id")do
|
53
|
+
request_target = :create_location
|
54
|
+
end
|
55
|
+
opts.on("-u", "--update", "update location specified by id w/ specified options")do
|
56
|
+
request_target = :update_location
|
57
|
+
end
|
58
|
+
opts.on("-b", "--subscribe", "subscribe to updates to location specified by id")do
|
59
|
+
request_target = :subscribe_to_location
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.separator ""
|
63
|
+
opts.separator "Options:"
|
64
|
+
opts.on("-i", "--id [location_id]", "Target location id") do |id|
|
65
|
+
location[:id] = id
|
66
|
+
end
|
67
|
+
opts.on("-p", "--parent-id [location_id]", "Target parent location id") do |id|
|
68
|
+
location[:parent_id] = id
|
69
|
+
end
|
70
|
+
opts.on("-x", "--xcoordinate [coordinate]", "Target location x coordinate") do |x|
|
71
|
+
location[:x] = x
|
72
|
+
end
|
73
|
+
opts.on("-y", "--ycoordinate [coordinate]", "Target location y coordinate") do |y|
|
74
|
+
location[:y] = y
|
75
|
+
end
|
76
|
+
opts.on("-z", "--zcoordinate [coordinate]", "Target location z coordinate") do |z|
|
77
|
+
location[:z] = z
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# parse cmd line
|
83
|
+
begin
|
84
|
+
opts.parse!(ARGV)
|
85
|
+
rescue OptionParser::InvalidOption => e
|
86
|
+
puts opts
|
87
|
+
puts e.to_s
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
|
91
|
+
if request_target.nil? || location[:id].nil? || schema_file.nil? ||
|
92
|
+
request_target == :update && location[:x].nil? && location[:y].nil? && location[:z].nil? && location[:parent_id].nil?
|
93
|
+
puts opts
|
94
|
+
puts "must specify schema, a command to perform, a location id, and other required options"
|
95
|
+
exit
|
96
|
+
end
|
97
|
+
|
98
|
+
lid = location[:id]
|
99
|
+
location = Motel::Location.new :id => location[:id],
|
100
|
+
:parent_id => location[:parent_id],
|
101
|
+
:x => location[:x],
|
102
|
+
:y => location[:y],
|
103
|
+
:z => location[:z]
|
104
|
+
args = []
|
105
|
+
case(request_target)
|
106
|
+
when :get_location
|
107
|
+
args.push location.id
|
108
|
+
when :create_location
|
109
|
+
args.push location.id
|
110
|
+
when :update_location
|
111
|
+
args.push location
|
112
|
+
when :subscribe_to_location
|
113
|
+
args.push location.id
|
114
|
+
end
|
115
|
+
|
116
|
+
# FIXME need configurable amqp broker ip/port
|
117
|
+
client = Motel::Client.new :schema_file => schema_file
|
118
|
+
result = client.request request_target, *args
|
119
|
+
|
120
|
+
if request_target == :subscribe_to_location
|
121
|
+
client.on_location_received = lambda { |loc|
|
122
|
+
puts "location received:"
|
123
|
+
puts "#{loc}"
|
124
|
+
}
|
125
|
+
client.join
|
126
|
+
end
|
127
|
+
|
128
|
+
puts "server returned #{result}"
|
129
|
+
end
|
130
|
+
|
131
|
+
main()
|
data/bin/server/main.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# A motel server executable
|
3
|
+
# Executable to use the motel library to track locations in
|
4
|
+
# real time and provide network access to read/write location data.
|
5
|
+
#
|
6
|
+
# Flags:
|
7
|
+
# -h --help
|
8
|
+
# -s --simrpc-schema
|
9
|
+
#
|
10
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
11
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
12
|
+
|
13
|
+
CURRENT_DIR=File.dirname(__FILE__)
|
14
|
+
$: << File.expand_path(CURRENT_DIR + "/../../lib")
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'optparse'
|
18
|
+
require 'motel'
|
19
|
+
|
20
|
+
include Motel
|
21
|
+
include Motel::MovementStrategies
|
22
|
+
|
23
|
+
######################
|
24
|
+
|
25
|
+
|
26
|
+
def main()
|
27
|
+
schema_file = nil
|
28
|
+
|
29
|
+
# setup cmd line options
|
30
|
+
opts = OptionParser.new do |opts|
|
31
|
+
opts.on("-h", "--help", "Print help message") do
|
32
|
+
puts opts
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
opts.on("-s", "--simrpc-schema [path]", "Motel Simrpc Schema File") do |path|
|
36
|
+
schema_file = path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# parse cmd line
|
41
|
+
begin
|
42
|
+
opts.parse!(ARGV)
|
43
|
+
rescue OptionParser::InvalidOption
|
44
|
+
puts opts
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
if schema_file.nil? || ! File.exists?(schema_file)
|
49
|
+
puts "motel simrpc schema file required"
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
|
53
|
+
# start location runner
|
54
|
+
Motel::Runner.instance.start :async => true
|
55
|
+
|
56
|
+
# start listening for requests / block
|
57
|
+
# FIXME need configurable amqp broker ip/port
|
58
|
+
server = Motel::Server.new(:schema_file => schema_file).join
|
59
|
+
end
|
60
|
+
|
61
|
+
main()
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<!-- The motel simrpc schema definition -->
|
2
|
+
<schema>
|
3
|
+
|
4
|
+
<class name="MovementStrategy" desc="paramaterized algorithm through which a location is moved">
|
5
|
+
<member name="id" type="int" desc="MovementStrategy identifier" ignore_null="true" />
|
6
|
+
<member name="type" type="str" desc="MovementStrategy type"/>
|
7
|
+
<member name="step_delay" type="float" desc="MovementStrategy movement delay"/>
|
8
|
+
</class>
|
9
|
+
|
10
|
+
<class name="Stopped" desc="stopped movement strategy" inherits="MovementStrategy">
|
11
|
+
</class>
|
12
|
+
|
13
|
+
<class name="Linear" desc="linear movement strategy" inherits="MovementStrategy">
|
14
|
+
<member name="speed" type="float" desc="Speed which location is moving" />
|
15
|
+
<member name="direction_vector_x" type="float" desc="x component of Linear direction vector" />
|
16
|
+
<member name="direction_vector_y" type="float" desc="y component of Linear direction vector" />
|
17
|
+
<member name="direction_vector_z" type="float" desc="z component of Linear direction vector" />
|
18
|
+
</class>
|
19
|
+
|
20
|
+
<class name="Elliptical" desc="elliptical movement strategy" inherits="MovementStrategy">
|
21
|
+
<member name="speed" type="float" desc="Speed which location is moving" />
|
22
|
+
<member name="relative_to" type="float" desc="how location is relative to its parent" />
|
23
|
+
<member name="eccentricity" type="float" desc="eccentricity of elliptical orbit" />
|
24
|
+
<member name="semi_latus_rectum" type="float" desc="semi latus rectum of elliptical orbit" />
|
25
|
+
<member name="direction_major_x" type="float" desc="x component of Elliptical Major direction vector" />
|
26
|
+
<member name="direction_major_y" type="float" desc="y component of Elliptical Major direction vector" />
|
27
|
+
<member name="direction_major_z" type="float" desc="z component of Elliptical Major direction vector" />
|
28
|
+
<member name="direction_minor_x" type="float" desc="x component of Elliptical Minor direction vector" />
|
29
|
+
<member name="direction_minor_y" type="float" desc="y component of Elliptical Minor direction vector" />
|
30
|
+
<member name="direction_minor_z" type="float" desc="z component of Elliptical Minor direction vector" />
|
31
|
+
</class>
|
32
|
+
|
33
|
+
<class name="Location" desc="location in 3d space w/ coordiantes & movement strategy">
|
34
|
+
<member name="id" type="int" desc="Location identifier" ignore_null="true" />
|
35
|
+
<member name="x" type="int" desc="x coordinate"/>
|
36
|
+
<member name="y" type="int" desc="y coordinate"/>
|
37
|
+
<member name="z" type="int" desc="z coordinate"/>
|
38
|
+
<member name="parent_id" type="int" desc="location id of parent, null if this is a root location" ignore_null="true" />
|
39
|
+
<member name="parent" type="obj" associated="Location" desc="parent location"/>
|
40
|
+
<member name="children" type="array" associated="Location" desc="children locations"/>
|
41
|
+
<member name="movement_strategy" type="obj" desc="associated movement strategy"/>
|
42
|
+
<member name="entity_id" type="int" desc="id of entity represented by this location" />
|
43
|
+
<member name="entity_type" type="str" desc="type of entity represented by this location" />
|
44
|
+
</class>
|
45
|
+
|
46
|
+
<method name="get_location" desc="get location from specified id">
|
47
|
+
<param name="location_id" type="int" desc="Location identifier"/>
|
48
|
+
<return_value name="location" type="obj" associated="Location" desc="Location corresponding to id or nil"/>
|
49
|
+
</method>
|
50
|
+
|
51
|
+
<method name="create_location" desc="create new location w/ specified id">
|
52
|
+
<param name="location_id" type="int" desc="Location identifier"/>
|
53
|
+
<return_value name="success" type="bool" desc="bool success"/>
|
54
|
+
</method>
|
55
|
+
|
56
|
+
<method name="update_location" desc="update running location w/ new location sharing the same id">
|
57
|
+
<param name="location" type="obj" associated="Location" desc="Location with new attributes and identifier of location to update"/>
|
58
|
+
<return_value name="success" type="bool" desc="bool success"/>
|
59
|
+
</method>
|
60
|
+
|
61
|
+
<!-- TODO delete_location -->
|
62
|
+
|
63
|
+
<method name="subscribe_to_location" desc="subscribe simrpc endpoint to updates to location of the specified id via the location_moved method">
|
64
|
+
<param name="location_id" type="int" desc="Location identifier"/>
|
65
|
+
<param name="node_id" type="str" desc="Node identifier which to update of location movements"/>
|
66
|
+
<return_value name="success" type="bool" desc="bool success"/>
|
67
|
+
</method>
|
68
|
+
|
69
|
+
<method name="location_moved" desc="inform simrpc endpoint that location was moved">
|
70
|
+
<param name="location" type="obj" associated="Location" desc="Location that was moved with new coordinates and original id"/>
|
71
|
+
</method>
|
72
|
+
</schema>
|
data/lib/motel/common.rb
CHANGED
@@ -2,11 +2,44 @@
|
|
2
2
|
#
|
3
3
|
# Things that don't fit elsewhere
|
4
4
|
#
|
5
|
-
# Copyright (C)
|
6
|
-
#
|
5
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
6
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
7
|
+
|
8
|
+
# include logger dependencies
|
9
|
+
require 'logger'
|
7
10
|
|
8
11
|
module Motel
|
9
12
|
|
13
|
+
# Logger helper class
|
14
|
+
class Logger
|
15
|
+
private
|
16
|
+
def self._instantiate_logger
|
17
|
+
unless defined? @@logger
|
18
|
+
# FIXME need configurable log_level, out-stream
|
19
|
+
@@log_level = ::Logger::FATAL
|
20
|
+
@@logger = ::Logger.new(STDOUT)
|
21
|
+
@@logger.level = @@log_level
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
public
|
26
|
+
|
27
|
+
def self.method_missing(method_id, *args)
|
28
|
+
_instantiate_logger
|
29
|
+
@@logger.send(method_id, args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.logger
|
33
|
+
_instantiate_logger
|
34
|
+
@@logger
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.log_level=(level)
|
38
|
+
@@log_level = level
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
10
43
|
# generate a random id
|
11
44
|
def gen_uuid
|
12
45
|
["%02x"*4, "%02x"*2, "%02x"*2, "%02x"*2, "%02x"*6].join("-") %
|
@@ -43,12 +76,3 @@ class Float
|
|
43
76
|
return (self * 10 ** precision).round.to_f / (10 ** precision)
|
44
77
|
end
|
45
78
|
end
|
46
|
-
|
47
|
-
# try to find key equal to method, returning value if found
|
48
|
-
#class Hash
|
49
|
-
# def method_missing(method, *params)
|
50
|
-
# method = method.to_sym
|
51
|
-
# return self[method] if self.keys.collect{ |k| k.to_sym }.include?(method)
|
52
|
-
# super
|
53
|
-
# end
|
54
|
-
#end
|
data/lib/motel/dsl.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Motel DSL
|
2
|
+
#
|
3
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
4
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
5
|
+
|
6
|
+
# establish client connection w/ specified args and invoke block w/
|
7
|
+
# newly created client, returning it after block terminates
|
8
|
+
def connect(args = {}, &block)
|
9
|
+
client = Motel::Client.new(args)
|
10
|
+
block.call client unless block.nil?
|
11
|
+
return client
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Exceptions used in the MOTEL project
|
2
|
+
#
|
3
|
+
# Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
|
4
|
+
# Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
|
5
|
+
|
6
|
+
module Motel
|
7
|
+
|
8
|
+
class InvalidMovementStrategy < RuntimeError
|
9
|
+
def initialize(msg)
|
10
|
+
super(msg)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# The Location entity
|
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/movement_strategy'
|
7
|
+
|
8
|
+
module Motel
|
9
|
+
|
10
|
+
# A Location defines an optional parent location and the x,y,z
|
11
|
+
# cartesian coordinates of the location relative to that parent.
|
12
|
+
# If parent is not specified x,y,z are ignored and this location
|
13
|
+
# is assumed to be the 'center' of the system to which it belongs
|
14
|
+
# Also is related to a movable object defining the parameters
|
15
|
+
# of the locations movement
|
16
|
+
class Location
|
17
|
+
|
18
|
+
# id of location and parent, and coordinates relative to that parent
|
19
|
+
attr_accessor :id, :x, :y, :z, :parent_id
|
20
|
+
|
21
|
+
# handle to parent location and array of children
|
22
|
+
attr_accessor :parent, :children
|
23
|
+
|
24
|
+
# movement strategy which location move in accordance to
|
25
|
+
attr_accessor :movement_strategy
|
26
|
+
|
27
|
+
# array of callbacks to be invoked on movement
|
28
|
+
attr_accessor :movement_callbacks
|
29
|
+
|
30
|
+
# a generic association which this location can belong to
|
31
|
+
attr_accessor :entity
|
32
|
+
|
33
|
+
def initialize(args = {})
|
34
|
+
# default to the stopped movement strategy
|
35
|
+
@movement_strategy = MovementStrategies::Stopped.instance
|
36
|
+
@movement_callbacks = []
|
37
|
+
@children = []
|
38
|
+
|
39
|
+
@id = args[:id] if args.has_key? :id
|
40
|
+
@parent_id = args[:parent_id] if args.has_key? :parent_id
|
41
|
+
@x = args[:x] if args.has_key? :x
|
42
|
+
@y = args[:y] if args.has_key? :y
|
43
|
+
@z = args[:z] if args.has_key? :z
|
44
|
+
@parent = args[:parent] if args.has_key? :parent
|
45
|
+
@parent.children.push self unless @parent.nil? || @parent.children.include?(self)
|
46
|
+
@movement_strategy = args[:movement_strategy] if args.has_key? :movement_strategy
|
47
|
+
|
48
|
+
@x = 0 if @x.nil?
|
49
|
+
@y = 0 if @y.nil?
|
50
|
+
@z = 0 if @z.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
# update this location's attributes to match other's set attributes
|
54
|
+
def update(location)
|
55
|
+
@x = location.x unless location.x.nil?
|
56
|
+
@y = location.y unless location.y.nil?
|
57
|
+
@z = location.z unless location.z.nil?
|
58
|
+
@movement_strategy = location.movement_strategy unless location.movement_strategy.nil?
|
59
|
+
@parent = location.parent unless location.parent.nil?
|
60
|
+
@parent_id = location.parent_id unless location.parent_id.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
# return this location's root location
|
64
|
+
def root
|
65
|
+
return self if parent.nil?
|
66
|
+
return parent.root
|
67
|
+
end
|
68
|
+
|
69
|
+
# traverse all chilren recursively, calling block for each
|
70
|
+
def traverse_descendants(&bl)
|
71
|
+
children.each { |child|
|
72
|
+
bl.call child
|
73
|
+
child.traverse_descendants &bl
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# return sum of the x values of this location and all its parents,
|
78
|
+
# eg the absolute 'x' of the location
|
79
|
+
def total_x
|
80
|
+
return 0 if parent.nil?
|
81
|
+
return parent.total_x + x
|
82
|
+
end
|
83
|
+
|
84
|
+
# return sum of the y values of this location and all its parents
|
85
|
+
# eg the absolute 'y' of the location
|
86
|
+
def total_y
|
87
|
+
return 0 if parent.nil?
|
88
|
+
return parent.total_y + y
|
89
|
+
end
|
90
|
+
|
91
|
+
# return sum of the z values of this location and all its parents
|
92
|
+
# eg the absolute 'z' of the location
|
93
|
+
def total_z
|
94
|
+
return 0 if parent.nil?
|
95
|
+
return parent.total_z + z
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end # module Motel
|