lib/openstudio-standards/btap/geometry.rb in openstudio-standards-0.2.9 vs lib/openstudio-standards/btap/geometry.rb in openstudio-standards-0.2.10.rc1

- old
+ new

@@ -135,17 +135,17 @@ end module Wizards def self.create_shape_courtyard(model, - length = 50, - width = 30, - courtyard_length = 15, - courtyard_width = 5, + length = 50.0, + width = 30.0, + courtyard_length = 15.0, + courtyard_width = 5.0, num_floors = 3, floor_to_floor_height = 3.8, - plenum_height = 1, + plenum_height = 1.0, perimeter_zone_depth = 4.57) if length <= 1e-4 raise("Length must be greater than 0.") return false end @@ -179,64 +179,64 @@ raise("Plenum height must be greater than or equal to 0.") return false end shortest_side = [length, width].min - if perimeter_zone_depth < 0 or 4*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/4}m.") + if perimeter_zone_depth < 0 or 4 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 4.0}m.") return false end - if courtyard_length >= (length - 4*perimeter_zone_depth - 1e-4) - raise("Courtyard length must be less than #{length - 4*perimeter_zone_depth}m.") + if courtyard_length >= (length - 4 * perimeter_zone_depth - 1e-4) + raise("Courtyard length must be less than #{length - 4.0 * perimeter_zone_depth}m.") return false end - if courtyard_width >= (width - 4*perimeter_zone_depth - 1e-4) - raise("Courtyard width must be less than #{width - 4*perimeter_zone_depth}m.") + if courtyard_width >= (width - 4 * perimeter_zone_depth - 1e-4) + raise("Courtyard width must be less than #{width - 4.0 * perimeter_zone_depth}m.") return false end # Loop through the number of floors - for floor in (0..num_floors-1) + for floor in (0..num_floors - 1) z = floor_to_floor_height * floor #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") - nw_point = OpenStudio::Point3d.new(0, width, z) + nw_point = OpenStudio::Point3d.new(0.0, width, z) ne_point = OpenStudio::Point3d.new(length, width, z) - se_point = OpenStudio::Point3d.new(length, 0, z) - sw_point = OpenStudio::Point3d.new(0, 0, z) + se_point = OpenStudio::Point3d.new(length, 0.0, z) + sw_point = OpenStudio::Point3d.new(0.0, 0.0, z) - courtyard_nw_point = OpenStudio::Point3d.new((length-courtyard_length)/2, (width-courtyard_width)/2+courtyard_width, z) - courtyard_ne_point = OpenStudio::Point3d.new((length-courtyard_length)/2+courtyard_length, (width-courtyard_width)/2+courtyard_width, z) - courtyard_se_point = OpenStudio::Point3d.new((length-courtyard_length)/2+courtyard_length, (width-courtyard_width)/2, z) - courtyard_sw_point = OpenStudio::Point3d.new((length-courtyard_length)/2, (width-courtyard_width)/2, z) + courtyard_nw_point = OpenStudio::Point3d.new((length - courtyard_length) / 2.0, (width - courtyard_width) / 2.0 + courtyard_width, z) + courtyard_ne_point = OpenStudio::Point3d.new((length - courtyard_length) / 2.0 + courtyard_length, (width - courtyard_width) / 2.0 + courtyard_width, z) + courtyard_se_point = OpenStudio::Point3d.new((length - courtyard_length) / 2.0 + courtyard_length, (width - courtyard_width) / 2.0, z) + courtyard_sw_point = OpenStudio::Point3d.new((length - courtyard_length) / 2.0, (width - courtyard_width) / 2.0, z) # Identity matrix for setting space origins - m = OpenStudio::Matrix.new(4, 4, 0) - m[0, 0] = 1 - m[1, 1] = 1 - m[2, 2] = 1 - m[3, 3] = 1 + m = OpenStudio::Matrix.new(4, 4, 0.0) + m[0, 0] = 1.0 + m[1, 1] = 1.0 + m[2, 2] = 1.0 + m[3, 3] = 1.0 # Define polygons for a building with a courtyard if perimeter_zone_depth > 0 - outer_perimeter_nw_point = nw_point + OpenStudio::Vector3d.new(perimeter_zone_depth, -perimeter_zone_depth, 0) - outer_perimeter_ne_point = ne_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, -perimeter_zone_depth, 0) - outer_perimeter_se_point = se_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, perimeter_zone_depth, 0) - outer_perimeter_sw_point = sw_point + OpenStudio::Vector3d.new(perimeter_zone_depth, perimeter_zone_depth, 0) - inner_perimeter_nw_point = courtyard_nw_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, perimeter_zone_depth, 0) - inner_perimeter_ne_point = courtyard_ne_point + OpenStudio::Vector3d.new(perimeter_zone_depth, perimeter_zone_depth, 0) - inner_perimeter_se_point = courtyard_se_point + OpenStudio::Vector3d.new(perimeter_zone_depth, -perimeter_zone_depth, 0) - inner_perimeter_sw_point = courtyard_sw_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, -perimeter_zone_depth, 0) + outer_perimeter_nw_point = nw_point + OpenStudio::Vector3d.new(perimeter_zone_depth, -perimeter_zone_depth, 0.0) + outer_perimeter_ne_point = ne_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, -perimeter_zone_depth, 0.0) + outer_perimeter_se_point = se_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, perimeter_zone_depth, 0.0) + outer_perimeter_sw_point = sw_point + OpenStudio::Vector3d.new(perimeter_zone_depth, perimeter_zone_depth, 0.0) + inner_perimeter_nw_point = courtyard_nw_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, perimeter_zone_depth, 0.0) + inner_perimeter_ne_point = courtyard_ne_point + OpenStudio::Vector3d.new(perimeter_zone_depth, perimeter_zone_depth, 0.0) + inner_perimeter_se_point = courtyard_se_point + OpenStudio::Vector3d.new(perimeter_zone_depth, -perimeter_zone_depth, 0.0) + inner_perimeter_sw_point = courtyard_sw_point + OpenStudio::Vector3d.new(-perimeter_zone_depth, -perimeter_zone_depth, 0.0) west_outer_perimeter_polygon = OpenStudio::Point3dVector.new west_outer_perimeter_polygon << sw_point west_outer_perimeter_polygon << nw_point west_outer_perimeter_polygon << outer_perimeter_nw_point @@ -246,11 +246,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z west_outer_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_outer_perimeter_space.setBuildingStory(story) - west_outer_perimeter_space.setName("Story #{floor+1} West Outer Perimeter Space") + west_outer_perimeter_space.setName("Story #{floor + 1} West Outer Perimeter Space") north_outer_perimeter_polygon = OpenStudio::Point3dVector.new north_outer_perimeter_polygon << nw_point north_outer_perimeter_polygon << ne_point @@ -261,11 +261,11 @@ m[0, 3] = outer_perimeter_nw_point.x m[1, 3] = outer_perimeter_nw_point.y m[2, 3] = outer_perimeter_nw_point.z north_outer_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_outer_perimeter_space.setBuildingStory(story) - north_outer_perimeter_space.setName("Story #{floor+1} North Outer Perimeter Space") + north_outer_perimeter_space.setName("Story #{floor + 1} North Outer Perimeter Space") east_outer_perimeter_polygon = OpenStudio::Point3dVector.new east_outer_perimeter_polygon << ne_point east_outer_perimeter_polygon << se_point @@ -276,11 +276,11 @@ m[0, 3] = outer_perimeter_se_point.x m[1, 3] = outer_perimeter_se_point.y m[2, 3] = outer_perimeter_se_point.z east_outer_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_outer_perimeter_space.setBuildingStory(story) - east_outer_perimeter_space.setName("Story #{floor+1} East Outer Perimeter Space") + east_outer_perimeter_space.setName("Story #{floor + 1} East Outer Perimeter Space") south_outer_perimeter_polygon = OpenStudio::Point3dVector.new south_outer_perimeter_polygon << se_point south_outer_perimeter_polygon << sw_point @@ -291,11 +291,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z south_outer_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_outer_perimeter_space.setBuildingStory(story) - south_outer_perimeter_space.setName("Story #{floor+1} South Outer Perimeter Space") + south_outer_perimeter_space.setName("Story #{floor + 1} South Outer Perimeter Space") west_core_polygon = OpenStudio::Point3dVector.new west_core_polygon << outer_perimeter_sw_point west_core_polygon << outer_perimeter_nw_point @@ -306,11 +306,11 @@ m[0, 3] = outer_perimeter_sw_point.x m[1, 3] = outer_perimeter_sw_point.y m[2, 3] = outer_perimeter_sw_point.z west_core_space.changeTransformation(OpenStudio::Transformation.new(m)) west_core_space.setBuildingStory(story) - west_core_space.setName("Story #{floor+1} West Core Space") + west_core_space.setName("Story #{floor + 1} West Core Space") north_core_polygon = OpenStudio::Point3dVector.new north_core_polygon << outer_perimeter_nw_point north_core_polygon << outer_perimeter_ne_point @@ -321,11 +321,11 @@ m[0, 3] = inner_perimeter_nw_point.x m[1, 3] = inner_perimeter_nw_point.y m[2, 3] = inner_perimeter_nw_point.z north_core_space.changeTransformation(OpenStudio::Transformation.new(m)) north_core_space.setBuildingStory(story) - north_core_space.setName("Story #{floor+1} North Core Space") + north_core_space.setName("Story #{floor + 1} North Core Space") east_core_polygon = OpenStudio::Point3dVector.new east_core_polygon << outer_perimeter_ne_point east_core_polygon << outer_perimeter_se_point @@ -336,11 +336,11 @@ m[0, 3] = inner_perimeter_se_point.x m[1, 3] = inner_perimeter_se_point.y m[2, 3] = inner_perimeter_se_point.z east_core_space.changeTransformation(OpenStudio::Transformation.new(m)) east_core_space.setBuildingStory(story) - east_core_space.setName("Story #{floor+1} East Core Space") + east_core_space.setName("Story #{floor + 1} East Core Space") south_core_polygon = OpenStudio::Point3dVector.new south_core_polygon << outer_perimeter_se_point south_core_polygon << outer_perimeter_sw_point @@ -351,11 +351,11 @@ m[0, 3] = outer_perimeter_sw_point.x m[1, 3] = outer_perimeter_sw_point.y m[2, 3] = outer_perimeter_sw_point.z south_core_space.changeTransformation(OpenStudio::Transformation.new(m)) south_core_space.setBuildingStory(story) - south_core_space.setName("Story #{floor+1} South Core Space") + south_core_space.setName("Story #{floor + 1} South Core Space") west_inner_perimeter_polygon = OpenStudio::Point3dVector.new west_inner_perimeter_polygon << inner_perimeter_sw_point west_inner_perimeter_polygon << inner_perimeter_nw_point @@ -366,11 +366,11 @@ m[0, 3] = inner_perimeter_sw_point.x m[1, 3] = inner_perimeter_sw_point.y m[2, 3] = inner_perimeter_sw_point.z west_inner_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_inner_perimeter_space.setBuildingStory(story) - west_inner_perimeter_space.setName("Story #{floor+1} West Inner Perimeter Space") + west_inner_perimeter_space.setName("Story #{floor + 1} West Inner Perimeter Space") north_inner_perimeter_polygon = OpenStudio::Point3dVector.new north_inner_perimeter_polygon << inner_perimeter_nw_point north_inner_perimeter_polygon << inner_perimeter_ne_point @@ -381,11 +381,11 @@ m[0, 3] = courtyard_nw_point.x m[1, 3] = courtyard_nw_point.y m[2, 3] = courtyard_nw_point.z north_inner_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_inner_perimeter_space.setBuildingStory(story) - north_inner_perimeter_space.setName("Story #{floor+1} North Inner Perimeter Space") + north_inner_perimeter_space.setName("Story #{floor + 1} North Inner Perimeter Space") east_inner_perimeter_polygon = OpenStudio::Point3dVector.new east_inner_perimeter_polygon << inner_perimeter_ne_point east_inner_perimeter_polygon << inner_perimeter_se_point @@ -396,11 +396,11 @@ m[0, 3] = courtyard_se_point.x m[1, 3] = courtyard_se_point.y m[2, 3] = courtyard_se_point.z east_inner_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_inner_perimeter_space.setBuildingStory(story) - east_inner_perimeter_space.setName("Story #{floor+1} East Inner Perimeter Space") + east_inner_perimeter_space.setName("Story #{floor + 1} East Inner Perimeter Space") south_inner_perimeter_polygon = OpenStudio::Point3dVector.new south_inner_perimeter_polygon << inner_perimeter_se_point south_inner_perimeter_polygon << inner_perimeter_sw_point @@ -411,11 +411,11 @@ m[0, 3] = inner_perimeter_sw_point.x m[1, 3] = inner_perimeter_sw_point.y m[2, 3] = inner_perimeter_sw_point.z south_inner_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_inner_perimeter_space.setBuildingStory(story) - south_inner_perimeter_space.setName("Story #{floor+1} South Inner Perimeter Space") + south_inner_perimeter_space.setName("Story #{floor + 1} South Inner Perimeter Space") # Minimal zones else west_polygon = OpenStudio::Point3dVector.new @@ -428,11 +428,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z west_space.changeTransformation(OpenStudio::Transformation.new(m)) west_space.setBuildingStory(story) - west_space.setName("Story #{floor+1} West Space") + west_space.setName("Story #{floor + 1} West Space") north_polygon = OpenStudio::Point3dVector.new north_polygon << nw_point north_polygon << ne_point @@ -443,11 +443,11 @@ m[0, 3] = courtyard_nw_point.x m[1, 3] = courtyard_nw_point.y m[2, 3] = courtyard_nw_point.z north_space.changeTransformation(OpenStudio::Transformation.new(m)) north_space.setBuildingStory(story) - north_space.setName("Story #{floor+1} North Space") + north_space.setName("Story #{floor + 1} North Space") east_polygon = OpenStudio::Point3dVector.new east_polygon << ne_point east_polygon << se_point @@ -458,11 +458,11 @@ m[0, 3] = courtyard_se_point.x m[1, 3] = courtyard_se_point.y m[2, 3] = courtyard_se_point.z east_space.changeTransformation(OpenStudio::Transformation.new(m)) east_space.setBuildingStory(story) - east_space.setName("Story #{floor+1} East Space") + east_space.setName("Story #{floor + 1} East Space") south_polygon = OpenStudio::Point3dVector.new south_polygon << se_point south_polygon << sw_point @@ -473,11 +473,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z south_space.changeTransformation(OpenStudio::Transformation.new(m)) south_space.setBuildingStory(story) - south_space.setName("Story #{floor+1} South Space") + south_space.setName("Story #{floor + 1} South Space") end #Set vertical story position story.setNominalZCoordinate(z) end #End of floor loop BTAP::Geometry::match_surfaces(model) @@ -552,26 +552,26 @@ if plenum_height < 0 raise("Plenum height must be greater than or equal to 0.") return false end - shortest_side = [length/2, left_width, center_width, right_width, left_end_length, right_end_length].min - if perimeter_zone_depth < 0 or 2*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/2}m.") + shortest_side = [length / 2, left_width, center_width, right_width, left_end_length, right_end_length].min + if perimeter_zone_depth < 0 or 2 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 2}m.") return false end # Loop through the number of floors - for floor in (0..num_floors-1) + for floor in (0..num_floors - 1) z = floor_to_floor_height * floor #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") left_origin = (right_width - right_upper_end_offset) > (left_width - left_upper_end_offset) ? (right_width - right_upper_end_offset) - (left_width - left_upper_end_offset) : 0 left_nw_point = OpenStudio::Point3d.new(0, left_width + left_origin, z) @@ -582,11 +582,11 @@ center_ne_point = OpenStudio::Point3d.new(length - right_end_length, center_nw_point.y, z) center_se_point = OpenStudio::Point3d.new(length - right_end_length, center_nw_point.y - center_width, z) center_sw_point = OpenStudio::Point3d.new(left_end_length, center_se_point.y, z) right_nw_point = OpenStudio::Point3d.new(length - right_end_length, center_ne_point.y + right_upper_end_offset, z) right_ne_point = OpenStudio::Point3d.new(length, right_nw_point.y, z) - right_se_point = OpenStudio::Point3d.new(length, right_ne_point.y-right_width, z) + right_se_point = OpenStudio::Point3d.new(length, right_ne_point.y - right_width, z) right_sw_point = OpenStudio::Point3d.new(length - right_end_length, right_se_point.y, z) # Identity matrix for setting space origins m = OpenStudio::Matrix.new(4, 4, 0) m[0, 0] = 1 @@ -619,11 +619,11 @@ m[0, 3] = left_sw_point.x m[1, 3] = left_sw_point.y m[2, 3] = left_sw_point.z west_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_left_perimeter_space.setBuildingStory(story) - west_left_perimeter_space.setName("Story #{floor+1} West Left Perimeter Space") + west_left_perimeter_space.setName("Story #{floor + 1} West Left Perimeter Space") north_left_perimeter_polygon = OpenStudio::Point3dVector.new north_left_perimeter_polygon << left_nw_point north_left_perimeter_polygon << left_ne_point @@ -634,11 +634,11 @@ m[0, 3] = perimeter_left_nw_point.x m[1, 3] = perimeter_left_nw_point.y m[2, 3] = perimeter_left_nw_point.z north_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_left_perimeter_space.setBuildingStory(story) - north_left_perimeter_space.setName("Story #{floor+1} North Left Perimeter Space") + north_left_perimeter_space.setName("Story #{floor + 1} North Left Perimeter Space") east_upper_left_perimeter_polygon = OpenStudio::Point3dVector.new east_upper_left_perimeter_polygon << left_ne_point east_upper_left_perimeter_polygon << center_nw_point @@ -649,11 +649,11 @@ m[0, 3] = perimeter_center_nw_point.x m[1, 3] = perimeter_center_nw_point.y m[2, 3] = perimeter_center_nw_point.z east_upper_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_upper_left_perimeter_space.setBuildingStory(story) - east_upper_left_perimeter_space.setName("Story #{floor+1} East Upper Left Perimeter Space") + east_upper_left_perimeter_space.setName("Story #{floor + 1} East Upper Left Perimeter Space") north_center_perimeter_polygon = OpenStudio::Point3dVector.new north_center_perimeter_polygon << center_nw_point north_center_perimeter_polygon << center_ne_point @@ -664,11 +664,11 @@ m[0, 3] = perimeter_center_nw_point.x m[1, 3] = perimeter_center_nw_point.y m[2, 3] = perimeter_center_nw_point.z north_center_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_center_perimeter_space.setBuildingStory(story) - north_center_perimeter_space.setName("Story #{floor+1} North Center Perimeter Space") + north_center_perimeter_space.setName("Story #{floor + 1} North Center Perimeter Space") west_upper_right_perimeter_polygon = OpenStudio::Point3dVector.new west_upper_right_perimeter_polygon << center_ne_point west_upper_right_perimeter_polygon << right_nw_point @@ -679,11 +679,11 @@ m[0, 3] = center_ne_point.x m[1, 3] = center_ne_point.y m[2, 3] = center_ne_point.z west_upper_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_upper_right_perimeter_space.setBuildingStory(story) - west_upper_right_perimeter_space.setName("Story #{floor+1} West Upper Right Perimeter Space") + west_upper_right_perimeter_space.setName("Story #{floor + 1} West Upper Right Perimeter Space") north_right_perimeter_polygon = OpenStudio::Point3dVector.new north_right_perimeter_polygon << right_nw_point north_right_perimeter_polygon << right_ne_point @@ -694,11 +694,11 @@ m[0, 3] = perimeter_right_nw_point.x m[1, 3] = perimeter_right_nw_point.y m[2, 3] = perimeter_right_nw_point.z north_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_right_perimeter_space.setBuildingStory(story) - north_right_perimeter_space.setName("Story #{floor+1} North Right Perimeter Space") + north_right_perimeter_space.setName("Story #{floor + 1} North Right Perimeter Space") east_right_perimeter_polygon = OpenStudio::Point3dVector.new east_right_perimeter_polygon << right_ne_point east_right_perimeter_polygon << right_se_point @@ -709,11 +709,11 @@ m[0, 3] = perimeter_right_se_point.x m[1, 3] = perimeter_right_se_point.y m[2, 3] = perimeter_right_se_point.z east_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_right_perimeter_space.setBuildingStory(story) - east_right_perimeter_space.setName("Story #{floor+1} East Right Perimeter Space") + east_right_perimeter_space.setName("Story #{floor + 1} East Right Perimeter Space") south_right_perimeter_polygon = OpenStudio::Point3dVector.new south_right_perimeter_polygon << right_se_point south_right_perimeter_polygon << right_sw_point @@ -724,11 +724,11 @@ m[0, 3] = right_sw_point.x m[1, 3] = right_sw_point.y m[2, 3] = right_sw_point.z south_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_right_perimeter_space.setBuildingStory(story) - south_right_perimeter_space.setName("Story #{floor+1} South Right Perimeter Space") + south_right_perimeter_space.setName("Story #{floor + 1} South Right Perimeter Space") west_lower_right_perimeter_polygon = OpenStudio::Point3dVector.new west_lower_right_perimeter_polygon << right_sw_point west_lower_right_perimeter_polygon << center_se_point @@ -739,11 +739,11 @@ m[0, 3] = right_sw_point.x m[1, 3] = right_sw_point.y m[2, 3] = right_sw_point.z west_lower_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_lower_right_perimeter_space.setBuildingStory(story) - west_lower_right_perimeter_space.setName("Story #{floor+1} West Lower Right Perimeter Space") + west_lower_right_perimeter_space.setName("Story #{floor + 1} West Lower Right Perimeter Space") south_center_perimeter_polygon = OpenStudio::Point3dVector.new south_center_perimeter_polygon << center_se_point south_center_perimeter_polygon << center_sw_point @@ -754,11 +754,11 @@ m[0, 3] = center_sw_point.x m[1, 3] = center_sw_point.y m[2, 3] = center_sw_point.z south_center_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_center_perimeter_space.setBuildingStory(story) - south_center_perimeter_space.setName("Story #{floor+1} South Center Perimeter Space") + south_center_perimeter_space.setName("Story #{floor + 1} South Center Perimeter Space") east_lower_left_perimeter_polygon = OpenStudio::Point3dVector.new east_lower_left_perimeter_polygon << center_sw_point east_lower_left_perimeter_polygon << left_se_point @@ -769,11 +769,11 @@ m[0, 3] = perimeter_left_se_point.x m[1, 3] = perimeter_left_se_point.y m[2, 3] = perimeter_left_se_point.z east_lower_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_lower_left_perimeter_space.setBuildingStory(story) - east_lower_left_perimeter_space.setName("Story #{floor+1} East Lower Left Perimeter Space") + east_lower_left_perimeter_space.setName("Story #{floor + 1} East Lower Left Perimeter Space") south_left_perimeter_polygon = OpenStudio::Point3dVector.new south_left_perimeter_polygon << left_se_point south_left_perimeter_polygon << left_sw_point @@ -784,11 +784,11 @@ m[0, 3] = left_sw_point.x m[1, 3] = left_sw_point.y m[2, 3] = left_sw_point.z south_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_left_perimeter_space.setBuildingStory(story) - south_left_perimeter_space.setName("Story #{floor+1} South Left Perimeter Space") + south_left_perimeter_space.setName("Story #{floor + 1} South Left Perimeter Space") west_core_polygon = OpenStudio::Point3dVector.new west_core_polygon << perimeter_left_sw_point west_core_polygon << perimeter_left_nw_point @@ -801,11 +801,11 @@ m[0, 3] = perimeter_left_sw_point.x m[1, 3] = perimeter_left_sw_point.y m[2, 3] = perimeter_left_sw_point.z west_core_space.changeTransformation(OpenStudio::Transformation.new(m)) west_core_space.setBuildingStory(story) - west_core_space.setName("Story #{floor+1} West Core Space") + west_core_space.setName("Story #{floor + 1} West Core Space") center_core_polygon = OpenStudio::Point3dVector.new center_core_polygon << perimeter_center_sw_point center_core_polygon << perimeter_center_nw_point @@ -816,11 +816,11 @@ m[0, 3] = perimeter_center_sw_point.x m[1, 3] = perimeter_center_sw_point.y m[2, 3] = perimeter_center_sw_point.z center_core_space.changeTransformation(OpenStudio::Transformation.new(m)) center_core_space.setBuildingStory(story) - center_core_space.setName("Story #{floor+1} Center Core Space") + center_core_space.setName("Story #{floor + 1} Center Core Space") east_core_polygon = OpenStudio::Point3dVector.new east_core_polygon << perimeter_right_sw_point east_core_polygon << perimeter_center_se_point @@ -833,11 +833,11 @@ m[0, 3] = perimeter_right_sw_point.x m[1, 3] = perimeter_right_sw_point.y m[2, 3] = perimeter_right_sw_point.z east_core_space.changeTransformation(OpenStudio::Transformation.new(m)) east_core_space.setBuildingStory(story) - east_core_space.setName("Story #{floor+1} East Core Space") + east_core_space.setName("Story #{floor + 1} East Core Space") # Minimal zones else west_polygon = OpenStudio::Point3dVector.new @@ -852,11 +852,11 @@ m[0, 3] = left_sw_point.x m[1, 3] = left_sw_point.y m[2, 3] = left_sw_point.z west_space.changeTransformation(OpenStudio::Transformation.new(m)) west_space.setBuildingStory(story) - west_space.setName("Story #{floor+1} West Space") + west_space.setName("Story #{floor + 1} West Space") center_polygon = OpenStudio::Point3dVector.new center_polygon << center_sw_point center_polygon << center_nw_point @@ -867,11 +867,11 @@ m[0, 3] = center_sw_point.x m[1, 3] = center_sw_point.y m[2, 3] = center_sw_point.z center_space.changeTransformation(OpenStudio::Transformation.new(m)) center_space.setBuildingStory(story) - center_space.setName("Story #{floor+1} Center Space") + center_space.setName("Story #{floor + 1} Center Space") east_polygon = OpenStudio::Point3dVector.new east_polygon << right_sw_point east_polygon << center_se_point @@ -884,11 +884,11 @@ m[0, 3] = right_sw_point.x m[1, 3] = right_sw_point.y m[2, 3] = right_sw_point.z east_space.changeTransformation(OpenStudio::Transformation.new(m)) east_space.setBuildingStory(story) - east_space.setName("Story #{floor+1} East Space") + east_space.setName("Story #{floor + 1} East Space") end #Set vertical story position @@ -945,29 +945,29 @@ raise("Plenum height must be greater than or equal to 0.") return false end shortest_side = [lower_end_width, upper_end_length].min - if perimeter_zone_depth < 0 or 2*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/2}m.") + if perimeter_zone_depth < 0 or 2 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 2}m.") return false end # Create progress bar # runner.createProgressBar("Creating Spaces") # num_total = perimeter_zone_depth>0 ? num_floors*8 : num_floors*2 # num_complete = 0 # Loop through the number of floors - for floor in (0..num_floors-1) + for floor in (0..num_floors - 1) z = floor_to_floor_height * floor #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") nw_point = OpenStudio::Point3d.new(0, width, z) upper_ne_point = OpenStudio::Point3d.new(upper_end_length, width, z) upper_sw_point = OpenStudio::Point3d.new(upper_end_length, lower_end_width, z) @@ -1001,11 +1001,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z west_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_perimeter_space.setBuildingStory(story) - west_perimeter_space.setName("Story #{floor+1} West Perimeter Space") + west_perimeter_space.setName("Story #{floor + 1} West Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_upper_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1018,11 +1018,11 @@ m[0, 3] = perimeter_nw_point.x m[1, 3] = perimeter_nw_point.y m[2, 3] = perimeter_nw_point.z north_upper_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_upper_perimeter_space.setBuildingStory(story) - north_upper_perimeter_space.setName("Story #{floor+1} North Upper Perimeter Space") + north_upper_perimeter_space.setName("Story #{floor + 1} North Upper Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_upper_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1035,11 +1035,11 @@ m[0, 3] = perimeter_upper_sw_point.x m[1, 3] = perimeter_upper_sw_point.y m[2, 3] = perimeter_upper_sw_point.z east_upper_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_upper_perimeter_space.setBuildingStory(story) - east_upper_perimeter_space.setName("Story #{floor+1} East Upper Perimeter Space") + east_upper_perimeter_space.setName("Story #{floor + 1} East Upper Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1052,11 +1052,11 @@ m[0, 3] = perimeter_upper_sw_point.x m[1, 3] = perimeter_upper_sw_point.y m[2, 3] = perimeter_upper_sw_point.z north_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_lower_perimeter_space.setBuildingStory(story) - north_lower_perimeter_space.setName("Story #{floor+1} North Lower Perimeter Space") + north_lower_perimeter_space.setName("Story #{floor + 1} North Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1069,11 +1069,11 @@ m[0, 3] = perimeter_se_point.x m[1, 3] = perimeter_se_point.y m[2, 3] = perimeter_se_point.z east_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_lower_perimeter_space.setBuildingStory(story) - east_lower_perimeter_space.setName("Story #{floor+1} East Lower Perimeter Space") + east_lower_perimeter_space.setName("Story #{floor + 1} East Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1086,11 +1086,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z south_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_perimeter_space.setBuildingStory(story) - south_perimeter_space.setName("Story #{floor+1} South Perimeter Space") + south_perimeter_space.setName("Story #{floor + 1} South Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) west_core_polygon = OpenStudio::Point3dVector.new @@ -1103,11 +1103,11 @@ m[0, 3] = perimeter_lower_sw_point.x m[1, 3] = perimeter_lower_sw_point.y m[2, 3] = perimeter_lower_sw_point.z west_core_space.changeTransformation(OpenStudio::Transformation.new(m)) west_core_space.setBuildingStory(story) - west_core_space.setName("Story #{floor+1} West Core Space") + west_core_space.setName("Story #{floor + 1} West Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_core_polygon = OpenStudio::Point3dVector.new @@ -1120,11 +1120,11 @@ m[0, 3] = perimeter_lower_sw_point.x m[1, 3] = perimeter_lower_sw_point.y m[2, 3] = perimeter_lower_sw_point.z east_core_space.changeTransformation(OpenStudio::Transformation.new(m)) east_core_space.setBuildingStory(story) - east_core_space.setName("Story #{floor+1} East Core Space") + east_core_space.setName("Story #{floor + 1} East Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) # Minimal zones @@ -1139,14 +1139,14 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z west_space.changeTransformation(OpenStudio::Transformation.new(m)) west_space.setBuildingStory(story) - west_space.setName("Story #{floor+1} West Space") + west_space.setName("Story #{floor + 1} West Space") num_complete += 1 - runner.updateProgress(100*num_complete/num_total) + runner.updateProgress(100 * num_complete / num_total) east_polygon = OpenStudio::Point3dVector.new east_polygon << sw_point east_polygon << upper_sw_point east_polygon << lower_ne_point @@ -1156,11 +1156,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z east_space.changeTransformation(OpenStudio::Transformation.new(m)) east_space.setBuildingStory(story) - east_space.setName("Story #{floor+1} East Space") + east_space.setName("Story #{floor + 1} East Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) end @@ -1233,25 +1233,25 @@ raise("Plenum height must be greater than or equal to 0.") return false end shortest_side = [length, width].min - if perimeter_zone_depth < 0 or 2*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/2}m") + if perimeter_zone_depth < 0 or 2 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 2}m") return false end building_stories = Array.new #Loop through the number of floors - for floor in ((under_ground_storys * -1)..above_ground_storys-1) + for floor in ((under_ground_storys * -1)..above_ground_storys - 1) z = floor_to_floor_height * floor + initial_height #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") building_stories << story nw_point = OpenStudio::Point3d.new(0, width, z) ne_point = OpenStudio::Point3d.new(length, width, z) @@ -1282,11 +1282,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z west_space.changeTransformation(OpenStudio::Transformation.new(m)) west_space.setBuildingStory(story) - west_space.setName("Story #{floor+1} West Perimeter Space") + west_space.setName("Story #{floor + 1} West Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_polygon = OpenStudio::Point3dVector.new @@ -1299,11 +1299,11 @@ m[0, 3] = perimeter_nw_point.x m[1, 3] = perimeter_nw_point.y m[2, 3] = perimeter_nw_point.z north_space.changeTransformation(OpenStudio::Transformation.new(m)) north_space.setBuildingStory(story) - north_space.setName("Story #{floor+1} North Perimeter Space") + north_space.setName("Story #{floor + 1} North Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_polygon = OpenStudio::Point3dVector.new @@ -1316,11 +1316,11 @@ m[0, 3] = perimeter_se_point.x m[1, 3] = perimeter_se_point.y m[2, 3] = perimeter_se_point.z east_space.changeTransformation(OpenStudio::Transformation.new(m)) east_space.setBuildingStory(story) - east_space.setName("Story #{floor+1} East Perimeter Space") + east_space.setName("Story #{floor + 1} East Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_polygon = OpenStudio::Point3dVector.new @@ -1333,11 +1333,11 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z south_space.changeTransformation(OpenStudio::Transformation.new(m)) south_space.setBuildingStory(story) - south_space.setName("Story #{floor+1} South Perimeter Space") + south_space.setName("Story #{floor + 1} South Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) core_polygon = OpenStudio::Point3dVector.new @@ -1350,11 +1350,11 @@ m[0, 3] = perimeter_sw_point.x m[1, 3] = perimeter_sw_point.y m[2, 3] = perimeter_sw_point.z core_space.changeTransformation(OpenStudio::Transformation.new(m)) core_space.setBuildingStory(story) - core_space.setName("Story #{floor+1} Core Space") + core_space.setName("Story #{floor + 1} Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) # Minimal zones @@ -1369,25 +1369,23 @@ m[0, 3] = sw_point.x m[1, 3] = sw_point.y m[2, 3] = sw_point.z core_space.changeTransformation(OpenStudio::Transformation.new(m)) core_space.setBuildingStory(story) - core_space.setName("Story #{floor+1} Core Space") + core_space.setName("Story #{floor + 1} Core Space") # # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) end #Set vertical story position story.setNominalZCoordinate(z) - #Ensure that underground stories (when z<0 have Ground set as Boundary conditions. - BTAP::Geometry::Surfaces::set_surfaces_boundary_condition(model, BTAP::Geometry::Surfaces::get_surfaces_from_building_stories(model, story), "Ground") if z <= 0 - BTAP::Geometry::Surfaces::set_surfaces_boundary_condition(model, BTAP::Geometry::Surfaces::get_surfaces_from_building_stories(model, story), "Outdoors") if z > 0 - - + #Ensure that underground stories (when z<0 have Ground set as Boundary conditions). Apply the Ground BC to all surfaces, the top ceiling will be + # corrected below when the surface matching algorithm is called. + BTAP::Geometry::Surfaces::set_surfaces_boundary_condition(model, BTAP::Geometry::Surfaces::get_surfaces_from_building_stories(model, story), "Ground") if z < 0 end #End of floor loop # runner.destroyProgressBar BTAP::Geometry::match_surfaces(model) return building_stories @@ -1444,29 +1442,29 @@ raise("Plenum height must be greater than or equal to 0.") return false end shortest_side = [length, width, upper_end_width, lower_end_length].min - if perimeter_zone_depth < 0 or 2*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/2}m.") + if perimeter_zone_depth < 0 or 2 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 2}m.") return false end # Create progress bar # runner.createProgressBar("Creating Spaces") # num_total = perimeter_zone_depth>0 ? num_floors*10 : num_floors*2 # num_complete = 0 # Loop through the number of floors - for floor in (0..num_floors-1) + for floor in (0..num_floors - 1) z = floor_to_floor_height * floor #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") lower_ne_point = OpenStudio::Point3d.new(left_end_offset, width - upper_end_width, z) upper_sw_point = OpenStudio::Point3d.new(0, width - upper_end_width, z) upper_nw_point = OpenStudio::Point3d.new(0, width, z) @@ -1504,11 +1502,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z west_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_lower_perimeter_space.setBuildingStory(story) - west_lower_perimeter_space.setName("Story #{floor+1} West Lower Perimeter Space") + west_lower_perimeter_space.setName("Story #{floor + 1} West Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_upper_left_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1521,11 +1519,11 @@ m[0, 3] = upper_sw_point.x m[1, 3] = upper_sw_point.y m[2, 3] = upper_sw_point.z south_upper_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_upper_left_perimeter_space.setBuildingStory(story) - south_upper_left_perimeter_space.setName("Story #{floor+1} South Upper Left Perimeter Space") + south_upper_left_perimeter_space.setName("Story #{floor + 1} South Upper Left Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) west_upper_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1538,11 +1536,11 @@ m[0, 3] = upper_sw_point.x m[1, 3] = upper_sw_point.y m[2, 3] = upper_sw_point.z west_upper_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_upper_perimeter_space.setBuildingStory(story) - west_upper_perimeter_space.setName("Story #{floor+1} West Upper Perimeter Space") + west_upper_perimeter_space.setName("Story #{floor + 1} West Upper Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1555,11 +1553,11 @@ m[0, 3] = perimeter_upper_nw_point.x m[1, 3] = perimeter_upper_nw_point.y m[2, 3] = perimeter_upper_nw_point.z north_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_perimeter_space.setBuildingStory(story) - north_perimeter_space.setName("Story #{floor+1} North Perimeter Space") + north_perimeter_space.setName("Story #{floor + 1} North Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_upper_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1572,11 +1570,11 @@ m[0, 3] = perimeter_upper_se_point.x m[1, 3] = perimeter_upper_se_point.y m[2, 3] = perimeter_upper_se_point.z east_upper_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_upper_perimeter_space.setBuildingStory(story) - east_upper_perimeter_space.setName("Story #{floor+1} East Upper Perimeter Space") + east_upper_perimeter_space.setName("Story #{floor + 1} East Upper Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_upper_right_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1589,11 +1587,11 @@ m[0, 3] = lower_nw_point.x m[1, 3] = lower_nw_point.y m[2, 3] = lower_nw_point.z south_upper_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_upper_right_perimeter_space.setBuildingStory(story) - south_upper_right_perimeter_space.setName("Story #{floor+1} South Upper Left Perimeter Space") + south_upper_right_perimeter_space.setName("Story #{floor + 1} South Upper Left Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1606,11 +1604,11 @@ m[0, 3] = perimeter_lower_se_point.x m[1, 3] = perimeter_lower_se_point.y m[2, 3] = perimeter_lower_se_point.z east_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_lower_perimeter_space.setBuildingStory(story) - east_lower_perimeter_space.setName("Story #{floor+1} East Lower Perimeter Space") + east_lower_perimeter_space.setName("Story #{floor + 1} East Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1623,11 +1621,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z south_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_lower_perimeter_space.setBuildingStory(story) - south_lower_perimeter_space.setName("Story #{floor+1} South Lower Perimeter Space") + south_lower_perimeter_space.setName("Story #{floor + 1} South Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_core_polygon = OpenStudio::Point3dVector.new @@ -1642,11 +1640,11 @@ m[0, 3] = perimeter_upper_sw_point.x m[1, 3] = perimeter_upper_sw_point.y m[2, 3] = perimeter_upper_sw_point.z north_core_space.changeTransformation(OpenStudio::Transformation.new(m)) north_core_space.setBuildingStory(story) - north_core_space.setName("Story #{floor+1} North Core Space") + north_core_space.setName("Story #{floor + 1} North Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_core_polygon = OpenStudio::Point3dVector.new @@ -1659,11 +1657,11 @@ m[0, 3] = perimeter_lower_sw_point.x m[1, 3] = perimeter_lower_sw_point.y m[2, 3] = perimeter_lower_sw_point.z south_core_space.changeTransformation(OpenStudio::Transformation.new(m)) south_core_space.setBuildingStory(story) - south_core_space.setName("Story #{floor+1} South Core Space") + south_core_space.setName("Story #{floor + 1} South Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) # Minimal zones @@ -1680,11 +1678,11 @@ m[0, 3] = upper_sw_point.x m[1, 3] = upper_sw_point.y m[2, 3] = upper_sw_point.z north_space.changeTransformation(OpenStudio::Transformation.new(m)) north_space.setBuildingStory(story) - north_space.setName("Story #{floor+1} North Space") + north_space.setName("Story #{floor + 1} North Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_polygon = OpenStudio::Point3dVector.new @@ -1697,11 +1695,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z south_space.changeTransformation(OpenStudio::Transformation.new(m)) south_space.setBuildingStory(story) - south_space.setName("Story #{floor+1} South Space") + south_space.setName("Story #{floor + 1} South Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) end @@ -1771,30 +1769,30 @@ if plenum_height < 0 raise("Plenum height must be greater than or equal to 0.") return false end - shortest_side = [length/2, left_width, right_width, left_end_length, right_end_length, left_width-left_end_offset].min - if perimeter_zone_depth < 0 or 2*perimeter_zone_depth >= (shortest_side - 1e-4) - raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side/2}m.") + shortest_side = [length / 2, left_width, right_width, left_end_length, right_end_length, left_width - left_end_offset].min + if perimeter_zone_depth < 0 or 2 * perimeter_zone_depth >= (shortest_side - 1e-4) + raise("Perimeter zone depth must be greater than or equal to 0 and less than #{shortest_side / 2}m.") return false end # Create progress bar # runner.createProgressBar("Creating Spaces") # num_total = perimeter_zone_depth>0 ? num_floors*11 : num_floors*3 # num_complete = 0 # Loop through the number of floors - for floor in (0..num_floors-1) + for floor in (0..num_floors - 1) z = floor_to_floor_height * floor #Create a new story within the building story = OpenStudio::Model::BuildingStory.new(model) story.setNominalFloortoFloorHeight(floor_to_floor_height) - story.setName("Story #{floor+1}") + story.setName("Story #{floor + 1}") left_nw_point = OpenStudio::Point3d.new(0, left_width, z) left_ne_point = OpenStudio::Point3d.new(left_end_length, left_width, z) upper_sw_point = OpenStudio::Point3d.new(left_end_length, left_width - left_end_offset, z) @@ -1832,11 +1830,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z west_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_left_perimeter_space.setBuildingStory(story) - west_left_perimeter_space.setName("Story #{floor+1} West Left Perimeter Space") + west_left_perimeter_space.setName("Story #{floor + 1} West Left Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_left_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1849,11 +1847,11 @@ m[0, 3] = perimeter_left_nw_point.x m[1, 3] = perimeter_left_nw_point.y m[2, 3] = perimeter_left_nw_point.z north_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_left_perimeter_space.setBuildingStory(story) - north_left_perimeter_space.setName("Story #{floor+1} North Left Perimeter Space") + north_left_perimeter_space.setName("Story #{floor + 1} North Left Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_left_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1866,11 +1864,11 @@ m[0, 3] = perimeter_upper_sw_point.x m[1, 3] = perimeter_upper_sw_point.y m[2, 3] = perimeter_upper_sw_point.z east_left_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_left_perimeter_space.setBuildingStory(story) - east_left_perimeter_space.setName("Story #{floor+1} East Left Perimeter Space") + east_left_perimeter_space.setName("Story #{floor + 1} East Left Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1883,11 +1881,11 @@ m[0, 3] = perimeter_upper_sw_point.x m[1, 3] = perimeter_upper_sw_point.y m[2, 3] = perimeter_upper_sw_point.z north_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_lower_perimeter_space.setBuildingStory(story) - north_lower_perimeter_space.setName("Story #{floor+1} North Lower Perimeter Space") + north_lower_perimeter_space.setName("Story #{floor + 1} North Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) west_right_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1900,11 +1898,11 @@ m[0, 3] = upper_se_point.x m[1, 3] = upper_se_point.y m[2, 3] = upper_se_point.z west_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) west_right_perimeter_space.setBuildingStory(story) - west_right_perimeter_space.setName("Story #{floor+1} West Right Perimeter Space") + west_right_perimeter_space.setName("Story #{floor + 1} West Right Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) north_right_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1917,11 +1915,11 @@ m[0, 3] = perimeter_right_nw_point.x m[1, 3] = perimeter_right_nw_point.y m[2, 3] = perimeter_right_nw_point.z north_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) north_right_perimeter_space.setBuildingStory(story) - north_right_perimeter_space.setName("Story #{floor+1} North Right Perimeter Space") + north_right_perimeter_space.setName("Story #{floor + 1} North Right Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_right_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1934,11 +1932,11 @@ m[0, 3] = perimeter_lower_se_point.x m[1, 3] = perimeter_lower_se_point.y m[2, 3] = perimeter_lower_se_point.z east_right_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) east_right_perimeter_space.setBuildingStory(story) - east_right_perimeter_space.setName("Story #{floor+1} East Right Perimeter Space") + east_right_perimeter_space.setName("Story #{floor + 1} East Right Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_lower_perimeter_polygon = OpenStudio::Point3dVector.new @@ -1951,11 +1949,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z south_lower_perimeter_space.changeTransformation(OpenStudio::Transformation.new(m)) south_lower_perimeter_space.setBuildingStory(story) - south_lower_perimeter_space.setName("Story #{floor+1} South Lower Perimeter Space") + south_lower_perimeter_space.setName("Story #{floor + 1} South Lower Perimeter Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) west_core_polygon = OpenStudio::Point3dVector.new @@ -1968,11 +1966,11 @@ m[0, 3] = perimeter_lower_sw_point.x m[1, 3] = perimeter_lower_sw_point.y m[2, 3] = perimeter_lower_sw_point.z west_core_space.changeTransformation(OpenStudio::Transformation.new(m)) west_core_space.setBuildingStory(story) - west_core_space.setName("Story #{floor+1} West Core Space") + west_core_space.setName("Story #{floor + 1} West Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_core_polygon = OpenStudio::Point3dVector.new @@ -1985,11 +1983,11 @@ m[0, 3] = perimeter_lower_sw_point.x m[1, 3] = perimeter_lower_sw_point.y m[2, 3] = perimeter_lower_sw_point.z south_core_space.changeTransformation(OpenStudio::Transformation.new(m)) south_core_space.setBuildingStory(story) - south_core_space.setName("Story #{floor+1} South Core Space") + south_core_space.setName("Story #{floor + 1} South Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_core_polygon = OpenStudio::Point3dVector.new @@ -2002,11 +2000,11 @@ m[0, 3] = perimeter_upper_se_point.x m[1, 3] = perimeter_upper_se_point.y m[2, 3] = perimeter_upper_se_point.z east_core_space.changeTransformation(OpenStudio::Transformation.new(m)) east_core_space.setBuildingStory(story) - east_core_space.setName("Story #{floor+1} East Core Space") + east_core_space.setName("Story #{floor + 1} East Core Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) # Minimal zones @@ -2021,11 +2019,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z west_space.changeTransformation(OpenStudio::Transformation.new(m)) west_space.setBuildingStory(story) - west_space.setName("Story #{floor+1} West Space") + west_space.setName("Story #{floor + 1} West Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) south_polygon = OpenStudio::Point3dVector.new @@ -2038,11 +2036,11 @@ m[0, 3] = lower_sw_point.x m[1, 3] = lower_sw_point.y m[2, 3] = lower_sw_point.z south_space.changeTransformation(OpenStudio::Transformation.new(m)) south_space.setBuildingStory(story) - south_space.setName("Story #{floor+1} South Space") + south_space.setName("Story #{floor + 1} South Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) east_polygon = OpenStudio::Point3dVector.new @@ -2055,11 +2053,11 @@ m[0, 3] = upper_se_point.x m[1, 3] = upper_se_point.y m[2, 3] = upper_se_point.z east_space.changeTransformation(OpenStudio::Transformation.new(m)) east_space.setBuildingStory(story) - east_space.setName("Story #{floor+1} East Space") + east_space.setName("Story #{floor + 1} East Space") # num_complete += 1 # runner.updateProgress(100*num_complete/num_total) end @@ -2130,13 +2128,13 @@ # @return [OpenStudio::Model::Model] the model object. def self.scale_model(model, x, y, z) # Identity matrix for setting space origins m = OpenStudio::Matrix.new(4, 4, 0) - m[0, 0] = 1.0/x - m[1, 1] = 1.0/y - m[2, 2] = 1.0/z + m[0, 0] = 1.0 / x + m[1, 1] = 1.0 / y + m[2, 2] = 1.0 / z m[3, 3] = 1.0 t = OpenStudio::Transformation.new(m) model.getPlanarSurfaceGroups().each do |planar_surface| planar_surface.changeTransformation(t) end @@ -2160,21 +2158,21 @@ total_net_surface_area = 0.0 surfaces.each do |surface| total_gross_surface_area = total_gross_surface_area + surface.grossArea total_net_surface_area = total_net_surface_area + surface.netArea end - return 1.0 - (total_net_surface_area/total_gross_surface_area) + return 1.0 - (total_net_surface_area / total_gross_surface_area) end # This method will rotate the model # @param model [OpenStudio::Model::Model] the model object. # @param degrees [Float] rotation value # @return [OpenStudio::Model::Model] the model object. def self.rotate_model(model, degrees) # Identity matrix for setting space origins - t = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), degrees*Math::PI/180) + t = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), degrees * Math::PI / 180) model.getPlanarSurfaceGroups().each {|planar_surface| planar_surface.changeTransformation(t)} return model end @@ -2233,11 +2231,11 @@ minz = z_points.min + space.zOrigin sorted_spaces[space] = minz end # pre-sort spaces - sorted_spaces = sorted_spaces.sort {|a, b| a[1]<=>b[1]} + sorted_spaces = sorted_spaces.sort {|a, b| a[1] <=> b[1]} # this should take the sorted list and make and assign stories sorted_spaces.sort.each do |space| space_obj = space[0] @@ -2308,10 +2306,11 @@ # largest. It will also return the top, bottom or middle conditions. def self.get_space_placement(space) horizontal_placement = nil vertical_placement = nil + json_data = nil #get all exterior surfaces. surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, ["Outdoors", "Ground", @@ -2348,60 +2347,95 @@ vertical_placement = "middle" end #determine if what cardinal direction has the majority of external - #surface area of the space. + #surface area of the space. + #set this to 'core' by default and change it if it is found to be a space exposed to a cardinal direction. + horizontal_placement = nil + #set up summing hashes for each direction. + json_data = Hash.new + walls_area_array = Hash.new + subsurface_area_array = Hash.new + boundary_conditions = {} + boundary_conditions[:outdoors] = ["Outdoors"] + boundary_conditions[:ground] = [ + "Ground", + "GroundFCfactorMethod", + "GroundSlabPreprocessorAverage", + "GroundSlabPreprocessorCore", + "GroundSlabPreprocessorPerimeter", + "GroundBasementPreprocessorAverageWall", + "GroundBasementPreprocessorAverageFloor", + "GroundBasementPreprocessorUpperWall", + "GroundBasementPreprocessorLowerWall"] + #go through all directions.. need to do north twice since that goes around zero degree mark. + orientations = [ + {:surface_type => 'Wall', :direction => 'north', :azimuth_from => 0.00, :azimuth_to => 45.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'Wall', :direction => 'north', :azimuth_from => 315.001, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'Wall', :direction => 'east', :azimuth_from => 45.001, :azimuth_to => 135.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'Wall', :direction => 'south', :azimuth_from => 135.001, :azimuth_to => 225.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'Wall', :direction => 'west', :azimuth_from => 225.001, :azimuth_to => 315.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'RoofCeiling', :direction => 'top', :azimuth_from => 0.0, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0}, + {:surface_type => 'Floor', :direction => 'bottom', :azimuth_from => 0.0, :azimuth_to => 360.0, :tilt_from => 0.0, :tilt_to => 180.0} + ] + [:outdoors, :ground].each do |bc| + orientations.each do |orientation| + walls_area_array[orientation[:direction]] = 0.0 + subsurface_area_array[orientation[:direction]] = 0.0 + json_data[orientation[:direction]] = {} if json_data[orientation[:direction]].nil? + json_data[orientation[:direction]][bc] = {:surface_area => 0.0, + :glazed_subsurface_area => 0.0, + :opaque_subsurface_area => 0.0} - walls_area_array = Array.new - [0, 1, 2, 3].each {|index| walls_area_array[index] = 0.0} - #east is defined as 315-45 degs - BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(ext_wall_surfaces, 0.00, 45.0, 0.00, 180.00).each do |surface| - # puts "northern surface found 0-46: #{surface}" - # puts surface.azimuth / ( Math::PI / 180.0 ) - walls_area_array[0] = walls_area_array[0] + surface.grossArea + end end - BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(ext_wall_surfaces, 315.001, 360.0, 0.00, 180.00).each do |surface| - # puts "northern surface found: #{surface}" - # puts surface.azimuth / ( Math::PI / 180.0 ) - walls_area_array[0] = walls_area_array[0] + surface.grossArea - end - BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(ext_wall_surfaces, 45.001, 135.0, 0.00, 180.00).each do |surface| - # puts "eastern surface found: #{surface}" - # puts surface.azimuth / ( Math::PI / 180.0 ) - walls_area_array[1] = walls_area_array[1] + surface.grossArea - end - BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(ext_wall_surfaces, 135.001, 225.0, 0.00, 180.00).each do |surface| - # puts "south surface found: #{surface}" - # puts surface.azimuth / ( Math::PI / 180.0 ) - walls_area_array[2] = walls_area_array[2] + surface.grossArea + [:outdoors, :ground].each do |bc| + orientations.each do |orientation| + # puts "bc= #{bc}" + # puts boundary_conditions[bc.to_sym] + # puts boundary_conditions + surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, boundary_conditions[bc]) + selected_surfaces = BTAP::Geometry::Surfaces::filter_by_surface_types(surfaces, [orientation[:surface_type]]) + BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(selected_surfaces, orientation[:azimuth_from], orientation[:azimuth_to], orientation[:tilt_from], orientation[:tilt_to]).each do |surface| + #sum wall area and subsurface area by direction. This is the old way so excluding top and bottom surfaces. + walls_area_array[orientation[:direction]] += surface.grossArea unless ['RoofCeiling', 'Floor'].include?(orientation[:surface_type]) + subsurface_area_array[orientation[:direction]] += surface.subSurfaces.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x} + json_data[orientation[:direction]][bc][:surface_area] += surface.grossArea + glazings = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(surface.subSurfaces, ["FixedWindow", "OperableWindow", "GlassDoor", "Skylight", "TubularDaylightDiffuser", "TubularDaylightDome"]) + doors = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(surface.subSurfaces, ["Door", "OverheadDoor"]) + json_data[orientation[:direction]][bc][:glazed_subsurface_area] += glazings.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x} + json_data[orientation[:direction]][bc][:opaque_subsurface_area] += doors.map {|subsurface| subsurface.grossArea}.inject(0) {|sum, x| sum + x} + end + end end + puts JSON.pretty_generate(json_data) - BTAP::Geometry::Surfaces::filter_by_azimuth_and_tilt(ext_wall_surfaces, 225.001, 315.0, 0.00, 180.00).each do |surface| - # puts "west surface found: #{surface}" - # puts surface.azimuth / ( Math::PI / 180.0 ) - walls_area_array[3] = walls_area_array[3] + surface.grossArea + puts walls_area_array + #find if no direction + sum= 0.0 + ['north','east','south','west'].each do |direction| + [:outdoors,:ground].each do |bc| + sum += json_data[direction][bc][:surface_area] + end end - - - #find our which cardinal driection has the most exterior surface and declare it that orientation. - case walls_area_array.index(walls_area_array.max) - when 0 - horizontal_placement = "north" - when 1 - horizontal_placement = "east" - when 2 - horizontal_placement = "south" - when 3 - horizontal_placement = "west" - end - if walls_area_array.inject {|sum, x| sum + x} == 0.0 + if sum == 0.0 horizontal_placement = "core" + else + #find our which cardinal direction has the most exterior surface and declare it that orientation. + horizontal_placement = walls_area_array.max_by {|k, v| v}[0] #include ext and ground. end - return horizontal_placement, vertical_placement + + #save JSON data + json_data = ({:horizontal_placement => horizontal_placement, + :vertical_placement => vertical_placement, + }).merge(json_data) + puts JSON.pretty_generate(json_data) + + return json_data end def self.is_perimeter_space?(model, space) exterior_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, @@ -2596,12 +2630,12 @@ # @param tilt_degrees [Float] rotation value # @param translation_vector [OpenStudio::Vector3d] a vector along which to move all surfaces # @return [OpenStudio::Model::Model] the model object. def self.rotate_tilt_translate_surfaces(planar_surfaces, azimuth_degrees, tilt_degrees = 0.0, translation_vector = OpenStudio::Vector3d.new(0.0, 0.0, 0.0)) # Identity matrix for setting space origins - azimuth_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), azimuth_degrees*Math::PI/180) - tilt_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), tilt_degrees*Math::PI/180) + azimuth_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), azimuth_degrees * Math::PI / 180) + tilt_matrix = OpenStudio::Transformation::rotation(OpenStudio::Vector3d.new(0, 0, 1), tilt_degrees * Math::PI / 180) translation_matrix = OpenStudio::createTranslation(translation_vector) planar_surfaces.each do |surface| surface.changeTransformation(azimuth_matrix) surface.changeTransformation(tilt_matrix) surface.changeTransformation(translation_matrix) @@ -2879,11 +2913,17 @@ end end # Azimuth start from Y axis, Tilts starts from Z-axis def self.filter_by_azimuth_and_tilt(surfaces, azimuth_from, azimuth_to, tilt_from, tilt_to, tolerance = 1.0) - return OpenStudio::Model::PlanarSurface::findPlanarSurfaces(surfaces, OpenStudio::OptionalDouble.new(azimuth_from), OpenStudio::OptionalDouble.new(azimuth_to), OpenStudio::OptionalDouble.new(tilt_from), OpenStudio::OptionalDouble.new(tilt_to), tolerance) + return_surfaces = [] + surfaces.each do |surface| + unless OpenStudio::Model::PlanarSurface::findPlanarSurfaces([surface], OpenStudio::OptionalDouble.new(azimuth_from), OpenStudio::OptionalDouble.new(azimuth_to), OpenStudio::OptionalDouble.new(tilt_from), OpenStudio::OptionalDouble.new(tilt_to), tolerance).empty? + return_surfaces << surface + end + end + return return_surfaces end def self.show(surfaces) surfaces.each do |surface| @@ -2903,9 +2943,759 @@ end end end end + # 2018-09-27 Chris Kirney + # This method takes a surface in the x-y plane (z coordinates are ignored) with an upwardly pointing normal and + # turns it into convex quadrialaterals. If the original surface is already a convex quadrilateral then this method + # will go to a lot of trouble to return the same thing (only with the coordinates of the points rounded). If + # the surface is already a concave surface then this method will return it broken into a bunch of quadrilaters + # (maybe a triangle here and there). Neither of the above are especially useful. However, the point of this + # method is if you pass this a concave surface it will return convex surfaces that you can then use with other + # methods that only apply to convex surfaces (such as a method which fits skylights into a roof). Note that + # surfaces per say are not returned. Rather, an array containing 4 points arranged in counter clockwise order is + # returned. These points are also in the x-y plane with an upwardly pointing normal. No z coordinate is returned. + # + # The method works by first looking for upward pointing lines. It then looks for cooresponding downward pointing + # lines. Since all of the surfaces are closed there should always be enough upward and downward pointing lines. + # Horizontal lines are ignored. It then checks to see which y projections of the upward and downward pointing + # lines overlap. It then sees which of these overlaping lines overlap. Ultimately you wind up with a whole bunch + # of overlapping y projections that coorespond with different upward pointing lines. These overlapping + # y projects are either unique, or they precisely match other overlapping y projections. The point is that, in + # the case of a convex shape, an upward pointing line may overlap with some lines close, and some far away, with + # some lines in between. The method then sorts through the overlapping y projections to see which are closest + # to a given upward pointing line. It keeps the unique ones, and the ones that are closest. The end result + # should be downward pointing line segments that correspond to an upward pointing line segment with no intervening + # lines. The last part of the method assembles the quadrilaterals from the remaining downward pointing line + # segments which correspond with a given upward pointing line segment. + def self.make_convex_surfaces(surface:, tol: 12) + # Note that points on surfaces are given counterclockwise when looking at the surface from the opposite direction as + # the outward normal (i.e. the outward normal is pointing at you). I use point_a1, point_a2, point_b1 and point b2 + # lots. For this, point_a refers to vectors pointing up. In this case point_a1 is at the top of the vector and + # point_a2 is at the bottom of the vector. Contrarily, point_b refers to vectors pointing down. In this case + # point_b1 is at the bottom of the vector and point_b2 is at the top. All of this comes about because I cycle + # through the points starting at the 2nd point and and going to the last point. I count vectors as starting from + # the last point and going toward the current point. + # See following where P1 through P4 are the points. When cycling through a is where you start and b is where you + # end. the o is the tip of the outward normal pointing at you. + # P2b------------aP1 + # a b + # | | + # | o | + # | | + # b a + # P3a-----------bP4 + surf_verts = [] + # Get the vertices from the surface, keep the x and y coordinates, and turn the vertices from OpenStudio's + # data structure to a differet one which is a little easier to deal with. Also, round them to the given + # tolerance. This is done because some numbers that should match don't because of tiny errors. + surface.vertices.each do |vert| + surf_vert = { + x: vert.x.to_f.round(tol), + y: vert.y.to_f.round(tol), + z: vert.z.to_f + } + surf_verts << surf_vert + end + # If the surface is a triangle or less then do nothing and return it. + return surf_verts if surf_verts.length <= 3 + # Adding the first vertex to the end so that it is accounted for. + surf_verts << surf_verts[0] + # Following we go through the points, look for upward pointing lines, then look for downward pointing lines to + # their left (only to the left because everything goes counter-clockwise). If there is a line find how much the + # current upward pointing line overlaps with it in the y direction. + overlap_segs = [] + new_surfs = [] + for i in 1..(surf_verts.length - 1) + # Is this line segment pointing up? If no, then ignore it and go to the next line segment. + if surf_verts[i][:y] > surf_verts[i - 1][:y] + # Go through each line segment + for j in 1..(surf_verts.length - 1) + # Is the line segment to the left of the current (index i) line segment? If no, then ignore it and go to the next one. + if surf_verts[j][:x] < surf_verts[i][:x] and surf_verts[j - 1][:x] < surf_verts[i - 1][:x] + # Is the line segment pointing down? If no, then ignore it and go to the next line segment. + if surf_verts[j][:y] < surf_verts[j - 1][:y] + # Do the y coordinates of the line segment overlap with the current (index i) line segment? If no + # then ignore it and go to the next line segment. + overlap_y = line_segment_overlap_y?(point_a1: surf_verts[i][:y], point_a2: surf_verts[i - 1][:y], point_b1: surf_verts[j][:y], point_b2: surf_verts[j - 1][:y]) + unless overlap_y[:overlap_start].nil? || overlap_y[:overlap_end].nil? + unless overlap_y[:overlap_start] == overlap_y[:overlap_end] + overlap_seg = { + index_a1: i, + index_a2: i - 1, + index_b1: j, + index_b2: j - 1, + point_b1: surf_verts[j], + point_b2: surf_verts[j - 1], + overlap_y: overlap_y + } + overlap_segs << overlap_seg + end + end + end + end + end + end + end + # This part: + # 1. Subdivides the overlapping segments found above into either unique overlaps between the upward and downward + # pointing lines or overlapping segments that exactly match one another. + # 2. Goes through each upward pointing line and finds the closest overlapping downward pointing line segments (if + # these downward pointing segments belong together they are re-attached). + # 3. Makes quadrilaterals (or triangles as the case may be) out of each upward poinding line and the closest + # downward pointing line segment. + if overlap_segs.length > 1 + # Subdivide the overlapping segments found above into either unique overlaps between the upward and downward + # pointing lines or overlapping segments that exactly match one another. + overlap_segs = subdivide_overlaps(overlap_segs: overlap_segs) + for i in 1..(surf_verts.length - 1) + # Does the line point up? No then ignore and go on to the next one. + if surf_verts[i][:y] > surf_verts[i - 1][:y] + # Finds the closest overlapping downward pointing line segments that correspond to this updard pointing + # line (if some of these downward pointing segments belong together then re-attached them). + closest_overlaps = get_overlapping_segments(overlap_segs: overlap_segs, index: i, point_a1: surf_verts[i], point_a2: surf_verts[i - 1]) + closest_overlaps = closest_overlaps.sort_by {|closest_overlap| [closest_overlap[:overlap_y][:overlap_start]]} + # Create the quadrilaterals out of the downward pointing line segments closest to the current upward + # pointing line. + for j in 0..(closest_overlaps.length - 1) + new_surf = [] + z_loc = surf_verts[closest_overlaps[j][:index_a1]][:z] + y_loc = closest_overlaps[j][:overlap_y][:overlap_start] + x_loc = line_segment_overlap_x_coord(y_check: y_loc, point_b1: surf_verts[closest_overlaps[j][:index_a1]], point_b2: surf_verts[closest_overlaps[j][:index_a2]]) + new_surf << {x: x_loc, y: y_loc, z: z_loc} + x_loc = line_segment_overlap_x_coord(y_check: y_loc, point_b1: closest_overlaps[j][:point_b1], point_b2: closest_overlaps[j][:point_b2]) + z_loc = surf_verts[closest_overlaps[j][:index_b2]][:z] + new_surf << {x: x_loc, y: y_loc, z: z_loc} + y_loc = closest_overlaps[j][:overlap_y][:overlap_end] + x_loc = line_segment_overlap_x_coord(y_check: y_loc, point_b1: closest_overlaps[j][:point_b1], point_b2: closest_overlaps[j][:point_b2]) + z_loc = surf_verts[closest_overlaps[j][:index_b1]][:z] + new_surf << {x: x_loc, y: y_loc, z: z_loc} + x_loc = line_segment_overlap_x_coord(y_check: y_loc, point_b1: surf_verts[closest_overlaps[j][:index_a1]], point_b2: surf_verts[closest_overlaps[j][:index_a2]]) + z_loc = surf_verts[closest_overlaps[j][:index_a2]][:z] + new_surf << {x: x_loc, y: y_loc, z: z_loc} + # Check if this should be a triangle. + for k in 0..(new_surf.length - 1) + break_now = false + for l in 0..(new_surf.length - 1) + next if k == l + if (new_surf[k][:x] == new_surf[l][:x]) && (new_surf[k][:y] == new_surf[l][:y]) + new_surf.delete_at(l) + break_now = true + break + end + end + if break_now == true + break + end + end + new_surfs << new_surf + end + end + end + elsif overlap_segs.length == 1 + # There is only one overlapping downward line, thus this is a quadrilateral already so just return it. + # Remove the last vertex as we had artificially added it at the start. + surf_verts.pop + new_surfs << surf_verts + end + return new_surfs + end + # This method takes the y projections of a bunch of overlapping line segments and sorts them to determines which + # are unique and, if they are not unique, which is closest to the current, upwardly pointing, line. If several + # overlapping segments belong to the same line they are put together (after the 'subdivide_overlaps' method broke + # them apart). The end result is the method returns the closet point downward pointing line segments closest to + # the given upward pointing line segment. + # + # overlap_segs: This is an array of hashes that looks like: + # overlap_seg = { + # index_a1: i, + # index_a2: i-1, + # index_b1: j, + # index_b2: j-1, + # point_b1: surf_verts[j], + # point_b2: surf_verts[j-1], + # overlap_y: overlap_y + # } + # index_a1: The index of the array of points that cooresponds with the top of line a (points up) + # index_a1: The index of the array of points that cooresponds with the bottom of line a (points up) + # index_b1: The index of the array of points that cooresponds with the bottom of line b (points down) + # index_b1: The index of the array of points that cooresponds with the top of line b (points down) + # point_b1: The coordinates of the bottom of line b + # point_b2: The coordinates of the top of line b + # + # overlap_y: A hash that contains the coordinates of the top and bottom of the y projection of the overlapping + # lines (line a and line b) + # overlap_y = { + # overlap_start: overlap_start, + # overlap_end: overlap_end + # } + # overlap_start: The y coordinate of the top of the overlap + # overlap_end: The y coordinate of the bottom of the overlap + # + # index: The index of the array of points that cooresponds with the top of of the current upward pointing line. + # + # point_a1: The coordinates of the top of the first line + # point_a2: The coordinates of the bottom of the first line + # This naming convention was chosen because this method was originally designed to work with the + # 'make_concave_surfaces' method (see above). That method choses lines that point up and then sees where they + # overlap with lines pointing down. The point_1 of each line is the end of the line. In this case a lines point + # up and b lines point down. + def self.get_overlapping_segments(overlap_segs:, index:, point_a1:, point_a2:) + closest_overlaps = [] + linea_overlaps = [] + # This goes through all the line segments and determines which correspond to the current upward pointing line + # segment(line a). It also determines the x coordinate distance between the top and bottom of the overlapping + # portions of the line segments. + for j in 0..(overlap_segs.length - 1) + if (overlap_segs[j][:index_a1] == index) && (overlap_segs[j][:index_a2] == (index - 1)) + linea_x_top = line_segment_overlap_x_coord(y_check: overlap_segs[j][:overlap_y][:overlap_start], point_b1: point_a1, point_b2: point_a2) + linea_x_bottom = line_segment_overlap_x_coord(y_check: overlap_segs[j][:overlap_y][:overlap_end], point_b1: point_a1, point_b2: point_a2) + lineb_x_top = line_segment_overlap_x_coord(y_check: overlap_segs[j][:overlap_y][:overlap_start], point_b1: overlap_segs[j][:point_b1], point_b2: overlap_segs[j][:point_b2]) + lineb_x_bottom = line_segment_overlap_x_coord(y_check: overlap_segs[j][:overlap_y][:overlap_end], point_b1: overlap_segs[j][:point_b1], point_b2: overlap_segs[j][:point_b2]) + x_distance_top = linea_x_top - lineb_x_top + x_distance_bottom = linea_x_bottom - lineb_x_bottom + linea_overlap = { + dx_top: x_distance_top, + dx_bottom: x_distance_bottom, + overlap: overlap_segs[j] + } + linea_overlaps << linea_overlap + end + end + # This sorts through the overlapping downward pointing line segments corresponding to the current upward pointing + # line a. The overlapping downward pointing line segments closest to the current upward pointing line segment + # are kept. The other are discarded. Unique overlapping line segments are kept as well. There should only be + # unuique overlapping line segments or overlapping line segments that precisely match one another because of + # the 'subdivide_overlaps' method which this method is supposed to work with. + for j in 0..(linea_overlaps.length - 1) + overlap_found = false + for k in 0..(linea_overlaps.length - 1) + if linea_overlaps[j][:overlap] == linea_overlaps[k][:overlap] + next + elsif (linea_overlaps[j][:overlap][:overlap_y][:overlap_start] == linea_overlaps[k][:overlap][:overlap_y][:overlap_start]) && (linea_overlaps[j][:overlap][:overlap_y][:overlap_end] == linea_overlaps[k][:overlap][:overlap_y][:overlap_end]) + overlap_found = true + if (linea_overlaps[j][:dx_top] < linea_overlaps[k][:dx_top]) && (linea_overlaps[j][:dx_bottom] < linea_overlaps[k][:dx_bottom]) + closest_overlaps << linea_overlaps[j][:overlap] + end + end + end + if overlap_found == false + closest_overlaps << linea_overlaps[j][:overlap] + end + end + # This combines the line segments that belong together. These were broken apart because of the + # 'subdivide_overlaps' method. + overlap_exts = [closest_overlaps[0]] + for j in 0..(closest_overlaps.length - 1) + index = 0 + found = false + for l in 0..(overlap_exts.length - 1) + if overlap_exts[l][:index_b1] == closest_overlaps[j][:index_b1] && overlap_exts[l][:index_b2] == closest_overlaps[j][:index_b2] + index = l + found = true + break + end + end + if found == false + overlap_exts << closest_overlaps[j] + index = overlap_exts.length - 1 + end + for k in 0..(closest_overlaps.length - 1) + if (closest_overlaps[j][:index_b1] == closest_overlaps[k][:index_b1]) && (closest_overlaps[j][:index_b2] == closest_overlaps[k][:index_b2]) + if closest_overlaps[k][:overlap_y][:overlap_start] >= overlap_exts[index][:overlap_y][:overlap_start] + overlap_exts[index][:overlap_y][:overlap_start] = closest_overlaps[k][:overlap_y][:overlap_start] + end + if closest_overlaps[k][:overlap_y][:overlap_end] <= overlap_exts[index][:overlap_y][:overlap_end] + overlap_exts[index][:overlap_y][:overlap_end] = closest_overlaps[k][:overlap_y][:overlap_end] + end + end + end + end + return overlap_exts + end + + # This method was originally written to work with the 'make_concave_surfaces' method above. It takes the + # y-components of a bunch of line segemnts and cuts them up until they either are unique (no other overlapping + # components) or they match the y-components of other line segments. + # overlap_segs: This is an array of hashes that looks like: + # overlap_seg = { + # index_a1: i, + # index_a2: i-1, + # index_b1: j, + # index_b2: j-1, + # point_b1: surf_verts[j], + # point_b2: surf_verts[j-1], + # overlap_y: overlap_y + # } + # index_a1: The index of the array of points that cooresponds with the top of line a (points up) + # index_a1: The index of the array of points that cooresponds with the bottom of line a (points up) + # index_b1: The index of the array of points that cooresponds with the bottom of line b (points down) + # index_b1: The index of the array of points that cooresponds with the top of line b (points down) + # point_b1: The coordinates of the bottom of line b + # point_b2: The coordinates of the top of line b + # + # overlap_y: A hash that contains the coordinates of the top and bottom of the y projection of the overlapping + # lines (line a and line b) + # overlap_y = { + # overlap_start: overlap_start, + # overlap_end: overlap_end + # } + # overlap_start: The y coordinate of the top of the overlap + # overlap_end: The y coordinate of the bottom of the overlap + def self.subdivide_overlaps(overlap_segs:) + restart = true + # Keep doing this until the y projections of the lines are either unique or the match the y projections of other + # lines. + while restart == true + restart = false + overlap_segs.each do |overlap_seg| + for j in 0..(overlap_segs.length - 1) + # Skip this y projection if it is the same as that in overlap_seg + if overlap_seg == overlap_segs[j] + next + end + # Check to see if the y projection of line a overlaps with the y prjoection of line b + overlap_segs_overlap = line_segment_overlap_y?(point_a1: overlap_seg[:overlap_y][:overlap_start], point_a2: overlap_seg[:overlap_y][:overlap_end], point_b1: overlap_segs[j][:overlap_y][:overlap_end], point_b2: overlap_segs[j][:overlap_y][:overlap_start]) + # If the y projections of the two lines overlap then the components of overlap_segs_overlap should not be + # nil. + unless ((overlap_segs_overlap[:overlap_start].nil?) || (overlap_segs_overlap[:overlap_end].nil?)) + # If the two overlaping segments start and end at the same point then do nothing and go to the next segment. + if (overlap_seg[:overlap_y][:overlap_start] == overlap_segs[j][:overlap_y][:overlap_start]) && (overlap_seg[:overlap_y][:overlap_end] == overlap_segs[j][:overlap_y][:overlap_end]) + next + # If the start point of one overlapping segment shares the end point of the other overlapping segment then + # they are not really overlapping. Ignore and go to the next point. + elsif overlap_segs_overlap[:overlap_start] == overlap_segs_overlap[:overlap_end] + next + # If the overlap_seg segment covers beyond the overlap_segs[j] segment then break overlap_seg into three smaller pieces: + # -One piece for where overlap_seg starts to where overlap_segs[j] starts; + # -One piece to cover overlap_segs[j] (the middle part); and + # -One piece for where overlap_segs[j] ends to where overlap_seg ends (the bottom part). + # The overlap_segs[j] remains as it is associated with another upward pointing line segment. + # If overlap_seg starts at the same point as overlap_segs[j] or ends at the same point as overlap_segs[j] + # then overlap_seg is broken into two pieces (no mid piece). + elsif (overlap_seg[:overlap_y][:overlap_start] >= overlap_segs[j][:overlap_y][:overlap_start]) && (overlap_seg[:overlap_y][:overlap_end] <= overlap_segs[j][:overlap_y][:overlap_end]) + # If the overlap_seg and overlap_segs[j] start at the same point replace overlap_seg with two segments ( + # one top and one bottom). + if overlap_seg[:overlap_y][:overlap_start] == overlap_segs[j][:overlap_y][:overlap_start] + overlap_top = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_seg[:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_seg) + overlap_segs << overlap_top + overlap_segs << overlap_bottom + elsif overlap_seg[:overlap_y][:overlap_end] == overlap_segs[j][:overlap_y][:overlap_end] + # If the overlap_seg and overlap_segs[j] end at the same point replace overlap_seg with two segments ( + # one top and one bottom). + overlap_top_over = { + overlap_start: overlap_seg[:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_top_over + } + overlap_bottom = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_segs_overlap + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_seg) + overlap_segs << overlap_top + overlap_segs << overlap_bottom + elsif (overlap_seg[:overlap_y][:overlap_start] > overlap_segs[j][:overlap_y][:overlap_start]) && (overlap_seg[:overlap_y][:overlap_end] < overlap_segs[j][:overlap_y][:overlap_end]) + # If the overlap_seg stretches above and below overlap_segs[j] then break overlap_seg into three pieces + # (one top, one middle, one bottom). + overlap_top_over = { + overlap_start: overlap_seg[:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_top_over + } + overlap_mid = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_seg[:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_seg) + overlap_segs << overlap_top + overlap_segs << overlap_mid + overlap_segs << overlap_bottom + end + restart = true + break + # If the overlap_segs[j] segment covers beyond the overlap_seg segment then break overlap_segs[j] into three smaller pieces: + # -One piece for where overlap_segs[j] starts to where overlap_seg starts; + # -One piece to cover overlap_seg (the middle part); and + # -One piece for where overlap_seg ends to where overlap_segs[j] ends (the bottom part). + # The overlap_seg remains as it is associated with another upward pointing line segment. + # If overlap_segs[j] starts at the same point as overlap_seg or ends at the same point as overlap_seg + # then overlap_segs[j] is broken into two pieces (no mid piece). + elsif overlap_seg[:overlap_y][:overlap_start] <= overlap_segs[j][:overlap_y][:overlap_start] && overlap_seg[:overlap_y][:overlap_end] >= overlap_segs[j][:overlap_y][:overlap_end] + # If the overlap_seg and overlap_segs[j] start at the same point replace overlap_segs[j] with two segments ( + # one top and one bottom). + if overlap_seg[:overlap_y][:overlap_start] == overlap_segs[j][:overlap_y][:overlap_start] + overlap_top = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_segs[j][:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_segs[j]) + overlap_segs << overlap_top + overlap_segs << overlap_bottom + elsif overlap_seg[:overlap_y][:overlap_end] == overlap_segs[j][:overlap_y][:overlap_end] + # If the overlap_seg and overlap_segs[j] end at the same point replace overlap_segs[j] with two segments ( + # one top and one bottom). + overlap_top_over = { + overlap_start: overlap_segs[j][:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_top_over + } + overlap_bottom = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_segs_overlap + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_segs[j]) + overlap_segs << overlap_top + overlap_segs << overlap_bottom + elsif overlap_seg[:overlap_y][:overlap_start] < overlap_segs[j][:overlap_y][:overlap_start] && overlap_seg[:overlap_y][:overlap_end] > overlap_segs[j][:overlap_y][:overlap_end] + # If the overlap_segs[j] stretches above and below overlap_seg then break overlap_segs[j] into three pieces + # (one top, one middle, one bottom). + overlap_top_over = { + overlap_start: overlap_segs[j][:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_top_over + } + overlap_mid = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_segs[j][:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_segs[j]) + overlap_segs << overlap_top + overlap_segs << overlap_mid + overlap_segs << overlap_bottom + end + restart = true + break + # if overlap_seg covers the top of overlap_segs[j] then break overlap_seg into a top and an overlap portion + # ond break overlap_segs[j] into an overlap portion and a bottom portion. + elsif (overlap_seg[:overlap_y][:overlap_start] >= overlap_segs[j][:overlap_y][:overlap_start]) && (overlap_seg[:overlap_end] <= overlap_segs[j][:overlap_start]) && (overlap_seg[:overlap_y][:overlap_end] > overlap_segs[j][:overlap_y][:overlap_end]) + overlap_top_over = { + overlap_start: overlap_seg[:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_top_over + } + overlap_mid_seg = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_mid_segs = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_segs[j][:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_seg) + overlap_segs.delete(overlap_segs[j]) + overlap_segs << overlap_top + overlap_segs << overlap_mid_seg + overlap_segs << overlap_mid_segs + overlap_segs << overlap_bottom + restart = true + break + elsif (overlap_seg[:overlap_y][:overlap_start] >= overlap_segs[j][:overlap_y][:overlap_end]) && (overlap_seg[:overlap_end] < overlap_segs[j][:overlap_end]) && (overlap_seg[:overlap_y][:overlap_start] <= overlap_segs[j][:overlap_y][:overlap_start]) + # if overlap_seg covers the bottom of overlap_segs[j] then break overlap_segs[j] into a top and an overlap portion + # ond break overlap_seg into an overlap portion and a bottom portion. + overlap_top_over = { + overlap_start: overlap_segs[j][:overlap_y][:overlap_start], + overlap_end: overlap_segs_overlap[:overlap_start] + } + overlap_top = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_top_over + } + overlap_mid_seg = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_mid_segs = { + index_a1: overlap_segs[j][:index_a1], + index_a2: overlap_segs[j][:index_a2], + index_b1: overlap_segs[j][:index_b1], + index_b2: overlap_segs[j][:index_b2], + point_b1: overlap_segs[j][:point_b1], + point_b2: overlap_segs[j][:point_b2], + overlap_y: overlap_segs_overlap + } + overlap_bottom_over = { + overlap_start: overlap_segs_overlap[:overlap_end], + overlap_end: overlap_seg[:overlap_y][:overlap_end] + } + overlap_bottom = { + index_a1: overlap_seg[:index_a1], + index_a2: overlap_seg[:index_a2], + index_b1: overlap_seg[:index_b1], + index_b2: overlap_seg[:index_b2], + point_b1: overlap_seg[:point_b1], + point_b2: overlap_seg[:point_b2], + overlap_y: overlap_bottom_over + } + # delete the existing y projection overlaps and replace it with the ones we just made. + overlap_segs.delete(overlap_seg) + overlap_segs.delete(overlap_seg[j]) + overlap_segs << overlap_top + overlap_segs << overlap_mid_seg + overlap_segs << overlap_mid_segs + overlap_segs << overlap_bottom + restart = true + break + end + end + end + if restart == true + break + end + end + end + return overlap_segs + end + + # This method determines if the y component of 2 lines overlap. + # point_a1: The top of the first line + # point_a2: The bottom of the first line + # point_b1: The bottom of the second line + # point_b2: The top of the second line. + # This naming convention was chosen because this method was originally designed to work with the + # 'make_concave_surfaces' method (see above). That method choses lines that point up and then sees where they + # overlap with lines pointing down. The point_1 of each line is the end of the line. In this case a lines point + # up and b lines point down. + def self.line_segment_overlap_y?(point_a1:, point_a2:, point_b1:, point_b2:) + overlap_start = nil + overlap_end = nil + # If line a overlaps with the bottom of line b do this: + if (point_a1 >= point_b1) && (point_a2 <= point_b1) + overlap_start = point_a1 + overlap_end = point_b1 + # This checks if all of line b is overlapped by line a + if point_a1 >= point_b2 + overlap_start = point_b2 + end + # If line a overlaps with the top of line b do this: + elsif (point_a1 >= point_b2) && (point_a2 <= point_b2) + overlap_start = point_b2 + overlap_end = point_a2 + # This checks if all of line b is overlapped by line a + if point_a2 <= point_b1 + overlap_end = point_b1 + end + # This checks if all of line a fits in line b + elsif (point_a1 <= point_b2) && (point_a2 >= point_b1) + overlap_start = point_a1 + overlap_end = point_a2 + end + # Overlap vectors always point down. Thus overlap_start is the y location of the top of the overlap vector and + # overlap_end is the y location of the bottom of the overlap vector. The overlap vector will later be constructed + # using point_b1 and point_b2 and checking which overlaps are closest (and not obstructed) by other overlaps. + overlap_y = { + overlap_start: overlap_start, + overlap_end: overlap_end + } + return overlap_y + end + + # This method determines the x coordinate of where a given y coordinate crosses a given line. + # y_check: The y coordinate that you want to determine the x coordinate for on a line + # point_b1: The coordinates of the bottom of the line + # point_b2: The coordinates of the top of the line + def self.line_segment_overlap_x_coord(y_check:, point_b1:, point_b2:) + # If the line is vertical then all x coordinates are the same + if point_b1[:x] == point_b2[:x] + xcross = point_b2[:x] + # If the line is horizontal you cannot find the y intercept + elsif point_b1[:y] == point_b2[:x] + raise("This line is horizontal so no y intercept can be found.") + # Otherwise determine the line coefficients and get the intercept + else + a = (point_b1[:y] - point_b2[:y]) / (point_b1[:x] - point_b2[:x]) + b = point_b1[:y] - a * point_b1[:x] + xcross = (y_check - b) / a + end + return xcross + end + + # This method finds the centroid of a surface using the point averaging method. OpenStudio already has something + # which does this but you have to turn something into a special OpenStudio surface first which you may not want + # to do. + def self.surf_centroid(surf:) + new_surf_cent = { + x: 0, + y: 0, + z: 0 + } + surf.each do |surf_vert| + new_surf_cent[:x] += surf_vert[:x] + new_surf_cent[:y] += surf_vert[:y] + new_surf_cent[:z] += surf_vert[:z] + end + new_surf_cent[:x] /= surf.length + new_surf_cent[:y] /= surf.length + new_surf_cent[:z] /= surf.length + return new_surf_cent + end end #Module Surfaces end #module Geometry -end \ No newline at end of file +end