lib/openstudio-standards/btap/geometry.rb in openstudio-standards-0.2.14 vs lib/openstudio-standards/btap/geometry.rb in openstudio-standards-0.2.15.pre.rc1

- old
+ new

@@ -3107,41 +3107,56 @@ # 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 + # 3. Makes quadrilaterals (or triangles as the case may be) out of each upward pointing 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) + # Remove redundant overlapping segments + recheck = true + while recheck + recheck = false + # Go through each overlapping segment and look for duplicate segments + overlap_segs.each_with_index do |ind_overlap_seg, seg_index| + # Find duplicate overlapping segments + redundant_segs = overlap_segs.select { |check_seg| check_seg == ind_overlap_seg} + # Remove the first one and then restart the while loop to recompile the seg_index + if redundant_segs.size > 1 + overlap_segs.delete_at(seg_index) + recheck = true + end + end + end 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 + # Finds the closest overlapping downward pointing line segments that correspond to this upward 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]]} + 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} + new_surf << {x: x_loc.to_f.round(tol), y: y_loc.to_f.round(tol), z: z_loc.to_f.round(tol)} 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} + new_surf << {x: x_loc.to_f.round(tol), y: y_loc.to_f.round(tol), z: z_loc.to_f.round(tol)} 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} + new_surf << {x: x_loc.to_f.round(tol), y: y_loc.to_f.round(tol), z: z_loc.to_f.round(tol)} 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} + new_surf << {x: x_loc.to_f.round(tol), y: y_loc.to_f.round(tol), z: z_loc.to_f.round(tol)} # 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 @@ -3212,47 +3227,41 @@ 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 + curr_overlap_segs = overlap_segs.select { |seg| (seg[:index_a1] == index) && (seg[:index_a2] == (index - 1)) } + curr_overlap_segs.each do |overlap_seg| + line_a_x_top = line_segment_overlap_x_coord(y_check: overlap_seg[:overlap_y][:overlap_start], point_b1: point_a1, point_b2: point_a2) + line_a_x_bottom = line_segment_overlap_x_coord(y_check: overlap_seg[:overlap_y][:overlap_end], point_b1: point_a1, point_b2: point_a2) + line_b_x_top = line_segment_overlap_x_coord(y_check: overlap_seg[:overlap_y][:overlap_start], point_b1: overlap_seg[:point_b1], point_b2: overlap_seg[:point_b2]) + line_b_x_bottom = line_segment_overlap_x_coord(y_check: overlap_seg[:overlap_y][:overlap_end], point_b1: overlap_seg[:point_b1], point_b2: overlap_seg[:point_b2]) + x_distance_top = line_a_x_top - line_b_x_top + x_distance_bottom = line_a_x_bottom - line_b_x_bottom + linea_overlap = { + dx_top: x_distance_top, + dx_bottom: x_distance_bottom, + overlap: overlap_seg + } + linea_overlaps << linea_overlap 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 + linea_overlaps.each do |line_a_overlap| + overlaps = linea_overlaps.select { |seg| seg[:overlap][:overlap_y] == line_a_overlap[:overlap][:overlap_y]} + if overlaps.size > 1 + redundant_overlap = closest_overlaps.select { |dup_seg| dup_seg[:overlap_y] == overlaps[0][:overlap][:overlap_y] } + closest_overlaps << (overlaps.min_by { |dup_seg| dup_seg[:dx_top] })[:overlap] if redundant_overlap.empty? + elsif overlaps.size == 1 + closest_overlaps << overlaps[0][:overlap] 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 @@ -3314,17 +3323,17 @@ 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| + overlap_segs.each_with_index do |overlap_seg, curr_seg_index| 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 + # Check to see if the y projection of line a overlaps with the y projection 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. @@ -3366,11 +3375,11 @@ 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_at(curr_seg_index) 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). @@ -3395,11 +3404,11 @@ 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.delete_at(curr_seg_index) 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). @@ -3437,11 +3446,11 @@ 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_at(curr_seg_index) overlap_segs << overlap_top overlap_segs << overlap_mid overlap_segs << overlap_bottom end restart = true @@ -3478,11 +3487,11 @@ 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.delete_at(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). @@ -3507,11 +3516,11 @@ 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.delete_at(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). @@ -3549,20 +3558,20 @@ 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.delete_at(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]) + 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_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 = { @@ -3604,12 +3613,17 @@ 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]) + if curr_seg_index > j + overlap_segs.delete_at(curr_seg_index) + overlap_segs.delete_at(j) + else + overlap_segs.delete_at(j) + overlap_segs.delete_at(curr_seg_index) + end overlap_segs << overlap_top overlap_segs << overlap_mid_seg overlap_segs << overlap_mid_segs overlap_segs << overlap_bottom restart = true @@ -3660,12 +3674,17 @@ 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]) + if curr_seg_index > j + overlap_segs.delete_at(curr_seg_index) + overlap_segs.delete_at(j) + else + overlap_segs.delete_at(j) + overlap_segs.delete_at(curr_seg_index) + end overlap_segs << overlap_top overlap_segs << overlap_mid_seg overlap_segs << overlap_mid_segs overlap_segs << overlap_bottom restart = true @@ -3760,9 +3779,37 @@ end new_surf_cent[:x] /= surf.length new_surf_cent[:y] /= surf.length new_surf_cent[:z] /= surf.length return new_surf_cent + end + + # This method calculates the surface area of a 2-D polygon from an array of OpenStudio vertices. It ignores any z + # vertices. This method assumes that the polygon is complete, has no holes, does not cross itself, and that the + # vertices are provided in counter-clockwise order. This method is used in cases when you want to find the area + # of something before creating an OpenStudio surface/subsurface. + # + # Input arguments: + # vetices: Array of openstudio vertices. + # + # Output: + # Area: Float, area of polygot represented by the vertices. + def self.getSurfaceAreafromVertices(vertices:) + area = 0.0 + numberVertices = vertices.size + + # Check that a polygon is actually provided and not just a line or point. Return 0 if the vertices are a line + # or point. + return 0.0 if numberVertices < 3 + + # Go through the vertices and get the cross product. This adopted from: + # https://web.archive.org/web/20100405070507/http://valis.cs.uiuc.edu/~sariel/research/CG/compgeom/msg00831.html + vertices.each_with_index do |vertex, i| + j = (i + 1) % numberVertices + area += vertex.x.to_f * vertices[j].y.to_f + area -= vertex.y.to_f * vertices[j].x.to_f + end + return area end end #Module Surfaces end #module Geometry end