tbd 3.4.5 → 3.5.0
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 +6 -6
- data/lib/measures/tbd/resources/geo.rb +10 -9
- data/lib/measures/tbd/resources/geometry.rb +351 -351
- data/lib/measures/tbd/resources/model.rb +1425 -1425
- data/lib/measures/tbd/resources/psi.rb +108 -84
- data/lib/measures/tbd/resources/transformation.rb +120 -120
- data/lib/measures/tbd/resources/ua.rb +65 -65
- data/lib/measures/tbd/resources/utils.rb +532 -301
- data/lib/measures/tbd/resources/version.rb +3 -3
- data/lib/tbd/geo.rb +10 -9
- data/lib/tbd/psi.rb +108 -84
- data/lib/tbd/ua.rb +65 -65
- data/lib/tbd/version.rb +1 -1
- data/lib/tbd.rb +17 -11
- data/tbd.gemspec +1 -1
- metadata +9 -6
@@ -1355,103 +1355,103 @@ module TBD
|
|
1355
1355
|
##
|
1356
1356
|
# Thermally derates insulating material within construction.
|
1357
1357
|
#
|
1358
|
-
# @param id [#
|
1358
|
+
# @param id [#to_sym] surface identifier
|
1359
1359
|
# @param [Hash] s TBD surface parameters
|
1360
|
-
# @option s [
|
1361
|
-
# @option s [
|
1360
|
+
# @option s [Numeric] :heatloss heat loss from major thermal bridging, in W/K
|
1361
|
+
# @option s [Numeric] :net surface net area, in m2
|
1362
1362
|
# @option s [:massless, :standard] :ltype indexed layer type
|
1363
|
-
# @option s [
|
1364
|
-
# @option s [
|
1363
|
+
# @option s [Integer] :index deratable construction layer index
|
1364
|
+
# @option s [Numeric] :r deratable layer Rsi-factor, in m2•K/W
|
1365
1365
|
# @param lc [OpenStudio::Model::LayeredConstruction] a layered construction
|
1366
1366
|
#
|
1367
|
-
# @return [OpenStudio::Model::
|
1367
|
+
# @return [OpenStudio::Model::OpaqueMaterial] derated (cloned) material
|
1368
1368
|
# @return [nil] if invalid input (see logs)
|
1369
1369
|
def derate(id = "", s = {}, lc = nil)
|
1370
1370
|
mth = "TBD::#{__callee__}"
|
1371
1371
|
m = nil
|
1372
|
-
id = trim(id)
|
1373
1372
|
kys = [:heatloss, :net, :ltype, :index, :r]
|
1374
|
-
|
1375
|
-
|
1376
|
-
return mismatch("id"
|
1377
|
-
|
1378
|
-
|
1373
|
+
cl = OpenStudio::Model::LayeredConstruction
|
1374
|
+
return mismatch("lc", lc, cl, mth) unless lc.respond_to?(NS)
|
1375
|
+
return mismatch("id", id, String, mth) unless id.respond_to?(:to_sym)
|
1376
|
+
|
1377
|
+
id = trim(id)
|
1378
|
+
nom = lc.nameString
|
1379
|
+
return invalid("id", mth, 1) if id.empty?
|
1380
|
+
return mismatch(nom, lc, cl, mth) unless lc.is_a?(cl)
|
1381
|
+
return mismatch("#{nom} surface", s, Hash, mth) unless s.is_a?(Hash)
|
1382
|
+
|
1383
|
+
if nom.downcase.include?(" tbd")
|
1384
|
+
log(WRN, "Won't derate '#{nom}': tagged as derated (#{mth})")
|
1385
|
+
return m
|
1386
|
+
end
|
1379
1387
|
|
1380
1388
|
kys.each do |k|
|
1381
1389
|
tag = "#{id} #{k}"
|
1382
|
-
return hashkey(tag, s, k, mth
|
1390
|
+
return hashkey(tag, s, k, mth) unless s.key?(k)
|
1383
1391
|
|
1384
1392
|
case k
|
1385
|
-
when :
|
1386
|
-
return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_f)
|
1387
|
-
return zero(tag, mth, WRN) if s[k].to_f.abs < 0.001
|
1388
|
-
when :net, :r
|
1389
|
-
return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_f)
|
1390
|
-
return negative(tag, mth, 2, ERR) if s[k].to_f < 0
|
1391
|
-
return zero(tag, mth, WRN) if s[k].to_f.abs < 0.001
|
1392
|
-
when :index
|
1393
|
-
return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_i)
|
1394
|
-
return negative(tag, mth, 2, ERR) if s[k].to_f < 0
|
1395
|
-
else # :ltype
|
1393
|
+
when :ltype
|
1396
1394
|
next if [:massless, :standard].include?(s[k])
|
1397
|
-
return invalid(tag, mth, 2
|
1398
|
-
|
1399
|
-
|
1395
|
+
return invalid(tag, mth, 2)
|
1396
|
+
when :index
|
1397
|
+
return mismatch(tag, s[k], Integer, mth) unless s[k].is_a?(Integer)
|
1398
|
+
return invalid(tag, mth, 2) unless s[k].between?(0, lc.numLayers - 1)
|
1399
|
+
else
|
1400
|
+
return mismatch(tag, s[k], Numeric, mth) unless s[k].is_a?(Numeric)
|
1401
|
+
next if k == :heatloss
|
1400
1402
|
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1403
|
+
return negative(tag, mth, 2) if s[k] < 0
|
1404
|
+
return zero(tag, mth) if s[k].abs < 0.001
|
1405
|
+
end
|
1404
1406
|
end
|
1405
1407
|
|
1406
1408
|
model = lc.model
|
1407
|
-
ltype = s[:ltype
|
1408
|
-
index = s[:index
|
1409
|
-
net = s[:net
|
1410
|
-
r = s[:r
|
1411
|
-
u = s[:heatloss]
|
1409
|
+
ltype = s[:ltype]
|
1410
|
+
index = s[:index]
|
1411
|
+
net = s[:net]
|
1412
|
+
r = s[:r]
|
1413
|
+
u = s[:heatloss] / net
|
1412
1414
|
loss = 0
|
1413
|
-
de_u = 1 / r + u # derated U
|
1414
|
-
de_r = 1 / de_u # derated R
|
1415
|
+
de_u = 1 / r + u # derated insulating material U
|
1416
|
+
de_r = 1 / de_u # derated insulating material R
|
1415
1417
|
|
1416
1418
|
if ltype == :massless
|
1417
|
-
m
|
1419
|
+
m = lc.getLayer(index).to_MasslessOpaqueMaterial
|
1418
1420
|
return invalid("#{id} massless layer?", mth, 0) if m.empty?
|
1419
|
-
|
1420
|
-
|
1421
|
-
up
|
1422
|
-
m
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1421
|
+
|
1422
|
+
m = m.get
|
1423
|
+
up = m.nameString.downcase.include?(" uprated") ? "uprated " : ""
|
1424
|
+
m = m.clone(model).to_MasslessOpaqueMaterial.get
|
1425
|
+
m.setName("#{id} #{up}m tbd")
|
1426
|
+
|
1427
|
+
de_r = RMIN unless de_r > RMIN
|
1428
|
+
loss = (de_u - 1 / de_r) * net unless de_r > RMIN
|
1429
|
+
|
1430
|
+
unless m.setThermalResistance(de_r)
|
1431
|
+
return invalid("Can't derate #{id}: RSi#{de_r.round(2)}", mth)
|
1432
|
+
end
|
1427
1433
|
else
|
1428
|
-
m
|
1434
|
+
m = lc.getLayer(index).to_StandardOpaqueMaterial
|
1429
1435
|
return invalid("#{id} standard layer?", mth, 0) if m.empty?
|
1430
|
-
|
1431
|
-
|
1432
|
-
up
|
1433
|
-
m
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
loss = (de_u - k / d) * net unless k < 3
|
1445
|
-
end
|
1446
|
-
else # de_r < 0.001 m2•K/W
|
1447
|
-
d = 0.001 * k
|
1448
|
-
d = 0.003 unless d > 0.003
|
1449
|
-
k = d / 0.001 unless d > 0.003
|
1450
|
-
loss = (de_u - k / d) * net
|
1436
|
+
|
1437
|
+
m = m.get
|
1438
|
+
up = m.nameString.downcase.include?(" uprated") ? "uprated " : ""
|
1439
|
+
m = m.clone(model).to_StandardOpaqueMaterial.get
|
1440
|
+
m.setName("#{id} #{up}m tbd")
|
1441
|
+
|
1442
|
+
d = m.thickness
|
1443
|
+
k = (d / de_r).clamp(KMIN, KMAX)
|
1444
|
+
d = (k * de_r).clamp(DMIN, DMAX)
|
1445
|
+
|
1446
|
+
loss = (de_u - k / d) * net unless d / k > RMIN
|
1447
|
+
|
1448
|
+
unless m.setThermalConductivity(k)
|
1449
|
+
return invalid("Can't derate #{id}: K#{k.round(3)}", mth)
|
1451
1450
|
end
|
1452
1451
|
|
1453
|
-
m.setThickness(d)
|
1454
|
-
|
1452
|
+
unless m.setThickness(d)
|
1453
|
+
return invalid("Can't derate #{id}: #{(d*1000).to_i}mm", mth)
|
1454
|
+
end
|
1455
1455
|
end
|
1456
1456
|
|
1457
1457
|
if m && loss > TOL
|
@@ -1941,14 +1941,38 @@ module TBD
|
|
1941
1941
|
ids = windows.keys + doors.keys + skylights.keys
|
1942
1942
|
end
|
1943
1943
|
|
1944
|
-
|
1945
|
-
|
1944
|
+
adj = nil
|
1945
|
+
|
1946
|
+
unless ids.include?(i) # adjacent sub surface?
|
1947
|
+
sb = model.getSubSurfaceByName(i)
|
1948
|
+
|
1949
|
+
if sb.empty?
|
1950
|
+
log(DBG, "Orphaned subsurface #{i} (#{mth})?")
|
1951
|
+
else
|
1952
|
+
sb = sb.get
|
1953
|
+
adj = sb.adjacentSubSurface
|
1954
|
+
|
1955
|
+
if adj.empty?
|
1956
|
+
log(DBG, "Orphaned sub #{i} (#{mth})?")
|
1957
|
+
end
|
1958
|
+
end
|
1959
|
+
|
1946
1960
|
next
|
1947
1961
|
end
|
1948
1962
|
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1963
|
+
if adj
|
1964
|
+
window = windows.key?(i) ? windows[i] : {}
|
1965
|
+
door = doors.key?(i) ? doors[i] : {}
|
1966
|
+
skylight = skylights.key?(i) ? skylights[i] : {}
|
1967
|
+
else
|
1968
|
+
window = windows.key?(i) ? windows[i] : {}
|
1969
|
+
door = doors.key?(i) ? doors[i] : {}
|
1970
|
+
skylight = skylights.key?(i) ? skylights[i] : {}
|
1971
|
+
end
|
1972
|
+
|
1973
|
+
# window = windows.key?(i) ? windows[i] : {}
|
1974
|
+
# door = doors.key?(i) ? doors[i] : {}
|
1975
|
+
# skylight = skylights.key?(i) ? skylights[i] : {}
|
1952
1976
|
|
1953
1977
|
sub = window unless window.empty?
|
1954
1978
|
sub = door unless door.empty?
|
@@ -2939,12 +2963,12 @@ module TBD
|
|
2939
2963
|
up = argh[:uprate_walls] || argh[:uprate_roofs] || argh[:uprate_floors]
|
2940
2964
|
uprate(model, tbd[:surfaces], argh) if up
|
2941
2965
|
|
2942
|
-
#
|
2943
|
-
#
|
2944
|
-
# and suffixed with " tbd", indicating that
|
2945
|
-
# henceforth thermally derated. The " tbd" expression
|
2946
|
-
# avoiding inadvertent derating - TBD will not
|
2947
|
-
#
|
2966
|
+
# A derated (cloned) construction and (cloned) insulating layer are unique
|
2967
|
+
# to each deratable surface. Unique construction and material names are
|
2968
|
+
# prefixed with the surface name, and suffixed with " tbd", indicating that
|
2969
|
+
# the construction is henceforth thermally derated. The " tbd" expression
|
2970
|
+
# is also key in avoiding inadvertent sequential derating - TBD will not
|
2971
|
+
# derate a construction/material pair having " tbd" in their OpenStudio name.
|
2948
2972
|
tbd[:surfaces].each do |id, surface|
|
2949
2973
|
next unless surface.key?(:construction)
|
2950
2974
|
next unless surface.key?(:index)
|
@@ -3138,9 +3162,9 @@ module TBD
|
|
3138
3162
|
argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
|
3139
3163
|
argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
|
3140
3164
|
argh[:uprate_floors] = false unless argh.key?(:uprate_floors)
|
3141
|
-
argh[:wall_ut ] =
|
3142
|
-
argh[:roof_ut ] =
|
3143
|
-
argh[:floor_ut ] =
|
3165
|
+
argh[:wall_ut ] = UMAX unless argh.key?(:wall_ut )
|
3166
|
+
argh[:roof_ut ] = UMAX unless argh.key?(:roof_ut )
|
3167
|
+
argh[:floor_ut ] = UMAX unless argh.key?(:floor_ut )
|
3144
3168
|
argh[:wall_option ] = "" unless argh.key?(:wall_option )
|
3145
3169
|
argh[:roof_option ] = "" unless argh.key?(:roof_option )
|
3146
3170
|
argh[:floor_option ] = "" unless argh.key?(:floor_option )
|
@@ -1,121 +1,121 @@
|
|
1
|
-
require 'matrix'
|
2
|
-
|
3
|
-
class Matrix
|
4
|
-
def []=(i, j, x)
|
5
|
-
@rows[i][j] = x
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
module Topolys
|
10
|
-
|
11
|
-
# Transformations can be applied to Geometry. Ported from OpenStudio Transformation library.
|
12
|
-
|
13
|
-
class Transformation
|
14
|
-
|
15
|
-
# @return [Matrix] internal 4x4 matrix
|
16
|
-
attr_reader :matrix
|
17
|
-
|
18
|
-
##
|
19
|
-
# Initializes an Transformation object
|
20
|
-
#
|
21
|
-
# @param [Matrix] matrix A 4x4 matrix, defaults to identity
|
22
|
-
def initialize(matrix=Matrix.identity(4))
|
23
|
-
raise "Incorrect argument for Transformation, expected Matrix but got #{matrix.class}" unless matrix.is_a?(Matrix)
|
24
|
-
@matrix = matrix
|
25
|
-
end
|
26
|
-
|
27
|
-
# translation along vector
|
28
|
-
def Transformation.translation(translation)
|
29
|
-
return nil if !translation.is_a?(Vector3D)
|
30
|
-
|
31
|
-
matrix = Matrix.identity(4)
|
32
|
-
matrix[0,3] = translation.x
|
33
|
-
matrix[1,3] = translation.y
|
34
|
-
matrix[2,3] = translation.z
|
35
|
-
|
36
|
-
return Transformation.new(matrix)
|
37
|
-
end
|
38
|
-
|
39
|
-
##
|
40
|
-
# Initializes a rotation about origin defined by axis and angle (radians)
|
41
|
-
#
|
42
|
-
def Transformation.rotation(axis, radians)
|
43
|
-
return nil if !axis.is_a?(Vector3D)
|
44
|
-
return nil if !radians.is_a?(Numeric)
|
45
|
-
return nil if (axis.magnitude < Float::EPSILON)
|
46
|
-
normal = axis
|
47
|
-
normal.normalize!
|
48
|
-
|
49
|
-
# Rodrigues' rotation formula / Rotation matrix from Euler axis/angle
|
50
|
-
# I*cos(radians) + I*(1-cos(radians))*axis*axis^T + Q*sin(radians)
|
51
|
-
# Q = [0, -axis[2], axis[1]; axis[2], 0, -axis[0]; -axis[1], axis[0], 0]
|
52
|
-
p = normal.outer_product(normal)
|
53
|
-
i = Matrix.identity(3)
|
54
|
-
q = Matrix.zero(3)
|
55
|
-
q[0,1] = -normal.z
|
56
|
-
q[0,2] = normal.y
|
57
|
-
q[1,0] = normal.z
|
58
|
-
q[1,2] = -normal.x
|
59
|
-
q[2,0] = -normal.y
|
60
|
-
q[2,1] = normal.x
|
61
|
-
|
62
|
-
# rotation matrix
|
63
|
-
r = i*Math.cos(radians) + (1-Math.cos(radians))*p + q*Math.sin(radians)
|
64
|
-
|
65
|
-
matrix = Matrix.identity(4)
|
66
|
-
matrix[0,0] = r[0,0]
|
67
|
-
matrix[0,1] = r[0,1]
|
68
|
-
matrix[0,2] = r[0,2]
|
69
|
-
matrix[1,0] = r[1,0]
|
70
|
-
matrix[1,1] = r[1,1]
|
71
|
-
matrix[1,2] = r[1,2]
|
72
|
-
matrix[2,0] = r[2,0]
|
73
|
-
matrix[2,1] = r[2,1]
|
74
|
-
matrix[2,2] = r[2,2]
|
75
|
-
|
76
|
-
return Transformation.new(matrix)
|
77
|
-
end
|
78
|
-
|
79
|
-
##
|
80
|
-
# Multiplies a Transformation by geometry class
|
81
|
-
#
|
82
|
-
# @param [Obj] obj A geometry object
|
83
|
-
#
|
84
|
-
# @return [Obj] Returns a new, transformed object - nil if not a geometry object
|
85
|
-
def *(obj)
|
86
|
-
if obj.is_a?(Point3D)
|
87
|
-
return mult_point(obj)
|
88
|
-
elsif obj.is_a?(Vector3D)
|
89
|
-
return mult_vector(obj)
|
90
|
-
elsif obj.is_a?(Array)
|
91
|
-
return mult_array(obj)
|
92
|
-
elsif obj.is_a?(Transformation)
|
93
|
-
return mult_transformation(obj)
|
94
|
-
end
|
95
|
-
return nil
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def mult_point(point)
|
101
|
-
temp = Matrix.column_vector([point.x, point.y, point.z, 1])
|
102
|
-
temp = @matrix*temp
|
103
|
-
return Point3D.new(temp[0,0],temp[1,0],temp[2,0])
|
104
|
-
end
|
105
|
-
|
106
|
-
def mult_vector(vector)
|
107
|
-
temp = Matrix.column_vector([vector.x, vector.y, vector.z, 1])
|
108
|
-
temp = @matrix*temp
|
109
|
-
return Vector3D.new(temp[0,0],temp[1,0],temp[2,0])
|
110
|
-
end
|
111
|
-
|
112
|
-
def mult_array(array)
|
113
|
-
array.map {|obj| self*obj}
|
114
|
-
end
|
115
|
-
|
116
|
-
def mult_transformation(obj)
|
117
|
-
Transformation.new(@matrix * obj.matrix)
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
1
|
+
require 'matrix'
|
2
|
+
|
3
|
+
class Matrix
|
4
|
+
def []=(i, j, x)
|
5
|
+
@rows[i][j] = x
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Topolys
|
10
|
+
|
11
|
+
# Transformations can be applied to Geometry. Ported from OpenStudio Transformation library.
|
12
|
+
|
13
|
+
class Transformation
|
14
|
+
|
15
|
+
# @return [Matrix] internal 4x4 matrix
|
16
|
+
attr_reader :matrix
|
17
|
+
|
18
|
+
##
|
19
|
+
# Initializes an Transformation object
|
20
|
+
#
|
21
|
+
# @param [Matrix] matrix A 4x4 matrix, defaults to identity
|
22
|
+
def initialize(matrix=Matrix.identity(4))
|
23
|
+
raise "Incorrect argument for Transformation, expected Matrix but got #{matrix.class}" unless matrix.is_a?(Matrix)
|
24
|
+
@matrix = matrix
|
25
|
+
end
|
26
|
+
|
27
|
+
# translation along vector
|
28
|
+
def Transformation.translation(translation)
|
29
|
+
return nil if !translation.is_a?(Vector3D)
|
30
|
+
|
31
|
+
matrix = Matrix.identity(4)
|
32
|
+
matrix[0,3] = translation.x
|
33
|
+
matrix[1,3] = translation.y
|
34
|
+
matrix[2,3] = translation.z
|
35
|
+
|
36
|
+
return Transformation.new(matrix)
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Initializes a rotation about origin defined by axis and angle (radians)
|
41
|
+
#
|
42
|
+
def Transformation.rotation(axis, radians)
|
43
|
+
return nil if !axis.is_a?(Vector3D)
|
44
|
+
return nil if !radians.is_a?(Numeric)
|
45
|
+
return nil if (axis.magnitude < Float::EPSILON)
|
46
|
+
normal = axis
|
47
|
+
normal.normalize!
|
48
|
+
|
49
|
+
# Rodrigues' rotation formula / Rotation matrix from Euler axis/angle
|
50
|
+
# I*cos(radians) + I*(1-cos(radians))*axis*axis^T + Q*sin(radians)
|
51
|
+
# Q = [0, -axis[2], axis[1]; axis[2], 0, -axis[0]; -axis[1], axis[0], 0]
|
52
|
+
p = normal.outer_product(normal)
|
53
|
+
i = Matrix.identity(3)
|
54
|
+
q = Matrix.zero(3)
|
55
|
+
q[0,1] = -normal.z
|
56
|
+
q[0,2] = normal.y
|
57
|
+
q[1,0] = normal.z
|
58
|
+
q[1,2] = -normal.x
|
59
|
+
q[2,0] = -normal.y
|
60
|
+
q[2,1] = normal.x
|
61
|
+
|
62
|
+
# rotation matrix
|
63
|
+
r = i*Math.cos(radians) + (1-Math.cos(radians))*p + q*Math.sin(radians)
|
64
|
+
|
65
|
+
matrix = Matrix.identity(4)
|
66
|
+
matrix[0,0] = r[0,0]
|
67
|
+
matrix[0,1] = r[0,1]
|
68
|
+
matrix[0,2] = r[0,2]
|
69
|
+
matrix[1,0] = r[1,0]
|
70
|
+
matrix[1,1] = r[1,1]
|
71
|
+
matrix[1,2] = r[1,2]
|
72
|
+
matrix[2,0] = r[2,0]
|
73
|
+
matrix[2,1] = r[2,1]
|
74
|
+
matrix[2,2] = r[2,2]
|
75
|
+
|
76
|
+
return Transformation.new(matrix)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Multiplies a Transformation by geometry class
|
81
|
+
#
|
82
|
+
# @param [Obj] obj A geometry object
|
83
|
+
#
|
84
|
+
# @return [Obj] Returns a new, transformed object - nil if not a geometry object
|
85
|
+
def *(obj)
|
86
|
+
if obj.is_a?(Point3D)
|
87
|
+
return mult_point(obj)
|
88
|
+
elsif obj.is_a?(Vector3D)
|
89
|
+
return mult_vector(obj)
|
90
|
+
elsif obj.is_a?(Array)
|
91
|
+
return mult_array(obj)
|
92
|
+
elsif obj.is_a?(Transformation)
|
93
|
+
return mult_transformation(obj)
|
94
|
+
end
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def mult_point(point)
|
101
|
+
temp = Matrix.column_vector([point.x, point.y, point.z, 1])
|
102
|
+
temp = @matrix*temp
|
103
|
+
return Point3D.new(temp[0,0],temp[1,0],temp[2,0])
|
104
|
+
end
|
105
|
+
|
106
|
+
def mult_vector(vector)
|
107
|
+
temp = Matrix.column_vector([vector.x, vector.y, vector.z, 1])
|
108
|
+
temp = @matrix*temp
|
109
|
+
return Vector3D.new(temp[0,0],temp[1,0],temp[2,0])
|
110
|
+
end
|
111
|
+
|
112
|
+
def mult_array(array)
|
113
|
+
array.map {|obj| self*obj}
|
114
|
+
end
|
115
|
+
|
116
|
+
def mult_transformation(obj)
|
117
|
+
Transformation.new(@matrix * obj.matrix)
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
121
|
end
|