Module: URBANopt::GeoJSON::Helper
- Defined in:
- lib/urbanopt/geojson/helper.rb
Class Method Summary collapse
-
.adjust_vertices_to_area(vertices, desired_area, runner, eps = 0.1) ⇒ Object
Used to scale footprint to desired area while keeping the original shape.
-
.convert_to_shading_surface_group(space) ⇒ Object
This method loops though all the surfaces of the space and creates shading surfaces.
-
.create_photovoltaics(feature, height, model, origin_lat_lon, runner) ⇒ Object
Returns array containing instance of
OpenStudio::Model::ShadingSurface. -
.create_shading_surfaces(feature, model, origin_lat_lon, runner, spaces) ⇒ Object
Returns array containing instance of
OpenStudio::Model::ShadingSurface. -
.create_space_types(stories, model, runner) ⇒ Object
This method loops through all the stories in the model, and returns any space types previously assigned.
-
.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning = false, scaled_footprint_area = 0) ⇒ Object
Returns an
OpenStudio::Point3dVector. -
.is_shaded(building_point, other_building_point, origin_lat_lon) ⇒ Object
Returns Boolean indicating if specified building is shadowed.
-
.is_shadowed(potentially_shaded, potential_shader, origin_lat_lon) ⇒ Object
Returns Boolean which indicates whether the specified building is shadowed by other building.
-
.process_other_buildings(building, other_building_type, other_buildings, model, origin_lat_lon, runner, zoning = false) ⇒ Object
Calculate which other buildings are shading the current feature and return as an array of
OpenStudio::Model::Space.
Class Method Details
.adjust_vertices_to_area(vertices, desired_area, runner, eps = 0.1) ⇒ Object
Used to scale footprint to desired area while keeping the original shape.
- Parameters
-
vertices- Type:Array - An array of vertices for the original floorprint -
desired_area- Type:String - Area to which you want to scale the vertices to -
runner- Type:String - An instance ofOpenstudio::Measure::OSRunnerfor the measure run.
215 216 217 218 219 220 221 |
# File 'lib/urbanopt/geojson/helper.rb', line 215 def self.adjust_vertices_to_area(vertices, desired_area, runner, eps = 0.1) ar = ScaleArea.new(vertices, desired_area, runner, eps) n = Newton.nlsolve(ar, [0]) return ar.new_vertices end |
.convert_to_shading_surface_group(space) ⇒ Object
This method loops though all the surfaces of the space and creates shading surfaces. It also removes the thermal zone and space type assigned to the space, if any.
Returns an Array of instances of OpenStudio::Model::ShadingSurfaceGroup .
Used to convert adjacent buildings to shading surfaces.
- Parameters
-
space- Type:String - An instance ofOpenStudio::Model::Space.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/urbanopt/geojson/helper.rb', line 19 def self.convert_to_shading_surface_group(space) name = space.name.to_s model = space.model shading_group = OpenStudio::Model::ShadingSurfaceGroup.new(model) space.surfaces.each do |surface| shading_surface = OpenStudio::Model::ShadingSurface.new(surface.vertices, model) shading_surface.setShadingSurfaceGroup(shading_group) end thermal_zone = space.thermalZone if !thermal_zone.empty? thermal_zone.get.remove end space_type = space.spaceType space.remove if !space_type.empty? && space_type.get.spaces.empty? space_type.get.remove end shading_group.setName(name) return [shading_group] end |
.create_photovoltaics(feature, height, model, origin_lat_lon, runner) ⇒ Object
Returns array containing instance of OpenStudio::Model::ShadingSurface .
Used to create Photovoltaics and assign efficiency.
- Parameters
-
feature- Type:String - An instance of Feature class. -
height- Type:Integer - Indicates the building height. -
model- Type:String - An instance ofOpenStudio::Model::Model. -
origin_lat_lon- Type:Float - An instance ofOpenStudio::PointLatLonindicating the origin’s latitude & longitude. -
runner- Type:String - An instance ofOpenstudio::Measure::OSRunnerfor the measure run.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/urbanopt/geojson/helper.rb', line 52 def self.create_photovoltaics(feature, height, model, origin_lat_lon, runner) feature_id = feature.feature_json[:properties][:properties] name = feature.name floor_prints = [] multi_polygons = feature.get_multi_polygons multi_polygons.each do |multi_polygon| if multi_polygon.size > 1 runner.registerWarning('Ignoring holes in polygon') end multi_polygon.each do |polygon| floor_print = floor_print_from_polygon(polygon, height, origin_lat_lon, runner) if floor_print floor_prints << OpenStudio.reverse(floor_print) else runner.registerWarning("Cannot create footprint for '#{name}'") end break end end shading_surfaces = [] floor_prints.each do |floor_print| shading_group = OpenStudio::Model::ShadingSurfaceGroup.new(model) shading_surface = OpenStudio::Model::ShadingSurface.new(floor_print, model) shading_surface.setShadingSurfaceGroup(shading_group) shading_surface.setName('Photovoltaic Panel') shading_surfaces << shading_surface end # create the inverter # :nodoc: inverter = OpenStudio::Model::ElectricLoadCenterInverterSimple.new(model) inverter.setInverterEfficiency(0.95) # create the distribution system # :nodoc: elcd = OpenStudio::Model::ElectricLoadCenterDistribution.new(model) elcd.setInverter(inverter) shading_surfaces.each do |shading_surface| panel = OpenStudio::Model::GeneratorPhotovoltaic.simple(model) panel.setSurface(shading_surface) performance = panel.photovoltaicPerformance.to_PhotovoltaicPerformanceSimple.get performance.setFractionOfSurfaceAreaWithActiveSolarCells(1.0) performance.setFixedEfficiency(0.3) elcd.addGenerator(panel) end return shading_surfaces end |
.create_shading_surfaces(feature, model, origin_lat_lon, runner, spaces) ⇒ Object
Returns array containing instance of OpenStudio::Model::ShadingSurface .
- Parameters
-
feature- Type:String - An instance of Feature class. -
model- Type:String - An instance of OpenStudio::Model::Model . -
origin_lat_lon- Type:Float - An instance of OpenStudio::PointLatLon indicating the origin’s latitude and longitude. -
runner- Type:String - The measure run’s instance of OpenStudio::Measure::OSRunner . -
spaces-Type:Array - Instances of OpenStudio::Model::Space .
106 107 108 109 110 111 112 113 |
# File 'lib/urbanopt/geojson/helper.rb', line 106 def self.create_shading_surfaces(feature, model, origin_lat_lon, runner, spaces) max_z = 0 spaces.each do |space| bb = space.boundingBox max_z = [max_z, bb.maxZ.get].max end return create_photovoltaics(feature, max_z + 1, model, origin_lat_lon, runner) end |
.create_space_types(stories, model, runner) ⇒ Object
This method loops through all the stories in the model, and returns any space types previously assigned.
Returns array of OpenStudio::Model::SpaceTypes .
Used to create space types for each building story.
- Parameters
-
stories- Type:Array - An array of model/building stories. -
model- Type:String - An instance of OpenStudio::Model::Model . -
runner- Type:String - The measure run’s instance of OpenStudio::Measure::OSRunner .
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/urbanopt/geojson/helper.rb', line 127 def self.create_space_types(stories, model, runner) space_types = [] stories.each_index do |i| space_type = nil space = stories[i].spaces.first if space&.spaceType&.is_initialized space_type = space.spaceType.get else space_type = OpenStudio::Model::SpaceType.new(model) runner.registerInfo("Story #{i} does not have a space type, creating new one") end space_types[i] = space_type end return space_types end |
.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning = false, scaled_footprint_area = 0) ⇒ Object
Returns an OpenStudio::Point3dVector .
Creates the floor print for a given polygon.
- Parameters
-
polygon- Type:Array - An array of coordinate pairs.
e.g.
polygon = [
[1, 5],
[5, 5],
[5, 1],
]
-
elevation- Type:Integer - Indicates the elevation. -
origin_lat_lon- Type:Float - An instance ofOpenStudio::PointLatLonindicating the origin’s latitude and longitude. -
runner- Type:String - The measure run’s instance ofOpenStudio::Measure::OSRunner. -
zoning- Type:Boolean - Value isTrueif utilizing detailed zoning, elseFalse. Zoning is set to False by default. -
scaled_footprint_area- Used to scale the footprint area using the floor area. 0 by default (no scaling).
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/urbanopt/geojson/helper.rb', line 163 def self.floor_print_from_polygon(polygon, elevation, origin_lat_lon, runner, zoning = false, scaled_footprint_area = 0) floor_print = OpenStudio::Point3dVector.new all_points = OpenStudio::Point3dVector.new polygon.each do |p| lon = p[0] lat = p[1] point_3d = origin_lat_lon.toLocalCartesian(OpenStudio::PointLatLon.new(lat, lon, 0)) point_3d = OpenStudio::Point3d.new(point_3d.x, point_3d.y, elevation) curr_print = zoning ? OpenStudio.getCombinedPoint(point_3d, all_points, 1.0) : point_3d floor_print << curr_print end if floor_print.size < 3 runner.registerWarning('Cannot create floor print, fewer than 3 points') return nil end floor_print = OpenStudio.removeCollinear(floor_print) normal = OpenStudio.getOutwardNormal(floor_print) if normal.empty? runner.registerWarning('Cannot create floor print, cannot compute outward normal') return nil elsif normal.get.z > 0 floor_print = OpenStudio.reverse(floor_print) runner.registerWarning('Reversing floor print') end # check for scaling if scaled_footprint_area > 0 # check that the scaled_footprint_area desired is no less than X % of the original original_floor_print_area = OpenStudio.getArea(floor_print).get if scaled_footprint_area / original_floor_print_area <= 0.5 || scaled_footprint_area / original_floor_print_area >= 2 # TOO MUCH SCALING...using original footprint when scaled is 2x bigger or smaller than the original runner.registerWarning('Desired scaled_footprint_area is a factor of 2 of the original footprint...keeping original footprint (no scaling!)') else new_floor_print = adjust_vertices_to_area(floor_print, scaled_footprint_area, runner) new_footprint_area = OpenStudio.getArea(new_floor_print).get runner.registerInfo("New floor area: #{new_footprint_area}, compared to scaled area desired: #{scaled_footprint_area}") floor_print = new_floor_print end end return floor_print end |
.is_shaded(building_point, other_building_point, origin_lat_lon) ⇒ Object
Returns Boolean indicating if specified building is shadowed.
- Parameters
-
building_point- Type:Float - An instance ofOpenStudio::Point3d. -
other_building_point- Type:Float - Other instance ofOpenStudio::Point3d. -
origin_lat_lon- Type:Float - An instance ofOpenStudio::PointLatLonindicating the origin’s latitude and longitude.
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/urbanopt/geojson/helper.rb', line 335 def self.is_shaded(building_point, other_building_point, origin_lat_lon) # not using origin_lat_lon but have not removed it yet vector = other_building_point - building_point distance = Math.sqrt(vector.x * vector.x + vector.y * vector.y) if distance < 1 return true end elevation_angle = 2.5 #not sure of best value maybe allow as project level argument height = vector.z apparent_angle_rad = Math.atan2(height, distance) apparent_angle = OpenStudio.radToDeg(apparent_angle_rad) if elevation_angle < apparent_angle result = true else result = false end return result end |
.is_shadowed(potentially_shaded, potential_shader, origin_lat_lon) ⇒ Object
Returns Boolean which indicates whether the specified building is shadowed by other building.
- Parameters
-
potentially_shaded- Type:Array - An array of instances ofOpenStudio::Point3d. -
potential_shader- Type:Array - Other array of instances ofOpenStudio::Point3d. -
origin_lat_lonType:Float - An instance of OpenStudio::PointLatLon indicating the origin’s latitude and longitude.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/urbanopt/geojson/helper.rb', line 301 def self.is_shadowed(potentially_shaded, potential_shader, origin_lat_lon) # not using origin_lat_lon but have not removed it yet min_distance = nil min_pair = nil potentially_shaded.each do |building_point| potential_shader.each do |other_building_point| vector = other_building_point - building_point distance = Math.sqrt(vector.x * vector.x + vector.y * vector.y) if min_distance.nil? || distance < min_distance min_distance = distance min_pair = { building_point: building_point, other_building_point: other_building_point, vector: vector, distance: vector.length } end end end if is_shaded(min_pair[:building_point], min_pair[:other_building_point], origin_lat_lon) return true end return false end |
.process_other_buildings(building, other_building_type, other_buildings, model, origin_lat_lon, runner, zoning = false) ⇒ Object
Calculate which other buildings are shading the current feature and return as an array of OpenStudio::Model::Space.
- Parameters
-
building- Type:URBANopt::GeoJSON::Building - The core building that other buildings will be referenced. -
other_building_type- Type:String - Describes the surrounding buildings. -
other_buildings- Type:URBANopt::GeoJSON::FeatureCollection - List of surrounding buildings to include (self will be ignored if present in list). -
model- Type:OpenStudio::Model::Model - An instance of an OpenStudio Model. -
origin_lat_lon- Type:Float - An instance ofOpenStudio::PointLatLonindicating the latitude and longitude of the origin. -
runner- Type:String - An instance ofOpenstudio::Measure::OSRunnerfor the measure run. -
zoning- Type:Boolean - Value istrueif utilizing detailed zoning, elsefalse. Zoning is set to false by default.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/urbanopt/geojson/helper.rb', line 236 def self.process_other_buildings(building, other_building_type, other_buildings, model, origin_lat_lon, runner, zoning = false) # Empty array to store the new OpenStudio model spaces that need to be converted to shading objects feature_points = building.feature_points(origin_lat_lon, runner, zoning) other_spaces = [] runner.registerInfo("#{other_buildings[:features].size} nearby buildings found") other_buildings[:features].each do |other_building| other_id = other_building[:properties][:id] next if other_id == building.id # Consider building, if other building type is ShadingOnly and other id is not equal to building id if other_building_type == 'ShadingOnly' && other_id != building.id # Checks if any building point is shaded by any other building point. roof_elevation = other_building[:properties][:roof_elevation] number_of_stories = other_building[:properties][:number_of_stories] number_of_stories_above_ground = other_building[:properties][:number_of_stories_above_ground] maximum_roof_height = other_building[:properties][:maximum_roof_height] if number_of_stories_above_ground.nil? number_of_stories_above_ground = number_of_stories number_of_stories_below_ground = 0 else number_of_stories_below_ground = number_of_stories - number_of_stories_above_ground end floor_to_floor_height = 3 if number_of_stories_above_ground && number_of_stories_above_ground > 0 && maximum_roof_height floor_to_floor_height = maximum_roof_height / number_of_stories_above_ground end # check that feature has a # stories if number_of_stories_above_ground.nil? runner.registerWarning("[geojson process_other_buildings] Unable to include feature #{other_building[:properties][:id]} in shading calculations: no 'number of stories' data") end next if number_of_stories_above_ground.nil? other_height = number_of_stories_above_ground * floor_to_floor_height # find the polygon of the other_building by passing it to the get_multi_polygons method other_building_points = building.other_points(other_building, other_height, origin_lat_lon, runner, zoning) shadowed = URBANopt::GeoJSON::Helper.is_shadowed(feature_points, other_building_points, origin_lat_lon) if shadowed runner.registerInfo("Feature #{other_building[:properties][:id]} is acting as shading object for #{building.id}") end next unless shadowed new_building = building.create_other_building(:space_per_building, model, origin_lat_lon, runner, zoning, 0, other_building) if new_building.nil? || new_building.empty? runner.registerWarning("Failed to create spaces for other building '#{name}'") end other_spaces.concat(new_building) elsif other_building_type == 'None' end end return other_spaces end |