Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question
5

Best practice for determining if two Surfaces intersect?

asked 2020-04-06 11:56:06 -0600

jugonzal07's avatar

updated 2020-04-06 15:26:37 -0600

Hi all,

I'm looking to find the best way to use the OpenStudio SDK to check if two surfaces intersect. Rather than write my own code to do this, I assumed there's likely something packaged into the SDK to help me do this.

Ideally, the code would look something like.

#Made up function 'intersectsWith'
surfaces_intersect = surface1.intersectsWith(surface2)

if surfaces_intersect 
   #DO SOMETHING
end

Where

  • surface1,surface2 are OpenStudio::Model::Surface
  • surfaces_intersect = a boolean that determines if surface1 and surface2 intersect

I've looked into the computeIntersection for Surface found here but am unsure if this is path would be the most elegant way to do this.

For context, I'm trying to dynamically determine the perimeter of a floor surface exposed to ambient to set them for a FFactorGroundFloorConstruction. I haven't seen any way to easily do this in OpenStudio. Here is my approach:

  1. Identify if floor with outside boundary condition equal to Ground. If so, flag as a floor requiring a FFactorGroundFloorConstruction
  2. Identify all walls in this floor's space. If the wall's outside boundary condition is Outdoors AND it intersects the floor of interest, find it's projection on the x, y plane (i.e. the length of floor that is exposed to perimeter along this wall). NOTE: This assumes a wall only touches 1 floor; this might not always be true.
  3. Add these perimeters for the floor to ultimately arrive at the exposed perimeter.

I cannot complete step two as I do not have a way to determine if a wall intersects a floor surface.

Any ideas? Thanks!

edit retag flag offensive close merge delete

Comments

1

My solution to the ground-exposed perimeter problem is to find the spaces with floor BCs of "Ground", loop through that space's "Outdoor"-exposed walls, find the two vertices with minimum z coordinates and calculate the distance between those two coordinates (and sum for all such surfaces). Probably not the most general or foolproof method, but works for most of my geometry.

ericringold's avatar ericringold  ( 2020-04-06 15:45:48 -0600 )edit

Thanks Eric! That's not a bad idea. The issue I ran into recently was when a building had "stacked" walls on the same plane. Since I didn't check whether each wall intersected with the floor surface, I ended up double counting perimeters. If I implemented something similar to what you suggested but then also did a check that the "z" coordinate was along the same plane as the floor, I bet it would work. I'm hoping to find a more elegant "OpenStudio" way of doing it, but so far finding nothing.

jugonzal07's avatar jugonzal07  ( 2020-04-06 15:53:35 -0600 )edit
2

Yeah or you could always store the global min-Z for all surfaces and compare against that. Which would fail if you had different ground elevations, but that's a pretty special case. BTW it looks like computeIntersection would fail if the surfaces are not coplanar.

ericringold's avatar ericringold  ( 2020-04-06 16:02:41 -0600 )edit

3 Answers

Sort by » oldest newest most voted
2

answered 2020-07-01 12:51:24 -0600

jugonzal07's avatar

updated 2020-10-16 11:31:52 -0600

Hi all,

I ended up writing my own script for calculating a wall and floor intersection. It comes with some caveats (found in the comments) but it can be found here:

https://github.com/NREL/openstudio-st...

It's how I ended up solving this issue. It's not super generalized, but works for calculating most cases of walls and floors. Any feedback on it would be greatly appreciated.

Thanks!

EDIT: Updated URL

edit flag offensive delete link more

Comments

@jugonzal07 the link is not available anymore.

Adrià González-Esteve's avatar Adrià González-Esteve  ( 2020-10-16 09:33:17 -0600 )edit

Thanks for catching that. I have updated the link.

jugonzal07's avatar jugonzal07  ( 2020-10-16 11:32:15 -0600 )edit
4

answered 2020-04-06 17:47:07 -0600

@jugonzal07 I think by intersect here you are referring to two surfaces which share a common edge, as opposed to intersect surfaces related to surface matching, where you have to split a surface into two more elements to be able to match it to the adjacent zone.

We have a method to calculate building perimeter by story that works very much as you describe. It does have some limitations but it works in most cases. It creates an array of edges in a space and then store surfaces that use that edge. It finds an edge which has an exterior wall, and also has a ground or interior exposed floor. It then adds these together. This is in the openstudio-extension gem which is included with OpenStudio much like the openstudio-standardsgem. https://github.com/NREL/openstudio-ex...

An alternative approach I have played with is using method in OpenStudio that merges multiple polygons into a single polygon. Then you can just sum the length of the edges. I have used this method to create a geojson footprint from an OpenStudio model. There were some issues with this so it was not stable enough for me to want to use to calculate perimeter yet but if you want to explore that I can find a link to it.

edit flag offensive delete link more

Comments

This looks super interesting. I will play around with the calculate_perimeter method.

Luis Lara's avatar Luis Lara  ( 2020-04-06 18:31:01 -0600 )edit

Thanks David, I ended up using a similar idea to what you had. You can find it in my answer above.

jugonzal07's avatar jugonzal07  ( 2020-07-01 12:52:29 -0600 )edit
1

answered 2020-10-16 09:33:59 -0600

Based on this, I wrote the following function that I've just shared.

  def self.get_length(vertices_a, vertices_b)
    length = 0.0

    vertices_a.each_with_index do |vertex_a, index_a|
      prev_a = vertices_a[index_a-1]
      vertices_b.each_with_index do |vertex_b, index_b|
        prev_b = vertices_b[index_b-1]

        p1 = prev_a
        p2 = vertex_a
        p3 = prev_b
        p4 = vertex_b

        p12 = p2-p1
        p34 = p4-p3

        next unless p12.cross(p34).length < 1e-6

        p13 = p3-p1

        next unless p12.cross(p13).length < 1e-6

        p14 = p4-p1

        k2 = p12.dot(p12)
        k3 = p12.dot(p13)
        k4 = p12.dot(p14)

        table = [
          [0.0, p14.length, p12.length],
          [p13.length, p34.length, (p3-p2).length],
          [p12.length, (p4-p2).length, 0.0]
        ]

        row = if k3 < 1e-6 then
          0
        elsif k3 < k2 then
          1
        else
          2
        end

        col = if k4 < 1e-6 then
          0
        elsif k4 < k2 then
          1
        else
          2
        end

        length += table[row][col]
      end
    end
    length /= 2 if vertices_a.length.eql?(2)
    length /= 2 if vertices_b.length.eql?(2)

    return length
  end
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Training Workshops

Careers

Question Tools

2 followers

Stats

Asked: 2020-04-06 11:56:06 -0600

Seen: 383 times

Last updated: Oct 16 '20