motel 0.2 → 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.
- 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
|