Class: DesignToolFixture

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable
Defined in:
app/models/design_tool_fixture.rb

Constant Summary collapse

FUDGE_FACTOR =

Martinez-Rueda polygon clipping algorithm cannot handle lines that overlap EXACTLY

0.0005
SCREEN_UNITS_IN_A_METER =
0.005
FEET_IN_A_METER =
3.2808
SCREEN_UNITS_IN_A_FOOT =

0.016404

SCREEN_UNITS_IN_A_METER * FEET_IN_A_METER

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Has and belongs to many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #creator, #should_not_save_version, #stamp_record, #updater

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.build_transform(key, x, y, rot, width, height, scaleX, scaleY) ⇒ Object



497
498
499
500
501
502
503
504
# File 'app/models/design_tool_fixture.rb', line 497

def self.build_transform(key, x, y, rot, width, height, scaleX, scaleY)
   scaled_half_width = width * scaleX / 2
   scaled_half_height = height * scaleY / 2
   final_rot = key != 'thermostat' ? rot : 0

   #`translate(${(x - scaledHalfWidth)}, ${(y - scaledHalfHeight)}) rotate(${finalRot}, ${scaledHalfWidth}, ${scaledHalfHeight}) scale(${scaleX}, ${scaleY})`
  "translate(#{x.to_f - scaled_half_width}, #{y.to_f - scaled_half_height}) rotate(#{final_rot}, #{scaled_half_width}, #{scaled_half_height}) scale(#{scaleX}, #{scaleY})"
end

.export_room_types_join_table_to_csvObject



436
437
438
439
440
441
442
443
444
445
# File 'app/models/design_tool_fixture.rb', line 436

def self.export_room_types_join_table_to_csv
  attributes = ["design_tool_fixture_id", "room_type_id"]
  CSV.generate(headers: true) do |csv|
    csv << attributes
    res = ActiveRecord::Base.connection.execute("SELECT * from design_tool_fixtures_room_types")
    res.to_a.each do |dtfrth|
      csv << attributes.map { |k| dtfrth[k] }
    end
  end
end

.export_to_csvObject



426
427
428
429
430
431
432
433
434
# File 'app/models/design_tool_fixture.rb', line 426

def self.export_to_csv
  attributes = DesignToolFixture.first.attributes.keys
  CSV.generate(headers: true) do |csv|
    csv << attributes
    DesignToolFixture.all.to_a.each do |dtf|
      csv << attributes.map { |k| dtf.send(k) }
    end
  end
end

.fix_snap_distance(options = {}, snap_distance = 0) ⇒ Object

These are for offline fixes to these design tool fixtures not to be used other than by me: Ramie



449
450
451
452
453
# File 'app/models/design_tool_fixture.rb', line 449

def self.fix_snap_distance(options = {}, snap_distance = 0)
  dtfs = DesignToolFixture.get_dtfs_from_options(options)
  logger.debug "fix_snap_distance about to: dtfs.update_all(snap_distance: #{snap_distance}), dtfs.count: #{dtfs.count}"
  dtfs.update_all(snap_distance: snap_distance)
end

.get_dtfs_from_options(options) ⇒ Object



484
485
486
487
488
489
490
491
492
493
494
495
# File 'app/models/design_tool_fixture.rb', line 484

def self.get_dtfs_from_options(options)
  if options.empty?
    dtfs = DesignToolFixture.all
  else
    dtfs = DesignToolFixture
    dtfs = dtfs.where(["updated_at > ?", (options[:updated_after_days_ago].days.ago)]) if (options[:updated_after_days_ago] and options[:updated_after_days_ago] >= 0)
    dtfs = dtfs.where(["updated_at < ?", (options[:updated_before_days_ago].days.ago)]) if (options[:updated_before_days_ago] and options[:updated_before_days_ago] >= 0)
    dtfs = dtfs.where(["snap_distance > ?", options[:snap_distance_gt]]) if (options[:snap_distance_gt] and options[:snap_distance_gt] >= 0)
    dtfs = dtfs.where(["snap_distance < ?", options[:snap_distance_lt]]) if (options[:snap_distance_lt] and options[:snap_distance_lt] >= 0)
  end
  dtfs
end

.import_from_xml(xml_path = nil) ⇒ Object



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'app/models/design_tool_fixture.rb', line 327

def self.import_from_xml(xml_path = nil)
  xml_path ||= '/Users/cbillen/Projects/myprojects/public/DT/params.xml'
  require 'nokogiri'
  doc = Nokogiri::XML(File.open(xml_path))
  doc.xpath('//Fixtures/Fixture').each do |i|
    class_key = i['classKey']
    # puts "Processing node #{class_key}"
    dtf = DesignToolFixture.find_by(class_key: class_key)
    dtf ||= DesignToolFixture.new(:class_key => class_key)

    dtf.menu_image_file = i['menuImageURL'].split('/')[1]
    dtf.room_image_file = i['roomImageURL'].split('/')[1]
    dtf.name = i.xpath('DisplayName').text
    dtf.symbol_key = i.xpath('SymbolKey').text
    lpa = i.xpath('LPAException').first
    if lpa['type'] == 'none'
      dtf.lpa_type = nil
      dtf.lpa_n = nil
      dtf.lpa_e = nil
      dtf.lpa_s = nil
      dtf.lpa_w = nil
      dtf.lpa_x = nil
      dtf.lpa_y = nil
    else
      dtf.lpa_type = lpa['type']
      dtf.lpa_n = lpa['north']
      dtf.lpa_e = lpa['east']
      dtf.lpa_s = lpa['south']
      dtf.lpa_w = lpa['west']
      dtf.lpa_x = lpa['offsetX']
      dtf.lpa_y = lpa['offsetY']
    end
    spa = i.xpath('SPAException').first
    if spa['type'] == 'none'
      dtf.spa_type = nil
      dtf.spa_n = nil
      dtf.spa_e = nil
      dtf.spa_s = nil
      dtf.spa_w = nil
      dtf.spa_x = nil
      dtf.spa_y = nil
    else
      dtf.spa_type = spa['type']
      dtf.spa_n = spa['north']
      dtf.spa_e = spa['east']
      dtf.spa_s = spa['south']
      dtf.spa_w = spa['west']
      dtf.spa_x = spa['offsetX']
      dtf.spa_y = spa['offsetY']
    end

    hpa = i.xpath('HPAException').first
    if hpa['type'] == 'none'
      dtf.hpa_type = nil
      dtf.hpa_n = nil
      dtf.hpa_e = nil
      dtf.hpa_s = nil
      dtf.hpa_w = nil
      dtf.hpa_x = nil
      dtf.hpa_y = nil
    else
      dtf.hpa_type = hpa['type']
      dtf.hpa_n = hpa['north']
      dtf.hpa_e = hpa['east']
      dtf.hpa_s = hpa['south']
      dtf.hpa_w = hpa['west']
      dtf.hpa_x = hpa['offsetX']
      dtf.hpa_y = hpa['offsetY']
    end

    dtf.size_x_min = i.xpath('SizeBounds').first['xdMin'].to_i
    dtf.size_x_max = i.xpath('SizeBounds').first['xdMax'].to_i
    dtf.size_y_min = i.xpath('SizeBounds').first['ydMin'].to_i
    dtf.size_y_max = i.xpath('SizeBounds').first['ydMax'].to_i

    dtf.size_x = i.xpath('DefaultSize').first['x'].to_i
    dtf.size_y = i.xpath('DefaultSize').first['y'].to_i

    dtf.auto_rotate = i.xpath('SnapParams').first['autoRotateEnabled'] || false
    dtf.snap_enabled = i.xpath('SnapParams').first['snapEnabled'] || false
    dtf.snap_to_center = i.xpath('SnapParams').first['snapToCenter'] || false
    dtf.snap_distance = i.xpath('SnapParams').first['snapDistance'].to_i
    dtf.snap_rotation = i.xpath('SnapParams').first['snapRotation'].to_i

    dtf.category = i.xpath('Category').text
    #Process rooms
    i.xpath('RoomType').each do |rt|
      room_type = RoomType.where("name ILIKE ?", rt.text).first
      if room_type
        dtf.room_types << room_type
      end
    end

    dtf.save
    # puts "DTF #{dtf.id} saved."
    # puts dtf.to_yaml
  end
end

.invert_n_and_s(options = {}) ⇒ Object



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'app/models/design_tool_fixture.rb', line 455

def self.invert_n_and_s(options = {})
  dtfs = DesignToolFixture.get_dtfs_from_options(options)
  logger.debug "invert_n_and_s, dtfs.count: #{dtfs.count}"
  dtfs.each do |dtf|
    before = "dtf.pha_n: #{dtf.pha_n}, dtf.pha_s: #{dtf.pha_s}, dtf.lpa_n: #{dtf.lpa_n}, dtf.lpa_s: #{dtf.lpa_s}, dtf.spa_n: #{dtf.spa_n}, dtf.spa_s: #{dtf.spa_s}, dtf.hpa_n: #{dtf.hpa_n}, dtf.hpa_s: #{dtf.hpa_s}"
    logger.debug "before: #{before}"
    n = dtf.pha_n
    s = dtf.pha_s
    dtf.pha_n = s
    dtf.pha_s = n
    n = dtf.lpa_n
    s = dtf.lpa_s
    dtf.lpa_n = s
    dtf.lpa_s = n
    n = dtf.spa_n
    s = dtf.spa_s
    dtf.spa_n = s
    dtf.spa_s = n
    n = dtf.hpa_n
    s = dtf.hpa_s
    dtf.hpa_n = s
    dtf.hpa_s = n
    after = "dtf.pha_n: #{dtf.pha_n}, dtf.pha_s: #{dtf.pha_s}, dtf.lpa_n: #{dtf.lpa_n}, dtf.lpa_s: #{dtf.lpa_s}, dtf.spa_n: #{dtf.spa_n}, dtf.spa_s: #{dtf.spa_s}, dtf.hpa_n: #{dtf.hpa_n}, dtf.hpa_s: #{dtf.hpa_s}"
    logger.debug "after: #{after}"
    logger.debug "invert_n_and_s about to dtf.save"
    dtf.save
  end
end

.update_measurementsObject



320
321
322
323
324
325
# File 'app/models/design_tool_fixture.rb', line 320

def self.update_measurements
  DesignToolFixture.all.each do |f|
    f.update_measurements
    f.save
  end
end

Instance Method Details

#as_json(options = {}) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'app/models/design_tool_fixture.rb', line 247

def as_json(options = {})
  hole_punches = spa_e.nil? ? [] : [{
    height: to_su(spa_height + FUDGE_FACTOR),
    width: to_su(spa_width + FUDGE_FACTOR),
    offset: {
      x: -to_su(spa_e),
      y: -to_su(spa_s)
    }
  }]

  toasty_zones = pha_e.nil? ? [] : [{
    height: to_su(pha_height - FUDGE_FACTOR),
    width: to_su(pha_width - FUDGE_FACTOR),
    offset: {
      x: -to_su(pha_e - FUDGE_FACTOR),
      y: -to_su(pha_s + FUDGE_FACTOR)
    }
  }]

  {
    id: id,
    name: name,
    key: class_key,
    category: category,
    x: nil,
    y: nil,
    height: to_su(size_y),
    width: to_su(size_x),
    rot: 0,
    scaleX: 1,
    scaleXMin: size_x_min.to_f / size_x.to_f,
    scaleXMax: size_x_max.to_f / size_x.to_f,
    scaleY: 1,
    scaleYMin: size_y_min.to_f / size_y.to_f,
    scaleYMax: size_y_max.to_f / size_y.to_f,
    # Snap params (used by the JS "magnet" snapping behavior)
    snapEnabled: snap_enabled,
    autoRotate: auto_rotate,
    snapRotation: snap_rotation,
    # snap_distance is stored in inches (from params.xml). Convert to screen units.
    snapDistance: to_su(snap_distance.to_f),
    snapToCenter: snap_to_center,
    # magnet: {
    #   x: 208,
    #   y: 482.9232829714554
    # },
    magnetOffset: {
      x: 0,
      y: (((snap_to_center? ? (size_y/2.0) : -snap_distance).to_f - 0.1) / 12 / SCREEN_UNITS_IN_A_FOOT)
    # snap_distance cannot be exactly half-height, so we +0.1
    },
    holePunches: hole_punches,
    toastyZones: toasty_zones,
    isInvalid: false,
    visual: visual,
  }
end

#room_typesActiveRecord::Relation<RoomType>

convertScreenUnitsToMeters = (su) => su * SCREEN_UNITS_IN_A_METER
convertScreenUnitsToFt = (su) => su * SCREEN_UNITS_IN_A_FOOT
convertScreenUnitsToInches = (su) => su * SCREEN_UNITS_IN_A_FOOT * 12
convertMetersToScreenUnits = (m) => m / SCREEN_UNITS_IN_A_METER
convertFtToScreenUnits = (feet) => feet / SCREEN_UNITS_IN_A_FOOT
convertInchesToScreenUnits = (inches) => inches / 12 / SCREEN_UNITS_IN_A_FOOT

Returns:

See Also:



234
# File 'app/models/design_tool_fixture.rb', line 234

has_and_belongs_to_many :room_types

#to_su(inches) ⇒ Object



243
244
245
# File 'app/models/design_tool_fixture.rb', line 243

def to_su(inches)
  inches.to_f / 12 / SCREEN_UNITS_IN_A_FOOT
end

#update_measurementsObject



305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'app/models/design_tool_fixture.rb', line 305

def update_measurements
  self.scale_x_min = self.size_x_min.to_f / self.size_x.to_f
  self.scale_x_max = self.size_x_max.to_f / self.size_x.to_f
  self.scale_y_min = self.size_y_min.to_f / self.size_y.to_f
  self.scale_y_max = self.size_y_max.to_f / self.size_y.to_f
  self.pha_height = self.pha_n.nil? ? nil : (self.pha_n + self.size_y + self.pha_s)
  self.pha_width = self.pha_w.nil? ? nil : (self.pha_w + self.size_x + self.pha_e)
  self.lpa_height = self.lpa_n.nil? ? nil : (self.lpa_n + self.size_y + self.lpa_s)
  self.lpa_width = self.lpa_w.nil? ? nil : (self.lpa_w + self.size_x + self.lpa_e)
  self.spa_height = self.spa_n.nil? ? nil : (self.spa_n + self.size_y + self.spa_s)
  self.spa_width = self.spa_w.nil? ? nil : (self.spa_w + self.size_x + self.spa_e)
  self.hpa_height = self.hpa_n.nil? ? nil : (self.hpa_n + self.size_y + self.hpa_s)
  self.hpa_width = self.hpa_w.nil? ? nil : (self.hpa_w + self.size_x + self.hpa_e)
end

#visualObject



239
240
241
# File 'app/models/design_tool_fixture.rb', line 239

def visual
  super&.gsub(/"/m, '\'')&.gsub(/\r\n\s+/m, '')
end