Module: BTAP::Geometry::Surfaces

Defined in:
lib/openstudio-standards/btap/geometry.rb

Class Method Summary collapse

Class Method Details

.create_surface(model, name, os_point3d_array, boundary_condition = "", construction = "") ⇒ Object



549
550
551
552
553
554
555
556
557
558
559
# File 'lib/openstudio-standards/btap/geometry.rb', line 549

def self.create_surface(model, name, os_point3d_array, boundary_condition = "", construction = "")
  os_surface = OpenStudio::Model::Surface.new(os_point3d_array, model)
  os_surface.setName(name)
  if OpenStudio::Model::Surface::validOutsideBoundaryConditionValues.include?(boundary_condition)
    self.set_surfaces_boundary_condition([os_surface], boundary_condition)
  else
    puts "boundary condition not set for #{name}"
  end
  os_surface.setConstruction(construction)
  return os_surface
end

.filter_by_azimuth_and_tilt(surfaces, azimuth_from, azimuth_to, tilt_from, tilt_to, tolerance = 1.0) ⇒ Object

Azimuth start from Y axis, Tilts starts from Z-axis



743
744
745
746
747
748
749
750
751
# File 'lib/openstudio-standards/btap/geometry.rb', line 743

def self.filter_by_azimuth_and_tilt(surfaces, azimuth_from, azimuth_to, tilt_from, tilt_to, tolerance = 1.0)
  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

.filter_by_boundary_condition(surfaces, boundary_conditions) ⇒ Object



674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/openstudio-standards/btap/geometry.rb', line 674

def self.filter_by_boundary_condition(surfaces, boundary_conditions)
  #check to see if a string or an array was passed.
  if boundary_conditions.kind_of?(String)
    temp = boundary_conditions
    boundary_conditions = Array.new()
    boundary_conditions.push(temp)
  end
  #ensure boundary conditions are valid
  boundary_conditions.each do |boundary_condition|
    unless OpenStudio::Model::Surface::validOutsideBoundaryConditionValues.include?(boundary_condition)
      raise "ERROR: Invalid Boundary Condition = " + boundary_condition + "Correct Values are:" + OpenStudio::Model::Surface::validOutsideBoundaryConditionValues.to_s
    end
  end
  #create return array.
  return_array = Array.new()

  if boundary_conditions.size == 0 or boundary_conditions[0].upcase == "All".upcase
    return_array = surfaces
  else
    surfaces.each do |surface|
      boundary_conditions.each do |condition|
        if surface.outsideBoundaryCondition == condition
          return_array.push(surface)
        end
      end
    end
  end
  return return_array
end

.filter_by_interzonal_surface(surfaces) ⇒ Object



732
733
734
735
736
737
738
739
740
# File 'lib/openstudio-standards/btap/geometry.rb', line 732

def self.filter_by_interzonal_surface(surfaces)
  return_array = Array.new()
  surfaces.each do |surface|
    unless surface.adjacentSurface().empty?
      return_array.push(surface)
    end
    return return_array
  end
end

.filter_by_non_defaulted_surfaces(surfaces) ⇒ Object



668
669
670
671
672
# File 'lib/openstudio-standards/btap/geometry.rb', line 668

def self.filter_by_non_defaulted_surfaces(surfaces)
  non_defaulted_surfaces = Array.new()
  surfaces.each {|surface| non_defaulted_surfaces << surface unless surface.isConstructionDefaulted}
  return non_defaulted_surfaces
end

.filter_by_surface_types(surfaces, surfaceTypes) ⇒ Object



704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
# File 'lib/openstudio-standards/btap/geometry.rb', line 704

def self.filter_by_surface_types(surfaces, surfaceTypes)

  #check to see if a string or an array was passed.
  if surfaceTypes.kind_of?(String)
    temp = surfaceTypes
    surfaceTypes = Array.new()
    surfaceTypes.push(temp)
  end
  surfaceTypes.each do |surfaceType|
    unless OpenStudio::Model::Surface::validSurfaceTypeValues.include?(surfaceType)
      raise("ERROR: Invalid surface type = #{surfaceType} Correct Values are: #{OpenStudio::Model::Surface::validSurfaceTypeValues}")
    end
  end
  return_array = Array.new()
  if surfaceTypes.size == 0 or surfaceTypes[0].upcase == "All".upcase
    return_array = self
  else
    surfaces.each do |surface|
      surfaceTypes.each do |surfaceType|
        if surface.surfaceType == surfaceType
          return_array.push(surface)
        end
      end
    end
  end
  return return_array
end

.filter_subsurfaces_by_types(subsurfaces, subSurfaceTypes) ⇒ Object

“FixedWindow” , “OperableWindow” , “Door” , “GlassDoor”, “OverheadDoor” , “Skylight”, “TubularDaylightDiffuser”,“TubularDaylightDome”


595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/openstudio-standards/btap/geometry.rb', line 595

def self.filter_subsurfaces_by_types(subsurfaces, subSurfaceTypes)

  #check to see if a string or an array was passed.
  if subSurfaceTypes.kind_of?(String)
    temp = subSurfaceTypes
    subSurfaceTypes = Array.new()
    subSurfaceTypes.push(temp)
  end
  subSurfaceTypes.each do |subSurfaceType|
    unless OpenStudio::Model::SubSurface::validSubSurfaceTypeValues.include?(subSurfaceType)
      raise("ERROR: Invalid surface type = #{subSurfaceType} Correct Values are: #{OpenStudio::Model::SubSurface::validSubSurfaceTypeValues}")
    end
  end
  return_array = Array.new()
  if subSurfaceTypes.size == 0 or subSurfaceTypes[0].upcase == "All".upcase
    return_array = self
  else
    subsurfaces.each do |subsurface|
      subSurfaceTypes.each do |subSurfaceType|
        if subsurface.subSurfaceType == subSurfaceType
          return_array.push(subsurface)
        end
      end
    end
  end
  return return_array

end

.get_overlapping_segments(overlap_segs:, index:, point_a1:, point_a2:) ⇒ Object

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.



987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
# File 'lib/openstudio-standards/btap/geometry.rb', line 987

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.
  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.
  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
  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

.getSurfaceAreafromVertices(vertices:) ⇒ Object

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.



1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
# File 'lib/openstudio-standards/btap/geometry.rb', line 1557

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

.hide(surfaces) ⇒ Object



763
764
765
766
767
768
769
770
771
# File 'lib/openstudio-standards/btap/geometry.rb', line 763

def self.hide(surfaces)
  surfaces.each do |surface|
    if drawing_interface = surface.drawing_interface
      if entity = drawing_interface.entity
        entity.visible = false
      end
    end
  end
end

.line_segment_overlap_x_coord(y_check:, point_b1:, point_b2:) ⇒ Object

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



1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
# File 'lib/openstudio-standards/btap/geometry.rb', line 1511

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[:y])
    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

.line_segment_overlap_y?(point_a1:, point_a2:, point_b1:, point_b2:) ⇒ Boolean

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.

Returns:

  • (Boolean)


1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
# File 'lib/openstudio-standards/btap/geometry.rb', line 1473

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

.make_convex_surfaces(surface:, tol: 12) ⇒ Object

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.



796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
# File 'lib/openstudio-standards/btap/geometry.rb', line 796

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.
        # I revised this to check if the start or end of the current (index i) line segment is to the left of the
        # line segment being checked.
        #if surf_verts[j][:x] < surf_verts[i][:x] and surf_verts[j - 1][:x] < surf_verts[i - 1][:x]
        if surf_verts[j][:x] < surf_verts[i][:x] || 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 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 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]}
        # 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.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.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.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.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
              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

.rotate_tilt_translate_surfaces(planar_surfaces, azimuth_degrees, tilt_degrees = 0.0, translation_vector = OpenStudio::Vector3d.new(0.0, 0.0, 0.0)) ⇒ OpenStudio::Model::Model

This method will rotate a surface

Parameters:

  • planar_surfaces (Array<OpenStudio::Model::Surface>)

    an array of surfaces

  • azimuth_degrees (Float)

    rotation value

  • tilt_degrees (Float) (defaults to: 0.0)

    rotation value

  • translation_vector (OpenStudio::Vector3d) (defaults to: OpenStudio::Vector3d.new(0.0, 0.0, 0.0))

    a vector along which to move all surfaces

Returns:

  • (OpenStudio::Model::Model)

    the model object.



567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/openstudio-standards/btap/geometry.rb', line 567

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)
  translation_matrix = OpenStudio::createTranslation(translation_vector)
  planar_surfaces.each do |surface|
    surface.changeTransformation(azimuth_matrix)
    surface.changeTransformation(tilt_matrix)
    surface.changeTransformation(translation_matrix)
  end
  return planar_surfaces
end

.set_fenestration_to_wall_ratio(surfaces, ratio, offset = 0, height_offset_from_floor = true, floor = "all") ⇒ Object



580
581
582
583
584
585
586
587
588
589
590
591
592
# File 'lib/openstudio-standards/btap/geometry.rb', line 580

def self.set_fenestration_to_wall_ratio(surfaces, ratio, offset = 0, height_offset_from_floor = true, floor = "all")
  surfaces.each do |surface|
    result = surface.setWindowToWallRatio(ratio, offset, height_offset_from_floor)
    raise("Unable to set FWR for surface " +
              surface.name.get.to_s +
              " . Possible reasons are  if the surface is not a wall, if the surface
    is not rectangular in face coordinates, if requested ratio is too large
    (window area ~= surface area) or too small (min dimension of window < 1 foot),
    or if the window clips any remaining sub surfaces. Otherwise, removes all
    existing windows and adds new window to meet requested ratio.") unless result
  end
  return surfaces
end

.set_surfaces_boundary_condition(model, surfaces, boundaryCondition) ⇒ Object

This method sets the boundary condition for a surface and it’s matching surface.

If set to adiabatic, it will remove all subsurfaces since E+ cannot have adiabatic sub surfaces.


640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/openstudio-standards/btap/geometry.rb', line 640

def self.set_surfaces_boundary_condition(model, surfaces, boundaryCondition)
  surfaces = BTAP::Common::validate_array(model, surfaces, "Surface")
  if OpenStudio::Model::Surface::validOutsideBoundaryConditionValues.include?(boundaryCondition)
    surfaces.each do |surface|
      if boundaryCondition == "Adiabatic"
        #need to remove subsurface as you cannot have a adiabatic surface with a
        #subsurface.
        surface.subSurfaces.each do |subsurface|
          subsurface.remove
        end

        #A bug with adiabatic surfaces. They do not hold the default contruction.
        surface.setConstruction(surface.construction.get()) if surface.isConstructionDefaulted
      end

      surface.setOutsideBoundaryCondition(boundaryCondition)
      adj_surface = surface.adjacentSurface
      unless adj_surface.empty?
        adj_surface.get.setOutsideBoundaryCondition(boundaryCondition)
      end
    end
  else
    puts "ERROR: Invalid Boundary Condition = " + boundary_condition
    puts "Correct Values are:"
    puts OpenStudio::Model::Surface::validOutsideBoundaryConditionValues
  end
end

.set_surfaces_construction_conductance(surfaces, conductance) ⇒ Object

This method creates a new construction based on the current, changes the rsi and assign the construction to the current surface. Most of the meat of this method is in the construction class. Testing is done there.



626
627
628
629
630
631
632
633
634
635
636
# File 'lib/openstudio-standards/btap/geometry.rb', line 626

def self.set_surfaces_construction_conductance(surfaces, conductance)
  surfaces.each do |surface|
    #a bit of acrobatics to get the construction object from the ConstrustionBase object's name.
    construction = OpenStudio::Model::getConstructionByName(surface.model, surface.construction.get.name.to_s).get
    #create a new construction with the requested conductance value based on the current construction.

    new_construction = BTAP::Resources::Envelope::Constructions::customize_opaque_construction(surface.model, construction, conductance)
    surface.setConstruction(new_construction)
  end
  return surfaces
end

.show(surfaces) ⇒ Object



753
754
755
756
757
758
759
760
761
# File 'lib/openstudio-standards/btap/geometry.rb', line 753

def self.show(surfaces)
  surfaces.each do |surface|
    if drawing_interface = surface.drawing_interface
      if entity = drawing_interface.entity
        entity.visible = false
      end
    end
  end
end

.subdivide_overlaps(overlap_segs:) ⇒ Object

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



1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
# File 'lib/openstudio-standards/btap/geometry.rb', line 1083

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_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 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.
          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_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).
              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_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).
              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_at(curr_seg_index)
              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_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).
              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_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).
              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_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_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 = {
                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.
            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
            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.
            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
            break
          end
        end
      end
      if restart == true
        break
      end
    end
  end
  return overlap_segs
end

.surf_centroid(surf:) ⇒ Object

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.



1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
# File 'lib/openstudio-standards/btap/geometry.rb', line 1530

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