Class: SpaceTimeId

Inherits:
Object
  • Object
show all
Defined in:
lib/space_time_id.rb

Constant Summary collapse

DEFAULTS =
{
  xy_base_step: 0.01, # 0.01 degrees
  xy_expansion: 5,    # expands into a 5x5 grid recursively
  ts_base_step: 600,  # 10 minutes
  ts_expansion: [1, 3, 2, 3, 2], # expands 3 times each interval, then 2, then 3....
  decimals: 2
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ SpaceTimeId

Returns a new instance of SpaceTimeId.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/space_time_id.rb', line 18

def initialize(*args)
  self.options = DEFAULTS.merge(args.extract_options!)
  self.interval = options.delete(:interval) || 0
  self.level = options.delete(:level) || 0
  options[:ts_expansion] = Array(options[:ts_expansion])
  if args.length == 1 && args.first.is_a?(String)
    initialize(*args.first.split("_").map(&:to_f), original_options)
  elsif args.length == 1 && args.first.is_a?(Array) && args.first.length == 2
    initialize(*(args.first), original_options)
  elsif args.all? { |arg| arg.is_a?(Fixnum) || arg.is_a?(Float) }
    case args.length
    when 1
      self.ts_sec = args.first
      self.ts_sec = ts_id.to_i
    when 2
      self.x, self.y = args
      self.x, self.y = xy_id_2d
    when 3
      self.ts_sec, self.x, self.y = args
      self.x, self.y = xy_id_2d
      self.ts_sec = ts_id.to_i
    else
      raise "Invalid initialize arguments! (#{args.inspect})"
    end
  elsif args.length == 2 &&
      (args.first.is_a?(Fixnum) || args.first.is_a?(Float)) && args.last.is_a?(Array)
    ts = args.first
    x, y = args.last
    initialize(ts, x, y, original_options)
  else
    raise "Invalid initialize arguments! (#{args.inspect})"
  end
end

Instance Attribute Details

#intervalObject

Returns the value of attribute interval.



15
16
17
# File 'lib/space_time_id.rb', line 15

def interval
  @interval
end

#levelObject

Returns the value of attribute level.



16
17
18
# File 'lib/space_time_id.rb', line 16

def level
  @level
end

#optionsObject

Returns the value of attribute options.



14
15
16
# File 'lib/space_time_id.rb', line 14

def options
  @options
end

#ts_secObject

Returns the value of attribute ts_sec.



11
12
13
# File 'lib/space_time_id.rb', line 11

def ts_sec
  @ts_sec
end

#xObject

Returns the value of attribute x.



12
13
14
# File 'lib/space_time_id.rb', line 12

def x
  @x
end

#yObject

Returns the value of attribute y.



13
14
15
# File 'lib/space_time_id.rb', line 13

def y
  @y
end

Instance Method Details

#==(other) ⇒ Object



79
80
81
# File 'lib/space_time_id.rb', line 79

def ==(other)
  other.nil? || !other.respond_to?(:id) ? false : id == other.id
end

#decObject



95
96
97
# File 'lib/space_time_id.rb', line 95

def dec
  options[:decimals]
end

#dup(new_id = id, options = self.options) ⇒ Object



91
92
93
# File 'lib/space_time_id.rb', line 91

def dup(new_id = id, options = self.options)
  SpaceTimeId.new(new_id, original_options.merge(options))
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/space_time_id.rb', line 83

def eql?(other)
  other.is_a?(SpaceTimeId) && self == other
end

#hashObject



87
88
89
# File 'lib/space_time_id.rb', line 87

def hash
  [id, interval, level].hash
end

#idObject



52
53
54
# File 'lib/space_time_id.rb', line 52

def id
  [ts_id, xy_id_str].compact.join("_")
end

#inspectObject



60
61
62
# File 'lib/space_time_id.rb', line 60

def inspect
  "<SpaceTimeId:#{id} #{original_options.inspect}>"
end

#next_ts(i = 1) ⇒ Object

# # # # # # # # # # # # T I M E R E L A T I O N S # # # # # # # # # # # #



147
148
149
150
# File 'lib/space_time_id.rb', line 147

def next_ts(i = 1)
  @_next_ts ||= {}
  @_next_ts[i] ||= digitize(ts_id + ts_step * i + ts_step / 2.0, ts_step) if ts?
end

#next_x(i = 1) ⇒ Object

# # # # # # # # # # # S P A C E R E L A T I O N S # # # # # # # # # # # #



204
205
206
207
# File 'lib/space_time_id.rb', line 204

def next_x(i = 1)
  @_next_x ||= {}
  @_next_x[i] ||= digitize(x + xy_step * i + xy_step / 2.0, xy_step) if xy?
end

#next_y(i = 1) ⇒ Object



209
210
211
212
# File 'lib/space_time_id.rb', line 209

def next_y(i = 1)
  @_next_y ||= {}
  @_next_y[i] ||= digitize(y + xy_step * i + xy_step / 2.0, xy_step) if xy?
end

#original_optionsObject



99
100
101
# File 'lib/space_time_id.rb', line 99

def original_options
  {level: level, interval: interval}.merge(options)
end

#to_htmlObject



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/space_time_id.rb', line 64

def to_html
  html = "id: #{id}<br/>"
  if ts?
    html << "interval: #{inteval}<br/>"
    html << "time_base_step: #{time_base_step}<br/>"
    html << "time_expansion: #{time_expansion}<br/>"
  end
  if xy?
    html << "level: #{level}<br/>"
    html << "xy_base_step: #{xy_base_step}<br/>"
    html << "xy_expansion: #{xy_expansion}<br/>"
  end
  html
end

#to_sObject



56
57
58
# File 'lib/space_time_id.rb', line 56

def to_s
  id
end

#tsObject



109
110
111
# File 'lib/space_time_id.rb', line 109

def ts
  Time.at(ts_sec) if ts_sec
end

#ts?Boolean

# # # # # # # # # # # T I M E # # # # # # # # # # # # # # # # # # # # # # #

Returns:

  • (Boolean)


105
106
107
# File 'lib/space_time_id.rb', line 105

def ts?
  !ts_sec.nil?
end

#ts_base_stepObject



129
130
131
# File 'lib/space_time_id.rb', line 129

def ts_base_step
  options[:ts_base_step]
end

#ts_expansionObject



133
134
135
136
# File 'lib/space_time_id.rb', line 133

def ts_expansion
  ts_expansion_aux
  options[:ts_expansion][0..interval].reduce(:*)
end

#ts_expansion_auxObject



138
139
140
141
142
143
# File 'lib/space_time_id.rb', line 138

def ts_expansion_aux
  if interval >= options[:ts_expansion].length
    padd = [options[:ts_expansion].last] * (options[:ts_expansion].length - interval + 1)
    options[:ts_expansion] += padd
  end
end

#ts_idObject



117
118
119
# File 'lib/space_time_id.rb', line 117

def ts_id
  digitize(ts_sec, ts_step).to_i if ts_sec
end

#ts_msObject



113
114
115
# File 'lib/space_time_id.rb', line 113

def ts_ms
  ts_sec * 1000 if ts_sec
end

#ts_neighborsObject



152
153
154
155
156
157
158
# File 'lib/space_time_id.rb', line 152

def ts_neighbors
  @ts_neighbors ||= begin
    prevt = dup(next_ts(-1))
    nextt = dup(next_ts)
    @ts_neighbors = [prevt, nextt]
  end if ts?
end

#ts_parentObject



160
161
162
# File 'lib/space_time_id.rb', line 160

def ts_parent
  dup(id, interval: interval + 1) if ts?
end

#ts_stepObject



121
122
123
# File 'lib/space_time_id.rb', line 121

def ts_step
  @ts_step ||= ts_step_aux(interval)
end

#ts_step_aux(interval) ⇒ Object



125
126
127
# File 'lib/space_time_id.rb', line 125

def ts_step_aux(interval)
  ts_base_step * ts_expansion
end

#xyObject



170
171
172
# File 'lib/space_time_id.rb', line 170

def xy
  [x, y].compact
end

#xy?Boolean

# # # # # # # # # # # S P A C E # # # # # # # # # # # # # # # # # # # # # #

Returns:

  • (Boolean)


166
167
168
# File 'lib/space_time_id.rb', line 166

def xy?
  !xy.empty?
end

#xy_base_stepObject



194
195
196
# File 'lib/space_time_id.rb', line 194

def xy_base_step
  options[:xy_base_step]
end

#xy_boundaryObject



262
263
264
# File 'lib/space_time_id.rb', line 262

def xy_boundary
  xy_four_corners << xy if xy?
end

#xy_boxObject



254
255
256
# File 'lib/space_time_id.rb', line 254

def xy_box
  [xy, [next_x, next_y]] if xy?
end

#xy_childrenObject



232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/space_time_id.rb', line 232

def xy_children
  raise "No children for level zero!" if level == 0
  @xy_children ||= begin
    bottom_left = dup(id, level: level - 1)
    @xy_children = []
    (0...xy_expansion).each do |h|
      (0...xy_expansion).each do |v|
        @xy_children << bottom_left.dup([bottom_left.next_x(h), bottom_left.next_y(v)])
      end
    end
    @xy_children
  end if xy?
end

#xy_descendantsObject



246
247
248
# File 'lib/space_time_id.rb', line 246

def xy_descendants
  xy_children + (level == 1 ? [] : xy_children.map(&:xy_descendants).flatten) if xy?
end

#xy_expansionObject



198
199
200
# File 'lib/space_time_id.rb', line 198

def xy_expansion
  options[:xy_expansion]
end

#xy_four_cornersObject



258
259
260
# File 'lib/space_time_id.rb', line 258

def xy_four_corners
  [xy, [next_x, y], [next_x, next_y], [x, next_y]] if xy?
end

#xy_id_2dObject



174
175
176
# File 'lib/space_time_id.rb', line 174

def xy_id_2d
  xy.map { |c| digitize(c, xy_step).round(dec) } if xy?
end

#xy_id_2d_centerObject



182
183
184
# File 'lib/space_time_id.rb', line 182

def xy_id_2d_center
  xy_id_2d.map { |c| (c + (xy_step / 2.0)).round(dec * 2) } if xy?
end

#xy_id_strObject



178
179
180
# File 'lib/space_time_id.rb', line 178

def xy_id_str
  xy.map { |c| digitize_str(c, xy_step, dec) } .join("_") if xy?
end

#xy_id_str_centerObject



186
187
188
# File 'lib/space_time_id.rb', line 186

def xy_id_str_center
  xy_id_2d_center.map { |c| digitize_str(c, (xy_step / 2.0), dec * 2) } .join("_") if xy?
end

#xy_neighborsObject



214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/space_time_id.rb', line 214

def xy_neighbors
  @xy_neighbors ||= begin
    topLeft      = dup([next_x(-1), next_y(1) ])
    top          = dup([x         , next_y(1) ])
    topRight     = dup([next_x(1) , next_y(1) ])
    right        = dup([next_x(1) , y         ])
    bottomRight  = dup([next_x(1) , next_y(-1)])
    bottom       = dup([x         , next_y(-1)])
    bottomLeft   = dup([next_x(-1), next_y(-1)])
    left         = dup([next_x(-1), y         ])
    @xy_neighbors = [topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left]
  end if xy?
end

#xy_parentObject



228
229
230
# File 'lib/space_time_id.rb', line 228

def xy_parent
  dup(id, level: level + 1) if xy?
end

#xy_siblingsObject



250
251
252
# File 'lib/space_time_id.rb', line 250

def xy_siblings
  xy_parent.xy_children if xy?
end

#xy_stepObject



190
191
192
# File 'lib/space_time_id.rb', line 190

def xy_step
  (xy_expansion ** level) * xy_base_step
end