create columns types

create columns types

hossam.amer666
Enthusiast Enthusiast
1,530 Views
4 Replies
Message 1 of 5

create columns types

hossam.amer666
Enthusiast
Enthusiast

Hello guys, 

Now I have the family (M_Concrete-Rectangular-Column) and I have two lists of double that represent b and h of the column. how can I extract the unique values of the two lists and then create new family types using them?

0 Likes
Accepted solutions (1)
1,531 Views
4 Replies
Replies (4)
Message 2 of 5

RPTHOMAS108
Mentor
Mentor
Accepted solution
Private Class ColumnType
        Inherits EqualityComparer(Of ColumnType)

        Private IntD As Integer() = New Integer(1) {}
        Public ReadOnly Property H As Integer
            Get
                Return IntD(0)
            End Get
        End Property
        Public ReadOnly Property W As Integer
            Get
                Return IntD(1)
            End Get
        End Property
        Public ReadOnly Property Name As String
            Get
                Return CStr(H) & "x" & CStr(W)
            End Get
        End Property

        Public Sub New(D1 As Integer, D2 As Integer)
            If D1 > D2 Then
                IntD = New Integer() {D1, D2}
            Else
                IntD = New Integer() {D2, D1}
            End If
        End Sub
        Public Overrides Function Equals(x As ColumnType, y As ColumnType) As Boolean
            Return x.H = y.H AndAlso x.W = y.W
        End Function

        Public Overrides Function GetHashCode(obj As ColumnType) As Integer
            Return obj.Name.GetHashCode
        End Function
    End Class

    Private Function TObj168(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result

        Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else
        Dim IntDoc As Document = UIDoc.Document

        Dim L1 As Double() = New Double() {100, 200, 150, 500, 400, 300, 250, 250}
        Dim L2 As Double() = New Double() {200, 200, 150, 500, 400, 300, 250, 250}

        Dim all As New List(Of ColumnType)
        For i = 0 To L1.Length - 1
            all.Add(New ColumnType(L1(i), L2(i)))
        Next
        all = all.Distinct(New ColumnType(0, 0)).ToList

        Dim FEC As New FilteredElementCollector(IntDoc)
        Dim ECF As New ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns)
        Dim Els As List(Of FamilySymbol) = FEC.WherePasses(ECF).WhereElementIsElementType.Cast(Of FamilySymbol).ToList

        'Use column name here
        Dim Existing As List(Of FamilySymbol) = Els.FindAll(Function(x) x.FamilyName = "Concrete-Rectangular-Column")
        If Existing.Count = 0 Then
            Return Result.Cancelled
        End If

        Dim AlreadyExists As New List(Of ColumnType)
        Dim ToBeMade As New List(Of ColumnType)

        For i = 0 To all.Count - 1
            Dim Ix As Integer = i
            Dim J As FamilySymbol = Existing.Find(Function(x) x.Name = all(Ix).Name)
            If J Is Nothing Then
                ToBeMade.Add(all(i))
            Else
                AlreadyExists.Add(all(i))
            End If
        Next
        If ToBeMade.Count = 0 Then
            Return Result.Cancelled
        End If

        Using Tr As New Transaction(IntDoc, "Make types")
            If Tr.Start = TransactionStatus.Started Then

                For i = 0 To ToBeMade.Count - 1
                    Dim Itm = ToBeMade(i)
                    Dim Et As ElementType = Existing(0).Duplicate(Itm.Name)
                    'Use actual type parameter names
                    'Use GUIDs instead of LookupParameter where possible
                    Et.LookupParameter("h")?.Set(304.8 * Itm.H)
                    Et.LookupParameter("b")?.Set(304.8 * Itm.W)
                Next

                Tr.Commit()
            End If
        End Using

        Return Result.Succeeded
    End Function
Message 3 of 5

jeremy_tammik
Alumni
Alumni

Nice solution. I converted it to C# and added it to The Building Coder samples for future reference:

 

https://github.com/jeremytammik/the_building_coder_samples/compare/2021.0.150.21...2021.0.150.22

 

    private class ColumnType : EqualityComparer<ColumnType>
    {
      int[] _dim = new int[ 2 ];

      public int H
      {
        get { return _dim[ 0 ]; }
      }

      public int W
      {
        get { return _dim[ 1 ]; }
      }

      public string Name
      {
        get { return H.ToString() + "x" + W.ToString(); }
      }

      public ColumnType( int d1, int d2 )
      {
        if( d1 > d2 )
        {
          _dim = new int[] { d1, d2 };
        }
        else
        {
          _dim = new int[] { d2, d1 };
        }
      }

      public override bool Equals( ColumnType x, ColumnType y )
      {
        return x.H == y.H && x.W == y.W;
      }

      public override int GetHashCode( ColumnType obj )
      {
        return obj.Name.GetHashCode();
      }
    }

    private Result CreateColumnTypes( Document doc )
    {
      int[] L1 = new int[] { 100, 200, 150, 500, 400, 300, 250, 250 };
      int[] L2 = new int[] { 200, 200, 150, 500, 400, 300, 250, 250 };

      List<ColumnType> all = new List<ColumnType>();

      for( int i = 0; i < L1.Length; ++i )
      {
        all.Add( new ColumnType( L1[ i ], L2[ i ] ) );
      }

      all = all.Distinct( new ColumnType( 0, 0 ) ).ToList();

      FilteredElementCollector symbols
        = new FilteredElementCollector( doc )
          .WhereElementIsElementType()
          .OfCategory( BuiltInCategory.OST_StructuralColumns );

      // Column name to use

      string column_name = "Concrete-Rectangular-Column";

      IEnumerable<FamilySymbol> existing 
        = symbols.Cast<FamilySymbol>()
          .Where<FamilySymbol>( x 
            => x.FamilyName.Equals( column_name ) ); 

      if( 0 == existing.Count() )
      {
        return Result.Cancelled;
      }

      List<ColumnType> AlreadyExists = new List<ColumnType>();
      List<ColumnType> ToBeMade = new List<ColumnType>();

      for( int i = 0; i < all.Count ; ++i )
      {
        FamilySymbol fs = existing.FirstOrDefault( 
          x => x.Name == all[ i ].Name );

        if( fs == null )
        {
          ToBeMade.Add( all[ i ] );
        }
        else
        {
          AlreadyExists.Add( all[ i ] );
        }
      }
      if( ToBeMade.Count == 0 )
      {
        return Result.Cancelled;
      }

      using( Transaction tx = new Transaction( doc ) )
      {
        if( tx.Start( "Make types" ) == TransactionStatus.Started )
        {
          FamilySymbol first = existing.First();

          foreach( ColumnType ct in ToBeMade )
          {
            ElementType et = first.Duplicate( ct.Name );

            // Use actual type parameter names
            // Use GUIDs instead of LookupParameter where possible

            et.LookupParameter( "h" ).Set( 304.8 * ct.H );
            et.LookupParameter( "b" ).Set( 304.8 * ct.W );
          }
          tx.Commit();
        }
      }
      return Result.Succeeded;
    }

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 4 of 5

RPTHOMAS108
Mentor
Mentor

@jeremy_tammik Thanks.

 

Isn't it also interesting that it comes back to the notion of units. If we were comparing internal units (fractions of feet) we could not have used the integer for comparison. However since we assume it is mm and column sizes are rounded we can use easily.

 

So if we take the smallest measurement of length then we usually have less problems. In an imperial example if we had used inches then we can compare an integer of 6 inches rather than a double 0.5 ft. I guess if it is 6.5 inches we are stuck. However the mm is the smallest unit we generally work with (unless we are talking paint) so can represent smaller fractions of something as whole numbers.

 

However it is what it is.

0 Likes
Message 5 of 5

jeremy_tammik
Alumni
Alumni

Interesting topic. 

 

Intelligent rounding and unit dependent real-number fuzz.

 

I consider 1 mm the minimal metric unit in Revit, since it does not (or hardly) support smaller lengths.

 

For imperial sizes, I guess I would go for 1/16 of an inch.

 

Depending on what units the model happens to prefer, I would select one or the other.

  

 

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes