tbd 3.2.2 → 3.2.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.
- checksums.yaml +4 -4
- data/lib/measures/tbd/measure.xml +12 -12
- data/lib/measures/tbd/resources/geo.rb +4 -40
- data/lib/measures/tbd/resources/ua.rb +1 -1
- data/lib/measures/tbd/resources/utils.rb +590 -2
- data/lib/tbd/geo.rb +4 -40
- data/lib/tbd/ua.rb +1 -1
- data/lib/tbd/version.rb +1 -1
- data/tbd.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15442c735a4591e22e609b8b2f73733a583a5f6b304c3c479866d98afcf63251
|
|
4
|
+
data.tar.gz: c4d53db567cc419b2e0eb5b4b48f85f19e6c12745bab19ee257566c0c1b38bea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e314e00796a8d0e6e44c6ccd23d0e9accaa45be119589da431d00f45354c622bbedd964b94053fd9823c33914713b07984e0f0df44f714d4311ac16f382c0407
|
|
7
|
+
data.tar.gz: 7344be85007deed2d9a22d83c0cb20d4860d4e048c1bf281e7f2c8024439696b75ba6d232c9f8985253003c1295d2e537fc29a9fb9322ea6d756bcd08ec0dcf9
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<schema_version>3.0</schema_version>
|
|
4
4
|
<name>tbd_measure</name>
|
|
5
5
|
<uid>8890787b-8c25-4dc8-8641-b6be1b6c2357</uid>
|
|
6
|
-
<version_id>
|
|
7
|
-
<version_modified>
|
|
6
|
+
<version_id>30d7ee3a-8327-4a32-92fd-5cc0b9ab24b0</version_id>
|
|
7
|
+
<version_modified>20230516T180637Z</version_modified>
|
|
8
8
|
<xml_checksum>99772807</xml_checksum>
|
|
9
9
|
<class_name>TBDMeasure</class_name>
|
|
10
10
|
<display_name>Thermal Bridging and Derating - TBD</display_name>
|
|
@@ -406,12 +406,6 @@
|
|
|
406
406
|
<usage_type>resource</usage_type>
|
|
407
407
|
<checksum>A4E8433C</checksum>
|
|
408
408
|
</file>
|
|
409
|
-
<file>
|
|
410
|
-
<filename>utils.rb</filename>
|
|
411
|
-
<filetype>rb</filetype>
|
|
412
|
-
<usage_type>resource</usage_type>
|
|
413
|
-
<checksum>283C976C</checksum>
|
|
414
|
-
</file>
|
|
415
409
|
<file>
|
|
416
410
|
<version>
|
|
417
411
|
<software_program>OpenStudio</software_program>
|
|
@@ -454,16 +448,22 @@
|
|
|
454
448
|
<checksum>A3BB982A</checksum>
|
|
455
449
|
</file>
|
|
456
450
|
<file>
|
|
457
|
-
<filename>
|
|
451
|
+
<filename>ua.rb</filename>
|
|
458
452
|
<filetype>rb</filetype>
|
|
459
453
|
<usage_type>resource</usage_type>
|
|
460
|
-
<checksum>
|
|
454
|
+
<checksum>EEFCA7DA</checksum>
|
|
461
455
|
</file>
|
|
462
456
|
<file>
|
|
463
|
-
<filename>
|
|
457
|
+
<filename>utils.rb</filename>
|
|
458
|
+
<filetype>rb</filetype>
|
|
459
|
+
<usage_type>resource</usage_type>
|
|
460
|
+
<checksum>C03764A5</checksum>
|
|
461
|
+
</file>
|
|
462
|
+
<file>
|
|
463
|
+
<filename>geo.rb</filename>
|
|
464
464
|
<filetype>rb</filetype>
|
|
465
465
|
<usage_type>resource</usage_type>
|
|
466
|
-
<checksum>
|
|
466
|
+
<checksum>5F84399F</checksum>
|
|
467
467
|
</file>
|
|
468
468
|
</files>
|
|
469
469
|
</measure>
|
|
@@ -218,42 +218,6 @@ module TBD
|
|
|
218
218
|
true
|
|
219
219
|
end
|
|
220
220
|
|
|
221
|
-
##
|
|
222
|
-
# Validate whether an OpenStudio planar surface is safe for TBD to process.
|
|
223
|
-
#
|
|
224
|
-
# @param s [OpenStudio::Model::PlanarSurface] a surface
|
|
225
|
-
#
|
|
226
|
-
# @return [Bool] true if valid surface
|
|
227
|
-
def validate(s = nil)
|
|
228
|
-
mth = "TBD::#{__callee__}"
|
|
229
|
-
cl = OpenStudio::Model::PlanarSurface
|
|
230
|
-
|
|
231
|
-
return mismatch("surface", s, cl, mth, DBG, false) unless s.is_a?(cl)
|
|
232
|
-
|
|
233
|
-
id = s.nameString
|
|
234
|
-
size = s.vertices.size
|
|
235
|
-
last = size - 1
|
|
236
|
-
|
|
237
|
-
log(ERR, "#{id} #{size} vertices? need +3 (#{mth})") unless size > 2
|
|
238
|
-
return false unless size > 2
|
|
239
|
-
|
|
240
|
-
[0, last].each do |i|
|
|
241
|
-
v1 = s.vertices[i]
|
|
242
|
-
v2 = s.vertices[i + 1] unless i == last
|
|
243
|
-
v2 = s.vertices.first if i == last
|
|
244
|
-
vector = v2 - v1
|
|
245
|
-
bad = vector.length < TOL
|
|
246
|
-
|
|
247
|
-
# As is, this comparison also catches collinear vertices (< 10mm apart)
|
|
248
|
-
# along an edge. Should avoid red-flagging such cases. TO DO.
|
|
249
|
-
log(ERR, "#{id}: < #{TOL}m (#{mth})") if bad
|
|
250
|
-
return false if bad
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
# Add as many extra tests as needed ...
|
|
254
|
-
true
|
|
255
|
-
end
|
|
256
|
-
|
|
257
221
|
##
|
|
258
222
|
# Return site-specific (or true) Topolys normal vector of OpenStudio surface.
|
|
259
223
|
#
|
|
@@ -290,9 +254,9 @@ module TBD
|
|
|
290
254
|
cl2 = OpenStudio::Model::Surface
|
|
291
255
|
cl3 = OpenStudio::Model::LayeredConstruction
|
|
292
256
|
|
|
293
|
-
return mismatch("model", model, cl1, mth)
|
|
294
|
-
return mismatch("surface", surface, cl2, mth)
|
|
295
|
-
return nil
|
|
257
|
+
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
|
258
|
+
return mismatch("surface", surface, cl2, mth) unless surface.is_a?(cl2)
|
|
259
|
+
return nil unless surface_valid?(surface)
|
|
296
260
|
|
|
297
261
|
nom = surface.nameString
|
|
298
262
|
surf = {}
|
|
@@ -356,7 +320,7 @@ module TBD
|
|
|
356
320
|
surf[:filmRSI ] = surface.filmResistance
|
|
357
321
|
|
|
358
322
|
surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
|
|
359
|
-
next unless
|
|
323
|
+
next unless surface_valid?(s)
|
|
360
324
|
|
|
361
325
|
id = s.nameString
|
|
362
326
|
valid = s.vertices.size == 3 || s.vertices.size == 4
|
|
@@ -929,7 +929,7 @@ module TBD
|
|
|
929
929
|
model = "* modèle : #{ua[:file]}" if ua.key?(:file) && lang == :fr
|
|
930
930
|
model += " (v#{ua[:version]})" if ua.key?(:version)
|
|
931
931
|
report << model unless model.empty?
|
|
932
|
-
report << "* TBD : v3.2.
|
|
932
|
+
report << "* TBD : v3.2.3"
|
|
933
933
|
report << "* date : #{ua[:date]}"
|
|
934
934
|
|
|
935
935
|
if lang == :en
|
|
@@ -41,6 +41,8 @@ module OSut
|
|
|
41
41
|
ERR = OSut::ERROR # flag invalid .osm inputs (then exit via 'return')
|
|
42
42
|
FTL = OSut::FATAL # not currently used in OSut
|
|
43
43
|
NS = "nameString" # OpenStudio IdfObject nameString method
|
|
44
|
+
HEAD = 2.032 # standard 80" door
|
|
45
|
+
SILL = 0.762 # standard 30" window sill
|
|
44
46
|
|
|
45
47
|
# This first set of utilities (~750 lines) help distinguishing spaces that
|
|
46
48
|
# are directly vs indirectly CONDITIONED, vs SEMI-HEATED. The solution here
|
|
@@ -1447,6 +1449,9 @@ module OSut
|
|
|
1447
1449
|
area = area.get
|
|
1448
1450
|
return false if area < TOL
|
|
1449
1451
|
|
|
1452
|
+
delta = (area - area1 - area2).abs
|
|
1453
|
+
return false if delta < TOL
|
|
1454
|
+
|
|
1450
1455
|
true
|
|
1451
1456
|
end
|
|
1452
1457
|
|
|
@@ -1460,7 +1465,7 @@ module OSut
|
|
|
1460
1465
|
# @return [OpenStudio::Point3dVector] offset points if successful
|
|
1461
1466
|
# @return [OpenStudio::Point3dVector] original points if invalid input
|
|
1462
1467
|
def offset(p1 = [], w = 0, v = 0)
|
|
1463
|
-
mth = "
|
|
1468
|
+
mth = "OSut::#{__callee__}"
|
|
1464
1469
|
cl = OpenStudio::Point3d
|
|
1465
1470
|
vrsn = OpenStudio.openStudioVersion.split(".").map(&:to_i).join.to_i
|
|
1466
1471
|
|
|
@@ -1499,7 +1504,7 @@ module OSut
|
|
|
1499
1504
|
|
|
1500
1505
|
pz = OpenStudio::Point3dVector.new
|
|
1501
1506
|
offset.each { |o| pz << OpenStudio::Point3d.new(o.x, o.y, o.z ) }
|
|
1502
|
-
|
|
1507
|
+
|
|
1503
1508
|
return pz
|
|
1504
1509
|
else # brute force approach
|
|
1505
1510
|
pz = {}
|
|
@@ -1684,6 +1689,589 @@ module OSut
|
|
|
1684
1689
|
end
|
|
1685
1690
|
end
|
|
1686
1691
|
|
|
1692
|
+
##
|
|
1693
|
+
# Validate whether an OpenStudio planar surface is safe to process.
|
|
1694
|
+
#
|
|
1695
|
+
# @param s [OpenStudio::Model::PlanarSurface] a surface
|
|
1696
|
+
#
|
|
1697
|
+
# @return [Bool] true if valid surface
|
|
1698
|
+
def surface_valid?(s = nil)
|
|
1699
|
+
mth = "OSut::#{__callee__}"
|
|
1700
|
+
cl = OpenStudio::Model::PlanarSurface
|
|
1701
|
+
|
|
1702
|
+
return mismatch("surface", s, cl, mth, DBG, false) unless s.is_a?(cl)
|
|
1703
|
+
|
|
1704
|
+
id = s.nameString
|
|
1705
|
+
size = s.vertices.size
|
|
1706
|
+
last = size - 1
|
|
1707
|
+
|
|
1708
|
+
log(ERR, "#{id} #{size} vertices? need +3 (#{mth})") unless size > 2
|
|
1709
|
+
return false unless size > 2
|
|
1710
|
+
|
|
1711
|
+
[0, last].each do |i|
|
|
1712
|
+
v1 = s.vertices[i]
|
|
1713
|
+
v2 = s.vertices[i + 1] unless i == last
|
|
1714
|
+
v2 = s.vertices.first if i == last
|
|
1715
|
+
vec = v2 - v1
|
|
1716
|
+
bad = vec.length < TOL
|
|
1717
|
+
|
|
1718
|
+
# As is, this comparison also catches collinear vertices (< 10mm apart)
|
|
1719
|
+
# along an edge. Should avoid red-flagging such cases. TO DO.
|
|
1720
|
+
log(ERR, "#{id}: < #{TOL}m (#{mth})") if bad
|
|
1721
|
+
return false if bad
|
|
1722
|
+
end
|
|
1723
|
+
|
|
1724
|
+
# Add as many extra tests as needed ...
|
|
1725
|
+
true
|
|
1726
|
+
end
|
|
1727
|
+
|
|
1728
|
+
##
|
|
1729
|
+
# Add sub surfaces (e.g. windows, doors, skylights) to surface.
|
|
1730
|
+
#
|
|
1731
|
+
# @param model [OpenStudio::Model::Model] a model
|
|
1732
|
+
# @param s [OpenStudio::Model::Surface] a model surface
|
|
1733
|
+
# @param subs [Array] requested sub surface attributes
|
|
1734
|
+
# @param clear [Bool] remove current sub surfaces if true
|
|
1735
|
+
# @param bfr [Double] safety buffer (m), when ~aligned along other edges
|
|
1736
|
+
#
|
|
1737
|
+
# @return [Bool] true if successful (check for logged messages if failures)
|
|
1738
|
+
def addSubs(model = nil, s = nil, subs = [], clear = false, bfr = 0.005)
|
|
1739
|
+
mth = "OSut::#{__callee__}"
|
|
1740
|
+
v = OpenStudio.openStudioVersion.split(".").join.to_i
|
|
1741
|
+
cl1 = OpenStudio::Model::Model
|
|
1742
|
+
cl2 = OpenStudio::Model::Surface
|
|
1743
|
+
cl3 = Array
|
|
1744
|
+
cl4 = Hash
|
|
1745
|
+
cl5 = Numeric
|
|
1746
|
+
min = 0.050 # minimum ratio value ( 5%)
|
|
1747
|
+
max = 0.950 # maximum ratio value (95%)
|
|
1748
|
+
no = false
|
|
1749
|
+
|
|
1750
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1751
|
+
# Exit if mismatched or invalid argument classes.
|
|
1752
|
+
return mismatch("model", model, cl1, mth, DBG, no) unless model.is_a?(cl1)
|
|
1753
|
+
return mismatch("surface", s, cl2, mth, DBG, no) unless s.is_a?(cl2)
|
|
1754
|
+
return mismatch("subs", subs, cl3, mth, DBG, no) unless subs.is_a?(cl3)
|
|
1755
|
+
return no unless surface_valid?(s)
|
|
1756
|
+
|
|
1757
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1758
|
+
# Clear existing sub surfaces if requested.
|
|
1759
|
+
nom = s.nameString
|
|
1760
|
+
|
|
1761
|
+
unless clear == true || clear == false
|
|
1762
|
+
log(WRN, "#{nom}: Keeping existing sub surfaces (#{mth})")
|
|
1763
|
+
clear = false
|
|
1764
|
+
end
|
|
1765
|
+
|
|
1766
|
+
s.subSurfaces.map(&:remove) if clear
|
|
1767
|
+
|
|
1768
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1769
|
+
# Allowable sub surface types ... & Frame&Divider enabled
|
|
1770
|
+
# - "FixedWindow" | true
|
|
1771
|
+
# - "OperableWindow" | true
|
|
1772
|
+
# - "Door" | false
|
|
1773
|
+
# - "GlassDoor" | true
|
|
1774
|
+
# - "OverheadDoor" | false
|
|
1775
|
+
# - "Skylight" | false if v < 321
|
|
1776
|
+
# - "TubularDaylightDome" | false
|
|
1777
|
+
# - "TubularDaylightDiffuser" | false
|
|
1778
|
+
type = "FixedWindow"
|
|
1779
|
+
types = OpenStudio::Model::SubSurface.validSubSurfaceTypeValues
|
|
1780
|
+
stype = s.surfaceType # Wall, RoofCeiling or Floor
|
|
1781
|
+
|
|
1782
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1783
|
+
# Fetch transform, as if host surface vertices were to "align", i.e.:
|
|
1784
|
+
# - rotated/tilted ... then flattened along XY plane
|
|
1785
|
+
# - all Z-axis coordinates ~= 0
|
|
1786
|
+
# - vertices with the lowest X-axis values are "aligned" along X-axis (0)
|
|
1787
|
+
# - vertices with the lowest Z-axis values are "aligned" along Y-axis (0)
|
|
1788
|
+
# - Z-axis values are represented as Y-axis values
|
|
1789
|
+
tr = OpenStudio::Transformation.alignFace(s.vertices)
|
|
1790
|
+
|
|
1791
|
+
# Aligned vertices of host surface, and fetch attributes.
|
|
1792
|
+
aligned = tr.inverse * s.vertices
|
|
1793
|
+
max_x = aligned.max_by(&:x).x
|
|
1794
|
+
max_y = aligned.max_by(&:y).y
|
|
1795
|
+
mid_x = max_x / 2
|
|
1796
|
+
mid_y = max_y / 2
|
|
1797
|
+
|
|
1798
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1799
|
+
# Assign default values to certain sub keys (if missing), +more validation.
|
|
1800
|
+
subs.each_with_index do |sub, index|
|
|
1801
|
+
return mismatch("sub", sub, cl4, mth, DBG, no) unless sub.is_a?(cl4)
|
|
1802
|
+
|
|
1803
|
+
# Required key:value pairs (either set by the user or defaulted).
|
|
1804
|
+
sub[:id ] = "" unless sub.key?(:id ) # "Window 007"
|
|
1805
|
+
sub[:type ] = type unless sub.key?(:type ) # "FixedWindow"
|
|
1806
|
+
sub[:count ] = 1 unless sub.key?(:count ) # for an array
|
|
1807
|
+
sub[:multiplier] = 1 unless sub.key?(:multiplier)
|
|
1808
|
+
sub[:frame ] = nil unless sub.key?(:frame ) # frame/divider
|
|
1809
|
+
sub[:assembly ] = nil unless sub.key?(:assembly ) # construction
|
|
1810
|
+
|
|
1811
|
+
# Optional key:value pairs.
|
|
1812
|
+
# sub[:ratio ] # e.g. %FWR
|
|
1813
|
+
# sub[:head ] # e.g. std 80" door + frame/buffers (+ m)
|
|
1814
|
+
# sub[:sill ] # e.g. std 30" sill + frame/buffers (+ m)
|
|
1815
|
+
# sub[:height ] # any sub surface height, below "head" (+ m)
|
|
1816
|
+
# sub[:width ] # e.g. 1.200 m
|
|
1817
|
+
# sub[:offset ] # if array (+ m)
|
|
1818
|
+
# sub[:centreline] # left or right of base surface centreline (+/- m)
|
|
1819
|
+
# sub[:r_buffer ] # buffer between sub/array and right-side corner (+ m)
|
|
1820
|
+
# sub[:l_buffer ] # buffer between sub/array and left-side corner (+ m)
|
|
1821
|
+
|
|
1822
|
+
sub[:id] = "#{nom}|#{index}" if sub[:id].empty?
|
|
1823
|
+
id = sub[:id]
|
|
1824
|
+
|
|
1825
|
+
# If sub surface type is invalid, log/reset. Additional corrections may
|
|
1826
|
+
# be enabled once a sub surface is actually instantiated.
|
|
1827
|
+
unless types.include?(sub[:type])
|
|
1828
|
+
log(WRN, "Reset invalid '#{id}' type to '#{type}' (#{mth})")
|
|
1829
|
+
sub[:type] = type
|
|
1830
|
+
end
|
|
1831
|
+
|
|
1832
|
+
# Log/ignore (optional) frame & divider object.
|
|
1833
|
+
unless sub[:frame].nil?
|
|
1834
|
+
if sub[:frame].respond_to?(:frameWidth)
|
|
1835
|
+
sub[:frame] = nil if sub[:type] == "Skylight" && v < 321
|
|
1836
|
+
sub[:frame] = nil if sub[:type] == "Door"
|
|
1837
|
+
sub[:frame] = nil if sub[:type] == "OverheadDoor"
|
|
1838
|
+
sub[:frame] = nil if sub[:type] == "TubularDaylightDome"
|
|
1839
|
+
sub[:frame] = nil if sub[:type] == "TubularDaylightDiffuser"
|
|
1840
|
+
log(WRN, "Skip '#{id}' FrameDivider (#{mth})") if sub[:frame].nil?
|
|
1841
|
+
else
|
|
1842
|
+
sub[:frame] = nil
|
|
1843
|
+
log(WRN, "Skip '#{id}' invalid FrameDivider object (#{mth})")
|
|
1844
|
+
end
|
|
1845
|
+
end
|
|
1846
|
+
|
|
1847
|
+
# The (optional) "assembly" must reference a valid OpenStudio
|
|
1848
|
+
# construction base, to explicitly assign to each instantiated sub
|
|
1849
|
+
# surface. If invalid, log/reset/ignore. Additional checks are later
|
|
1850
|
+
# activated once a sub surface is actually instantiated.
|
|
1851
|
+
unless sub[:assembly].nil?
|
|
1852
|
+
unless sub[:assembly].respond_to?(:isFenestration)
|
|
1853
|
+
log(WRN, "Skip invalid '#{id}' construction (#{mth})")
|
|
1854
|
+
sub[:assembly] = nil
|
|
1855
|
+
end
|
|
1856
|
+
end
|
|
1857
|
+
|
|
1858
|
+
# Log/reset negative numerical values. Set ~0 values to 0.
|
|
1859
|
+
sub.each do |key, value|
|
|
1860
|
+
next if key == :id
|
|
1861
|
+
next if key == :type
|
|
1862
|
+
next if key == :frame
|
|
1863
|
+
next if key == :assembly
|
|
1864
|
+
|
|
1865
|
+
return mismatch(key, value, cl5, mth, DBG, no) unless value.is_a?(cl5)
|
|
1866
|
+
next if key == :centreline
|
|
1867
|
+
|
|
1868
|
+
negative(key, mth, WRN) if value < 0
|
|
1869
|
+
value = 0.0 if value.abs < TOL
|
|
1870
|
+
end
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
# --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- #
|
|
1874
|
+
# Log/reset (or abandon) conflicting user-set geometry key:value pairs:
|
|
1875
|
+
# :head e.g. std 80" door + frame/buffers (+ m)
|
|
1876
|
+
# :sill e.g. std 30" sill + frame/buffers (+ m)
|
|
1877
|
+
# :height any sub surface height, below "head" (+ m)
|
|
1878
|
+
# :width e.g. 1.200 m
|
|
1879
|
+
# :offset if array (+ m)
|
|
1880
|
+
# :centreline left or right of base surface centreline (+/- m)
|
|
1881
|
+
# :r_buffer buffer between sub/array and right-side corner (+ m)
|
|
1882
|
+
# :l_buffer buffer between sub/array and left-side corner (+ m)
|
|
1883
|
+
#
|
|
1884
|
+
# If successful, this will generate sub surfaces and add them to the model.
|
|
1885
|
+
subs.each do |sub|
|
|
1886
|
+
# Set-up unique sub parameters:
|
|
1887
|
+
# - Frame & Divider "width"
|
|
1888
|
+
# - minimum "clear glazing" limits
|
|
1889
|
+
# - buffers, etc.
|
|
1890
|
+
id = sub[:id]
|
|
1891
|
+
frame = 0
|
|
1892
|
+
frame = sub[:frame].frameWidth unless sub[:frame].nil?
|
|
1893
|
+
frames = 2 * frame
|
|
1894
|
+
buffer = frame + bfr
|
|
1895
|
+
buffers = 2 * buffer
|
|
1896
|
+
dim = 0.200 unless (3 * frame) > 0.200
|
|
1897
|
+
dim = 3 * frame if (3 * frame) > 0.200
|
|
1898
|
+
glass = dim - frames
|
|
1899
|
+
min_sill = buffer
|
|
1900
|
+
min_head = buffers + glass
|
|
1901
|
+
max_head = max_y - buffer
|
|
1902
|
+
max_sill = max_head - (buffers + glass)
|
|
1903
|
+
min_ljamb = buffer
|
|
1904
|
+
max_ljamb = max_x - (buffers + glass)
|
|
1905
|
+
min_rjamb = buffers + glass
|
|
1906
|
+
max_rjamb = max_x - buffer
|
|
1907
|
+
max_height = max_y - buffers
|
|
1908
|
+
max_width = max_x - buffers
|
|
1909
|
+
|
|
1910
|
+
# Default sub surface "head" & "sill" height (unless user-specified).
|
|
1911
|
+
typ_head = HEAD # standard 80" door
|
|
1912
|
+
typ_sill = SILL # standard 30" window sill
|
|
1913
|
+
|
|
1914
|
+
if sub.key?(:ratio)
|
|
1915
|
+
typ_head = mid_y * (1 + sub[:ratio]) if sub[:ratio] > 0.75
|
|
1916
|
+
typ_head = mid_y * (1 + sub[:ratio]) unless stype.downcase == "wall"
|
|
1917
|
+
typ_sill = mid_y * (1 - sub[:ratio]) if sub[:ratio] > 0.75
|
|
1918
|
+
typ_sill = mid_y * (1 - sub[:ratio]) unless stype.downcase == "wall"
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
# Log/reset "height" if beyond min/max.
|
|
1922
|
+
if sub.key?(:height)
|
|
1923
|
+
unless sub[:height].between?(glass, max_height)
|
|
1924
|
+
sub[:height] = glass if sub[:height] < glass
|
|
1925
|
+
sub[:height] = max_height if sub[:height] > max_height
|
|
1926
|
+
log(WRN, "Reset '#{id}' height to #{sub[:height]} m (#{mth})")
|
|
1927
|
+
end
|
|
1928
|
+
end
|
|
1929
|
+
|
|
1930
|
+
# Log/reset "head" height if beyond min/max.
|
|
1931
|
+
if sub.key?(:head)
|
|
1932
|
+
unless sub[:head].between?(min_head, max_head)
|
|
1933
|
+
sub[:head] = max_head if sub[:head] > max_head
|
|
1934
|
+
sub[:head] = min_head if sub[:head] < min_head
|
|
1935
|
+
log(WRN, "Reset '#{id}' head height to #{sub[:head]} m (#{mth})")
|
|
1936
|
+
end
|
|
1937
|
+
end
|
|
1938
|
+
|
|
1939
|
+
# Log/reset "sill" height if beyond min/max.
|
|
1940
|
+
if sub.key?(:sill)
|
|
1941
|
+
unless sub[:sill].between?(min_sill, max_sill)
|
|
1942
|
+
sub[:sill] = max_sill if sub[:sill] > max_sill
|
|
1943
|
+
sub[:sill] = min_sill if sub[:sill] < min_sill
|
|
1944
|
+
log(WRN, "Reset '#{id}' sill height to #{sub[:sill]} m (#{mth})")
|
|
1945
|
+
end
|
|
1946
|
+
end
|
|
1947
|
+
|
|
1948
|
+
# At this point, "head", "sill" and/or "height" have been tentatively
|
|
1949
|
+
# validated (and/or have been corrected) independently from one another.
|
|
1950
|
+
# Log/reset "head" & "sill" heights if conflicting.
|
|
1951
|
+
if sub.key?(:head) && sub.key?(:sill) && sub[:head] < sub[:sill] + glass
|
|
1952
|
+
sill = sub[:head] - glass
|
|
1953
|
+
|
|
1954
|
+
if sill < min_sill
|
|
1955
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
1956
|
+
sub[:count ] = 0
|
|
1957
|
+
sub[:multiplier] = 0
|
|
1958
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
1959
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
1960
|
+
log(ERR, "Skip: invalid '#{id}' head/sill combo (#{mth})")
|
|
1961
|
+
next
|
|
1962
|
+
else
|
|
1963
|
+
sub[:sill] = sill
|
|
1964
|
+
log(WRN, "(Re)set '#{id}' sill height to #{sub[:sill]} m (#{mth})")
|
|
1965
|
+
end
|
|
1966
|
+
end
|
|
1967
|
+
|
|
1968
|
+
# Attempt to reconcile "head", "sill" and/or "height". If successful,
|
|
1969
|
+
# all 3x parameters are set (if missing), or reset if invalid.
|
|
1970
|
+
if sub.key?(:head) && sub.key?(:sill)
|
|
1971
|
+
height = sub[:head] - sub[:sill]
|
|
1972
|
+
|
|
1973
|
+
if sub.key?(:height) && (sub[:height] - height).abs > TOL
|
|
1974
|
+
log(WRN, "(Re)set '#{id}' height to #{height} m (#{mth})")
|
|
1975
|
+
end
|
|
1976
|
+
|
|
1977
|
+
sub[:height] = height
|
|
1978
|
+
elsif sub.key?(:head) # no "sill"
|
|
1979
|
+
if sub.key?(:height)
|
|
1980
|
+
sill = sub[:head] - sub[:height]
|
|
1981
|
+
|
|
1982
|
+
if sill < min_sill
|
|
1983
|
+
sill = min_sill
|
|
1984
|
+
height = sub[:head] - sill
|
|
1985
|
+
|
|
1986
|
+
if height < glass
|
|
1987
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
1988
|
+
sub[:count ] = 0
|
|
1989
|
+
sub[:multiplier] = 0
|
|
1990
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
1991
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
1992
|
+
log(ERR, "Skip: invalid '#{id}' head/height combo (#{mth})")
|
|
1993
|
+
next
|
|
1994
|
+
else
|
|
1995
|
+
sub[:sill ] = sill
|
|
1996
|
+
sub[:height] = height
|
|
1997
|
+
log(WRN, "(Re)set '#{id}' height to #{sub[:height]} m (#{mth})")
|
|
1998
|
+
end
|
|
1999
|
+
else
|
|
2000
|
+
sub[:sill] = sill
|
|
2001
|
+
end
|
|
2002
|
+
else
|
|
2003
|
+
sub[:sill ] = typ_sill
|
|
2004
|
+
sub[:height] = sub[:head] - sub[:sill]
|
|
2005
|
+
end
|
|
2006
|
+
elsif sub.key?(:sill) # no "head"
|
|
2007
|
+
if sub.key?(:height)
|
|
2008
|
+
head = sub[:sill] + sub[:height]
|
|
2009
|
+
|
|
2010
|
+
if head > max_head
|
|
2011
|
+
head = max_head
|
|
2012
|
+
height = head - sub[:sill]
|
|
2013
|
+
|
|
2014
|
+
if height < glass
|
|
2015
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
2016
|
+
sub[:count ] = 0
|
|
2017
|
+
sub[:multiplier] = 0
|
|
2018
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
2019
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
2020
|
+
log(ERR, "Skip: invalid '#{id}' sill/height combo (#{mth})")
|
|
2021
|
+
next
|
|
2022
|
+
else
|
|
2023
|
+
sub[:head ] = head
|
|
2024
|
+
sub[:height] = height
|
|
2025
|
+
log(WRN, "(Re)set '#{id}' height to #{sub[:height]} m (#{mth})")
|
|
2026
|
+
end
|
|
2027
|
+
else
|
|
2028
|
+
sub[:head] = head
|
|
2029
|
+
end
|
|
2030
|
+
else
|
|
2031
|
+
sub[:head ] = typ_head
|
|
2032
|
+
sub[:height] = sub[:head] - sub[:sill]
|
|
2033
|
+
end
|
|
2034
|
+
elsif sub.key?(:height) # neither "head" nor "sill"
|
|
2035
|
+
head = typ_head
|
|
2036
|
+
sill = head - sub[:height]
|
|
2037
|
+
|
|
2038
|
+
if sill < min_sill
|
|
2039
|
+
sill = min_sill
|
|
2040
|
+
head = sill + sub[:height]
|
|
2041
|
+
end
|
|
2042
|
+
|
|
2043
|
+
sub[:head] = head
|
|
2044
|
+
sub[:sill] = sill
|
|
2045
|
+
else
|
|
2046
|
+
sub[:head ] = typ_head
|
|
2047
|
+
sub[:sill ] = typ_sill
|
|
2048
|
+
sub[:height] = sub[:head] - sub[:sill]
|
|
2049
|
+
end
|
|
2050
|
+
|
|
2051
|
+
# Log/reset "width" if beyond min/max.
|
|
2052
|
+
if sub.key?(:width)
|
|
2053
|
+
unless sub[:width].between?(glass, max_width)
|
|
2054
|
+
sub[:width] = glass if sub[:width] < glass
|
|
2055
|
+
sub[:width] = max_width if sub[:width] > max_width
|
|
2056
|
+
log(WRN, "Reset '#{id}' width to #{sub[:width]} m (#{mth})")
|
|
2057
|
+
end
|
|
2058
|
+
end
|
|
2059
|
+
|
|
2060
|
+
# Log/reset "count" if < 1.
|
|
2061
|
+
if sub.key?(:count)
|
|
2062
|
+
if sub[:count] < 1
|
|
2063
|
+
sub[:count] = 1
|
|
2064
|
+
log(WRN, "Reset '#{id}' count to #{sub[:count]} (#{mth})")
|
|
2065
|
+
end
|
|
2066
|
+
end
|
|
2067
|
+
|
|
2068
|
+
sub[:count] = 1 unless sub.key?(:count)
|
|
2069
|
+
|
|
2070
|
+
# Log/reset if left-sided buffer under min jamb position.
|
|
2071
|
+
if sub.key?(:l_buffer)
|
|
2072
|
+
if sub[:l_buffer] < min_ljamb
|
|
2073
|
+
sub[:l_buffer] = min_ljamb
|
|
2074
|
+
log(WRN, "Reset '#{id}' left buffer to #{sub[:l_buffer]} m (#{mth})")
|
|
2075
|
+
end
|
|
2076
|
+
end
|
|
2077
|
+
|
|
2078
|
+
# Log/reset if right-sided buffer beyond max jamb position.
|
|
2079
|
+
if sub.key?(:r_buffer)
|
|
2080
|
+
if sub[:r_buffer] > max_rjamb
|
|
2081
|
+
sub[:r_buffer] = min_rjamb
|
|
2082
|
+
log(WRN, "Reset '#{id}' right buffer to #{sub[:r_buffer]} m (#{mth})")
|
|
2083
|
+
end
|
|
2084
|
+
end
|
|
2085
|
+
|
|
2086
|
+
centre = mid_x
|
|
2087
|
+
centre += sub[:centreline] if sub.key?(:centreline)
|
|
2088
|
+
n = sub[:count ]
|
|
2089
|
+
h = sub[:height ] + frames
|
|
2090
|
+
w = 0 # overall width of sub(s) bounding box (to calculate)
|
|
2091
|
+
x0 = 0 # left-side X-axis coordinate of sub(s) bounding box
|
|
2092
|
+
xf = 0 # right-side X-axis coordinate of sub(s) bounding box
|
|
2093
|
+
|
|
2094
|
+
# Log/reset "offset", if conflicting vs "width".
|
|
2095
|
+
if sub.key?(:ratio)
|
|
2096
|
+
if sub[:ratio] < TOL
|
|
2097
|
+
sub[:ratio ] = 0
|
|
2098
|
+
sub[:count ] = 0
|
|
2099
|
+
sub[:multiplier] = 0
|
|
2100
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
2101
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
2102
|
+
log(ERR, "Skip: '#{id}' ratio ~0 (#{mth})")
|
|
2103
|
+
next
|
|
2104
|
+
end
|
|
2105
|
+
|
|
2106
|
+
# Log/reset if "ratio" beyond min/max?
|
|
2107
|
+
unless sub[:ratio].between?(min, max)
|
|
2108
|
+
sub[:ratio] = min if sub[:ratio] < min
|
|
2109
|
+
sub[:ratio] = max if sub[:ratio] > max
|
|
2110
|
+
log(WRN, "Reset ratio (min/max) to #{sub[:ratio]} (#{mth})")
|
|
2111
|
+
end
|
|
2112
|
+
|
|
2113
|
+
# Log/reset "count" unless 1.
|
|
2114
|
+
unless sub[:count] == 1
|
|
2115
|
+
sub[:count] = 1
|
|
2116
|
+
log(WRN, "Reset count (ratio) to 1 (#{mth})")
|
|
2117
|
+
end
|
|
2118
|
+
|
|
2119
|
+
area = s.grossArea * sub[:ratio] # sub m2, including (optional) frames
|
|
2120
|
+
w = area / h
|
|
2121
|
+
width = w - frames
|
|
2122
|
+
x0 = centre - w/2
|
|
2123
|
+
xf = centre + w/2
|
|
2124
|
+
|
|
2125
|
+
if sub.key?(:l_buffer)
|
|
2126
|
+
if sub.key?(:centreline)
|
|
2127
|
+
log(WRN, "Skip #{id} left buffer (vs centreline) (#{mth})")
|
|
2128
|
+
else
|
|
2129
|
+
x0 = sub[:l_buffer] - frame
|
|
2130
|
+
xf = x0 + w
|
|
2131
|
+
centre = x0 + w/2
|
|
2132
|
+
end
|
|
2133
|
+
elsif sub.key?(:r_buffer)
|
|
2134
|
+
if sub.key?(:centreline)
|
|
2135
|
+
log(WRN, "Skip #{id} right buffer (vs centreline) (#{mth})")
|
|
2136
|
+
else
|
|
2137
|
+
xf = max_x - sub[:r_buffer] + frame
|
|
2138
|
+
x0 = xf - w
|
|
2139
|
+
centre = x0 + w/2
|
|
2140
|
+
end
|
|
2141
|
+
end
|
|
2142
|
+
|
|
2143
|
+
# Too wide?
|
|
2144
|
+
if x0 < min_ljamb || xf > max_rjamb
|
|
2145
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
2146
|
+
sub[:count ] = 0
|
|
2147
|
+
sub[:multiplier] = 0
|
|
2148
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
2149
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
2150
|
+
log(ERR, "Skip: invalid (ratio) width/centreline (#{mth})")
|
|
2151
|
+
next
|
|
2152
|
+
end
|
|
2153
|
+
|
|
2154
|
+
if sub.key?(:width) && (sub[:width] - width).abs > TOL
|
|
2155
|
+
sub[:width] = width
|
|
2156
|
+
log(WRN, "Reset width (ratio) to #{sub[:width]} (#{mth})")
|
|
2157
|
+
end
|
|
2158
|
+
|
|
2159
|
+
sub[:width] = width unless sub.key?(:width)
|
|
2160
|
+
else
|
|
2161
|
+
unless sub.key?(:width)
|
|
2162
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
2163
|
+
sub[:count ] = 0
|
|
2164
|
+
sub[:multiplier] = 0
|
|
2165
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
2166
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
2167
|
+
log(ERR, "Skip: missing '#{id}' width (#{mth})")
|
|
2168
|
+
next
|
|
2169
|
+
end
|
|
2170
|
+
|
|
2171
|
+
width = sub[:width] + frames
|
|
2172
|
+
gap = (max_x - n * width) / (n + 1)
|
|
2173
|
+
gap = sub[:offset] - width if sub.key?(:offset)
|
|
2174
|
+
gap = 0 if gap < bfr
|
|
2175
|
+
offset = gap + width
|
|
2176
|
+
|
|
2177
|
+
if sub.key?(:offset) && (offset - sub[:offset]).abs > TOL
|
|
2178
|
+
sub[:offset] = offset
|
|
2179
|
+
log(WRN, "Reset sub offset to #{sub[:offset]} m (#{mth})")
|
|
2180
|
+
end
|
|
2181
|
+
|
|
2182
|
+
sub[:offset] = offset unless sub.key?(:offset)
|
|
2183
|
+
|
|
2184
|
+
# Overall width (including frames) of bounding box around array.
|
|
2185
|
+
w = n * width + (n - 1) * gap
|
|
2186
|
+
x0 = centre - w/2
|
|
2187
|
+
xf = centre + w/2
|
|
2188
|
+
|
|
2189
|
+
if sub.key?(:l_buffer)
|
|
2190
|
+
if sub.key?(:centreline)
|
|
2191
|
+
log(WRN, "Skip #{id} left buffer (vs centreline) (#{mth})")
|
|
2192
|
+
else
|
|
2193
|
+
x0 = sub[:l_buffer] - frame
|
|
2194
|
+
xf = x0 + w
|
|
2195
|
+
centre = x0 + w/2
|
|
2196
|
+
end
|
|
2197
|
+
elsif sub.key?(:r_buffer)
|
|
2198
|
+
if sub.key?(:centreline)
|
|
2199
|
+
log(WRN, "Skip #{id} right buffer (vs centreline) (#{mth})")
|
|
2200
|
+
else
|
|
2201
|
+
xf = max_x - sub[:r_buffer] + frame
|
|
2202
|
+
x0 = xf - w
|
|
2203
|
+
centre = x0 + w/2
|
|
2204
|
+
end
|
|
2205
|
+
end
|
|
2206
|
+
|
|
2207
|
+
# Too wide?
|
|
2208
|
+
if x0 < bfr || xf > max_x - bfr
|
|
2209
|
+
sub[:ratio ] = 0 if sub.key?(:ratio)
|
|
2210
|
+
sub[:count ] = 0
|
|
2211
|
+
sub[:multiplier] = 0
|
|
2212
|
+
sub[:height ] = 0 if sub.key?(:height)
|
|
2213
|
+
sub[:width ] = 0 if sub.key?(:width)
|
|
2214
|
+
log(ERR, "Skip: invalid array width/centreline (#{mth})")
|
|
2215
|
+
next
|
|
2216
|
+
end
|
|
2217
|
+
end
|
|
2218
|
+
|
|
2219
|
+
# Initialize left-side X-axis coordinate of only/first sub.
|
|
2220
|
+
pos = x0 + frame
|
|
2221
|
+
|
|
2222
|
+
# Generate sub(s).
|
|
2223
|
+
sub[:count].times do |i|
|
|
2224
|
+
name = "#{id}:#{i}"
|
|
2225
|
+
fr = 0
|
|
2226
|
+
fr = sub[:frame].frameWidth if sub[:frame]
|
|
2227
|
+
|
|
2228
|
+
vec = OpenStudio::Point3dVector.new
|
|
2229
|
+
vec << OpenStudio::Point3d.new(pos, sub[:head], 0)
|
|
2230
|
+
vec << OpenStudio::Point3d.new(pos, sub[:sill], 0)
|
|
2231
|
+
vec << OpenStudio::Point3d.new(pos + sub[:width], sub[:sill], 0)
|
|
2232
|
+
vec << OpenStudio::Point3d.new(pos + sub[:width], sub[:head], 0)
|
|
2233
|
+
vec = tr * vec
|
|
2234
|
+
|
|
2235
|
+
# Log/skip if conflict between individual sub and base surface.
|
|
2236
|
+
vc = vec
|
|
2237
|
+
vc = offset(vc, fr, 300) if fr > 0
|
|
2238
|
+
ok = fits?(vc, s.vertices, name, nom)
|
|
2239
|
+
log(ERR, "Skip '#{name}': won't fit in '#{nom}' (#{mth})") unless ok
|
|
2240
|
+
break unless ok
|
|
2241
|
+
|
|
2242
|
+
# Log/skip if conflicts with existing subs (even if same array).
|
|
2243
|
+
s.subSurfaces.each do |sb|
|
|
2244
|
+
nome = sb.nameString
|
|
2245
|
+
fd = sb.windowPropertyFrameAndDivider
|
|
2246
|
+
fr = 0 if fd.empty?
|
|
2247
|
+
fr = fd.get.frameWidth unless fd.empty?
|
|
2248
|
+
vk = sb.vertices
|
|
2249
|
+
vk = offset(vk, fr, 300) if fr > 0
|
|
2250
|
+
oops = overlaps?(vc, vk, name, nome)
|
|
2251
|
+
log(ERR, "Skip '#{name}': overlaps '#{nome}' (#{mth})") if oops
|
|
2252
|
+
ok = false if oops
|
|
2253
|
+
break if oops
|
|
2254
|
+
end
|
|
2255
|
+
|
|
2256
|
+
break unless ok
|
|
2257
|
+
|
|
2258
|
+
sb = OpenStudio::Model::SubSurface.new(vec, model)
|
|
2259
|
+
sb.setName(name)
|
|
2260
|
+
sb.setSubSurfaceType(sub[:type])
|
|
2261
|
+
sb.setConstruction(sub[:assembly]) if sub[:assembly]
|
|
2262
|
+
ok = sb.allowWindowPropertyFrameAndDivider
|
|
2263
|
+
sb.setWindowPropertyFrameAndDivider(sub[:frame]) if sub[:frame] && ok
|
|
2264
|
+
sb.setMultiplier(sub[:multiplier]) if sub[:multiplier] > 1
|
|
2265
|
+
sb.setSurface(s)
|
|
2266
|
+
|
|
2267
|
+
# Reset "pos" if array.
|
|
2268
|
+
pos += sub[:offset] if sub.key?(:offset)
|
|
2269
|
+
end
|
|
2270
|
+
end
|
|
2271
|
+
|
|
2272
|
+
true
|
|
2273
|
+
end
|
|
2274
|
+
|
|
1687
2275
|
##
|
|
1688
2276
|
# Callback when other modules extend OSlg
|
|
1689
2277
|
#
|
data/lib/tbd/geo.rb
CHANGED
|
@@ -218,42 +218,6 @@ module TBD
|
|
|
218
218
|
true
|
|
219
219
|
end
|
|
220
220
|
|
|
221
|
-
##
|
|
222
|
-
# Validate whether an OpenStudio planar surface is safe for TBD to process.
|
|
223
|
-
#
|
|
224
|
-
# @param s [OpenStudio::Model::PlanarSurface] a surface
|
|
225
|
-
#
|
|
226
|
-
# @return [Bool] true if valid surface
|
|
227
|
-
def validate(s = nil)
|
|
228
|
-
mth = "TBD::#{__callee__}"
|
|
229
|
-
cl = OpenStudio::Model::PlanarSurface
|
|
230
|
-
|
|
231
|
-
return mismatch("surface", s, cl, mth, DBG, false) unless s.is_a?(cl)
|
|
232
|
-
|
|
233
|
-
id = s.nameString
|
|
234
|
-
size = s.vertices.size
|
|
235
|
-
last = size - 1
|
|
236
|
-
|
|
237
|
-
log(ERR, "#{id} #{size} vertices? need +3 (#{mth})") unless size > 2
|
|
238
|
-
return false unless size > 2
|
|
239
|
-
|
|
240
|
-
[0, last].each do |i|
|
|
241
|
-
v1 = s.vertices[i]
|
|
242
|
-
v2 = s.vertices[i + 1] unless i == last
|
|
243
|
-
v2 = s.vertices.first if i == last
|
|
244
|
-
vector = v2 - v1
|
|
245
|
-
bad = vector.length < TOL
|
|
246
|
-
|
|
247
|
-
# As is, this comparison also catches collinear vertices (< 10mm apart)
|
|
248
|
-
# along an edge. Should avoid red-flagging such cases. TO DO.
|
|
249
|
-
log(ERR, "#{id}: < #{TOL}m (#{mth})") if bad
|
|
250
|
-
return false if bad
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
# Add as many extra tests as needed ...
|
|
254
|
-
true
|
|
255
|
-
end
|
|
256
|
-
|
|
257
221
|
##
|
|
258
222
|
# Return site-specific (or true) Topolys normal vector of OpenStudio surface.
|
|
259
223
|
#
|
|
@@ -290,9 +254,9 @@ module TBD
|
|
|
290
254
|
cl2 = OpenStudio::Model::Surface
|
|
291
255
|
cl3 = OpenStudio::Model::LayeredConstruction
|
|
292
256
|
|
|
293
|
-
return mismatch("model", model, cl1, mth)
|
|
294
|
-
return mismatch("surface", surface, cl2, mth)
|
|
295
|
-
return nil
|
|
257
|
+
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
|
258
|
+
return mismatch("surface", surface, cl2, mth) unless surface.is_a?(cl2)
|
|
259
|
+
return nil unless surface_valid?(surface)
|
|
296
260
|
|
|
297
261
|
nom = surface.nameString
|
|
298
262
|
surf = {}
|
|
@@ -356,7 +320,7 @@ module TBD
|
|
|
356
320
|
surf[:filmRSI ] = surface.filmResistance
|
|
357
321
|
|
|
358
322
|
surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
|
|
359
|
-
next unless
|
|
323
|
+
next unless surface_valid?(s)
|
|
360
324
|
|
|
361
325
|
id = s.nameString
|
|
362
326
|
valid = s.vertices.size == 3 || s.vertices.size == 4
|
data/lib/tbd/ua.rb
CHANGED
|
@@ -929,7 +929,7 @@ module TBD
|
|
|
929
929
|
model = "* modèle : #{ua[:file]}" if ua.key?(:file) && lang == :fr
|
|
930
930
|
model += " (v#{ua[:version]})" if ua.key?(:version)
|
|
931
931
|
report << model unless model.empty?
|
|
932
|
-
report << "* TBD : v3.2.
|
|
932
|
+
report << "* TBD : v3.2.3"
|
|
933
933
|
report << "* date : #{ua[:date]}"
|
|
934
934
|
|
|
935
935
|
if lang == :en
|
data/lib/tbd/version.rb
CHANGED
data/tbd.gemspec
CHANGED
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
|
29
29
|
s.metadata = {}
|
|
30
30
|
|
|
31
31
|
s.add_dependency "topolys", "~> 0"
|
|
32
|
-
s.add_dependency "osut", "~> 0"
|
|
32
|
+
s.add_dependency "osut", "~> 0.3.0"
|
|
33
33
|
s.add_dependency "json-schema", "~> 2.7.0"
|
|
34
34
|
|
|
35
35
|
s.add_development_dependency "bundler", "~> 2.1"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tbd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.2.
|
|
4
|
+
version: 3.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Denis Bourgeois & Dan Macumber
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-05-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: topolys
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 0.3.0
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 0.3.0
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: json-schema
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -161,7 +161,7 @@ licenses:
|
|
|
161
161
|
- MIT
|
|
162
162
|
metadata:
|
|
163
163
|
homepage_uri: https://github.com/rd2/tbd
|
|
164
|
-
source_code_uri: https://github.com/rd2/tbd/tree/v3.2.
|
|
164
|
+
source_code_uri: https://github.com/rd2/tbd/tree/v3.2.3
|
|
165
165
|
bug_tracker_uri: https://github.com/rd2/tbd/issues
|
|
166
166
|
post_install_message:
|
|
167
167
|
rdoc_options: []
|