zoukankan      html  css  js  c++  java
  • 寻找房间中心zz

    Finding the Centroid of a Room Boundary

    It's been a while since my last post and I'm sure most of you were like... "Where the hell is Don!".... it's ok! I'm still around. I've been busy working on stuff I can't talk about. Don't worry though, I'm not a good secret keeper.
    So this post is going to explain something that a bunch of folks have issues with that involves finding the actual centroid of a polygon, or in this case a Room element. Now let's be careful not to confuse a centroid with a pair of midpoints taken from the furthest X and Y planes... a centroid is more closely described as the center of mass within a polygon.

    pic_0

    Now this is done by taking a series of 2D points and running some tricky math on them and dividing the points by 6x the area of the polygon. So to make it simple for you guys, I've taken the liberty of sharing a couple of functions that makes this all possible. The samples here are in Revit 2011 format.
    First you'll need a function that iterates through the boundary segments of a Room Element and builds up a series of 2D points taken from either endpoints of each segment (no need to worry about curved segments since they usually wont effect the centroid too much, or you can add the midpoint of the curve arc to get it closer).
    This little Function will return a list of 2D PointF from a boundary of a Room element.

    ''' <summary>
        ''' Extract a List of 2D Points from a Room's Boundary
        ''' </summary>
        ''' <param name="p_room"></param>
        ''' <remarks></remarks>
        Private Sub ExtractBoundaryPointsFromRoom(p_room As Room)
            ' The Points List
            Dim m_pts As New List(Of PointF)
            ' The Z Height
            Dim m_z As Double = 0
            ' Work with the Boundary
            Dim m_bsaa As Autodesk.Revit.DB.Architecture.BoundarySegmentArrayArray = m_room.Boundary
            ' Segment Array at Floor Level
            For Each bsa As Autodesk.Revit.DB.Architecture.BoundarySegmentArray In m_bsaa
                Try
                    For Each bs As Autodesk.Revit.DB.Architecture.BoundarySegment In bsa
                        Dim m_c As Curve = bs.Curve
                        ' First Endpoint
                        Dim m_EndPoint1 As XYZ = m_c.EndPoint(0)
                        Dim m_PointF1 As New PointF(m_EndPoint1(0), m_EndPoint1(1))
                        m_pts.Add(m_PointF1)
                        ' Second Endpoint
                        Dim m_EndPoint2 As XYZ = m_c.EndPoint(1)
                        Dim m_PointF2 As New PointF(m_EndPoint2(0), m_EndPoint2(1))
                        m_pts.Add(m_PointF2)
                        ' The Height
                        m_z = m_EndPoint1(2)
                    Next
                Catch ex As Exception
    
                End Try
            Next
            ' Return the 2D Centroid
            Dim m_2Dcentroid As PointF = FindCentroid(m_pts.ToArray, m_room.Area)
            ' Add the Floor Level of Boundary for Z Elevation
            InsertionPoint = New XYZ(m_2Dcentroid.X, m_2Dcentroid.Y, m_z)
        End Sub

    The Function below will take a list of points (first gathered from the segments array of a room) and convert them to a real life centroid in 2D format. The Z elevation is pretty easy to figure out for a room and what ever you're using this for is typically going to use 0 or a preset elevation for the result anyway.
    ''' <summary>
        ''' Find 2D Centroid
        ''' </summary>
        ''' <param name="pts">Collection of Points Describing the Polygon</param>
        ''' <param name="p_rmArea">The Area of the Polygon</param>
        ''' <returns>2D Point (Pointf)</returns>
        ''' <remarks>This Function Kicks Ass</remarks>
        Private Function FindCentroid(ByVal pts() As PointF, p_rmArea As Single) As PointF
            ' Add the First PT to the End of the Array (full circulation)
            ReDim Preserve pts(pts.Length)
            pts(pts.Length - 1) = New PointF(pts(0).X, pts(0).Y)
            ' Get the Centroid
            Dim X As Single = 0
            Dim Y As Single = 0
            Dim m_sf As Single
            ' This is Where the Magic Happens
            For i As Integer = 0 To pts.Length - 2
                m_sf = pts(i).X * pts(i + 1).Y - pts(i + 1).X * pts(i).Y
                X += (pts(i).X + pts(i + 1).X) * m_sf
                Y += (pts(i).Y + pts(i + 1).Y) * m_sf
            Next i
            ' Divide by 6X the Are of the Polygon
            X /= (6 * p_rmArea)
            Y /= (6 * p_rmArea)
            ' This is the Final Result
            Return New PointF(X, Y)
        End Function

    That's all until next time...
  • 相关阅读:
    C# 系统应用之通过注册表获取USB使用记录(一)
    web项目测试方法总结
    C#面向对象编程实例-猜拳游戏
    c#基础这些你都看过吗?(一)-----仅供初学者使用
    .NET事件监听机制的局限与扩展
    SQL代码
    泛型接口委托
    存储过程
    小操作
    DataGridView
  • 原文地址:https://www.cnblogs.com/xpvincent/p/3842033.html
Copyright © 2011-2022 走看看