osut 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/osut/utils.rb +336 -70
  3. data/lib/osut/version.rb +1 -1
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04db3007d81904287c0c36c677270a1e1bc5e45375d3b37bbac9068d51c43754
4
- data.tar.gz: aafa2bb60bdfaf5b5df03e99aca0cb3181f6270468a761652d2b6d0438037daa
3
+ metadata.gz: 6bbbc6887949cfd0d1aed5c460d993196fa86d1a13f366f7f852e418aa9457a0
4
+ data.tar.gz: b38eaa81d84a79655adb10a06bb1fa299ffff60051d187f2b36bad38fa4d78e0
5
5
  SHA512:
6
- metadata.gz: ca60fd088aa106b52bfe15fe4fd352c55a2c79083f95212d7e9e37250f1832b3b94f0dc415e664f5289e837600aad2ab936eff304e9d5cdba0c3a977a56cd7d0
7
- data.tar.gz: 8aa96937a55520f99a9c122d0fe98f69ec97d45cbe0cac1e0db7626b48cacee5d65f801eb4a9791e3a6953d64473555b981b3bd9646d7948b6b5c26b2d02e041
6
+ metadata.gz: 1eb2cd49987ce2a4bf7a6a9fe0ed7048bc78dce644aa88e68173861ce4e52fc2bfe59bb3c4a7b353426a1bfa30f45af102ca3e509ac91945b82673545f1a4d4d
7
+ data.tar.gz: bb8075d22d660b3f177716463baf3bc2b0e788269dc05f60086272dc5fec193b93a207f94500fa26cf8d786fdcd3810c0d3defb50eca4c39b3a05cf7c8d2412c
data/lib/osut/utils.rb CHANGED
@@ -628,7 +628,7 @@ module OSut
628
628
  mth = "OSut::#{__callee__}"
629
629
  cl = OpenStudio::Model::Model
630
630
 
631
- return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
631
+ return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
632
632
 
633
633
  model.getThermalZones.each do |zone|
634
634
  return true if minCoolScheduledSetpoint(zone)[:spt]
@@ -648,12 +648,12 @@ module OSut
648
648
  mth = "OSut::#{__callee__}"
649
649
  cl = OpenStudio::Model::Model
650
650
 
651
- return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
651
+ return mismatch("model", model, cl, mth, DBG, false) unless model.is_a?(cl)
652
652
 
653
653
  model.getThermalZones.each do |zone|
654
- next if zone.canBePlenum
655
- return true unless zone.airLoopHVACs.empty?
656
- return true if zone.isPlenum
654
+ next if zone.canBePlenum
655
+ return true unless zone.airLoopHVACs.empty?
656
+ return true if zone.isPlenum
657
657
  end
658
658
 
659
659
  false
@@ -678,7 +678,7 @@ module OSut
678
678
  # A space may be tagged as a plenum if:
679
679
  #
680
680
  # CASE A: its zone's "isPlenum" == true (SDK method) for a fully-developed
681
- # OpenStudio model (complete with HVAC air loops);
681
+ # OpenStudio model (complete with HVAC air loops); OR
682
682
  #
683
683
  # CASE B: (IN ABSENCE OF HVAC AIRLOOPS) if it's excluded from a building's
684
684
  # total floor area yet linked to a zone holding an 'inactive'
@@ -737,8 +737,8 @@ module OSut
737
737
  cl = OpenStudio::Model::Model
738
738
  limits = nil
739
739
 
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)
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)
742
742
 
743
743
  # Either fetch availability ScheduleTypeLimits object, or create one.
744
744
  model.getScheduleTypeLimitss.each do |l|
@@ -769,9 +769,9 @@ module OSut
769
769
  off = OpenStudio::Model::ScheduleDay.new(model, 0)
770
770
 
771
771
  # Seasonal availability start/end dates.
772
- year = model.yearDescription
773
- return empty("yearDescription", mth, ERR) if year.empty?
774
- year = year.get
772
+ year = model.yearDescription
773
+ return empty("yearDescription", mth, ERR) if year.empty?
774
+ year = year.get
775
775
  may01 = year.makeDate(OpenStudio::MonthOfYear.new("May"), 1)
776
776
  oct31 = year.makeDate(OpenStudio::MonthOfYear.new("Oct"), 31)
777
777
 
@@ -957,17 +957,17 @@ module OSut
957
957
  cl1 = OpenStudio::Model::Model
958
958
  cl2 = OpenStudio::Model::Surface
959
959
 
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)
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)
964
964
 
965
965
  ok = s.isConstructionDefaulted
966
966
  log(ERR, "'#{id}' construction not defaulted (#{mth})") unless ok
967
967
  return nil unless ok
968
- return empty("'#{id}' construction", mth, ERR) if s.construction.empty?
968
+ return empty("'#{id}' construction", mth, ERR) if s.construction.empty?
969
969
  base = s.construction.get
970
- return empty("'#{id}' space", mth, ERR) if s.space.empty?
970
+ return empty("'#{id}' space", mth, ERR) if s.space.empty?
971
971
  space = s.space.get
972
972
  type = s.surfaceType
973
973
  ground = false
@@ -981,7 +981,7 @@ module OSut
981
981
 
982
982
  unless space.defaultConstructionSet.empty?
983
983
  set = space.defaultConstructionSet.get
984
- return set if holdsConstruction?(set, base, ground, exterior, type)
984
+ return set if holdsConstruction?(set, base, ground, exterior, type)
985
985
  end
986
986
 
987
987
  unless space.spaceType.empty?
@@ -989,7 +989,7 @@ module OSut
989
989
 
990
990
  unless spacetype.defaultConstructionSet.empty?
991
991
  set = spacetype.defaultConstructionSet.get
992
- return set if holdsConstruction?(set, base, ground, exterior, type)
992
+ return set if holdsConstruction?(set, base, ground, exterior, type)
993
993
  end
994
994
  end
995
995
 
@@ -998,7 +998,7 @@ module OSut
998
998
 
999
999
  unless story.defaultConstructionSet.empty?
1000
1000
  set = story.defaultConstructionSet.get
1001
- return set if holdsConstruction?(set, base, ground, exterior, type)
1001
+ return set if holdsConstruction?(set, base, ground, exterior, type)
1002
1002
  end
1003
1003
  end
1004
1004
 
@@ -1006,7 +1006,7 @@ module OSut
1006
1006
 
1007
1007
  unless building.defaultConstructionSet.empty?
1008
1008
  set = building.defaultConstructionSet.get
1009
- return set if holdsConstruction?(set, base, ground, exterior, type)
1009
+ return set if holdsConstruction?(set, base, ground, exterior, type)
1010
1010
  end
1011
1011
 
1012
1012
  nil
@@ -1036,15 +1036,15 @@ module OSut
1036
1036
  #
1037
1037
  # @param lc [OpenStudio::LayeredConstruction] a layered construction
1038
1038
  #
1039
- # @return [Double] total layered construction thickness
1040
- # @return [Double] 0 if invalid input
1039
+ # @return [Float] total layered construction thickness
1040
+ # @return [Float] 0 if invalid input
1041
1041
  def thickness(lc = nil)
1042
1042
  mth = "OSut::#{__callee__}"
1043
1043
  cl = OpenStudio::Model::LayeredConstruction
1044
1044
 
1045
- return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
1045
+ return invalid("lc", mth, 1, DBG, 0.0) unless lc.respond_to?(NS)
1046
1046
  id = lc.nameString
1047
- return mismatch(id, lc, cl, mth, DBG, 0.0) unless lc.is_a?(cl)
1047
+ return mismatch(id, lc, cl, mth, DBG, 0.0) unless lc.is_a?(cl)
1048
1048
 
1049
1049
  ok = standardOpaqueLayers?(lc)
1050
1050
  log(ERR, "'#{id}' holds non-StandardOpaqueMaterial(s) (#{mth})") unless ok
@@ -1166,9 +1166,9 @@ module OSut
1166
1166
  res = { index: nil, type: nil, r: 0.0 }
1167
1167
  i = 0 # iterator
1168
1168
 
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)
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)
1172
1172
 
1173
1173
  lc.layers.each do |m|
1174
1174
  unless m.to_MasslessOpaqueMaterial.empty?
@@ -1178,9 +1178,9 @@ module OSut
1178
1178
  i += 1
1179
1179
  next
1180
1180
  else
1181
- res[:r] = m.thermalResistance
1181
+ res[:r ] = m.thermalResistance
1182
1182
  res[:index] = i
1183
- res[:type] = :massless
1183
+ res[:type ] = :massless
1184
1184
  end
1185
1185
  end
1186
1186
 
@@ -1193,9 +1193,9 @@ module OSut
1193
1193
  i += 1
1194
1194
  next
1195
1195
  else
1196
- res[:r] = d / k
1196
+ res[:r ] = d / k
1197
1197
  res[:index] = i
1198
- res[:type] = :standard
1198
+ res[:type ] = :standard
1199
1199
  end
1200
1200
  end
1201
1201
 
@@ -1230,6 +1230,28 @@ module OSut
1230
1230
  res
1231
1231
  end
1232
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
+
1233
1255
  ##
1234
1256
  # Flatten OpenStudio 3D points vs Z-axis (Z=0).
1235
1257
  #
@@ -1243,8 +1265,8 @@ module OSut
1243
1265
  v = OpenStudio::Point3dVector.new
1244
1266
 
1245
1267
  valid = pts.is_a?(cl1) || pts.is_a?(Array)
1246
- return mismatch("points", pts, cl1, mth, DBG, v) unless valid
1247
- pts.each { |pt| mismatch("pt", pt, cl2, mth, ERR, v) unless pt.is_a?(cl2) }
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) }
1248
1270
  pts.each { |pt| v << OpenStudio::Point3d.new(pt.x, pt.y, 0) }
1249
1271
 
1250
1272
  v
@@ -1268,40 +1290,47 @@ module OSut
1268
1290
 
1269
1291
  return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
1270
1292
  return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
1293
+
1271
1294
  i1 = id1.to_s
1272
1295
  i2 = id2.to_s
1273
1296
  i1 = "poly1" if i1.empty?
1274
1297
  i2 = "poly2" if i2.empty?
1298
+
1275
1299
  valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
1276
1300
  valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
1301
+
1277
1302
  return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
1278
1303
  return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
1279
- return empty(i1, mth, ERR, a) if p1.empty?
1280
- return empty(i2, mth, ERR, a) if p2.empty?
1304
+ return empty(i1, mth, ERR, a) if p1.empty?
1305
+ return empty(i2, mth, ERR, a) if p2.empty?
1306
+
1281
1307
  p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1282
1308
  p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1283
1309
 
1284
- ft = OpenStudio::Transformation::alignFace(p1).inverse
1285
- ft_p1 = flatZ( (ft * p1).reverse )
1286
- return false if ft_p1.empty?
1287
- area1 = OpenStudio::getArea(ft_p1)
1288
- return empty("#{i1} area", mth, ERR, a) if area1.empty?
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?
1289
1323
  area1 = area1.get
1290
- ft_p2 = flatZ( (ft * p2).reverse )
1291
- return false if ft_p2.empty?
1292
- area2 = OpenStudio::getArea(ft_p2)
1293
- return empty("#{i2} area", mth, ERR, a) if area2.empty?
1294
1324
  area2 = area2.get
1295
- union = OpenStudio::join(ft_p1, ft_p2, TOL2)
1296
- return false if union.empty?
1325
+ union = OpenStudio.join(ft_p1, ft_p2, TOL2)
1326
+ return false if union.empty?
1297
1327
  union = union.get
1298
- area = OpenStudio::getArea(union)
1299
- return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1328
+ area = OpenStudio.getArea(union)
1329
+ return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1300
1330
  area = area.get
1301
-
1302
- return false if area < TOL
1303
- return true if (area - area2).abs < TOL
1304
- 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
1305
1334
 
1306
1335
  true
1307
1336
  end
@@ -1324,42 +1353,279 @@ module OSut
1324
1353
 
1325
1354
  return invalid("id1", mth, 3, DBG, a) unless id1.respond_to?(:to_s)
1326
1355
  return invalid("id2", mth, 4, DBG, a) unless id2.respond_to?(:to_s)
1356
+
1327
1357
  i1 = id1.to_s
1328
1358
  i2 = id2.to_s
1329
1359
  i1 = "poly1" if i1.empty?
1330
1360
  i2 = "poly2" if i2.empty?
1361
+
1331
1362
  valid1 = p1.is_a?(cl1) || p1.is_a?(Array)
1332
1363
  valid2 = p2.is_a?(cl1) || p2.is_a?(Array)
1364
+
1333
1365
  return mismatch(i1, p1, cl1, mth, DBG, a) unless valid1
1334
1366
  return mismatch(i2, p2, cl1, mth, DBG, a) unless valid2
1335
- return empty(i1, mth, ERR, a) if p1.empty?
1336
- return empty(i2, mth, ERR, a) if p2.empty?
1367
+ return empty(i1, mth, ERR, a) if p1.empty?
1368
+ return empty(i2, mth, ERR, a) if p2.empty?
1369
+
1337
1370
  p1.each { |v| return mismatch(i1, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1338
1371
  p2.each { |v| return mismatch(i2, v, cl2, mth, ERR, a) unless v.is_a?(cl2) }
1339
1372
 
1340
- ft = OpenStudio::Transformation::alignFace(p1).inverse
1341
- ft_p1 = flatZ( (ft * p1).reverse )
1342
- return false if ft_p1.empty?
1343
- area1 = OpenStudio::getArea(ft_p1)
1344
- return empty("#{i1} area", mth, ERR, a) if area1.empty?
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?
1345
1388
  area1 = area1.get
1346
- ft_p2 = flatZ( (ft * p2).reverse )
1347
- return false if ft_p2.empty?
1348
- area2 = OpenStudio::getArea(ft_p2)
1349
- return empty("#{i2} area", mth, ERR, a) if area2.empty?
1350
1389
  area2 = area2.get
1351
- union = OpenStudio::join(ft_p1, ft_p2, TOL2)
1352
- return false if union.empty?
1390
+ union = OpenStudio.join(ft_p1, ft_p2, TOL2)
1391
+ return false if union.empty?
1353
1392
  union = union.get
1354
- area = OpenStudio::getArea(union)
1355
- return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1393
+ area = OpenStudio.getArea(union)
1394
+ return empty("#{i1}:#{i2} union area", mth, ERR, a) if area.empty?
1356
1395
  area = area.get
1357
-
1358
- return false if area < TOL
1396
+ return false if area < TOL
1359
1397
 
1360
1398
  true
1361
1399
  end
1362
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
+
1363
1629
  ##
1364
1630
  # Callback when other modules extend OSlg
1365
1631
  #
data/lib/osut/version.rb CHANGED
@@ -29,5 +29,5 @@
29
29
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
31
  module OSut
32
- VERSION = "0.2.6".freeze
32
+ VERSION = "0.2.7".freeze
33
33
  end
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.6
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-15 00:00:00.000000000 Z
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.6
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: []