osut 0.2.3 → 0.2.7
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/osut/utils.rb +337 -81
- data/lib/osut/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6bbbc6887949cfd0d1aed5c460d993196fa86d1a13f366f7f852e418aa9457a0
|
|
4
|
+
data.tar.gz: b38eaa81d84a79655adb10a06bb1fa299ffff60051d187f2b36bad38fa4d78e0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1eb2cd49987ce2a4bf7a6a9fe0ed7048bc78dce644aa88e68173861ce4e52fc2bfe59bb3c4a7b353426a1bfa30f45af102ca3e509ac91945b82673545f1a4d4d
|
|
7
|
+
data.tar.gz: bb8075d22d660b3f177716463baf3bc2b0e788269dc05f60086272dc5fec193b93a207f94500fa26cf8d786fdcd3810c0d3defb50eca4c39b3a05cf7c8d2412c
|
data/lib/osut/utils.rb
CHANGED
|
@@ -304,19 +304,9 @@ module OSut
|
|
|
304
304
|
end
|
|
305
305
|
end
|
|
306
306
|
|
|
307
|
-
# unless equip.to_ZoneHVACLowTemperatureRadiantElectric.empty?
|
|
308
|
-
# equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get
|
|
309
|
-
#
|
|
310
|
-
# unless equip.heatingSetpointTemperatureSchedule.empty?
|
|
311
|
-
# sched = equip.heatingSetpointTemperatureSchedule.get
|
|
312
|
-
# end
|
|
313
|
-
# end
|
|
314
|
-
|
|
315
307
|
unless equip.to_ZoneHVACLowTemperatureRadiantElectric.empty?
|
|
316
308
|
equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get
|
|
317
|
-
|
|
318
|
-
sched = equip.heatingSetpointTemperatureSchedule.get
|
|
319
|
-
end
|
|
309
|
+
sched = equip.heatingSetpointTemperatureSchedule
|
|
320
310
|
end
|
|
321
311
|
|
|
322
312
|
unless equip.to_ZoneHVACLowTempRadiantConstFlow.empty?
|
|
@@ -638,7 +628,7 @@ module OSut
|
|
|
638
628
|
mth = "OSut::#{__callee__}"
|
|
639
629
|
cl = OpenStudio::Model::Model
|
|
640
630
|
|
|
641
|
-
return mismatch("model", model, cl, mth, DBG, false)
|
|
631
|
+
return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
|
|
642
632
|
|
|
643
633
|
model.getThermalZones.each do |zone|
|
|
644
634
|
return true if minCoolScheduledSetpoint(zone)[:spt]
|
|
@@ -658,12 +648,12 @@ module OSut
|
|
|
658
648
|
mth = "OSut::#{__callee__}"
|
|
659
649
|
cl = OpenStudio::Model::Model
|
|
660
650
|
|
|
661
|
-
return mismatch("model", model, cl, mth, DBG, false)
|
|
651
|
+
return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
|
|
662
652
|
|
|
663
653
|
model.getThermalZones.each do |zone|
|
|
664
|
-
next
|
|
665
|
-
return true
|
|
666
|
-
return true
|
|
654
|
+
next if zone.canBePlenum
|
|
655
|
+
return true unless zone.airLoopHVACs.empty?
|
|
656
|
+
return true if zone.isPlenum
|
|
667
657
|
end
|
|
668
658
|
|
|
669
659
|
false
|
|
@@ -688,7 +678,7 @@ module OSut
|
|
|
688
678
|
# A space may be tagged as a plenum if:
|
|
689
679
|
#
|
|
690
680
|
# CASE A: its zone's "isPlenum" == true (SDK method) for a fully-developed
|
|
691
|
-
# OpenStudio model (complete with HVAC air loops);
|
|
681
|
+
# OpenStudio model (complete with HVAC air loops); OR
|
|
692
682
|
#
|
|
693
683
|
# CASE B: (IN ABSENCE OF HVAC AIRLOOPS) if it's excluded from a building's
|
|
694
684
|
# total floor area yet linked to a zone holding an 'inactive'
|
|
@@ -747,8 +737,8 @@ module OSut
|
|
|
747
737
|
cl = OpenStudio::Model::Model
|
|
748
738
|
limits = nil
|
|
749
739
|
|
|
750
|
-
return mismatch("model", model, cl, mth)
|
|
751
|
-
return invalid("availability", avl, 2, mth)
|
|
740
|
+
return mismatch("model", model, cl, mth) unless model.is_a?(cl)
|
|
741
|
+
return invalid("availability", avl, 2, mth) unless avl.respond_to?(:to_s)
|
|
752
742
|
|
|
753
743
|
# Either fetch availability ScheduleTypeLimits object, or create one.
|
|
754
744
|
model.getScheduleTypeLimitss.each do |l|
|
|
@@ -779,9 +769,9 @@ module OSut
|
|
|
779
769
|
off = OpenStudio::Model::ScheduleDay.new(model, 0)
|
|
780
770
|
|
|
781
771
|
# Seasonal availability start/end dates.
|
|
782
|
-
year
|
|
783
|
-
return
|
|
784
|
-
year
|
|
772
|
+
year = model.yearDescription
|
|
773
|
+
return empty("yearDescription", mth, ERR) if year.empty?
|
|
774
|
+
year = year.get
|
|
785
775
|
may01 = year.makeDate(OpenStudio::MonthOfYear.new("May"), 1)
|
|
786
776
|
oct31 = year.makeDate(OpenStudio::MonthOfYear.new("Oct"), 31)
|
|
787
777
|
|
|
@@ -967,17 +957,17 @@ module OSut
|
|
|
967
957
|
cl1 = OpenStudio::Model::Model
|
|
968
958
|
cl2 = OpenStudio::Model::Surface
|
|
969
959
|
|
|
970
|
-
return mismatch("model", model, cl1, mth)
|
|
971
|
-
return invalid("s", mth, 2)
|
|
972
|
-
id
|
|
973
|
-
return mismatch(id, s, cl2, mth)
|
|
960
|
+
return mismatch("model", model, cl1, mth) unless model.is_a?(cl1)
|
|
961
|
+
return invalid("s", mth, 2) unless s.respond_to?(NS)
|
|
962
|
+
id = s.nameString
|
|
963
|
+
return mismatch(id, s, cl2, mth) unless s.is_a?(cl2)
|
|
974
964
|
|
|
975
965
|
ok = s.isConstructionDefaulted
|
|
976
966
|
log(ERR, "'#{id}' construction not defaulted (#{mth})") unless ok
|
|
977
967
|
return nil unless ok
|
|
978
|
-
return empty("'#{id}' construction", mth, ERR)
|
|
968
|
+
return empty("'#{id}' construction", mth, ERR) if s.construction.empty?
|
|
979
969
|
base = s.construction.get
|
|
980
|
-
return empty("'#{id}' space", mth, ERR)
|
|
970
|
+
return empty("'#{id}' space", mth, ERR) if s.space.empty?
|
|
981
971
|
space = s.space.get
|
|
982
972
|
type = s.surfaceType
|
|
983
973
|
ground = false
|
|
@@ -991,7 +981,7 @@ module OSut
|
|
|
991
981
|
|
|
992
982
|
unless space.defaultConstructionSet.empty?
|
|
993
983
|
set = space.defaultConstructionSet.get
|
|
994
|
-
return set
|
|
984
|
+
return set if holdsConstruction?(set, base, ground, exterior, type)
|
|
995
985
|
end
|
|
996
986
|
|
|
997
987
|
unless space.spaceType.empty?
|
|
@@ -999,7 +989,7 @@ module OSut
|
|
|
999
989
|
|
|
1000
990
|
unless spacetype.defaultConstructionSet.empty?
|
|
1001
991
|
set = spacetype.defaultConstructionSet.get
|
|
1002
|
-
return set
|
|
992
|
+
return set if holdsConstruction?(set, base, ground, exterior, type)
|
|
1003
993
|
end
|
|
1004
994
|
end
|
|
1005
995
|
|
|
@@ -1008,7 +998,7 @@ module OSut
|
|
|
1008
998
|
|
|
1009
999
|
unless story.defaultConstructionSet.empty?
|
|
1010
1000
|
set = story.defaultConstructionSet.get
|
|
1011
|
-
return set
|
|
1001
|
+
return set if holdsConstruction?(set, base, ground, exterior, type)
|
|
1012
1002
|
end
|
|
1013
1003
|
end
|
|
1014
1004
|
|
|
@@ -1016,7 +1006,7 @@ module OSut
|
|
|
1016
1006
|
|
|
1017
1007
|
unless building.defaultConstructionSet.empty?
|
|
1018
1008
|
set = building.defaultConstructionSet.get
|
|
1019
|
-
return set
|
|
1009
|
+
return set if holdsConstruction?(set, base, ground, exterior, type)
|
|
1020
1010
|
end
|
|
1021
1011
|
|
|
1022
1012
|
nil
|
|
@@ -1046,15 +1036,15 @@ module OSut
|
|
|
1046
1036
|
#
|
|
1047
1037
|
# @param lc [OpenStudio::LayeredConstruction] a layered construction
|
|
1048
1038
|
#
|
|
1049
|
-
# @return [
|
|
1050
|
-
# @return [
|
|
1039
|
+
# @return [Float] total layered construction thickness
|
|
1040
|
+
# @return [Float] 0 if invalid input
|
|
1051
1041
|
def thickness(lc = nil)
|
|
1052
1042
|
mth = "OSut::#{__callee__}"
|
|
1053
1043
|
cl = OpenStudio::Model::LayeredConstruction
|
|
1054
1044
|
|
|
1055
|
-
return invalid("lc", mth, 1, DBG, 0.0)
|
|
1045
|
+
return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
|
|
1056
1046
|
id = lc.nameString
|
|
1057
|
-
return mismatch(id, lc, cl, mth, DBG, 0.0)
|
|
1047
|
+
return mismatch(id, lc, cl, mth, DBG, 0.0) unless lc.is_a?(cl)
|
|
1058
1048
|
|
|
1059
1049
|
ok = standardOpaqueLayers?(lc)
|
|
1060
1050
|
log(ERR, "'#{id}' holds non-StandardOpaqueMaterial(s) (#{mth})") unless ok
|
|
@@ -1176,9 +1166,9 @@ module OSut
|
|
|
1176
1166
|
res = { index: nil, type: nil, r: 0.0 }
|
|
1177
1167
|
i = 0 # iterator
|
|
1178
1168
|
|
|
1179
|
-
return invalid("lc", mth, 1, DBG, res)
|
|
1180
|
-
id
|
|
1181
|
-
return mismatch(id, lc, cl1, mth, DBG, res)
|
|
1169
|
+
return invalid("lc", mth, 1, DBG, res) unless lc.respond_to?(NS)
|
|
1170
|
+
id = lc.nameString
|
|
1171
|
+
return mismatch(id, lc, cl1, mth, DBG, res) unless lc.is_a?(cl)
|
|
1182
1172
|
|
|
1183
1173
|
lc.layers.each do |m|
|
|
1184
1174
|
unless m.to_MasslessOpaqueMaterial.empty?
|
|
@@ -1188,9 +1178,9 @@ module OSut
|
|
|
1188
1178
|
i += 1
|
|
1189
1179
|
next
|
|
1190
1180
|
else
|
|
1191
|
-
res[:r]
|
|
1181
|
+
res[:r ] = m.thermalResistance
|
|
1192
1182
|
res[:index] = i
|
|
1193
|
-
res[:type]
|
|
1183
|
+
res[:type ] = :massless
|
|
1194
1184
|
end
|
|
1195
1185
|
end
|
|
1196
1186
|
|
|
@@ -1203,9 +1193,9 @@ module OSut
|
|
|
1203
1193
|
i += 1
|
|
1204
1194
|
next
|
|
1205
1195
|
else
|
|
1206
|
-
res[:r]
|
|
1196
|
+
res[:r ] = d / k
|
|
1207
1197
|
res[:index] = i
|
|
1208
|
-
res[:type]
|
|
1198
|
+
res[:type ] = :standard
|
|
1209
1199
|
end
|
|
1210
1200
|
end
|
|
1211
1201
|
|
|
@@ -1240,6 +1230,28 @@ module OSut
|
|
|
1240
1230
|
res
|
|
1241
1231
|
end
|
|
1242
1232
|
|
|
1233
|
+
##
|
|
1234
|
+
# Return a scalar product of an OpenStudio Vector3d.
|
|
1235
|
+
#
|
|
1236
|
+
# @param v [OpenStudio::Vector3d] a vector
|
|
1237
|
+
# @param m [Float] a scalar
|
|
1238
|
+
#
|
|
1239
|
+
# @return [OpenStudio::Vector3d] modified vector
|
|
1240
|
+
# @return [OpenStudio::Vector3d] provided (or empty) vector if invalid input
|
|
1241
|
+
def scalar(v = OpenStudio::Vector3d.new(0,0,0), m = 0)
|
|
1242
|
+
mth = "OSut::#{__callee__}"
|
|
1243
|
+
cl1 = OpenStudio::Vector3d
|
|
1244
|
+
cl2 = Numeric
|
|
1245
|
+
|
|
1246
|
+
return mismatch("vector", v, cl1, mth, DBG, v) unless v.is_a?(cl1)
|
|
1247
|
+
return mismatch("x", v.x, cl2, mth, DBG, v) unless v.x.respond_to?(:to_f)
|
|
1248
|
+
return mismatch("y", v.y, cl2, mth, DBG, v) unless v.y.respond_to?(:to_f)
|
|
1249
|
+
return mismatch("z", v.z, cl2, mth, DBG, v) unless v.z.respond_to?(:to_f)
|
|
1250
|
+
return mismatch("m", m, cl2, mth, DBG, v) unless m.respond_to?(:to_f)
|
|
1251
|
+
|
|
1252
|
+
OpenStudio::Vector3d.new(m * v.x, m * v.y, m * v.z)
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1243
1255
|
##
|
|
1244
1256
|
# Flatten OpenStudio 3D points vs Z-axis (Z=0).
|
|
1245
1257
|
#
|
|
@@ -1253,8 +1265,8 @@ module OSut
|
|
|
1253
1265
|
v = OpenStudio::Point3dVector.new
|
|
1254
1266
|
|
|
1255
1267
|
valid = pts.is_a?(cl1) || pts.is_a?(Array)
|
|
1256
|
-
return mismatch("points", pts, cl1, mth, DBG, v)
|
|
1257
|
-
pts.each { |pt| mismatch("pt", pt, cl2, mth, ERR, v)
|
|
1268
|
+
return mismatch("points", pts, cl1, mth, DBG, v) unless valid
|
|
1269
|
+
pts.each { |pt| mismatch("pt", pt, cl2, mth, ERR, v) unless pt.is_a?(cl2) }
|
|
1258
1270
|
pts.each { |pt| v << OpenStudio::Point3d.new(pt.x, pt.y, 0) }
|
|
1259
1271
|
|
|
1260
1272
|
v
|
|
@@ -1278,40 +1290,47 @@ module OSut
|
|
|
1278
1290
|
|
|
1279
1291
|
return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
|
|
1280
1292
|
return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
|
|
1293
|
+
|
|
1281
1294
|
i1 = id1.to_s
|
|
1282
1295
|
i2 = id2.to_s
|
|
1283
1296
|
i1 = "poly1" if i1.empty?
|
|
1284
1297
|
i2 = "poly2" if i2.empty?
|
|
1298
|
+
|
|
1285
1299
|
valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
|
|
1286
1300
|
valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1301
|
+
|
|
1287
1302
|
return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
|
|
1288
1303
|
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
|
|
1289
|
-
return empty(i1, mth, ERR, a)
|
|
1290
|
-
return empty(i2, mth, ERR, a)
|
|
1304
|
+
return empty(i1, mth, ERR, a) if p1.empty?
|
|
1305
|
+
return empty(i2, mth, ERR, a) if p2.empty?
|
|
1306
|
+
|
|
1291
1307
|
p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1292
1308
|
p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1293
1309
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1310
|
+
# XY-plane transformation matrix ... needs to be clockwise for boost.
|
|
1311
|
+
ft = OpenStudio::Transformation.alignFace(p1)
|
|
1312
|
+
ft_p1 = flatZ( (ft.inverse * p1) )
|
|
1313
|
+
return false if ft_p1.empty?
|
|
1314
|
+
cw = OpenStudio.pointInPolygon(ft_p1.first, ft_p1, TOL)
|
|
1315
|
+
ft_p1 = flatZ( (ft.inverse * p1).reverse ) unless cw
|
|
1316
|
+
ft_p2 = flatZ( (ft.inverse * p2).reverse ) unless cw
|
|
1317
|
+
ft_p2 = flatZ( (ft.inverse * p2) ) if cw
|
|
1318
|
+
return false if ft_p2.empty?
|
|
1319
|
+
area1 = OpenStudio.getArea(ft_p1)
|
|
1320
|
+
area2 = OpenStudio.getArea(ft_p2)
|
|
1321
|
+
return empty("#{i1} area", mth, ERR, a) if area1.empty?
|
|
1322
|
+
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1299
1323
|
area1 = area1.get
|
|
1300
|
-
ft_p2 = flatZ( (ft * p2).reverse )
|
|
1301
|
-
return false if ft_p2.empty?
|
|
1302
|
-
area2 = OpenStudio::getArea(ft_p2)
|
|
1303
|
-
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1304
1324
|
area2 = area2.get
|
|
1305
|
-
union = OpenStudio
|
|
1306
|
-
return
|
|
1325
|
+
union = OpenStudio.join(ft_p1, ft_p2, TOL2)
|
|
1326
|
+
return false if union.empty?
|
|
1307
1327
|
union = union.get
|
|
1308
|
-
area
|
|
1309
|
-
return
|
|
1328
|
+
area = OpenStudio.getArea(union)
|
|
1329
|
+
return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
|
|
1310
1330
|
area = area.get
|
|
1311
|
-
|
|
1312
|
-
return
|
|
1313
|
-
return
|
|
1314
|
-
return false if (area - area2).abs > TOL
|
|
1331
|
+
return false if area < TOL
|
|
1332
|
+
return true if (area - area2).abs < TOL
|
|
1333
|
+
return false if (area - area2).abs > TOL
|
|
1315
1334
|
|
|
1316
1335
|
true
|
|
1317
1336
|
end
|
|
@@ -1334,42 +1353,279 @@ module OSut
|
|
|
1334
1353
|
|
|
1335
1354
|
return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
|
|
1336
1355
|
return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
|
|
1356
|
+
|
|
1337
1357
|
i1 = id1.to_s
|
|
1338
1358
|
i2 = id2.to_s
|
|
1339
1359
|
i1 = "poly1" if i1.empty?
|
|
1340
1360
|
i2 = "poly2" if i2.empty?
|
|
1361
|
+
|
|
1341
1362
|
valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
|
|
1342
1363
|
valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
|
|
1364
|
+
|
|
1343
1365
|
return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
|
|
1344
1366
|
return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
|
|
1345
|
-
return empty(i1, mth, ERR, a)
|
|
1346
|
-
return empty(i2, mth, ERR, a)
|
|
1367
|
+
return empty(i1, mth, ERR, a) if p1.empty?
|
|
1368
|
+
return empty(i2, mth, ERR, a) if p2.empty?
|
|
1369
|
+
|
|
1347
1370
|
p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1348
1371
|
p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
|
|
1349
1372
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
return
|
|
1373
|
+
# XY-plane transformation matrix ... needs to be clockwise for boost.
|
|
1374
|
+
ft = OpenStudio::Transformation.alignFace(p1)
|
|
1375
|
+
ft_p1 = flatZ( (ft.inverse * p1) )
|
|
1376
|
+
ft_p2 = flatZ( (ft.inverse * p2) )
|
|
1377
|
+
return false if ft_p1.empty?
|
|
1378
|
+
return false if ft_p2.empty?
|
|
1379
|
+
cw = OpenStudio.pointInPolygon(ft_p1.first, ft_p1, TOL)
|
|
1380
|
+
ft_p1 = flatZ( (ft.inverse * p1).reverse ) unless cw
|
|
1381
|
+
ft_p2 = flatZ( (ft.inverse * p2).reverse ) unless cw
|
|
1382
|
+
return false if ft_p1.empty?
|
|
1383
|
+
return false if ft_p2.empty?
|
|
1384
|
+
area1 = OpenStudio.getArea(ft_p1)
|
|
1385
|
+
area2 = OpenStudio.getArea(ft_p2)
|
|
1386
|
+
return empty("#{i1} area", mth, ERR, a) if area1.empty?
|
|
1387
|
+
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1355
1388
|
area1 = area1.get
|
|
1356
|
-
ft_p2 = flatZ( (ft * p2).reverse )
|
|
1357
|
-
return false if ft_p2.empty?
|
|
1358
|
-
area2 = OpenStudio::getArea(ft_p2)
|
|
1359
|
-
return empty("#{i2} area", mth, ERR, a) if area2.empty?
|
|
1360
1389
|
area2 = area2.get
|
|
1361
|
-
union = OpenStudio
|
|
1362
|
-
return
|
|
1390
|
+
union = OpenStudio.join(ft_p1, ft_p2, TOL2)
|
|
1391
|
+
return false if union.empty?
|
|
1363
1392
|
union = union.get
|
|
1364
|
-
area
|
|
1365
|
-
return empty("#{i1}:#{i2} union area", mth, ERR, a)
|
|
1393
|
+
area = OpenStudio.getArea(union)
|
|
1394
|
+
return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
|
|
1366
1395
|
area = area.get
|
|
1367
|
-
|
|
1368
|
-
return false if area < TOL
|
|
1396
|
+
return false if area < TOL
|
|
1369
1397
|
|
|
1370
1398
|
true
|
|
1371
1399
|
end
|
|
1372
1400
|
|
|
1401
|
+
##
|
|
1402
|
+
# Generate offset vertices (by width) for a 3- or 4-sided, convex polygon.
|
|
1403
|
+
#
|
|
1404
|
+
# @param p1 [OpenStudio::Point3dVector] OpenStudio Point3D vector/array
|
|
1405
|
+
# @param w [Float] offset width (min: 0.0254m)
|
|
1406
|
+
# @param v [Integer] OpenStudio SDK version, eg '321' for 'v3.2.1' (optional)
|
|
1407
|
+
#
|
|
1408
|
+
# @return [OpenStudio::Point3dVector] offset points if successful
|
|
1409
|
+
# @return [OpenStudio::Point3dVector] original points if invalid input
|
|
1410
|
+
def offset(p1 = [], w = 0, v = 0)
|
|
1411
|
+
mth = "TBD::#{__callee__}"
|
|
1412
|
+
cl = OpenStudio::Point3d
|
|
1413
|
+
vrsn = OpenStudio.openStudioVersion.split(".").map(&:to_i).join.to_i
|
|
1414
|
+
|
|
1415
|
+
valid = p1.is_a?(OpenStudio::Point3dVector) || p1.is_a?(Array)
|
|
1416
|
+
return mismatch("pts", p1, cl1, mth, DBG, p1) unless valid
|
|
1417
|
+
return empty("pts", mth, ERR, p1) if p1.empty?
|
|
1418
|
+
valid = p1.size == 3 || p1.size == 4
|
|
1419
|
+
iv = true if p1.size == 4
|
|
1420
|
+
return invalid("pts", mth, 1, DBG, p1) unless valid
|
|
1421
|
+
return invalid("width", mth, 2, DBG, p1) unless w.respond_to?(:to_f)
|
|
1422
|
+
w = w.to_f
|
|
1423
|
+
return p1 if w < 0.0254
|
|
1424
|
+
v = v.to_i if v.respond_to?(:to_i)
|
|
1425
|
+
v = 0 unless v.respond_to?(:to_i)
|
|
1426
|
+
v = vrsn if v.zero?
|
|
1427
|
+
|
|
1428
|
+
p1.each { |x| return mismatch("p", x, cl, mth, ERR, p1) unless x.is_a?(cl) }
|
|
1429
|
+
|
|
1430
|
+
unless v < 340
|
|
1431
|
+
# XY-plane transformation matrix ... needs to be clockwise for boost.
|
|
1432
|
+
ft = OpenStudio::Transformation::alignFace(p1)
|
|
1433
|
+
ft_pts = flatZ( (ft.inverse * p1) )
|
|
1434
|
+
return p1 if ft_pts.empty?
|
|
1435
|
+
cw = OpenStudio::pointInPolygon(ft_pts.first, ft_pts, TOL)
|
|
1436
|
+
ft_pts = flatZ( (ft.inverse * p1).reverse ) unless cw
|
|
1437
|
+
offset = OpenStudio.buffer(ft_pts, w, TOL)
|
|
1438
|
+
return p1 if offset.empty?
|
|
1439
|
+
offset = offset.get
|
|
1440
|
+
offset = ft * offset if cw
|
|
1441
|
+
offset = (ft * offset).reverse unless cw
|
|
1442
|
+
|
|
1443
|
+
pz = OpenStudio::Point3dVector.new
|
|
1444
|
+
offset.each { |o| pz << OpenStudio::Point3d.new(o.x, o.y, o.z ) }
|
|
1445
|
+
return pz
|
|
1446
|
+
else # brute force approach
|
|
1447
|
+
pz = {}
|
|
1448
|
+
pz[:A] = {}
|
|
1449
|
+
pz[:B] = {}
|
|
1450
|
+
pz[:C] = {}
|
|
1451
|
+
pz[:D] = {} if iv
|
|
1452
|
+
|
|
1453
|
+
pz[:A][:p] = OpenStudio::Point3d.new(p1[0].x, p1[0].y, p1[0].z)
|
|
1454
|
+
pz[:B][:p] = OpenStudio::Point3d.new(p1[1].x, p1[1].y, p1[1].z)
|
|
1455
|
+
pz[:C][:p] = OpenStudio::Point3d.new(p1[2].x, p1[2].y, p1[2].z)
|
|
1456
|
+
pz[:D][:p] = OpenStudio::Point3d.new(p1[3].x, p1[3].y, p1[3].z) if iv
|
|
1457
|
+
|
|
1458
|
+
pzAp = pz[:A][:p]
|
|
1459
|
+
pzBp = pz[:B][:p]
|
|
1460
|
+
pzCp = pz[:C][:p]
|
|
1461
|
+
pzDp = pz[:D][:p] if iv
|
|
1462
|
+
|
|
1463
|
+
# Generate vector pairs, from next point & from previous point.
|
|
1464
|
+
# :f_n : "from next"
|
|
1465
|
+
# :f_p : "from previous"
|
|
1466
|
+
#
|
|
1467
|
+
#
|
|
1468
|
+
#
|
|
1469
|
+
#
|
|
1470
|
+
#
|
|
1471
|
+
#
|
|
1472
|
+
# A <---------- B
|
|
1473
|
+
# ^
|
|
1474
|
+
# \
|
|
1475
|
+
# \
|
|
1476
|
+
# C (or D)
|
|
1477
|
+
#
|
|
1478
|
+
pz[:A][:f_n] = pzAp - pzBp
|
|
1479
|
+
pz[:A][:f_p] = pzAp - pzCp unless iv
|
|
1480
|
+
pz[:A][:f_p] = pzAp - pzDp if iv
|
|
1481
|
+
|
|
1482
|
+
pz[:B][:f_n] = pzBp - pzCp
|
|
1483
|
+
pz[:B][:f_p] = pzBp - pzAp
|
|
1484
|
+
|
|
1485
|
+
pz[:C][:f_n] = pzCp - pzAp unless iv
|
|
1486
|
+
pz[:C][:f_n] = pzCp - pzDp if iv
|
|
1487
|
+
pz[:C][:f_p] = pzCp - pzBp
|
|
1488
|
+
|
|
1489
|
+
pz[:D][:f_n] = pzDp - pzAp if iv
|
|
1490
|
+
pz[:D][:f_p] = pzDp - pzCp if iv
|
|
1491
|
+
|
|
1492
|
+
# Generate 3D plane from vectors.
|
|
1493
|
+
#
|
|
1494
|
+
#
|
|
1495
|
+
# | <<< 3D plane ... from point A, with normal B>A
|
|
1496
|
+
# |
|
|
1497
|
+
# |
|
|
1498
|
+
# |
|
|
1499
|
+
# <---------- A <---------- B
|
|
1500
|
+
# |\
|
|
1501
|
+
# | \
|
|
1502
|
+
# | \
|
|
1503
|
+
# | C (or D)
|
|
1504
|
+
#
|
|
1505
|
+
pz[:A][:pl_f_n] = OpenStudio::Plane.new(pzAp, pz[:A][:f_n])
|
|
1506
|
+
pz[:A][:pl_f_p] = OpenStudio::Plane.new(pzAp, pz[:A][:f_p])
|
|
1507
|
+
|
|
1508
|
+
pz[:B][:pl_f_n] = OpenStudio::Plane.new(pzBp, pz[:B][:f_n])
|
|
1509
|
+
pz[:B][:pl_f_p] = OpenStudio::Plane.new(pzBp, pz[:B][:f_p])
|
|
1510
|
+
|
|
1511
|
+
pz[:C][:pl_f_n] = OpenStudio::Plane.new(pzCp, pz[:C][:f_n])
|
|
1512
|
+
pz[:C][:pl_f_p] = OpenStudio::Plane.new(pzCp, pz[:C][:f_p])
|
|
1513
|
+
|
|
1514
|
+
pz[:D][:pl_f_n] = OpenStudio::Plane.new(pzDp, pz[:D][:f_n]) if iv
|
|
1515
|
+
pz[:D][:pl_f_p] = OpenStudio::Plane.new(pzDp, pz[:D][:f_p]) if iv
|
|
1516
|
+
|
|
1517
|
+
# Project an extended point (pC) unto 3D plane.
|
|
1518
|
+
#
|
|
1519
|
+
# pC <<< projected unto extended B>A 3D plane
|
|
1520
|
+
# eC |
|
|
1521
|
+
# \ |
|
|
1522
|
+
# \ |
|
|
1523
|
+
# \|
|
|
1524
|
+
# <---------- A <---------- B
|
|
1525
|
+
# |\
|
|
1526
|
+
# | \
|
|
1527
|
+
# | \
|
|
1528
|
+
# | C (or D)
|
|
1529
|
+
#
|
|
1530
|
+
pz[:A][:p_n_pl] = pz[:A][:pl_f_n].project(pz[:A][:p] + pz[:A][:f_p])
|
|
1531
|
+
pz[:A][:n_p_pl] = pz[:A][:pl_f_p].project(pz[:A][:p] + pz[:A][:f_n])
|
|
1532
|
+
|
|
1533
|
+
pz[:B][:p_n_pl] = pz[:B][:pl_f_n].project(pz[:B][:p] + pz[:B][:f_p])
|
|
1534
|
+
pz[:B][:n_p_pl] = pz[:B][:pl_f_p].project(pz[:B][:p] + pz[:B][:f_n])
|
|
1535
|
+
|
|
1536
|
+
pz[:C][:p_n_pl] = pz[:C][:pl_f_n].project(pz[:C][:p] + pz[:C][:f_p])
|
|
1537
|
+
pz[:C][:n_p_pl] = pz[:C][:pl_f_p].project(pz[:C][:p] + pz[:C][:f_n])
|
|
1538
|
+
|
|
1539
|
+
pz[:D][:p_n_pl] = pz[:D][:pl_f_n].project(pz[:D][:p] + pz[:D][:f_p]) if iv
|
|
1540
|
+
pz[:D][:n_p_pl] = pz[:D][:pl_f_p].project(pz[:D][:p] + pz[:D][:f_n]) if iv
|
|
1541
|
+
|
|
1542
|
+
# Generate vector from point (e.g. A) to projected extended point (pC).
|
|
1543
|
+
#
|
|
1544
|
+
# pC
|
|
1545
|
+
# eC ^
|
|
1546
|
+
# \ |
|
|
1547
|
+
# \ |
|
|
1548
|
+
# \|
|
|
1549
|
+
# <---------- A <---------- B
|
|
1550
|
+
# |\
|
|
1551
|
+
# | \
|
|
1552
|
+
# | \
|
|
1553
|
+
# | C (or D)
|
|
1554
|
+
#
|
|
1555
|
+
pz[:A][:n_p_n_pl] = pz[:A][:p_n_pl] - pzAp
|
|
1556
|
+
pz[:A][:n_n_p_pl] = pz[:A][:n_p_pl] - pzAp
|
|
1557
|
+
|
|
1558
|
+
pz[:B][:n_p_n_pl] = pz[:B][:p_n_pl] - pzBp
|
|
1559
|
+
pz[:B][:n_n_p_pl] = pz[:B][:n_p_pl] - pzBp
|
|
1560
|
+
|
|
1561
|
+
pz[:C][:n_p_n_pl] = pz[:C][:p_n_pl] - pzCp
|
|
1562
|
+
pz[:C][:n_n_p_pl] = pz[:C][:n_p_pl] - pzCp
|
|
1563
|
+
|
|
1564
|
+
pz[:D][:n_p_n_pl] = pz[:D][:p_n_pl] - pzDp if iv
|
|
1565
|
+
pz[:D][:n_n_p_pl] = pz[:D][:n_p_pl] - pzDp if iv
|
|
1566
|
+
|
|
1567
|
+
# Fetch angle between both extended vectors (A>pC & A>pB),
|
|
1568
|
+
# ... then normalize (Cn).
|
|
1569
|
+
#
|
|
1570
|
+
# pC
|
|
1571
|
+
# eC ^
|
|
1572
|
+
# \ |
|
|
1573
|
+
# \ Cn
|
|
1574
|
+
# \|
|
|
1575
|
+
# <---------- A <---------- B
|
|
1576
|
+
# |\
|
|
1577
|
+
# | \
|
|
1578
|
+
# | \
|
|
1579
|
+
# | C (or D)
|
|
1580
|
+
#
|
|
1581
|
+
a1 = OpenStudio.getAngle(pz[:A][:n_p_n_pl], pz[:A][:n_n_p_pl])
|
|
1582
|
+
a2 = OpenStudio.getAngle(pz[:B][:n_p_n_pl], pz[:B][:n_n_p_pl])
|
|
1583
|
+
a3 = OpenStudio.getAngle(pz[:C][:n_p_n_pl], pz[:C][:n_n_p_pl])
|
|
1584
|
+
a4 = OpenStudio.getAngle(pz[:D][:n_p_n_pl], pz[:D][:n_n_p_pl]) if iv
|
|
1585
|
+
|
|
1586
|
+
# Generate new 3D points A', B', C' (and D') ... zigzag.
|
|
1587
|
+
#
|
|
1588
|
+
#
|
|
1589
|
+
#
|
|
1590
|
+
#
|
|
1591
|
+
# A' ---------------------- B'
|
|
1592
|
+
# \
|
|
1593
|
+
# \ A <---------- B
|
|
1594
|
+
# \ \
|
|
1595
|
+
# \ \
|
|
1596
|
+
# \ \
|
|
1597
|
+
# C' C
|
|
1598
|
+
pz[:A][:f_n].normalize
|
|
1599
|
+
pz[:A][:n_p_n_pl].normalize
|
|
1600
|
+
pzAp = pzAp + scalar(pz[:A][:n_p_n_pl], w)
|
|
1601
|
+
pzAp = pzAp + scalar(pz[:A][:f_n], w * Math.tan(a1/2))
|
|
1602
|
+
|
|
1603
|
+
pz[:B][:f_n].normalize
|
|
1604
|
+
pz[:B][:n_p_n_pl].normalize
|
|
1605
|
+
pzBp = pzBp + scalar(pz[:B][:n_p_n_pl], w)
|
|
1606
|
+
pzBp = pzBp + scalar(pz[:B][:f_n], w * Math.tan(a2/2))
|
|
1607
|
+
|
|
1608
|
+
pz[:C][:f_n].normalize
|
|
1609
|
+
pz[:C][:n_p_n_pl].normalize
|
|
1610
|
+
pzCp = pzCp + scalar(pz[:C][:n_p_n_pl], w)
|
|
1611
|
+
pzCp = pzCp + scalar(pz[:C][:f_n], w * Math.tan(a3/2))
|
|
1612
|
+
|
|
1613
|
+
pz[:D][:f_n].normalize if iv
|
|
1614
|
+
pz[:D][:n_p_n_pl].normalize if iv
|
|
1615
|
+
pzDp = pzDp + scalar(pz[:D][:n_p_n_pl], w) if iv
|
|
1616
|
+
pzDp = pzDp + scalar(pz[:D][:f_n], w * Math.tan(a4/2)) if iv
|
|
1617
|
+
|
|
1618
|
+
# Re-convert to OpenStudio 3D points.
|
|
1619
|
+
vec = OpenStudio::Point3dVector.new
|
|
1620
|
+
vec << OpenStudio::Point3d.new(pzAp.x, pzAp.y, pzAp.z)
|
|
1621
|
+
vec << OpenStudio::Point3d.new(pzBp.x, pzBp.y, pzBp.z)
|
|
1622
|
+
vec << OpenStudio::Point3d.new(pzCp.x, pzCp.y, pzCp.z)
|
|
1623
|
+
vec << OpenStudio::Point3d.new(pzDp.x, pzDp.y, pzDp.z) if iv
|
|
1624
|
+
|
|
1625
|
+
return vec
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
|
|
1373
1629
|
##
|
|
1374
1630
|
# Callback when other modules extend OSlg
|
|
1375
1631
|
#
|
data/lib/osut/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: osut
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Denis Bourgeois
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-08-
|
|
11
|
+
date: 2022-08-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: oslg
|
|
@@ -90,7 +90,7 @@ licenses:
|
|
|
90
90
|
- BSD-3-Clause
|
|
91
91
|
metadata:
|
|
92
92
|
homepage_uri: https://github.com/rd2/osut
|
|
93
|
-
source_code_uri: https://github.com/rd2/osut/tree/v0.2.
|
|
93
|
+
source_code_uri: https://github.com/rd2/osut/tree/v0.2.7
|
|
94
94
|
bug_tracker_uri: https://github.com/rd2/osut/issues
|
|
95
95
|
post_install_message:
|
|
96
96
|
rdoc_options: []
|