openstudio-common-measures 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/Rakefile +3 -0
- data/lib/measures/ChangeBuildingLocation/measure.xml +11 -11
- data/lib/measures/ExportScheduleCSV/measure.rb +1 -1
- data/lib/measures/ExportScheduleCSV/measure.xml +16 -15
- data/lib/measures/ImportEnvelopeAndInternalLoadsFromIdf/measure.xml +7 -6
- data/lib/measures/MeterFlodPlot/measure.rb +1 -1
- data/lib/measures/MeterFlodPlot/measure.xml +16 -15
- data/lib/measures/ReportModelChanges/measure.xml +2 -2
- data/lib/measures/RunPeriodMultiple/measure.xml +12 -11
- data/lib/measures/ServerDirectoryCleanup/README.md +97 -3
- data/lib/measures/ServerDirectoryCleanup/measure.rb +1 -1
- data/lib/measures/ServerDirectoryCleanup/measure.xml +10 -59
- data/lib/measures/UnmetLoadHoursTroubleshooting/README.md +9 -3
- data/lib/measures/UnmetLoadHoursTroubleshooting/measure.rb +1 -1
- data/lib/measures/UnmetLoadHoursTroubleshooting/measure.xml +66 -17
- data/lib/measures/VentilationQAQC/README.md +9 -3
- data/lib/measures/VentilationQAQC/measure.rb +52 -45
- data/lib/measures/VentilationQAQC/measure.xml +25 -30
- data/lib/measures/ZoneReport/README.md +2 -2
- data/lib/measures/ZoneReport/measure.rb +1 -1
- data/lib/measures/ZoneReport/measure.xml +10 -11
- data/lib/measures/add_ems_to_control_ev_charging/LICENSE.MD.txt +15 -0
- data/lib/measures/{AddDaylightSensors → add_ems_to_control_ev_charging}/LICENSE.md +0 -0
- data/lib/measures/add_ems_to_control_ev_charging/ReadMe.MD +29 -0
- data/lib/measures/add_ems_to_control_ev_charging/measure.rb +288 -0
- data/lib/measures/add_ems_to_control_ev_charging/measure.xml +87 -0
- data/lib/measures/add_ev_load/LICENSE.MD.txt +15 -0
- data/lib/measures/{EnableDemandControlledVentilation → add_ev_load}/LICENSE.md +0 -0
- data/lib/measures/add_ev_load/ReadMe.MD +34 -0
- data/lib/measures/add_ev_load/measure.rb +328 -0
- data/lib/measures/add_ev_load/measure.xml +153 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/PSN_BuildingKey.csv +104 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/PSN_BuildingKey_v2.csv +104 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow1_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow1_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow1_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow2_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow2_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow2_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow3_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow3_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg1_dow3_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow1_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow1_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow1_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow2_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow2_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow2_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow3_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow3_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg2_dow3_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow1_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow1_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow1_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow2_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow2_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow2_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow3_flex1.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow3_flex2.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/chg3_dow3_flex3.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/fast_charge_15min_Saturday.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/fast_charge_15min_Sunday.csv +96 -0
- data/lib/measures/add_ev_load/resources/EV_Load_Profiles/fast_charge_15min_Weekday.csv +96 -0
- data/lib/measures/envelope_and_internal_load_breakdown/README.md +4 -3
- data/lib/measures/envelope_and_internal_load_breakdown/measure.rb +7 -4
- data/lib/measures/envelope_and_internal_load_breakdown/measure.xml +16 -17
- data/lib/measures/envelope_and_internal_load_breakdown/resources/report.html.erb +1 -0
- data/lib/measures/example_report/README.md +27 -5
- data/lib/measures/example_report/measure.rb +7 -4
- data/lib/measures/example_report/measure.xml +16 -29
- data/lib/measures/example_report/resources/report.html.erb +1 -0
- data/lib/measures/gem_env_report/measure.xml +1 -1
- data/lib/measures/generic_qaqc/README.md +187 -5
- data/lib/measures/generic_qaqc/measure.rb +1 -1
- data/lib/measures/generic_qaqc/measure.xml +15 -85
- data/lib/measures/generic_qaqc/resources/report.html.erb +1 -0
- data/lib/measures/hvac_psychrometric_chart/README.md +11 -5
- data/lib/measures/hvac_psychrometric_chart/measure.rb +1 -1
- data/lib/measures/hvac_psychrometric_chart/measure.xml +13 -18
- data/lib/measures/hvac_psychrometric_chart/resources/report.html.erb +1 -0
- data/lib/measures/inject_idf_objects/measure.xml +25 -24
- data/lib/measures/openstudio_results/README.md +195 -5
- data/lib/measures/openstudio_results/measure.rb +2 -2
- data/lib/measures/openstudio_results/measure.xml +30 -154
- data/lib/measures/openstudio_results/resources/report.html.erb +1 -0
- data/lib/measures/set_run_period/measure.xml +2 -2
- data/lib/measures/{EnableEconomizerControl → view_data}/LICENSE.md +0 -0
- data/lib/measures/view_data/README.md +64 -0
- data/lib/measures/{AddDaylightSensors → view_data}/README.md.erb +0 -0
- data/lib/measures/view_data/measure.rb +454 -0
- data/lib/measures/view_data/measure.xml +159 -0
- data/lib/measures/view_data/resources/report.html.in +2881 -0
- data/lib/measures/view_data/resources/va3c.rb +1021 -0
- data/lib/measures/{ImproveFanBeltEfficiency → view_model}/LICENSE.md +0 -0
- data/lib/measures/view_model/README.md +26 -0
- data/lib/measures/{EnableDemandControlledVentilation → view_model}/README.md.erb +0 -0
- data/lib/measures/view_model/measure.rb +146 -0
- data/lib/measures/view_model/measure.xml +98 -0
- data/lib/measures/view_model/resources/report.html.in +2881 -0
- data/lib/measures/view_model/resources/va3c.rb +1021 -0
- data/lib/openstudio/common_measures/version.rb +1 -1
- data/openstudio-common-measures.gemspec +1 -1
- metadata +61 -71
- data/lib/measures/AddDaylightSensors/README.md +0 -136
- data/lib/measures/AddDaylightSensors/measure.rb +0 -521
- data/lib/measures/AddDaylightSensors/measure.xml +0 -233
- data/lib/measures/EnableDemandControlledVentilation/README.md +0 -32
- data/lib/measures/EnableDemandControlledVentilation/measure.rb +0 -154
- data/lib/measures/EnableDemandControlledVentilation/measure.xml +0 -99
- data/lib/measures/EnableEconomizerControl/README.md +0 -48
- data/lib/measures/EnableEconomizerControl/README.md.erb +0 -42
- data/lib/measures/EnableEconomizerControl/measure.rb +0 -172
- data/lib/measures/EnableEconomizerControl/measure.xml +0 -124
- data/lib/measures/ImproveFanBeltEfficiency/README.md +0 -104
- data/lib/measures/ImproveFanBeltEfficiency/README.md.erb +0 -42
- data/lib/measures/ImproveFanBeltEfficiency/measure.rb +0 -366
- data/lib/measures/ImproveFanBeltEfficiency/measure.xml +0 -185
- data/lib/measures/ImproveMotorEfficiency/LICENSE.md +0 -27
- data/lib/measures/ImproveMotorEfficiency/README.md +0 -104
- data/lib/measures/ImproveMotorEfficiency/README.md.erb +0 -42
- data/lib/measures/ImproveMotorEfficiency/measure.rb +0 -365
- data/lib/measures/ImproveMotorEfficiency/measure.xml +0 -182
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/LICENSE.md +0 -27
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/README.md +0 -64
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/README.md.erb +0 -42
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.rb +0 -422
- data/lib/measures/IncreaseInsulationRValueForExteriorWalls/measure.xml +0 -150
- data/lib/measures/IncreaseInsulationRValueForRoofs/LICENSE.md +0 -27
- data/lib/measures/IncreaseInsulationRValueForRoofs/README.md +0 -64
- data/lib/measures/IncreaseInsulationRValueForRoofs/README.md.erb +0 -42
- data/lib/measures/IncreaseInsulationRValueForRoofs/measure.rb +0 -422
- data/lib/measures/IncreaseInsulationRValueForRoofs/measure.xml +0 -143
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/LICENSE.md +0 -27
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/README.md +0 -97
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/README.md.erb +0 -42
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.rb +0 -450
- data/lib/measures/ReduceElectricEquipmentLoadsByPercentage/measure.xml +0 -186
- data/lib/measures/ReduceLightingLoadsByPercentage/LICENSE.md +0 -27
- data/lib/measures/ReduceLightingLoadsByPercentage/README.md +0 -96
- data/lib/measures/ReduceLightingLoadsByPercentage/README.md.erb +0 -42
- data/lib/measures/ReduceLightingLoadsByPercentage/measure.rb +0 -513
- data/lib/measures/ReduceLightingLoadsByPercentage/measure.xml +0 -191
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/LICENSE.md +0 -27
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/README.md +0 -104
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/README.md.erb +0 -42
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.rb +0 -349
- data/lib/measures/ReduceSpaceInfiltrationByPercentage/measure.xml +0 -181
- data/lib/measures/ReduceVentilationByPercentage/LICENSE.md +0 -27
- data/lib/measures/ReduceVentilationByPercentage/README.md +0 -40
- data/lib/measures/ReduceVentilationByPercentage/README.md.erb +0 -42
- data/lib/measures/ReduceVentilationByPercentage/measure.rb +0 -291
- data/lib/measures/ReduceVentilationByPercentage/measure.xml +0 -96
- data/lib/measures/VentilationQAQC/ExampleModel.osm +0 -28468
- data/lib/measures/create_variable_speed_rtu/LICENSE.md +0 -27
- data/lib/measures/create_variable_speed_rtu/README.md +0 -120
- data/lib/measures/create_variable_speed_rtu/README.md.erb +0 -42
- data/lib/measures/create_variable_speed_rtu/measure.rb +0 -539
- data/lib/measures/create_variable_speed_rtu/measure.xml +0 -207
- data/lib/measures/radiant_slab_with_doas/LICENSE.md +0 -27
- data/lib/measures/radiant_slab_with_doas/README.md +0 -156
- data/lib/measures/radiant_slab_with_doas/README.md.erb +0 -42
- data/lib/measures/radiant_slab_with_doas/measure.rb +0 -403
- data/lib/measures/radiant_slab_with_doas/measure.xml +0 -345
@@ -0,0 +1,1021 @@
|
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
24
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
27
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
28
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
30
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
33
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
36
|
+
require 'openstudio'
|
37
|
+
|
38
|
+
if /^1\.8/.match(RUBY_VERSION)
|
39
|
+
class Struct
|
40
|
+
def to_h
|
41
|
+
h = {}
|
42
|
+
self.class.members.each { |m| h[m.to_sym] = self[m] }
|
43
|
+
return h
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module THREE
|
49
|
+
FrontSide = 0
|
50
|
+
BackSide = 1
|
51
|
+
DoubleSide = 2
|
52
|
+
end
|
53
|
+
|
54
|
+
# Va3c class converts an OpenStudio model to vA3C JSON format for rendering in Three.js
|
55
|
+
# using export at http://va3c.github.io/projects/#./osm-data-viewer/latest/index.html# as a guide
|
56
|
+
# many thanks to Theo Armour and the vA3C team for figuring out many of the details here
|
57
|
+
class VA3C
|
58
|
+
Scene = Struct.new(:geometries, :materials, :object)
|
59
|
+
|
60
|
+
Geometry = Struct.new(:uuid, :type, :data)
|
61
|
+
GeometryData = Struct.new(:vertices, :normals, :uvs, :faces, :scale, :visible, :castShadow, :receiveShadow, :doubleSided)
|
62
|
+
|
63
|
+
Material = Struct.new(:uuid, :type, :color, :ambient, :emissive, :specular, :shininess, :side, :opacity, :transparent, :wireframe)
|
64
|
+
|
65
|
+
SceneObject = Struct.new(:uuid, :type, :matrix, :children)
|
66
|
+
SceneChild = Struct.new(:uuid, :name, :type, :geometry, :material, :matrix, :userData)
|
67
|
+
UserData = Struct.new(:handle, :name, :surfaceType, :constructionName, :spaceName, :thermalZoneName, :spaceTypeName, :buildingStoryName,
|
68
|
+
:outsideBoundaryCondition, :outsideBoundaryConditionObjectName,
|
69
|
+
:outsideBoundaryConditionObjectHandle, :coincidentWithOutsideObject,
|
70
|
+
:sunExposure, :windExposure, #:vertices,
|
71
|
+
:surfaceTypeMaterialName, :boundaryMaterialName, :constructionMaterialName, :thermalZoneMaterialName,
|
72
|
+
:spaceTypeMaterialName, :buildingStoryMaterialName) do
|
73
|
+
def initialize(*)
|
74
|
+
super
|
75
|
+
self.surfaceTypeMaterialName = 'Undefined' if surfaceTypeMaterialName.nil?
|
76
|
+
self.boundaryMaterialName = 'Undefined' if boundaryMaterialName.nil?
|
77
|
+
self.constructionMaterialName = 'Undefined' if constructionMaterialName.nil?
|
78
|
+
self.thermalZoneMaterialName = 'Undefined' if thermalZoneMaterialName.nil?
|
79
|
+
self.spaceTypeMaterialName = 'Undefined' if spaceTypeMaterialName.nil?
|
80
|
+
self.buildingStoryMaterialName = 'Undefined' if buildingStoryMaterialName.nil?
|
81
|
+
|
82
|
+
self.constructionName = '' if constructionName.nil?
|
83
|
+
self.spaceName = '' if spaceName.nil?
|
84
|
+
self.thermalZoneName = '' if thermalZoneName.nil?
|
85
|
+
self.spaceTypeName = '' if spaceTypeName.nil?
|
86
|
+
self.buildingStoryName = '' if buildingStoryName.nil?
|
87
|
+
self.outsideBoundaryCondition = '' if outsideBoundaryCondition.nil?
|
88
|
+
self.outsideBoundaryConditionObjectName = '' if outsideBoundaryConditionObjectName.nil?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
Vertex = Struct.new(:x, :y, :z)
|
92
|
+
|
93
|
+
AmbientLight = Struct.new(:uuid, :type, :color, :matrix)
|
94
|
+
|
95
|
+
def self.convert_model(model)
|
96
|
+
scene = build_scene(model)
|
97
|
+
|
98
|
+
northAxis = -model.getBuilding.northAxis
|
99
|
+
|
100
|
+
boundingBox = OpenStudio::BoundingBox.new
|
101
|
+
boundingBox.addPoint(OpenStudio::Point3d.new(0, 0, 0))
|
102
|
+
boundingBox.addPoint(OpenStudio::Point3d.new(1, 1, 1))
|
103
|
+
model.getPlanarSurfaceGroups.each do |group|
|
104
|
+
boundingBox.add(group.transformation * group.boundingBox)
|
105
|
+
end
|
106
|
+
|
107
|
+
lookAtX = 0 # (boundingBox.minX.get + boundingBox.maxX.get) / 2.0
|
108
|
+
lookAtY = 0 # (boundingBox.minY.get + boundingBox.maxY.get) / 2.0
|
109
|
+
lookAtZ = 0 # (boundingBox.minZ.get + boundingBox.maxZ.get) / 2.0
|
110
|
+
lookAtR = [Math.sqrt((boundingBox.maxX.get / 2.0)**2 + (boundingBox.maxY.get / 2.0)**2 + (boundingBox.maxZ.get / 2.0)**2),
|
111
|
+
Math.sqrt((boundingBox.minX.get / 2.0)**2 + (boundingBox.maxY.get / 2.0)**2 + (boundingBox.maxZ.get / 2.0)**2),
|
112
|
+
Math.sqrt((boundingBox.maxX.get / 2.0)**2 + (boundingBox.minY.get / 2.0)**2 + (boundingBox.maxZ.get / 2.0)**2),
|
113
|
+
Math.sqrt((boundingBox.maxX.get / 2.0)**2 + (boundingBox.maxY.get / 2.0)**2 + (boundingBox.minZ.get / 2.0)**2),
|
114
|
+
Math.sqrt((boundingBox.minX.get / 2.0)**2 + (boundingBox.minY.get / 2.0)**2 + (boundingBox.maxZ.get / 2.0)**2),
|
115
|
+
Math.sqrt((boundingBox.minX.get / 2.0)**2 + (boundingBox.maxY.get / 2.0)**2 + (boundingBox.minZ.get / 2.0)**2),
|
116
|
+
Math.sqrt((boundingBox.maxX.get / 2.0)**2 + (boundingBox.minY.get / 2.0)**2 + (boundingBox.minZ.get / 2.0)**2),
|
117
|
+
Math.sqrt((boundingBox.minX.get / 2.0)**2 + (boundingBox.minY.get / 2.0)**2 + (boundingBox.minZ.get / 2.0)**2)].max
|
118
|
+
|
119
|
+
boundingBoxHash = { 'minX' => boundingBox.minX.get, 'minY' => boundingBox.minY.get, 'minZ' => boundingBox.minZ.get,
|
120
|
+
'maxX' => boundingBox.maxX.get, 'maxY' => boundingBox.maxY.get, 'maxZ' => boundingBox.maxZ.get,
|
121
|
+
'lookAtX' => lookAtX, 'lookAtY' => lookAtY, 'lookAtZ' => lookAtZ, 'lookAtR' => lookAtR }
|
122
|
+
|
123
|
+
buildingStoryNames = []
|
124
|
+
model.getBuildingStorys.each do |buildingStory|
|
125
|
+
buildingStoryNames << buildingStory.name.to_s
|
126
|
+
end
|
127
|
+
buildingStoryNames.sort! { |x, y| x.upcase <=> y.upcase } # case insensitive sort
|
128
|
+
|
129
|
+
# build up the json hash
|
130
|
+
result = {}
|
131
|
+
result['metadata'] = { 'version' => 4.3, 'type' => 'Object', 'generator' => 'OpenStudio',
|
132
|
+
'buildingStoryNames' => buildingStoryNames, 'boundingBox' => boundingBoxHash,
|
133
|
+
'northAxis' => northAxis }
|
134
|
+
result['geometries'] = scene.geometries
|
135
|
+
result['materials'] = scene.materials
|
136
|
+
result['object'] = scene.object
|
137
|
+
|
138
|
+
return result
|
139
|
+
end
|
140
|
+
|
141
|
+
# format a uuid
|
142
|
+
def self.format_uuid(uuid)
|
143
|
+
return uuid.to_s.gsub('{', '').gsub('}', '')
|
144
|
+
end
|
145
|
+
|
146
|
+
# format color
|
147
|
+
def self.format_color(r, g, b)
|
148
|
+
return "0x#{r.to_s(16).rjust(2, '0')}#{g.to_s(16).rjust(2, '0')}#{b.to_s(16).rjust(2, '0')}"
|
149
|
+
end
|
150
|
+
|
151
|
+
# create a material
|
152
|
+
def self.make_material(name, color, opacity, side, shininess = 50)
|
153
|
+
transparent = false
|
154
|
+
if opacity < 1
|
155
|
+
transparent = true
|
156
|
+
end
|
157
|
+
|
158
|
+
material = { uuid: format_uuid(OpenStudio.createUUID).to_s,
|
159
|
+
name: name,
|
160
|
+
type: 'MeshPhongMaterial',
|
161
|
+
color: color.to_s.hex,
|
162
|
+
ambient: color.to_s.hex,
|
163
|
+
emissive: '0x000000'.hex,
|
164
|
+
specular: color.to_s.hex,
|
165
|
+
shininess: shininess,
|
166
|
+
opacity: opacity,
|
167
|
+
transparent: transparent,
|
168
|
+
wireframe: false,
|
169
|
+
side: side }
|
170
|
+
return material
|
171
|
+
end
|
172
|
+
|
173
|
+
# create the standard materials
|
174
|
+
def self.build_materials(model)
|
175
|
+
materials = []
|
176
|
+
|
177
|
+
# materials << make_material('Undefined', format_color(255, 255, 255), 1, THREE::DoubleSide)
|
178
|
+
materials << { uuid: format_uuid(OpenStudio.createUUID).to_s, name: 'Undefined', type: 'MeshBasicMaterial', color: '0xffffff'.hex, side: THREE::DoubleSide }
|
179
|
+
|
180
|
+
materials << make_material('NormalMaterial', format_color(255, 255, 255), 1, THREE::DoubleSide)
|
181
|
+
# materials << make_material('NormalMaterial_Ext', format_color(255, 255, 255), 1, THREE::FrontSide)
|
182
|
+
materials << { uuid: format_uuid(OpenStudio.createUUID).to_s, name: 'NormalMaterial_Ext', type: 'MeshBasicMaterial', color: '0xffffff'.hex, side: THREE::FrontSide }
|
183
|
+
materials << make_material('NormalMaterial_Int', format_color(255, 0, 0), 1, THREE::BackSide)
|
184
|
+
|
185
|
+
# materials from 'openstudio\openstudiocore\ruby\openstudio\sketchup_plugin\lib\interfaces\MaterialsInterface.rb'
|
186
|
+
materials << make_material('Floor', format_color(128, 128, 128), 1, THREE::DoubleSide)
|
187
|
+
materials << make_material('Floor_Ext', format_color(128, 128, 128), 1, THREE::FrontSide)
|
188
|
+
materials << make_material('Floor_Int', format_color(191, 191, 191), 1, THREE::BackSide)
|
189
|
+
|
190
|
+
materials << make_material('Wall', format_color(204, 178, 102), 1, THREE::DoubleSide)
|
191
|
+
materials << make_material('Wall_Ext', format_color(204, 178, 102), 1, THREE::FrontSide)
|
192
|
+
materials << make_material('Wall_Int', format_color(235, 226, 197), 1, THREE::BackSide)
|
193
|
+
|
194
|
+
materials << make_material('RoofCeiling', format_color(153, 76, 76), 1, THREE::DoubleSide)
|
195
|
+
materials << make_material('RoofCeiling_Ext', format_color(153, 76, 76), 1, THREE::FrontSide)
|
196
|
+
materials << make_material('RoofCeiling_Int', format_color(202, 149, 149), 1, THREE::BackSide)
|
197
|
+
|
198
|
+
materials << make_material('Window', format_color(102, 178, 204), 0.6, THREE::DoubleSide)
|
199
|
+
materials << make_material('Window_Ext', format_color(102, 178, 204), 0.6, THREE::FrontSide)
|
200
|
+
materials << make_material('Window_Int', format_color(192, 226, 235), 0.6, THREE::BackSide)
|
201
|
+
|
202
|
+
materials << make_material('Door', format_color(153, 133, 76), 1, THREE::DoubleSide)
|
203
|
+
materials << make_material('Door_Ext', format_color(153, 133, 76), 1, THREE::FrontSide)
|
204
|
+
materials << make_material('Door_Int', format_color(202, 188, 149), 1, THREE::BackSide)
|
205
|
+
|
206
|
+
materials << make_material('SiteShading', format_color(75, 124, 149), 1, THREE::DoubleSide)
|
207
|
+
materials << make_material('SiteShading_Ext', format_color(75, 124, 149), 1, THREE::FrontSide)
|
208
|
+
materials << make_material('SiteShading_Int', format_color(187, 209, 220), 1, THREE::BackSide)
|
209
|
+
|
210
|
+
materials << make_material('BuildingShading', format_color(113, 76, 153), 1, THREE::DoubleSide)
|
211
|
+
materials << make_material('BuildingShading_Ext', format_color(113, 76, 153), 1, THREE::FrontSide)
|
212
|
+
materials << make_material('BuildingShading_Int', format_color(216, 203, 229), 1, THREE::BackSide)
|
213
|
+
|
214
|
+
materials << make_material('SpaceShading', format_color(76, 110, 178), 1, THREE::DoubleSide)
|
215
|
+
materials << make_material('SpaceShading_Ext', format_color(76, 110, 178), 1, THREE::FrontSide)
|
216
|
+
materials << make_material('SpaceShading_Int', format_color(183, 197, 224), 1, THREE::BackSide)
|
217
|
+
|
218
|
+
materials << make_material('InteriorPartitionSurface', format_color(158, 188, 143), 1, THREE::DoubleSide)
|
219
|
+
materials << make_material('InteriorPartitionSurface_Ext', format_color(158, 188, 143), 1, THREE::FrontSide)
|
220
|
+
materials << make_material('InteriorPartitionSurface_Int', format_color(213, 226, 207), 1, THREE::BackSide)
|
221
|
+
|
222
|
+
# start textures for boundary conditions
|
223
|
+
materials << make_material('Boundary_Surface', format_color(0, 153, 0), 1, THREE::DoubleSide)
|
224
|
+
materials << make_material('Boundary_Adiabatic', format_color(255, 101, 178), 1, THREE::DoubleSide)
|
225
|
+
materials << make_material('Boundary_Space', format_color(255, 0, 0), 1, THREE::DoubleSide)
|
226
|
+
materials << make_material('Boundary_Outdoors', format_color(163, 204, 204), 1, THREE::DoubleSide)
|
227
|
+
materials << make_material('Boundary_Outdoors_Sun', format_color(40, 204, 204), 1, THREE::DoubleSide)
|
228
|
+
materials << make_material('Boundary_Outdoors_Wind', format_color(9, 159, 162), 1, THREE::DoubleSide)
|
229
|
+
materials << make_material('Boundary_Outdoors_SunWind', format_color(68, 119, 161), 1, THREE::DoubleSide)
|
230
|
+
materials << make_material('Boundary_Ground', format_color(204, 183, 122), 1, THREE::DoubleSide)
|
231
|
+
materials << make_material('Boundary_Groundfcfactormethod', format_color(153, 122, 30), 1, THREE::DoubleSide)
|
232
|
+
materials << make_material('Boundary_Groundslabpreprocessoraverage', format_color(255, 191, 0), 1, THREE::DoubleSide)
|
233
|
+
materials << make_material('Boundary_Groundslabpreprocessorcore', format_color(255, 182, 50), 1, THREE::DoubleSide)
|
234
|
+
materials << make_material('Boundary_Groundslabpreprocessorperimeter', format_color(255, 178, 101), 1, THREE::DoubleSide)
|
235
|
+
materials << make_material('Boundary_Groundbasementpreprocessoraveragewall', format_color(204, 51, 0), 1, THREE::DoubleSide)
|
236
|
+
materials << make_material('Boundary_Groundbasementpreprocessoraveragefloor', format_color(204, 81, 40), 1, THREE::DoubleSide)
|
237
|
+
materials << make_material('Boundary_Groundbasementpreprocessorupperwall', format_color(204, 112, 81), 1, THREE::DoubleSide)
|
238
|
+
materials << make_material('Boundary_Groundbasementpreprocessorlowerwall', format_color(204, 173, 163), 1, THREE::DoubleSide)
|
239
|
+
materials << make_material('Boundary_Othersidecoefficients', format_color(63, 63, 63), 1, THREE::DoubleSide)
|
240
|
+
materials << make_material('Boundary_Othersideconditionsmodel', format_color(153, 0, 76), 1, THREE::DoubleSide)
|
241
|
+
|
242
|
+
# make construction materials
|
243
|
+
model.getConstructionBases.each do |construction|
|
244
|
+
color = construction.renderingColor
|
245
|
+
if color.empty?
|
246
|
+
color = OpenStudio::Model::RenderingColor.new(model)
|
247
|
+
construction.setRenderingColor(color)
|
248
|
+
else
|
249
|
+
color = color.get
|
250
|
+
end
|
251
|
+
name = "Construction_#{construction.name}"
|
252
|
+
materials << make_material(name, format_color(color.renderingRedValue, color.renderingGreenValue, color.renderingBlueValue), color.renderingAlphaValue / 255.to_f, THREE::DoubleSide)
|
253
|
+
end
|
254
|
+
|
255
|
+
# make thermal zone materials
|
256
|
+
model.getThermalZones.each do |zone|
|
257
|
+
color = zone.renderingColor
|
258
|
+
if color.empty?
|
259
|
+
color = OpenStudio::Model::RenderingColor.new(model)
|
260
|
+
zone.setRenderingColor(color)
|
261
|
+
else
|
262
|
+
color = color.get
|
263
|
+
end
|
264
|
+
name = "ThermalZone_#{zone.name}"
|
265
|
+
materials << make_material(name, format_color(color.renderingRedValue, color.renderingGreenValue, color.renderingBlueValue), color.renderingAlphaValue / 255.to_f, THREE::DoubleSide)
|
266
|
+
end
|
267
|
+
|
268
|
+
# make space type materials
|
269
|
+
model.getSpaceTypes.each do |spaceType|
|
270
|
+
color = spaceType.renderingColor
|
271
|
+
if color.empty?
|
272
|
+
color = OpenStudio::Model::RenderingColor.new(model)
|
273
|
+
spaceType.setRenderingColor(color)
|
274
|
+
else
|
275
|
+
color = color.get
|
276
|
+
end
|
277
|
+
name = "SpaceType_#{spaceType.name}"
|
278
|
+
materials << make_material(name, format_color(color.renderingRedValue, color.renderingGreenValue, color.renderingBlueValue), color.renderingAlphaValue / 255.to_f, THREE::DoubleSide)
|
279
|
+
end
|
280
|
+
|
281
|
+
# make building story materials
|
282
|
+
model.getBuildingStorys.each do |buildingStory|
|
283
|
+
color = buildingStory.renderingColor
|
284
|
+
if color.empty?
|
285
|
+
color = OpenStudio::Model::RenderingColor.new(model)
|
286
|
+
buildingStory.setRenderingColor(color)
|
287
|
+
else
|
288
|
+
color = color.get
|
289
|
+
end
|
290
|
+
name = "BuildingStory_#{buildingStory.name}"
|
291
|
+
materials << make_material(name, format_color(color.renderingRedValue, color.renderingGreenValue, color.renderingBlueValue), color.renderingAlphaValue / 255.to_f, THREE::DoubleSide)
|
292
|
+
end
|
293
|
+
|
294
|
+
return materials
|
295
|
+
end
|
296
|
+
|
297
|
+
# get the index of a vertex out of a list
|
298
|
+
def self.get_vertex_index(vertex, vertices, tol = 0.001)
|
299
|
+
vertices.each_index do |i|
|
300
|
+
if OpenStudio.getDistance(vertex, vertices[i]) < tol
|
301
|
+
return i
|
302
|
+
end
|
303
|
+
end
|
304
|
+
vertices << vertex
|
305
|
+
return (vertices.length - 1)
|
306
|
+
end
|
307
|
+
|
308
|
+
# flatten array of vertices into a single array
|
309
|
+
def self.flatten_vertices(vertices)
|
310
|
+
result = []
|
311
|
+
vertices.each do |vertex|
|
312
|
+
# result << vertex.x
|
313
|
+
# result << vertex.y
|
314
|
+
# result << vertex.z
|
315
|
+
|
316
|
+
result << vertex.x.round(3)
|
317
|
+
result << vertex.z.round(3)
|
318
|
+
result << -vertex.y.round(3)
|
319
|
+
end
|
320
|
+
return result
|
321
|
+
end
|
322
|
+
|
323
|
+
# turn a surface into geometries, the first one is the surface, remaining are sub surfaces
|
324
|
+
def self.make_geometries(surface)
|
325
|
+
geometries = []
|
326
|
+
user_datas = []
|
327
|
+
|
328
|
+
# get the transformation to site coordinates
|
329
|
+
site_transformation = OpenStudio::Transformation.new
|
330
|
+
building = surface.model.getBuilding
|
331
|
+
|
332
|
+
space = surface.space
|
333
|
+
if space.is_initialized
|
334
|
+
site_transformation = building.transformation * space.get.transformation
|
335
|
+
else
|
336
|
+
site_transformation = building.transformation
|
337
|
+
end
|
338
|
+
|
339
|
+
# get the vertices
|
340
|
+
surface_vertices = surface.vertices
|
341
|
+
t = OpenStudio::Transformation.alignFace(surface_vertices)
|
342
|
+
r = t.rotationMatrix
|
343
|
+
tInv = t.inverse
|
344
|
+
surface_vertices = OpenStudio.reverse(tInv * surface_vertices)
|
345
|
+
|
346
|
+
# get vertices of all sub surfaces
|
347
|
+
sub_surface_vertices = OpenStudio::Point3dVectorVector.new
|
348
|
+
sub_surfaces = surface.subSurfaces
|
349
|
+
sub_surfaces.each do |sub_surface|
|
350
|
+
sub_surface_vertices << OpenStudio.reverse(tInv * sub_surface.vertices)
|
351
|
+
end
|
352
|
+
|
353
|
+
# triangulate surface
|
354
|
+
triangles = OpenStudio.computeTriangulation(surface_vertices, sub_surface_vertices)
|
355
|
+
if triangles.empty?
|
356
|
+
puts "Failed to triangulate surface #{surface.name} with #{sub_surfaces.size} sub surfaces"
|
357
|
+
return geometries
|
358
|
+
end
|
359
|
+
|
360
|
+
all_vertices = []
|
361
|
+
face_indices = []
|
362
|
+
triangles.each do |vertices|
|
363
|
+
vertices = site_transformation * t * vertices
|
364
|
+
# normal = site_transformation.rotationMatrix*r*z
|
365
|
+
|
366
|
+
# https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3
|
367
|
+
# 0 indicates triangle
|
368
|
+
# 16 indicates triangle with normals
|
369
|
+
face_indices << 0
|
370
|
+
vertices.reverse_each do |vertex|
|
371
|
+
face_indices << get_vertex_index(vertex, all_vertices)
|
372
|
+
end
|
373
|
+
|
374
|
+
# convert to 1 based indices
|
375
|
+
# face_indices.each_index {|i| face_indices[i] = face_indices[i] + 1}
|
376
|
+
end
|
377
|
+
|
378
|
+
data = GeometryData.new
|
379
|
+
data.vertices = flatten_vertices(all_vertices)
|
380
|
+
data.normals = []
|
381
|
+
data.uvs = []
|
382
|
+
data.faces = face_indices
|
383
|
+
data.scale = 1
|
384
|
+
data.visible = true
|
385
|
+
data.castShadow = true
|
386
|
+
data.receiveShadow = false
|
387
|
+
data.doubleSided = true
|
388
|
+
|
389
|
+
geometry = Geometry.new
|
390
|
+
geometry.uuid = format_uuid(surface.handle)
|
391
|
+
geometry.type = 'Geometry'
|
392
|
+
geometry.data = data.to_h
|
393
|
+
geometries << geometry.to_h
|
394
|
+
|
395
|
+
surface_user_data = UserData.new
|
396
|
+
surface_user_data.handle = format_uuid(surface.handle)
|
397
|
+
surface_user_data.name = surface.name.to_s
|
398
|
+
surface_user_data.coincidentWithOutsideObject = false
|
399
|
+
surface_user_data.surfaceType = surface.surfaceType
|
400
|
+
surface_user_data.surfaceTypeMaterialName = surface.surfaceType
|
401
|
+
|
402
|
+
surface_user_data.outsideBoundaryCondition = surface.outsideBoundaryCondition
|
403
|
+
adjacent_surface = surface.adjacentSurface
|
404
|
+
if adjacent_surface.is_initialized
|
405
|
+
surface_user_data.outsideBoundaryConditionObjectName = adjacent_surface.get.name.to_s
|
406
|
+
surface_user_data.outsideBoundaryConditionObjectHandle = format_uuid(adjacent_surface.get.handle)
|
407
|
+
|
408
|
+
other_site_transformation = OpenStudio::Transformation.new
|
409
|
+
other_space = adjacent_surface.get.space
|
410
|
+
if !other_space.empty?
|
411
|
+
other_site_transformation = building.transformation * other_space.get.transformation
|
412
|
+
else
|
413
|
+
other_site_transformation = building.transformation
|
414
|
+
end
|
415
|
+
|
416
|
+
other_vertices = other_site_transformation * adjacent_surface.get.vertices
|
417
|
+
if OpenStudio.circularEqual(site_transformation * surface.vertices, OpenStudio.reverse(other_vertices))
|
418
|
+
# puts "adjacent surfaces are coincident"
|
419
|
+
surface_user_data.coincidentWithOutsideObject = true # controls display only, not energy model
|
420
|
+
else
|
421
|
+
# puts "adjacent surfaces are not coincident"
|
422
|
+
surface_user_data.coincidentWithOutsideObject = false # controls display only, not energy model
|
423
|
+
end
|
424
|
+
|
425
|
+
end
|
426
|
+
surface_user_data.sunExposure = surface.sunExposure
|
427
|
+
surface_user_data.windExposure = surface.windExposure
|
428
|
+
|
429
|
+
if surface.outsideBoundaryCondition == 'Outdoors'
|
430
|
+
if surface.sunExposure == 'SunExposed' && surface.windExposure == 'WindExposed'
|
431
|
+
surface_user_data.boundaryMaterialName = 'Boundary_Outdoors_SunWind'
|
432
|
+
elsif surface.sunExposure == 'SunExposed'
|
433
|
+
surface_user_data.boundaryMaterialName = 'Boundary_Outdoors_Sun'
|
434
|
+
elsif surface.sunExposure == 'WindExposed'
|
435
|
+
surface_user_data.boundaryMaterialName = 'Boundary_Outdoors_Wind'
|
436
|
+
else
|
437
|
+
surface_user_data.boundaryMaterialName = 'Boundary_Outdoors'
|
438
|
+
end
|
439
|
+
else
|
440
|
+
surface_user_data.boundaryMaterialName = 'Boundary_' + surface.outsideBoundaryCondition
|
441
|
+
end
|
442
|
+
|
443
|
+
construction = surface.construction
|
444
|
+
if construction.is_initialized
|
445
|
+
surface_user_data.constructionName = construction.get.name.to_s
|
446
|
+
surface_user_data.constructionMaterialName = 'Construction_' + construction.get.name.to_s
|
447
|
+
end
|
448
|
+
|
449
|
+
space = surface.space
|
450
|
+
if space.is_initialized
|
451
|
+
space = space.get
|
452
|
+
surface_user_data.spaceName = space.name.to_s
|
453
|
+
|
454
|
+
thermal_zone = space.thermalZone
|
455
|
+
if thermal_zone.is_initialized
|
456
|
+
surface_user_data.thermalZoneName = thermal_zone.get.name.to_s
|
457
|
+
surface_user_data.thermalZoneMaterialName = 'ThermalZone_' + thermal_zone.get.name.to_s
|
458
|
+
end
|
459
|
+
|
460
|
+
space_type = space.spaceType
|
461
|
+
if space_type.is_initialized
|
462
|
+
surface_user_data.spaceTypeName = space_type.get.name.to_s
|
463
|
+
surface_user_data.spaceTypeMaterialName = 'SpaceType_' + space_type.get.name.to_s
|
464
|
+
end
|
465
|
+
|
466
|
+
building_story = space.buildingStory
|
467
|
+
if building_story.is_initialized
|
468
|
+
surface_user_data.buildingStoryName = building_story.get.name.to_s
|
469
|
+
surface_user_data.buildingStoryMaterialName = 'BuildingStory_' + building_story.get.name.to_s
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
# vertices = []
|
474
|
+
# surface.vertices.each do |v|
|
475
|
+
# vertex = Vertex.new
|
476
|
+
# vertex.x = v.x
|
477
|
+
# vertex.y = v.y
|
478
|
+
# vertex.z = v.z
|
479
|
+
# vertices << vertex.to_h
|
480
|
+
# end
|
481
|
+
# surface_user_data.vertices = vertices
|
482
|
+
user_datas << surface_user_data.to_h
|
483
|
+
|
484
|
+
# now add geometry for each sub surface
|
485
|
+
sub_surfaces.each do |sub_surface|
|
486
|
+
# triangulate sub surface
|
487
|
+
sub_surface_vertices = OpenStudio.reverse(tInv * sub_surface.vertices)
|
488
|
+
triangles = OpenStudio.computeTriangulation(sub_surface_vertices, OpenStudio::Point3dVectorVector.new)
|
489
|
+
|
490
|
+
all_vertices = []
|
491
|
+
face_indices = []
|
492
|
+
triangles.each do |vertices|
|
493
|
+
vertices = site_transformation * t * vertices
|
494
|
+
# normal = site_transformation.rotationMatrix*r*z
|
495
|
+
|
496
|
+
# https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3
|
497
|
+
# 0 indicates triangle
|
498
|
+
# 16 indicates triangle with normals
|
499
|
+
face_indices << 0
|
500
|
+
vertices.reverse_each do |vertex|
|
501
|
+
face_indices << get_vertex_index(vertex, all_vertices)
|
502
|
+
end
|
503
|
+
|
504
|
+
# convert to 1 based indices
|
505
|
+
# face_indices.each_index {|i| face_indices[i] = face_indices[i] + 1}
|
506
|
+
end
|
507
|
+
|
508
|
+
data = GeometryData.new
|
509
|
+
data.vertices = flatten_vertices(all_vertices)
|
510
|
+
data.normals = []
|
511
|
+
data.uvs = []
|
512
|
+
data.faces = face_indices
|
513
|
+
data.scale = 1
|
514
|
+
data.visible = true
|
515
|
+
data.castShadow = true
|
516
|
+
data.receiveShadow = false
|
517
|
+
data.doubleSided = true
|
518
|
+
|
519
|
+
geometry = Geometry.new
|
520
|
+
geometry.uuid = format_uuid(sub_surface.handle)
|
521
|
+
geometry.type = 'Geometry'
|
522
|
+
geometry.data = data.to_h
|
523
|
+
geometries << geometry.to_h
|
524
|
+
|
525
|
+
sub_surface_user_data = UserData.new
|
526
|
+
sub_surface_user_data.handle = format_uuid(sub_surface.handle)
|
527
|
+
sub_surface_user_data.name = sub_surface.name.to_s
|
528
|
+
sub_surface_user_data.coincidentWithOutsideObject = false
|
529
|
+
|
530
|
+
sub_surface_user_data.surfaceType = sub_surface.subSurfaceType
|
531
|
+
if /Window/.match(sub_surface.subSurfaceType) || /Glass/.match(sub_surface.subSurfaceType) ||
|
532
|
+
/Skylight/.match(sub_surface.subSurfaceType) || /TubularDaylight/.match(sub_surface.subSurfaceType)
|
533
|
+
sub_surface_user_data.surfaceTypeMaterialName = 'Window'
|
534
|
+
else
|
535
|
+
sub_surface_user_data.surfaceTypeMaterialName = 'Door'
|
536
|
+
end
|
537
|
+
|
538
|
+
sub_surface_user_data.outsideBoundaryCondition = surface_user_data.outsideBoundaryCondition
|
539
|
+
adjacent_sub_surface = sub_surface.adjacentSubSurface
|
540
|
+
if adjacent_sub_surface.is_initialized
|
541
|
+
sub_surface_user_data.outsideBoundaryConditionObjectName = adjacent_sub_surface.get.name.to_s
|
542
|
+
sub_surface_user_data.outsideBoundaryConditionObjectHandle = format_uuid(adjacent_sub_surface.get.handle)
|
543
|
+
|
544
|
+
other_site_transformation = OpenStudio::Transformation.new
|
545
|
+
other_space = adjacent_sub_surface.get.space
|
546
|
+
if !other_space.empty?
|
547
|
+
other_site_transformation = building.transformation * other_space.get.transformation
|
548
|
+
else
|
549
|
+
other_site_transformation = building.transformation
|
550
|
+
end
|
551
|
+
|
552
|
+
other_vertices = other_site_transformation * adjacent_sub_surface.get.vertices
|
553
|
+
if OpenStudio.circularEqual(site_transformation * sub_surface.vertices, OpenStudio.reverse(other_vertices))
|
554
|
+
# puts "adjacent sub surfaces are coincident"
|
555
|
+
surface_user_data.coincidentWithOutsideObject = true # controls display only, not energy model
|
556
|
+
else
|
557
|
+
# puts "adjacent sub surfaces are not coincident"
|
558
|
+
surface_user_data.coincidentWithOutsideObject = false # controls display only, not energy model
|
559
|
+
end
|
560
|
+
|
561
|
+
sub_surface_user_data.boundaryMaterialName = 'Boundary_Surface'
|
562
|
+
else
|
563
|
+
if surface_user_data.boundaryMaterialName == 'Boundary_Surface'
|
564
|
+
sub_surface_user_data.boundaryMaterialName = 'Undefined'
|
565
|
+
else
|
566
|
+
sub_surface_user_data.boundaryMaterialName = surface_user_data.boundaryMaterialName
|
567
|
+
end
|
568
|
+
end
|
569
|
+
sub_surface_user_data.sunExposure = surface_user_data.sunExposure
|
570
|
+
sub_surface_user_data.windExposure = surface_user_data.windExposure
|
571
|
+
|
572
|
+
construction = sub_surface.construction
|
573
|
+
if construction.is_initialized
|
574
|
+
sub_surface_user_data.constructionName = construction.get.name.to_s
|
575
|
+
sub_surface_user_data.constructionMaterialName = 'Construction_' + construction.get.name.to_s
|
576
|
+
end
|
577
|
+
sub_surface_user_data.spaceName = surface_user_data.spaceName
|
578
|
+
sub_surface_user_data.thermalZoneName = surface_user_data.thermalZoneName
|
579
|
+
sub_surface_user_data.thermalZoneMaterialName = surface_user_data.thermalZoneMaterialName
|
580
|
+
sub_surface_user_data.spaceTypeName = surface_user_data.spaceTypeName
|
581
|
+
sub_surface_user_data.spaceTypeMaterialName = surface_user_data.spaceTypeMaterialName
|
582
|
+
sub_surface_user_data.buildingStoryName = surface_user_data.buildingStoryName
|
583
|
+
sub_surface_user_data.buildingStoryMaterialName = surface_user_data.buildingStoryMaterialName
|
584
|
+
|
585
|
+
# vertices = []
|
586
|
+
# surface.vertices.each do |v|
|
587
|
+
# vertex = Vertex.new
|
588
|
+
# vertex.x = v.x
|
589
|
+
# vertex.y = v.y
|
590
|
+
# vertex.z = v.z
|
591
|
+
# vertices << vertex.to_h
|
592
|
+
# end
|
593
|
+
# sub_surface_user_data.vertices = vertices
|
594
|
+
user_datas << sub_surface_user_data.to_h
|
595
|
+
end
|
596
|
+
|
597
|
+
return [geometries, user_datas]
|
598
|
+
end
|
599
|
+
|
600
|
+
# turn a shading surface into geometries
|
601
|
+
def self.make_shade_geometries(surface)
|
602
|
+
geometries = []
|
603
|
+
user_datas = []
|
604
|
+
|
605
|
+
# get the transformation to site coordinates
|
606
|
+
site_transformation = OpenStudio::Transformation.new
|
607
|
+
building = surface.model.getBuilding
|
608
|
+
|
609
|
+
shading_surface_group = surface.shadingSurfaceGroup
|
610
|
+
shading_surface_type = 'Building'
|
611
|
+
space_name = nil
|
612
|
+
thermal_zone_name = nil
|
613
|
+
space_type_name = nil
|
614
|
+
building_story_name = nil
|
615
|
+
if !shading_surface_group.empty?
|
616
|
+
shading_surface_type = shading_surface_group.get.shadingSurfaceType
|
617
|
+
|
618
|
+
space = shading_surface_group.get.space
|
619
|
+
if space.is_initialized
|
620
|
+
space = space.get
|
621
|
+
space_name = space.name.to_s
|
622
|
+
|
623
|
+
thermal_zone = space.thermalZone
|
624
|
+
if thermal_zone.is_initialized
|
625
|
+
thermal_zone_name = thermal_zone.get.name.to_s
|
626
|
+
end
|
627
|
+
|
628
|
+
space_type = space.spaceType
|
629
|
+
if space_type.is_initialized
|
630
|
+
space_type_name = space_type.get.name.to_s
|
631
|
+
end
|
632
|
+
|
633
|
+
building_story = space.buildingStory
|
634
|
+
if building_story.is_initialized
|
635
|
+
building_story_name = building_story.get.name.to_s
|
636
|
+
end
|
637
|
+
|
638
|
+
site_transformation = building.transformation * space.transformation * shading_surface_group.get.transformation
|
639
|
+
elsif /Site/i.match(shading_surface_type)
|
640
|
+
site_transformation = shading_surface_group.get.transformation
|
641
|
+
else
|
642
|
+
site_transformation = building.transformation * shading_surface_group.get.transformation
|
643
|
+
end
|
644
|
+
|
645
|
+
end
|
646
|
+
|
647
|
+
# get the vertices
|
648
|
+
surface_vertices = surface.vertices
|
649
|
+
t = OpenStudio::Transformation.alignFace(surface_vertices)
|
650
|
+
r = t.rotationMatrix
|
651
|
+
tInv = t.inverse
|
652
|
+
surface_vertices = OpenStudio.reverse(tInv * surface_vertices)
|
653
|
+
|
654
|
+
# triangulate surface
|
655
|
+
triangles = OpenStudio.computeTriangulation(surface_vertices, OpenStudio::Point3dVectorVector.new)
|
656
|
+
if triangles.empty?
|
657
|
+
puts "Failed to triangulate shading surface #{surface.name}"
|
658
|
+
return geometries
|
659
|
+
end
|
660
|
+
|
661
|
+
all_vertices = []
|
662
|
+
face_indices = []
|
663
|
+
triangles.each do |vertices|
|
664
|
+
vertices = site_transformation * t * vertices
|
665
|
+
# normal = site_transformation.rotationMatrix*r*z
|
666
|
+
|
667
|
+
# https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3
|
668
|
+
# 0 indicates triangle
|
669
|
+
# 16 indicates triangle with normals
|
670
|
+
face_indices << 0
|
671
|
+
vertices.reverse_each do |vertex|
|
672
|
+
face_indices << get_vertex_index(vertex, all_vertices)
|
673
|
+
end
|
674
|
+
|
675
|
+
# convert to 1 based indices
|
676
|
+
# face_indices.each_index {|i| face_indices[i] = face_indices[i] + 1}
|
677
|
+
end
|
678
|
+
|
679
|
+
data = GeometryData.new
|
680
|
+
data.vertices = flatten_vertices(all_vertices)
|
681
|
+
data.normals = []
|
682
|
+
data.uvs = []
|
683
|
+
data.faces = face_indices
|
684
|
+
data.scale = 1
|
685
|
+
data.visible = true
|
686
|
+
data.castShadow = true
|
687
|
+
data.receiveShadow = false
|
688
|
+
data.doubleSided = true
|
689
|
+
|
690
|
+
geometry = Geometry.new
|
691
|
+
geometry.uuid = format_uuid(surface.handle)
|
692
|
+
geometry.type = 'Geometry'
|
693
|
+
geometry.data = data.to_h
|
694
|
+
geometries << geometry.to_h
|
695
|
+
|
696
|
+
surface_user_data = UserData.new
|
697
|
+
surface_user_data.handle = format_uuid(surface.handle)
|
698
|
+
surface_user_data.name = surface.name.to_s
|
699
|
+
surface_user_data.coincidentWithOutsideObject = false
|
700
|
+
|
701
|
+
surface_user_data.surfaceType = shading_surface_type + 'Shading'
|
702
|
+
surface_user_data.surfaceTypeMaterialName = shading_surface_type + 'Shading'
|
703
|
+
|
704
|
+
# surface_user_data.outsideBoundaryCondition = nil
|
705
|
+
# surface_user_data.outsideBoundaryConditionObjectName = nil
|
706
|
+
# surface_user_data.outsideBoundaryConditionObjectHandle = nil
|
707
|
+
surface_user_data.sunExposure = 'SunExposed'
|
708
|
+
surface_user_data.windExposure = 'WindExposed'
|
709
|
+
|
710
|
+
construction = surface.construction
|
711
|
+
if construction.is_initialized
|
712
|
+
surface_user_data.constructionName = construction.get.name.to_s
|
713
|
+
surface_user_data.constructionMaterialName = 'Construction_' + construction.get.name.to_s
|
714
|
+
end
|
715
|
+
|
716
|
+
if space_name
|
717
|
+
surface_user_data.spaceName = space_name
|
718
|
+
end
|
719
|
+
if thermal_zone_name
|
720
|
+
surface_user_data.thermalZoneName = thermal_zone_name
|
721
|
+
surface_user_data.thermalZoneMaterialName = 'ThermalZone_' + thermal_zone_name
|
722
|
+
end
|
723
|
+
if space_type_name
|
724
|
+
surface_user_data.spaceTypeName = space_type_name
|
725
|
+
surface_user_data.spaceTypeMaterialName = 'SpaceType_' + space_type_name
|
726
|
+
end
|
727
|
+
if building_story_name
|
728
|
+
surface_user_data.buildingStoryName = building_story_name
|
729
|
+
surface_user_data.buildingStoryMaterialName = 'BuildingStory_' + building_story_name
|
730
|
+
end
|
731
|
+
|
732
|
+
# vertices = []
|
733
|
+
# surface.vertices.each do |v|
|
734
|
+
# vertex = Vertex.new
|
735
|
+
# vertex.x = v.x
|
736
|
+
# vertex.y = v.y
|
737
|
+
# vertex.z = v.z
|
738
|
+
# vertices << vertex.to_h
|
739
|
+
# end
|
740
|
+
# surface_user_data.vertices = vertices
|
741
|
+
user_datas << surface_user_data.to_h
|
742
|
+
|
743
|
+
return [geometries, user_datas]
|
744
|
+
end
|
745
|
+
|
746
|
+
# turn an interior partition surface into geometries
|
747
|
+
def self.make_interior_partition_geometries(surface)
|
748
|
+
geometries = []
|
749
|
+
user_datas = []
|
750
|
+
|
751
|
+
# get the transformation to site coordinates
|
752
|
+
site_transformation = OpenStudio::Transformation.new
|
753
|
+
building = surface.model.getBuilding
|
754
|
+
interior_partition_surface_group = surface.interiorPartitionSurfaceGroup
|
755
|
+
|
756
|
+
space_name = nil
|
757
|
+
thermal_zone_name = nil
|
758
|
+
space_type_name = nil
|
759
|
+
building_story_name = nil
|
760
|
+
if !interior_partition_surface_group.empty?
|
761
|
+
|
762
|
+
space = interior_partition_surface_group.get.space
|
763
|
+
if space.is_initialized
|
764
|
+
space = space.get
|
765
|
+
space_name = space.name.to_s
|
766
|
+
|
767
|
+
thermal_zone = space.thermalZone
|
768
|
+
if thermal_zone.is_initialized
|
769
|
+
thermal_zone_name = thermal_zone.get.name.to_s
|
770
|
+
end
|
771
|
+
|
772
|
+
space_type = space.spaceType
|
773
|
+
if space_type.is_initialized
|
774
|
+
space_type_name = space_type.get.name.to_s
|
775
|
+
end
|
776
|
+
|
777
|
+
building_story = space.buildingStory
|
778
|
+
if building_story.is_initialized
|
779
|
+
building_story_name = building_story.get.name.to_s
|
780
|
+
end
|
781
|
+
|
782
|
+
site_transformation = building.transformation * space.transformation * interior_partition_surface_group.get.transformation
|
783
|
+
else
|
784
|
+
site_transformation = building.transformation * interior_partition_surface_group.get.transformation
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
# get the vertices
|
789
|
+
surface_vertices = surface.vertices
|
790
|
+
t = OpenStudio::Transformation.alignFace(surface_vertices)
|
791
|
+
r = t.rotationMatrix
|
792
|
+
tInv = t.inverse
|
793
|
+
surface_vertices = OpenStudio.reverse(tInv * surface_vertices)
|
794
|
+
|
795
|
+
# triangulate surface
|
796
|
+
triangles = OpenStudio.computeTriangulation(surface_vertices, OpenStudio::Point3dVectorVector.new)
|
797
|
+
if triangles.empty?
|
798
|
+
puts "Failed to triangulate interior partition surface #{surface.name}"
|
799
|
+
return geometries
|
800
|
+
end
|
801
|
+
|
802
|
+
all_vertices = []
|
803
|
+
face_indices = []
|
804
|
+
triangles.each do |vertices|
|
805
|
+
vertices = site_transformation * t * vertices
|
806
|
+
# normal = site_transformation.rotationMatrix*r*z
|
807
|
+
|
808
|
+
# https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3
|
809
|
+
# 0 indicates triangle
|
810
|
+
# 16 indicates triangle with normals
|
811
|
+
face_indices << 0
|
812
|
+
vertices.reverse_each do |vertex|
|
813
|
+
face_indices << get_vertex_index(vertex, all_vertices)
|
814
|
+
end
|
815
|
+
|
816
|
+
# convert to 1 based indices
|
817
|
+
# face_indices.each_index {|i| face_indices[i] = face_indices[i] + 1}
|
818
|
+
end
|
819
|
+
|
820
|
+
data = GeometryData.new
|
821
|
+
data.vertices = flatten_vertices(all_vertices)
|
822
|
+
data.normals = []
|
823
|
+
data.uvs = []
|
824
|
+
data.faces = face_indices
|
825
|
+
data.scale = 1
|
826
|
+
data.visible = true
|
827
|
+
data.castShadow = true
|
828
|
+
data.receiveShadow = false
|
829
|
+
data.doubleSided = true
|
830
|
+
|
831
|
+
geometry = Geometry.new
|
832
|
+
geometry.uuid = format_uuid(surface.handle)
|
833
|
+
geometry.type = 'Geometry'
|
834
|
+
geometry.data = data.to_h
|
835
|
+
geometries << geometry.to_h
|
836
|
+
|
837
|
+
surface_user_data = UserData.new
|
838
|
+
surface_user_data.handle = format_uuid(surface.handle)
|
839
|
+
surface_user_data.name = surface.name.to_s
|
840
|
+
surface_user_data.coincidentWithOutsideObject = false
|
841
|
+
|
842
|
+
surface_user_data.surfaceType = 'InteriorPartitionSurface'
|
843
|
+
surface_user_data.surfaceTypeMaterialName = 'InteriorPartitionSurface'
|
844
|
+
|
845
|
+
# surface_user_data.outsideBoundaryCondition = nil
|
846
|
+
# surface_user_data.outsideBoundaryConditionObjectName = nil
|
847
|
+
# surface_user_data.outsideBoundaryConditionObjectHandle = nil
|
848
|
+
surface_user_data.sunExposure = 'NoSun'
|
849
|
+
surface_user_data.windExposure = 'NoWind'
|
850
|
+
|
851
|
+
construction = surface.construction
|
852
|
+
if construction.is_initialized
|
853
|
+
surface_user_data.constructionName = construction.get.name.to_s
|
854
|
+
surface_user_data.constructionMaterialName = 'Construction_' + construction.get.name.to_s
|
855
|
+
end
|
856
|
+
|
857
|
+
if space_name
|
858
|
+
surface_user_data.spaceName = space_name
|
859
|
+
end
|
860
|
+
if thermal_zone_name
|
861
|
+
surface_user_data.thermalZoneName = thermal_zone_name
|
862
|
+
surface_user_data.thermalZoneMaterialName = 'ThermalZone_' + thermal_zone_name
|
863
|
+
end
|
864
|
+
if space_type_name
|
865
|
+
surface_user_data.spaceTypeName = space_type_name
|
866
|
+
surface_user_data.spaceTypeMaterialName = 'SpaceType_' + space_type_name
|
867
|
+
end
|
868
|
+
if building_story_name
|
869
|
+
surface_user_data.buildingStoryName = building_story_name
|
870
|
+
surface_user_data.buildingStoryMaterialName = 'BuildingStory_' + building_story_name
|
871
|
+
end
|
872
|
+
|
873
|
+
# vertices = []
|
874
|
+
# surface.vertices.each do |v|
|
875
|
+
# vertex = Vertex.new
|
876
|
+
# vertex.x = v.x
|
877
|
+
# vertex.y = v.y
|
878
|
+
# vertex.z = v.z
|
879
|
+
# vertices << vertex.to_h
|
880
|
+
# end
|
881
|
+
# surface_user_data.vertices = vertices
|
882
|
+
user_datas << surface_user_data.to_h
|
883
|
+
|
884
|
+
return [geometries, user_datas]
|
885
|
+
end
|
886
|
+
|
887
|
+
def self.identity_matrix
|
888
|
+
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
889
|
+
end
|
890
|
+
|
891
|
+
def self.build_scene(model)
|
892
|
+
materials = build_materials(model)
|
893
|
+
|
894
|
+
object = {}
|
895
|
+
object[:uuid] = format_uuid(OpenStudio.createUUID)
|
896
|
+
object[:type] = 'Scene'
|
897
|
+
object[:matrix] = identity_matrix
|
898
|
+
object[:children] = []
|
899
|
+
|
900
|
+
floor_material = materials.find { |m| m[:name] == 'Floor' }
|
901
|
+
wall_material = materials.find { |m| m[:name] == 'Wall' }
|
902
|
+
roof_material = materials.find { |m| m[:name] == 'RoofCeiling' }
|
903
|
+
window_material = materials.find { |m| m[:name] == 'Window' }
|
904
|
+
door_material = materials.find { |m| m[:name] == 'Door' }
|
905
|
+
site_shading_material = materials.find { |m| m[:name] == 'SiteShading' }
|
906
|
+
building_shading_material = materials.find { |m| m[:name] == 'BuildingShading' }
|
907
|
+
space_shading_material = materials.find { |m| m[:name] == 'SpaceShading' }
|
908
|
+
interior_partition_surface_material = materials.find { |m| m[:name] == 'InteriorPartitionSurface' }
|
909
|
+
|
910
|
+
# loop over all surfaces
|
911
|
+
all_geometries = []
|
912
|
+
model.getSurfaces.each do |surface|
|
913
|
+
material = nil
|
914
|
+
surfaceType = surface.surfaceType.upcase
|
915
|
+
if surfaceType == 'FLOOR'
|
916
|
+
material = floor_material
|
917
|
+
elsif surfaceType == 'WALL'
|
918
|
+
material = wall_material
|
919
|
+
elsif surfaceType == 'ROOFCEILING'
|
920
|
+
material = roof_material
|
921
|
+
end
|
922
|
+
|
923
|
+
geometries, user_datas = make_geometries(surface)
|
924
|
+
geometries&.each_index do |i|
|
925
|
+
geometry = geometries[i]
|
926
|
+
user_data = user_datas[i]
|
927
|
+
|
928
|
+
all_geometries << geometry
|
929
|
+
|
930
|
+
scene_child = SceneChild.new
|
931
|
+
scene_child.uuid = format_uuid(OpenStudio.createUUID)
|
932
|
+
scene_child.name = user_data[:name]
|
933
|
+
scene_child.type = 'Mesh'
|
934
|
+
scene_child.geometry = geometry[:uuid]
|
935
|
+
|
936
|
+
if i == 0
|
937
|
+
# first geometry is base surface
|
938
|
+
scene_child.material = material[:uuid]
|
939
|
+
else
|
940
|
+
# sub surface
|
941
|
+
if /Window/.match(user_data[:surfaceType]) || /Glass/.match(user_data[:surfaceType])
|
942
|
+
scene_child.material = window_material[:uuid]
|
943
|
+
else
|
944
|
+
scene_child.material = door_material[:uuid]
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
scene_child.matrix = identity_matrix
|
949
|
+
scene_child.userData = user_data
|
950
|
+
object[:children] << scene_child.to_h
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
# loop over all shading surfaces
|
955
|
+
model.getShadingSurfaces.each do |surface|
|
956
|
+
geometries, user_datas = make_shade_geometries(surface)
|
957
|
+
geometries&.each_index do |i|
|
958
|
+
geometry = geometries[i]
|
959
|
+
user_data = user_datas[i]
|
960
|
+
|
961
|
+
material = nil
|
962
|
+
if /Site/.match(user_data[:surfaceType])
|
963
|
+
material = site_shading_material
|
964
|
+
elsif /Building/.match(user_data[:surfaceType])
|
965
|
+
material = building_shading_material
|
966
|
+
elsif /Space/.match(user_data[:surfaceType])
|
967
|
+
material = space_shading_material
|
968
|
+
end
|
969
|
+
|
970
|
+
all_geometries << geometry
|
971
|
+
|
972
|
+
scene_child = SceneChild.new
|
973
|
+
scene_child.uuid = format_uuid(OpenStudio.createUUID)
|
974
|
+
scene_child.name = user_data[:name]
|
975
|
+
scene_child.type = 'Mesh'
|
976
|
+
scene_child.geometry = geometry[:uuid]
|
977
|
+
scene_child.material = material[:uuid]
|
978
|
+
scene_child.matrix = identity_matrix
|
979
|
+
scene_child.userData = user_data
|
980
|
+
object[:children] << scene_child.to_h
|
981
|
+
end
|
982
|
+
end
|
983
|
+
|
984
|
+
# loop over all interior partition surfaces
|
985
|
+
model.getInteriorPartitionSurfaces.each do |surface|
|
986
|
+
geometries, user_datas = make_interior_partition_geometries(surface)
|
987
|
+
geometries.each_index do |i|
|
988
|
+
geometry = geometries[i]
|
989
|
+
user_data = user_datas[i]
|
990
|
+
|
991
|
+
material = interior_partition_surface_material
|
992
|
+
|
993
|
+
all_geometries << geometry
|
994
|
+
|
995
|
+
scene_child = SceneChild.new
|
996
|
+
scene_child.uuid = format_uuid(OpenStudio.createUUID)
|
997
|
+
scene_child.name = user_data[:name]
|
998
|
+
scene_child.type = 'Mesh'
|
999
|
+
scene_child.geometry = geometry[:uuid]
|
1000
|
+
scene_child.material = material[:uuid]
|
1001
|
+
scene_child.matrix = identity_matrix
|
1002
|
+
scene_child.userData = user_data
|
1003
|
+
object[:children] << scene_child.to_h
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
# light = AmbientLight.new
|
1008
|
+
# light.uuid = "#{format_uuid(OpenStudio::createUUID)}"
|
1009
|
+
# light.type = "AmbientLight"
|
1010
|
+
# light.color = "0xFFFFFF".hex
|
1011
|
+
# light.matrix = identity_matrix
|
1012
|
+
# object[:children] << light.to_h
|
1013
|
+
|
1014
|
+
scene = Scene.new
|
1015
|
+
scene.geometries = all_geometries
|
1016
|
+
scene.materials = materials
|
1017
|
+
scene.object = object
|
1018
|
+
|
1019
|
+
return scene
|
1020
|
+
end
|
1021
|
+
end
|