Class: RoomPlan
Overview
== Schema Information
Table name: room_plans
Database name: primary
id :integer not null, primary key
heated_area :jsonb
heated_area_offset :decimal(, )
heated_sq_ft :decimal(, )
parent_room :integer
points :jsonb
room_area :decimal(, )
room_plan_fixtures_count :integer default(0), not null
step :integer
units :string
created_at :datetime not null
updated_at :datetime not null
party_id :integer
Indexes
index_room_plans_on_party_id (party_id) USING hash
Foreign Keys
fk_rails_... (party_id => parties.id) ON DELETE => cascade
Constant Summary
collapse
- DEFAULT_POINTS =
[
{ x: 243.84296513045595, y: 243.84296513045595 },
{ x: 731.5288953913679, y: 243.84296513045595 },
{ x: 731.5288953913679, y: 731.5288953913679 },
{ x: 243.84296513045595, y: 731.5288953913679 }
].freeze
- SCREEN_UNITS_IN_A_METER =
200
- FEET_IN_A_METER =
3.2808
SCREEN_UNITS_IN_A_METER / FEET_IN_A_METER
- SCREEN_UNITS_IN_AN_INCH =
SCREEN_UNITS_IN_A_FOOT / 12
- DEFAULT_HEATED_AREA_WALL_OFFSET =
Default heated area wall offset.
4.0
Constants included
from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Class Method Summary
collapse
Instance Method Summary
collapse
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
config
#after_commit
#publish_event
Class Method Details
.get_nominal_wall_length(d) ⇒ Object
224
225
226
227
228
229
230
231
232
233
|
# File 'app/models/room_plan.rb', line 224
def self.get_nominal_wall_length(d)
d_in_ft = (d / SCREEN_UNITS_IN_A_FOOT).round(12)
ft = d_in_ft.floor
inches = ((d_in_ft - ft) * 12).round(2)
inches = inches.to_i if inches % 1 == 0
inches = '' if inches == 0
"#{ft}' #{inches}#{'"' if inches != ''}"
end
|
.has_fixtures ⇒ ActiveRecord::Relation<RoomPlan>
A relation of RoomPlans that are has fixtures. Active Record Scope
57
|
# File 'app/models/room_plan.rb', line 57
scope :has_fixtures, ->(val = 1) { where(RoomPlan[:room_plan_fixtures_count].gteq(val)) }
|
.migrate_legacy_fixtures ⇒ Object
This is a destructive operation, beware
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# File 'app/models/room_plan.rb', line 82
def self.migrate_legacy_fixtures
RoomPlanFixture.delete_all
dt_key_map = DesignToolFixture.all.to_h { |dtf| [dtf['class_key'], dtf.id] }
puts "Design Tool Fixture map initializex with #{dt_key_map.size} entries"
RoomPlanFixture.transaction do
RoomPlan.find_each do |rp|
puts "Processing room plan #{rp.id}"
(rp.legacy_fixtures || {}).each do |f|
if (class_key = f['key'])
puts " - Converting fixture #{class_key}"
dtf_id = dt_key_map[class_key]
rp.room_plan_fixtures.create!(
design_tool_fixture_id: dtf_id,
fixture_data: f
)
else
puts " !! fixture class_key: #{class_key} is missing"
end
end
end
end
end
|
.options_for_select(_ev = nil) ⇒ Object
68
69
70
71
|
# File 'app/models/room_plan.rb', line 68
def self.options_for_select(_ev = nil)
res = all
res.map { |rp| [rp.selection_name, rp.id] }
end
|
.ransackable_scopes(_auth_object = nil) ⇒ Object
77
78
79
|
# File 'app/models/room_plan.rb', line 77
def self.ransackable_scopes(_auth_object = nil)
[:has_fixtures]
end
|
Instance Method Details
#build_heated_area ⇒ Object
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# File 'app/models/room_plan.rb', line 150
def build_heated_area
heated_area&.reduce(+'') do |pathAcc, area| i = 0
pathAcc << area.reduce('') do |haAcc, shape| if (shape.length === 1) && shape[0].is_a?(Array)
shape = shape[0]
shape = shape[0] if (shape.length === 1) && shape[0].is_a?(Array)
end
points = i.positive? ? shape.reverse : shape i += 1
points.reduce("#{haAcc} M #{points[0][0]},#{points[0][1]}") do |acc, (x, y)|
"#{acc} L #{x.to_f},#{y.to_f}"
end + 'z '
end
end
end
|
#build_walls ⇒ Object
168
169
170
171
172
173
|
# File 'app/models/room_plan.rb', line 168
def build_walls
walls = points.map { |wall| [wall['x'], wall['y']] }
walls.reduce("M #{walls[0][0]}, #{walls[0][1]} ") do |acc, (x, y)|
"#{acc} L #{x} #{y}"
end + ' z'
end
|
#clone(party_for_clone = nil) ⇒ Object
268
269
270
271
272
273
|
# File 'app/models/room_plan.rb', line 268
def clone(party_for_clone = nil)
my_clone = deep_dup
my_clone.party = party_for_clone if party_for_clone.present?
my_clone.save
my_clone
end
|
#deep_dup ⇒ Object
62
63
64
65
66
|
# File 'app/models/room_plan.rb', line 62
def deep_dup
deep_clone(include: :room_plan_fixtures) do |original, copy|
copy.parent_room = original.id if copy.is_a?(RoomPlan)
end
end
|
#determine_system_type_for_room_plan ⇒ Object
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
# File 'app/models/room_plan.rb', line 235
def determine_system_type_for_room_plan
rcs = room_configurations.includes(:room_type)
if rcs.empty?
'floor-heating'
else
environments = rcs.filter_map { |rc| rc.room_type&.environment }.uniq
if environments.include?('Outdoor')
'snow-melting'
else
'floor-heating'
end
end
end
|
#editing_locked? ⇒ Boolean
260
261
262
|
# File 'app/models/room_plan.rb', line 260
def editing_locked?
room_configurations.any?(&:room_plan_editing_locked?)
end
|
#fixtures ⇒ Object
208
209
210
|
# File 'app/models/room_plan.rb', line 208
def fixtures
room_plan_fixtures.map(&:fixture_data)
end
|
#get_distance_between_points(a, b) ⇒ Object
200
201
202
|
# File 'app/models/room_plan.rb', line 200
def get_distance_between_points(a, b)
Math.sqrt(((a['x'] - b['x'])**2) + ((a['y'] - b['y'])**2))
end
|
#get_next_point(index) ⇒ Object
204
205
206
|
# File 'app/models/room_plan.rb', line 204
def get_next_point(index)
points[modulo(index + 1, points.length)]
end
|
#get_viewbox ⇒ Object
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
# File 'app/models/room_plan.rb', line 183
def get_viewbox
all_x, all_y = points.reduce([[], []]) { |(acc_x, acc_y), h| [[*acc_x, h['x']], [*acc_y, h['y']]] }
x_min = all_x.min
y_min = all_y.min
x_size = all_x.max - x_min
y_size = all_y.max - y_min
padding = 100
padding_x = padding padding_y = padding [
x_min - padding_x,
y_min - padding_y,
x_size + (padding_x * 2),
y_size + (padding_y * 2)
].join(' ')
end
|
#hydrated_fixtures(include_visual: true) ⇒ Object
212
213
214
215
216
217
218
219
220
221
222
|
# File 'app/models/room_plan.rb', line 212
def hydrated_fixtures(include_visual: true)
preloaded_room_plan_fixtures.map do |rpf|
hsh = {
**rpf.fixture_data.symbolize_keys,
width: rpf.design_tool_fixture['size_x'] * SCREEN_UNITS_IN_AN_INCH,
height: rpf.design_tool_fixture['size_y'] * SCREEN_UNITS_IN_AN_INCH
}
hsh[:visual] = rpf.design_tool_fixture['visual'] if include_visual
hsh
end
end
|
#is_designable? ⇒ Boolean
179
180
181
|
# File 'app/models/room_plan.rb', line 179
def is_designable?
is_valid? && room_area.present? && fixtures.any? { |f| f['key'] == 'thermostat' }
end
|
#is_valid? ⇒ Boolean
175
176
177
|
# File 'app/models/room_plan.rb', line 175
def is_valid?
points.present? && fixtures.present?
end
|
#modulo(n, m) ⇒ Object
264
265
266
|
# File 'app/models/room_plan.rb', line 264
def modulo(n, m)
((n % m) + m) % m
end
|
#ok_to_delete? ⇒ Boolean
256
257
258
|
# File 'app/models/room_plan.rb', line 256
def ok_to_delete?
room_configurations.empty?
end
|
#owned_or_cloned(customer) ⇒ Object
275
276
277
278
279
280
281
|
# File 'app/models/room_plan.rb', line 275
def owned_or_cloned(customer)
if party_id == customer.id
self
else
clone(customer)
end
end
|
51
|
# File 'app/models/room_plan.rb', line 51
belongs_to :party, inverse_of: :room_plans, optional: true
|
#preloaded_room_plan_fixtures ⇒ ActiveRecord::Relation<RoomPlanFixture>
55
|
# File 'app/models/room_plan.rb', line 55
has_many :preloaded_room_plan_fixtures, -> { eager_load(:design_tool_fixture) }, class_name: 'RoomPlanFixture'
|
#room_configurations ⇒ ActiveRecord::Relation<RoomConfiguration>
53
|
# File 'app/models/room_plan.rb', line 53
has_many :room_configurations, inverse_of: :room_plan, dependent: :nullify
|
#room_plan_fixtures ⇒ ActiveRecord::Relation<RoomPlanFixture>
54
|
# File 'app/models/room_plan.rb', line 54
has_many :room_plan_fixtures, dependent: :destroy, autosave: true
|
#save_state(state) ⇒ Object
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
# File 'app/models/room_plan.rb', line 131
def save_state(state)
self.step = state['step']
self.units = state['units']
self.points = state['points']
self.room_area = state['roomArea']
self.heated_area = state['heatedArea']
self.heated_sq_ft = state['rawHeatedAreaSqft']
self.heated_area_offset = [2, state['heatedAreaOffset'].to_f].max
room_plan_fixtures.destroy_all
(state['fixtures'] || []).each do |fixture_data|
if (design_tool_fixture = DesignToolFixture.find_by(class_key: fixture_data['key']))
room_plan_fixtures.build(design_tool_fixture_id: design_tool_fixture.id, fixture_data: fixture_data)
end
end
save
end
|
#selection_name ⇒ Object
73
74
75
|
# File 'app/models/room_plan.rb', line 73
def selection_name
"##{id}#{" by #{party}" if party}"
end
|
#serialize_data ⇒ Object
105
106
107
108
109
110
111
112
113
114
115
|
# File 'app/models/room_plan.rb', line 105
def serialize_data
{
fixtures: hydrated_fixtures(include_visual: false),
points: points.map { |p| [p['x'], p['y']] },
units: units || 'ftin',
roomArea: room_area&.to_f,
heatedArea: heated_area,
rawHeatedAreaSqft: heated_sq_ft&.to_f,
heatedAreaOffset: heated_area_offset&.to_f || DEFAULT_HEATED_AREA_WALL_OFFSET
}
end
|
#serialize_state ⇒ Object
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'app/models/room_plan.rb', line 117
def serialize_state
{
step: step || 1,
id: id,
units: units || 'ftin',
points: points || DEFAULT_POINTS,
fixtures: fixtures,
roomArea: room_area&.to_f,
heatedArea: heated_area,
rawHeatedAreaSqft: heated_sq_ft&.to_f,
heatedAreaOffset: heated_area_offset&.to_f || DEFAULT_HEATED_AREA_WALL_OFFSET
}
end
|