Tuesday, August 30, 2011

Relax Dataset Constraints for TableAdapters in .NET

This is a very common issue that people run into as they begin to use complex dataset objects in their .NET development work. This applies to ASP.NET as well as Winforms development work... even WPF.

If you've ever put together a complex join query in one of your TableAdapter objects and then in your code attempted to apply it to a DataTable object, you may have seen this warning and had no idea what to do about it:

The solution is simple. Open your XSD in design view and select on the background area (do not select a query or a TableAdapter).

Then in the properties pallet you will see a property named "EnforceConstraints". Set this property to False.


This option gives you the ability to provide dataset level constraints which are usually not necessary if your database backend has its own constraints.

Wednesday, August 24, 2011

Using the Find Items Feature in Navisworks 2012 for Revit Rooms

I've heard some frustrations from people on how to use the Find Items feature in Navisworks 2012 to find Revit rooms within the model.

The first thing that you need to make sure is that the "Export room geometry" option is checked prior to exporting the Revit model to Navisworks 2012.


Then in the "Find Items" dialog accessible from the View tab of the ribbon under the Windows drop-down set the following line in your search:

  • Category = Category
  • Property = Name
  • Condition = =
  • Value = Rooms
This will find all Revit rooms in your Navisworks model where you can then save this as a search set for future use without ever having to update your selections.


Monday, August 15, 2011

Check a String for Valid File Naming Characters

Here's a super simple solution to a surprisingly common problem for validating file naming strings using .NET.

If you have ever required a user to enter a file name and had to validate the characters they entered, I'm sure you have some sort of function that can do this. Surprisingly though, I see a bunch of code where people build their own file name character validation functions.

There is a built-in .NET function for validating file naming characters available from the System.IO namespace. The snippet below shows a very basic use of this command accepting an input of a string to validate and returns the same string back out if valid and an empty string if invalid file naming characters are detected.

    ''' <summary>
    ''' Make sure the path does not contain any invalid file naming characters
    ''' </summary>
    ''' <param name="fileName">The Filename to check</param>
    ''' <returns>A string</returns>
    ''' <remarks></remarks>
    Private Function CheckValidFileName(ByVal fileName As String) As String
        For Each c In Path.GetInvalidFileNameChars()
            If fileName.Contains(c) Then
                ' Invalid filename characters detected...
                ' Could either replace characters or return empty
                Return ""
            End If
        Next
        Return fileName
    End Function
You can call this function like:

If CheckValidFileName(m_string) = "" Then Throw New Exception
If an empty string is returned, you've got invalid characters in the file name...

Tuesday, August 2, 2011

Revit 2011 Categories that Do NOT Have Types

I've taken the liberty of listing each Revit 2011 category that does not contain types for anyone looking to impress their spouse with some pointless trivia (more for my own future reference than anything else).

Can anyone name the one category that only has types and no instances??....


AREAS
AREA LOADS
DUCT SYSTEMS
ELECTRICAL CIRCUITS
EXTERIOR
GBXML SURFACE
LEVELS
HVAC ZONES
INTERIOR
INTERNAL AREA LOADS
INTERNAL LINE LOADS
INTERNAL POINT LOADS
LINE LOADS
MASS EXTERIOR WALL
MASS FLOOR
MASS GLAZING
MASS INTERIOR WALL
MASS OPENING
MASS ROOF
MASS SKYLIGHT
MASS ZONE
MATERIALS
OPENING
PADS
PIPING SYSTEMS
POINT LOADS
PROJECT INFORMATION
ROADS
ROOMS
SHADE
SHAFT OPENINGS
SHEETS
SPACES
SWITCH SYSTEM
UNDERGROUND
VIEWS

FACIAS is the category that only contains types and no instances...

Monday, August 1, 2011

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.


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