urbanopt-geojson 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.rakeTasks +7 -0
- data/.rdoc_options +43 -0
- data/.rspec +2 -0
- data/.rubocop.yml +10 -0
- data/.travis.yml +35 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +27 -0
- data/Jenkinsfile +10 -0
- data/LICENSE.md +27 -0
- data/RDOC_MAIN.md +48 -0
- data/README.md +40 -0
- data/Rakefile +45 -0
- data/deploy_docs.sh +4 -0
- data/doc_templates/LICENSE.md +27 -0
- data/doc_templates/README.md.erb +42 -0
- data/doc_templates/copyright_erb.txt +31 -0
- data/doc_templates/copyright_js.txt +4 -0
- data/doc_templates/copyright_ruby.txt +29 -0
- data/docs/.gitignore +3 -0
- data/docs/.vuepress/components/BuildingProperties.vue +12 -0
- data/docs/.vuepress/components/DistrictSystemProperties.vue +12 -0
- data/docs/.vuepress/components/ElectricalConnectorProperties.vue +12 -0
- data/docs/.vuepress/components/ElectricalJunctionProperties.vue +12 -0
- data/docs/.vuepress/components/InnerJsonSchema.vue +80 -0
- data/docs/.vuepress/components/JsonSchema.vue +12 -0
- data/docs/.vuepress/components/RegionProperties.vue +12 -0
- data/docs/.vuepress/components/SiteProperties.vue +12 -0
- data/docs/.vuepress/components/StaticLink.vue +8 -0
- data/docs/.vuepress/components/ThermalConnectorProperties.vue +12 -0
- data/docs/.vuepress/components/ThermalJunctionProperties.vue +12 -0
- data/docs/.vuepress/config.js +22 -0
- data/docs/.vuepress/highlight.js +8 -0
- data/docs/.vuepress/public/custom_rdoc_styles.css +64 -0
- data/docs/.vuepress/utils.js +17 -0
- data/docs/README.md +30 -0
- data/docs/doc/created.rid +0 -0
- data/docs/package-lock.json +11771 -0
- data/docs/package.json +22 -0
- data/docs/schemas/building-properties.md +3 -0
- data/docs/schemas/district-system-properties.md +3 -0
- data/docs/schemas/electrical-connector-properties.md +3 -0
- data/docs/schemas/electrical-junction-properties.md +3 -0
- data/docs/schemas/region-properties.md +3 -0
- data/docs/schemas/site-properties.md +3 -0
- data/docs/schemas/thermal-connector-properties.md +3 -0
- data/docs/schemas/thermal-junction-properties.md +3 -0
- data/lib/measures/.rubocop.yml +5 -0
- data/lib/measures/urban_geometry_creation/LICENSE.md +27 -0
- data/lib/measures/urban_geometry_creation/README.md +48 -0
- data/lib/measures/urban_geometry_creation/README.md.erb +42 -0
- data/lib/measures/urban_geometry_creation/measure.rb +199 -0
- data/lib/measures/urban_geometry_creation/measure.xml +139 -0
- data/lib/measures/urban_geometry_creation/tests/nrel_stm_footprints.geojson +3238 -0
- data/lib/measures/urban_geometry_creation/tests/shadowed_tests.rb +80 -0
- data/lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb +143 -0
- data/lib/measures/urban_geometry_creation_zoning/LICENSE.md +27 -0
- data/lib/measures/urban_geometry_creation_zoning/README.md +48 -0
- data/lib/measures/urban_geometry_creation_zoning/README.md.erb +42 -0
- data/lib/measures/urban_geometry_creation_zoning/measure.rb +203 -0
- data/lib/measures/urban_geometry_creation_zoning/measure.xml +133 -0
- data/lib/measures/urban_geometry_creation_zoning/tests/nrel_stm_footprints.geojson +3238 -0
- data/lib/measures/urban_geometry_creation_zoning/tests/urban_geometry_creation_test.rb +143 -0
- data/lib/urbanopt/geojson.rb +41 -0
- data/lib/urbanopt/geojson/building.rb +341 -0
- data/lib/urbanopt/geojson/district_system.rb +53 -0
- data/lib/urbanopt/geojson/extension.rb +63 -0
- data/lib/urbanopt/geojson/feature.rb +206 -0
- data/lib/urbanopt/geojson/geo_file.rb +154 -0
- data/lib/urbanopt/geojson/helper.rb +340 -0
- data/lib/urbanopt/geojson/logging.rb +46 -0
- data/lib/urbanopt/geojson/mapper_classes.rb +85 -0
- data/lib/urbanopt/geojson/model.rb +133 -0
- data/lib/urbanopt/geojson/region.rb +55 -0
- data/lib/urbanopt/geojson/schema/building_properties.json +358 -0
- data/lib/urbanopt/geojson/schema/district_system_properties.json +137 -0
- data/lib/urbanopt/geojson/schema/electrical_connector_properties.json +77 -0
- data/lib/urbanopt/geojson/schema/electrical_junction_properties.json +64 -0
- data/lib/urbanopt/geojson/schema/geojson_schema.json +323 -0
- data/lib/urbanopt/geojson/schema/region_properties.json +93 -0
- data/lib/urbanopt/geojson/schema/site_properties.json +87 -0
- data/lib/urbanopt/geojson/schema/thermal_connector_properties.json +107 -0
- data/lib/urbanopt/geojson/schema/thermal_junction_properties.json +83 -0
- data/lib/urbanopt/geojson/update_areas.rb +102 -0
- data/lib/urbanopt/geojson/validate_geojson.rb +147 -0
- data/lib/urbanopt/geojson/version.rb +35 -0
- data/lib/urbanopt/geojson/workflows/building.osw +187 -0
- data/lib/urbanopt/geojson/workflows/building.osw.out +2806 -0
- data/lib/urbanopt/geojson/workflows/district_system.osw +84 -0
- data/lib/urbanopt/geojson/workflows/district_system.osw.out +646 -0
- data/lib/urbanopt/geojson/zoning.rb +134 -0
- data/package-lock.json +3 -0
- data/urbanopt-geojson-gem.gemspec +39 -0
- metadata +238 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
module URBANopt
|
32
|
+
module GeoJSON
|
33
|
+
module Helper
|
34
|
+
##
|
35
|
+
# This method loops though all the surfaces of the space and creates shading
|
36
|
+
# surfaces. It also removes the thermal zone and space type assigned to the space,
|
37
|
+
# if any.
|
38
|
+
#
|
39
|
+
# Returns an Array of instances of +OpenStudio::Model::ShadingSurfaceGroup+ .
|
40
|
+
#
|
41
|
+
# Used to convert adjacent buildings to shading surfaces.
|
42
|
+
# [Parameters]
|
43
|
+
# * +space+ - _Type:String_ - An instance of +OpenStudio::Model::Space+ .
|
44
|
+
def self.convert_to_shading_surface_group(space)
|
45
|
+
name = space.name.to_s
|
46
|
+
model = space.model
|
47
|
+
shading_group = OpenStudio::Model::ShadingSurfaceGroup.new(model)
|
48
|
+
space.surfaces.each do |surface|
|
49
|
+
shading_surface = OpenStudio::Model::ShadingSurface.new(surface.vertices, model)
|
50
|
+
shading_surface.setShadingSurfaceGroup(shading_group)
|
51
|
+
end
|
52
|
+
thermal_zone = space.thermalZone
|
53
|
+
if !thermal_zone.empty?
|
54
|
+
thermal_zone.get.remove
|
55
|
+
end
|
56
|
+
space_type = space.spaceType
|
57
|
+
space.remove
|
58
|
+
if !space_type.empty? && space_type.get.spaces.empty?
|
59
|
+
space_type.get.remove
|
60
|
+
end
|
61
|
+
shading_group.setName(name)
|
62
|
+
return [shading_group]
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns array containing instance of +OpenStudio::Model::ShadingSurface+ .
|
67
|
+
#
|
68
|
+
# Used to create Photovoltaics and assign efficiency.
|
69
|
+
#
|
70
|
+
# [Parameters]
|
71
|
+
# * +feature+ - _Type:String_ - An instance of Feature class.
|
72
|
+
# * +height+ - _Type:Integer_ - Indicates the building height.
|
73
|
+
# * +model+ - _Type:String_ - An instance of +OpenStudio::Model::Model+ .
|
74
|
+
# * +origin_lat_lon+ - _Type:Float_ - An instance of +OpenStudio::PointLatLon+ indicating the
|
75
|
+
# origin's latitude & longitude.
|
76
|
+
# * +runner+ - _Type:String_ - An instance of +Openstudio::Measure::OSRunner+ for the measure run.
|
77
|
+
def self.create_photovoltaics(feature, height, model, origin_lat_lon, runner)
|
78
|
+
feature_id = feature.feature_json[:properties][:properties]
|
79
|
+
name = feature.name
|
80
|
+
floor_prints = []
|
81
|
+
multi_polygons = feature.get_multi_polygons
|
82
|
+
multi_polygons.each do |multi_polygon|
|
83
|
+
if multi_polygon.size > 1
|
84
|
+
runner.registerWarning('Ignoring holes in polygon')
|
85
|
+
end
|
86
|
+
multi_polygon.each do |polygon|
|
87
|
+
floor_print = floor_print_from_polygon(polygon, height, origin_lat_lon, runner)
|
88
|
+
if floor_print
|
89
|
+
floor_prints << OpenStudio.reverse(floor_print)
|
90
|
+
else
|
91
|
+
runner.registerWarning("Cannot create footprint for '#{name}'")
|
92
|
+
end
|
93
|
+
break
|
94
|
+
end
|
95
|
+
end
|
96
|
+
shading_surfaces = []
|
97
|
+
floor_prints.each do |floor_print|
|
98
|
+
shading_group = OpenStudio::Model::ShadingSurfaceGroup.new(model)
|
99
|
+
shading_surface = OpenStudio::Model::ShadingSurface.new(floor_print, model)
|
100
|
+
shading_surface.setShadingSurfaceGroup(shading_group)
|
101
|
+
shading_surface.setName('Photovoltaic Panel')
|
102
|
+
shading_surfaces << shading_surface
|
103
|
+
end
|
104
|
+
# create the inverter # :nodoc:
|
105
|
+
inverter = OpenStudio::Model::ElectricLoadCenterInverterSimple.new(model)
|
106
|
+
inverter.setInverterEfficiency(0.95)
|
107
|
+
# create the distribution system # :nodoc:
|
108
|
+
elcd = OpenStudio::Model::ElectricLoadCenterDistribution.new(model)
|
109
|
+
elcd.setInverter(inverter)
|
110
|
+
shading_surfaces.each do |shading_surface|
|
111
|
+
panel = OpenStudio::Model::GeneratorPhotovoltaic.simple(model)
|
112
|
+
panel.setSurface(shading_surface)
|
113
|
+
performance = panel.photovoltaicPerformance.to_PhotovoltaicPerformanceSimple.get
|
114
|
+
performance.setFractionOfSurfaceAreaWithActiveSolarCells(1.0)
|
115
|
+
performance.setFixedEfficiency(0.3)
|
116
|
+
elcd.addGenerator(panel)
|
117
|
+
end
|
118
|
+
return shading_surfaces
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns array containing instance of +OpenStudio::Model::ShadingSurface+ .
|
123
|
+
#
|
124
|
+
# [Parameters]
|
125
|
+
# * +feature+ - _Type:String_ - An instance of Feature class.
|
126
|
+
# * +model+ - _Type:String_ - An instance of _OpenStudio::Model::Model_ .
|
127
|
+
# * +origin_lat_lon+ - _Type:Float_ - An instance of _OpenStudio::PointLatLon_ indicating the
|
128
|
+
# origin's latitude and longitude.
|
129
|
+
# * +runner+ - _Type:String_ - The measure run's instance of _OpenStudio::Measure::OSRunner_ .
|
130
|
+
# * +spaces+ -_Type:Array_ - Instances of _OpenStudio::Model::Space_ .
|
131
|
+
def self.create_shading_surfaces(feature, model, origin_lat_lon, runner, spaces)
|
132
|
+
max_z = 0
|
133
|
+
spaces.each do |space|
|
134
|
+
bb = space.boundingBox
|
135
|
+
max_z = [max_z, bb.maxZ.get].max
|
136
|
+
end
|
137
|
+
return create_photovoltaics(feature, max_z + 1, model, origin_lat_lon, runner)
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# This method loops through all the stories in the model, and returns any space
|
142
|
+
# types previously assigned.
|
143
|
+
#
|
144
|
+
# Returns array of +OpenStudio::Model::SpaceTypes+ .
|
145
|
+
#
|
146
|
+
# Used to create space types for each building story.
|
147
|
+
#
|
148
|
+
# [Parameters]
|
149
|
+
# * +stories+ - _Type:Array_ - An array of model/building stories.
|
150
|
+
# * +model+ - _Type:String_ - An instance of _OpenStudio::Model::Model_ .
|
151
|
+
# * +runner+ - _Type:String_ - The measure run's instance of _OpenStudio::Measure::OSRunner_ .
|
152
|
+
def self.create_space_types(stories, model, runner)
|
153
|
+
space_types = []
|
154
|
+
stories.each_index do |i|
|
155
|
+
space_type = nil
|
156
|
+
space = stories[i].spaces.first
|
157
|
+
if space && space.spaceType.is_initialized
|
158
|
+
space_type = space.spaceType.get
|
159
|
+
else
|
160
|
+
space_type = OpenStudio::Model::SpaceType.new(model)
|
161
|
+
runner.registerInfo("Story #{i} does not have a space type, creating new one")
|
162
|
+
end
|
163
|
+
space_types[i] = space_type
|
164
|
+
end
|
165
|
+
return space_types
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Returns an +OpenStudio::Point3dVector+ .
|
170
|
+
#
|
171
|
+
# Creates the floor print for a given polygon.
|
172
|
+
#
|
173
|
+
# [Parameters]
|
174
|
+
# * +polygon+ - _Type:Array_ - An array of coordinate pairs.
|
175
|
+
# e.g.
|
176
|
+
# polygon = [
|
177
|
+
# [1, 5],
|
178
|
+
# [5, 5],
|
179
|
+
# [5, 1],
|
180
|
+
# ]
|
181
|
+
#
|
182
|
+
# * +elevation+ - _Type:Integer_ - Indicates the elevation.
|
183
|
+
# * +origin_lat_lon+ - _Type:Float_ - An instance of +OpenStudio::PointLatLon+ indicating the origin's latitude and longitude.
|
184
|
+
# * +runner+ - _Type:String_ - The measure run's instance of +OpenStudio::Measure::OSRunner+ .
|
185
|
+
# * +zoning+ - _Type:Boolean_ - Value is +True+ if utilizing detailed zoning, else +False+. Zoning is set to False by default.
|
186
|
+
def self.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning = false)
|
187
|
+
floor_print = OpenStudio::Point3dVector.new
|
188
|
+
all_points = OpenStudio::Point3dVector.new
|
189
|
+
polygon.each do |p|
|
190
|
+
lon = p[0]
|
191
|
+
lat = p[1]
|
192
|
+
point_3d = origin_lat_lon.toLocalCartesian(OpenStudio::PointLatLon.new(lat, lon, 0))
|
193
|
+
point_3d = OpenStudio::Point3d.new(point_3d.x, point_3d.y, elevation)
|
194
|
+
curr_print = zoning ? OpenStudio.getCombinedPoint(point_3d, all_points, 1.0) : point_3d
|
195
|
+
floor_print << curr_print
|
196
|
+
end
|
197
|
+
if floor_print.size < 3
|
198
|
+
runner.registerWarning('Cannot create floor print, fewer than 3 points')
|
199
|
+
return nil
|
200
|
+
end
|
201
|
+
floor_print = OpenStudio.removeCollinear(floor_print)
|
202
|
+
normal = OpenStudio.getOutwardNormal(floor_print)
|
203
|
+
if normal.empty?
|
204
|
+
runner.registerWarning('Cannot create floor print, cannot compute outward normal')
|
205
|
+
return nil
|
206
|
+
elsif normal.get.z > 0
|
207
|
+
floor_print = OpenStudio.reverse(floor_print)
|
208
|
+
runner.registerWarning('Reversing floor print')
|
209
|
+
end
|
210
|
+
return floor_print
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# Calculate which other buildings are shading the current feature and return as an array of
|
215
|
+
# +OpenStudio::Model::Space+.
|
216
|
+
#
|
217
|
+
# [Parameters]
|
218
|
+
# * +building+ - _Type:URBANopt::GeoJSON::Building_ - The core building that other buildings will be referenced.
|
219
|
+
# * +other_building_type+ - _Type:String_ - Describes the surrounding buildings. Currently 'ShadingOnly' is the only option that is processed.
|
220
|
+
# * +other_buildings+ - _Type:URBANopt::GeoJSON::FeatureCollection_ - List of surrounding buildings to include (self will be ignored if present in list).
|
221
|
+
# * +model+ - _Type:OpenStudio::Model::Model_ - An instance of an OpenStudio Model.
|
222
|
+
# * +origin_lat_lon+ - _Type:Float_ - An instance of +OpenStudio::PointLatLon+ indicating the latitude and longitude of the origin.
|
223
|
+
# * +runner+ - _Type:String_ - An instance of +Openstudio::Measure::OSRunner+ for the measure run.
|
224
|
+
# * +zoning+ - _Type:Boolean_ - Value is +true+ if utilizing detailed zoning, else
|
225
|
+
# +false+. Zoning is set to false by default. Currently, zoning set to +false+ is
|
226
|
+
# only supported.
|
227
|
+
def self.process_other_buildings(building, other_building_type, other_buildings, model, origin_lat_lon, runner, zoning = false)
|
228
|
+
# Empty array to store the new OpenStudio model spaces that need to be converted to shading objects
|
229
|
+
feature_points = building.feature_points(origin_lat_lon, runner, zoning)
|
230
|
+
|
231
|
+
other_spaces = []
|
232
|
+
runner.registerInfo("#{other_buildings[:features].size} nearby buildings found")
|
233
|
+
other_buildings[:features].each do |other_building|
|
234
|
+
other_id = other_building[:properties][:id]
|
235
|
+
next if other_id == building.id
|
236
|
+
if other_building_type == 'ShadingOnly'
|
237
|
+
# Checks if any building point is shaded by any other building point.
|
238
|
+
roof_elevation = other_building[:properties][:roof_elevation]
|
239
|
+
number_of_stories = other_building[:properties][:number_of_stories]
|
240
|
+
number_of_stories_above_ground = other_building[:properties][:number_of_stories_above_ground]
|
241
|
+
maximum_roof_height = other_building[:properties][:maximum_roof_height]
|
242
|
+
|
243
|
+
if number_of_stories_above_ground.nil?
|
244
|
+
number_of_stories_above_ground = number_of_stories
|
245
|
+
number_of_stories_below_ground = 0
|
246
|
+
else
|
247
|
+
number_of_stories_below_ground = number_of_stories - number_of_stories_above_ground
|
248
|
+
end
|
249
|
+
|
250
|
+
floor_to_floor_height = 3
|
251
|
+
if number_of_stories_above_ground && number_of_stories_above_ground > 0 && maximum_roof_height
|
252
|
+
floor_to_floor_height = maximum_roof_height / number_of_stories_above_ground
|
253
|
+
end
|
254
|
+
other_height = number_of_stories_above_ground * floor_to_floor_height
|
255
|
+
# find the polygon of the other_building by passing it to the get_multi_polygons method
|
256
|
+
other_building_points = building.other_points(other_building, other_height, origin_lat_lon, runner, zoning)
|
257
|
+
shadowed = URBANopt::GeoJSON::Helper.is_shadowed(feature_points, other_building_points, origin_lat_lon)
|
258
|
+
next unless shadowed
|
259
|
+
end
|
260
|
+
|
261
|
+
new_building = building.create_other_building(:space_per_building, model, origin_lat_lon, runner, zoning, other_building)
|
262
|
+
if new_building.nil? || new_building.empty?
|
263
|
+
runner.registerWarning("Failed to create spaces for other building '#{name}'")
|
264
|
+
end
|
265
|
+
other_spaces.concat(new_building)
|
266
|
+
end
|
267
|
+
return other_spaces
|
268
|
+
end
|
269
|
+
|
270
|
+
##
|
271
|
+
# Returns Boolean which indicates whether the specified building is shadowed by
|
272
|
+
# other building.
|
273
|
+
#
|
274
|
+
# [Parameters]
|
275
|
+
# * +potentially_shaded+ - _Type:Array_ - An array of instances of +OpenStudio::Point3d+ .
|
276
|
+
# * +potential_shader+ - _Type:Array_ - Other array of instances of +OpenStudio::Point3d+ .
|
277
|
+
# * +origin_lat_lon+ _Type:Float_ - An instance of OpenStudio::PointLatLon indicating the origin's
|
278
|
+
# latitude and longitude.
|
279
|
+
def self.is_shadowed(potentially_shaded, potential_shader, origin_lat_lon)
|
280
|
+
all_pairs = []
|
281
|
+
potentially_shaded.each do |building_point|
|
282
|
+
potential_shader.each do |other_building_point|
|
283
|
+
vector = other_building_point - building_point
|
284
|
+
all_pairs << {
|
285
|
+
building_point: building_point,
|
286
|
+
other_building_point: other_building_point,
|
287
|
+
vector: vector,
|
288
|
+
distance: vector.length
|
289
|
+
}
|
290
|
+
end
|
291
|
+
end
|
292
|
+
all_pairs.sort! { |x, y| x[:distance] <=> y[:distance] }
|
293
|
+
all_pairs.each do |pair|
|
294
|
+
if is_shaded(pair[:building_point], pair[:other_building_point], origin_lat_lon)
|
295
|
+
return true
|
296
|
+
end
|
297
|
+
end
|
298
|
+
return false
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# Returns Boolean indicating if specified building is shadowed.
|
303
|
+
#
|
304
|
+
# [Parameters]
|
305
|
+
# * +building_point+ - _Type:Float_ - An instance of +OpenStudio::Point3d+ .
|
306
|
+
# * +other_building_point+ - _Type:Float_ - Other instance of +OpenStudio::Point3d+ .
|
307
|
+
# * +origin_lat_lon+ - _Type:Float_ - An instance of +OpenStudio::PointLatLon+ indicating the
|
308
|
+
# origin's latitude and longitude.
|
309
|
+
def self.is_shaded(building_point, other_building_point, origin_lat_lon)
|
310
|
+
vector = other_building_point - building_point
|
311
|
+
height = vector.z
|
312
|
+
distance = Math.sqrt(vector.x * vector.x + vector.y * vector.y)
|
313
|
+
if distance < 1
|
314
|
+
return true
|
315
|
+
end
|
316
|
+
hour_angle_rad = Math.atan2(-vector.x, -vector.y)
|
317
|
+
hour_angle = OpenStudio.radToDeg(hour_angle_rad)
|
318
|
+
latitude_rad = OpenStudio.degToRad(origin_lat_lon.lat)
|
319
|
+
result = false
|
320
|
+
(-24..24).each do |declination|
|
321
|
+
declination_rad = OpenStudio.degToRad(declination)
|
322
|
+
zenith_angle_rad = Math.acos(Math.sin(latitude_rad) * Math.sin(declination_rad) + Math.cos(latitude_rad) * Math.cos(declination_rad) * Math.cos(hour_angle_rad))
|
323
|
+
zenith_angle = OpenStudio.radToDeg(zenith_angle_rad)
|
324
|
+
elevation_angle = 90 - zenith_angle
|
325
|
+
apparent_angle_rad = Math.atan2(height, distance)
|
326
|
+
apparent_angle = OpenStudio.radToDeg(apparent_angle_rad)
|
327
|
+
if elevation_angle > 0 && elevation_angle < apparent_angle
|
328
|
+
result = true
|
329
|
+
break
|
330
|
+
end
|
331
|
+
end
|
332
|
+
return result
|
333
|
+
end
|
334
|
+
|
335
|
+
class << self
|
336
|
+
private :is_shaded
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'logger'
|
32
|
+
|
33
|
+
module URBANopt
|
34
|
+
module GeoJSON
|
35
|
+
@@logger = Logger.new(STDERR)
|
36
|
+
@@logger.progname = 'URBANopt::GeoJSON'
|
37
|
+
|
38
|
+
def self.logger
|
39
|
+
@@logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.setLogger(l)
|
43
|
+
@@logger = l
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# *********************************************************************************
|
2
|
+
# URBANopt, Copyright (c) 2019, Alliance for Sustainable Energy, LLC, and other
|
3
|
+
# contributors. All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# Redistributions of source code must retain the above copyright notice, this list
|
9
|
+
# of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# Redistributions in binary form must reproduce the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer in the documentation and/or other
|
13
|
+
# materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# Neither the name of the copyright holder nor the names of its contributors may be
|
16
|
+
# used to endorse or promote products derived from this software without specific
|
17
|
+
# prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
22
|
+
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
23
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
24
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
26
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
27
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
28
|
+
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
# *********************************************************************************
|
30
|
+
|
31
|
+
require 'urbanopt/scenario'
|
32
|
+
require 'json'
|
33
|
+
|
34
|
+
module URBANopt
|
35
|
+
module GeoJSON
|
36
|
+
class Mapper < MapperBase
|
37
|
+
@@instance_lock = Mutex.new
|
38
|
+
@@osw = nil
|
39
|
+
|
40
|
+
##
|
41
|
+
# This class inherits from the +MapperBase+ .
|
42
|
+
# Used to perform initializing functions, used to define the osw_path for
|
43
|
+
# baseline.osw for the URBANopt GeoJSON example project and the weather file.
|
44
|
+
|
45
|
+
def initialize()
|
46
|
+
@@instance_lock.synchronize do
|
47
|
+
if @@osw.nil?
|
48
|
+
osw_path = File.join(File.dirname(__FILE__), 'baseline.osw')
|
49
|
+
File.open(osw_path, 'r') do |file|
|
50
|
+
@@osw = JSON.parse(file.read, symbolize_names: true)
|
51
|
+
end
|
52
|
+
@@osw[:file_paths] << File.join(File.dirname(__FILE__), '../weather/')
|
53
|
+
@@osw = OpenStudio::Extension.configure_osw(@@osw)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Creates an OpenStudio Workflow file for a given ScenarioBase object,
|
59
|
+
# feature id and feature name.
|
60
|
+
#
|
61
|
+
# [Parameters]
|
62
|
+
# * +scenario+ - _Type:String_ - Used to define the Scenario for the osw.
|
63
|
+
|
64
|
+
# * +feature_id+ - _Type:String/Number_ - Used to define the feature_id for
|
65
|
+
# which the osw is implemented.
|
66
|
+
#
|
67
|
+
# * +feature_name+ - _Type:String_ - The name of the feature.
|
68
|
+
def create_osw(scenario, feature_id, feature_name)
|
69
|
+
# get the feature from the scenario's feature_file #:nodoc:
|
70
|
+
feature_file = scenario.feature_file
|
71
|
+
feature = feature_file.get_feature_by_id(feature_id)
|
72
|
+
|
73
|
+
raise "Cannot find feature '#{feature_id}' in '#{scenario.geometry_file}'" if feature.nil?
|
74
|
+
|
75
|
+
# deep clone of @@osw before we configure it #:nodoc:
|
76
|
+
osw = Marshal.load(Marshal.dump(@@osw))
|
77
|
+
|
78
|
+
osw[:name] = feature_name
|
79
|
+
osw[:description] = feature_name
|
80
|
+
|
81
|
+
return osw
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|