Ray Projection Not Picking Up Beams

Ray Projection Not Picking Up Beams

zrodgersTSSSU
Advocate Advocate
1,219 Views
16 Replies
Message 1 of 17

Ray Projection Not Picking Up Beams

zrodgersTSSSU
Advocate
Advocate

Hey Everyone, Im trying to create a ray projection that finds the closest beam or slab from a column and attach it to the top to beam/slab found by the ray projection. For some reason i cant get it to find the beams i want it to attach too. It only finds the slab. Any Ideas?

 

 

 

 

using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Adjust Column Heights");

                        foreach (ElementId elemId in selectedIds)
                        {
                            Element elem = uidoc.Document.GetElement(elemId);

                            

                            //checks if element is column
                            if ((BuiltInCategory)elem.Category.Id.IntegerValue == BuiltInCategory.OST_StructuralColumns)
                            {
                                allColumns++;
                                
                                //get column location
                                XYZ elemLoc = (elem.Location as LocationPoint).Point;

                                //ray direction for raybounce
                                XYZ newPP = new XYZ(elemLoc.X, elemLoc.Y, elemLoc.Z + 1);
                                XYZ rayd = new XYZ(0, 0, 1);

                                List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
                                builtInCats.Add(BuiltInCategory.OST_Floors);
                                builtInCats.Add(BuiltInCategory.OST_StructuralFraming);
                                

                                ElementMulticategoryFilter filter = new ElementMulticategoryFilter(builtInCats);

                                //ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_Floors);

                                ReferenceIntersector refI = new ReferenceIntersector(filter, FindReferenceTarget.All, (View3D)doc.ActiveView);

                                ReferenceWithContext refC = refI.FindNearest(newPP, rayd);
                                if(refC != null)
                                {
                                    Reference reference = refC.GetReference();

                                    //gets reference element id & Element
                                    ElementId refEle = reference.ElementId;
                                    Element refElem = uidoc.Document.GetElement(refEle);
                                    
                                    ColumnAttachment.AddColumnAttachment(doc, elem as FamilyInstance, refElem , 1, ColumnAttachmentCutStyle.None, ColumnAttachmentJustification.Minimum, 0);
                                    
                                    successColumns++;
                                }
                                else
                                {
                                    //change color of columns to red
                                    Color color = new Color((byte)255, (byte)0, (byte)0);
                                    OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                                    ogs.SetProjectionLineColor(color);
                                    uidoc.ActiveView.SetElementOverrides(elem.Id, ogs);
                                }
                            }
                        }

                        TaskDialog.Show("Columns Changed", string.Format("{0} of {1} Columns Changed", successColumns, allColumns));
                        tx.Commit();
                    }

 

 

 

 

This it what it looks Like Before I run it:

zrodgersTSSSU_0-1623322675932.png

 

This is what it looks like after i run it (it only finds the slabs): I want it to stop at the bottom of beams & slabs

zrodgersTSSSU_1-1623322750589.png

 

Sooo... i tried to change the code to just pick up the beams 

 

 

 

using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Adjust Column Heights");

                        foreach (ElementId elemId in selectedIds)
                        {
                            Element elem = uidoc.Document.GetElement(elemId);

                            

                            //checks if element is column
                            if ((BuiltInCategory)elem.Category.Id.IntegerValue == BuiltInCategory.OST_StructuralColumns)
                            {
                                allColumns++;
                                

                                //get column location
                                XYZ elemLoc = (elem.Location as LocationPoint).Point;

                                //ray direction for raybounce
                                XYZ newPP = new XYZ(elemLoc.X, elemLoc.Y, elemLoc.Z + 1);
                                XYZ rayd = new XYZ(0, 0, 1);

                                //List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
                                //builtInCats.Add(BuiltInCategory.OST_Floors);
                                //builtInCats.Add(BuiltInCategory.OST_StructuralFraming);
                                //ElementMulticategoryFilter filter = new ElementMulticategoryFilter(builtInCats);

                                ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralFraming);

                                ReferenceIntersector refI = new ReferenceIntersector(filter, FindReferenceTarget.All, (View3D)doc.ActiveView);

                                ReferenceWithContext refC = refI.FindNearest(newPP, rayd);
                                if(refC != null)
                                {
                                    Reference reference = refC.GetReference();

                                    //gets reference element id & Element
                                    ElementId refEle = reference.ElementId;
                                    Element refElem = uidoc.Document.GetElement(refEle);
                                    
                                    ColumnAttachment.AddColumnAttachment(doc, elem as FamilyInstance, refElem , 1, ColumnAttachmentCutStyle.None, ColumnAttachmentJustification.Minimum, 0);
                                    
                                    successColumns++;
                                }
                                else
                                {
                                    //change color of columns to red
                                    Color color = new Color((byte)255, (byte)0, (byte)0);
                                    OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                                    ogs.SetProjectionLineColor(color);
                                    uidoc.ActiveView.SetElementOverrides(elem.Id, ogs);
                                }
                            }
                        }

                        TaskDialog.Show("Columns Changed", string.Format("{0} of {1} Columns Changed", successColumns, allColumns));
                        tx.Commit();
                    }

 

 

 

 

This is what i have before:

zrodgersTSSSU_0-1623322675932.png

This is what i have after (circled in blue is what didnt attach to the beam above. Some did attach):

zrodgersTSSSU_2-1623323049470.png

 

so why is this? And is there anything i can do to fix it.

 

Thanks ahead of time for any responses!

0 Likes
Accepted solutions (3)
1,220 Views
16 Replies
Replies (16)
Message 2 of 17

zrodgersTSSSU
Advocate
Advocate

I think It has something to do with whether the column is centered under the beam.. but i didnt think that would matter because im using "FindReferenceTarget.All" in my ray projection

 

(example of off center column not attaching)

zrodgersTSSSU_0-1623325059940.png

 

0 Likes
Message 3 of 17

jeremy_tammik
Autodesk
Autodesk

It absolutely matters. The ray you shoot is an infinitely thin line, so you can easily miss something. You could try using five rays per pillar, e.g., one in the centre and one in each corner. I would suggest that you add some visual debugging code that represents part of your infinite shooting ray with a model line to visualise what is going on and whether a beam is hit or missed.

  

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

zrodgersTSSSU
Advocate
Advocate

@jeremy_tammik thanks for the quick response. I dont really understand, if the center of my column (which is where the ray is generated from) is within the bounds of the beam how does it not pick up the face of the beam? It seems to only pick up the centerline of the beam... Does "FindReferenceTarget.All" not find the face of beam? and if I added rays to the corners of the column i dont see how that would help if it only finds the beam when you hit the beam centerline straight on. I hope that made sense.  Any ideas?

0 Likes
Message 5 of 17

jeremy_tammik
Autodesk
Autodesk

Normally, the reference intersector is set up so that an infinitely thin ray is shot and all intersections with faces or edges are reported. Just as you say, hitting an edge or a centerline or any other infinitely thin object is infinitely improbable.

 

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

zrodgersTSSSU
Advocate
Advocate

@jeremy_tammik Whats a good way to do multiple rays for a single object?

0 Likes
Message 7 of 17

zrodgersTSSSU
Advocate
Advocate

@jeremy_tammik I also just figured out why the ray bounce isnt working. It wasnt working on columns that extended past the beam already. Thats becuase revit already cuts out the column from the beam. so there is no face for it to hit. It works if the columns are below the beam. 

 

zrodgersTSSSU_0-1623336363049.png

 

when i hide the column:

zrodgersTSSSU_1-1623336398558.png

 

 

so i think that your method of doing rays on the corners of the columns would help possibly pick up the intersecting edge. I just dont know of a way to assign 5 rays to the column. Can you point me in the correct direction. I havent seen anything on multiple rays per single object.

 

0 Likes
Message 8 of 17

jeremy_tammik
Autodesk
Autodesk

Simply calculate the four column bottom face corner points and the column centre line direction vector and use that data to define the four rays.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 9 of 17

zrodgersTSSSU
Advocate
Advocate

lol i wish it was "simply" haha!  I have been trying to figure out how to get the bottom column corners. with little success... I have seen your blog about finding the bottom of walls and top of sloped walls but cant find anything on bottom of columns. also once i get the points where do i place them so it generates multiple rays?

 

 

 

 

List<XYZ> columnCorners = new List<XYZ>();
                                        XYZ startpt = null;
                                        
                                        Options opt = app.Create.NewGeometryOptions();
                                        GeometryElement geoEle = elem.get_Geometry(opt);

                                        foreach (GeometryObject obj in geoEle)
                                        {
                                            Solid solid = obj as Solid;
                                            if (null != solid)
                                            {
                                                foreach (Face face in solid.Faces)
                                                {
                                                    PlanarFace pf= face as PlanarFace;
                                                    if(null != pf)
                                                    {
                                                        XYZ normal = pf.FaceNormal;
                                                        if(normal.Z == -1)
                                                        {
                                                            foreach(Edge edge in face.EdgeLoops)
                                                            {
                                                                foreach(XYZ ii in edge.Tessellate())
                                                                {
                                                                    XYZ point = ii;
                                                                    columnCorners.Add(point);
                                                                }
                                                            }

                                                            

                                                        }
                                                    }
                                                }
                                            }

 

 

 

 

0 Likes
Message 10 of 17

jeremy_tammik
Autodesk
Autodesk

There are ever so many different ways.

 

Maybe easier to iterate over the faces rather than the edges. Either way is fine, though.

 

If you know that the cross section is rectangular. and the column is vertical, you know that you have four bottom corners, and you can differentiate them from all other vertices simply by picking the four ones with minimal Z coordinates.

 

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

RPTHOMAS108
Mentor
Mentor
Accepted solution

This task can actually be done without ReferenceIntersector

 

1) You can extract the Z extents of slabs/beams and columns from bounding box to compare level proximity.

2) You can use  Face.IsInside to determine if a column location line is within the limits of the bottom face of slab or beam matching (1). For slanted columns you'll have to follow a point at base up the vector of the slant (to see where point end up at slab/beam underside). Multiply XY components of vector by height difference between point at column base and underside of beam/slab then add them to point at base.

 

Likely however that the face.IsInside will be affected by joins as the ReferenceIntersector is.

You can probably identify a second capture group via bounding box intersection filters i.e. the cases where the ray missing the faces due to join will be a cases where there is a bounding box intersection between such elements.

 

Could also use JoinGeometry.UnjoinGeometry between columns and slabs/beams prior to investigation.

 

Note that occasionally attaching column to underside will fail if column profile is not completely covered. Often you can partially cover a column and still get it to attach but there is a limit on that.

Message 12 of 17

zrodgersTSSSU
Advocate
Advocate
Accepted solution

@jeremy_tammik @RPTHOMAS108  Thank you both for the responses. I changed my approach to use bounding boxes like you said @RPTHOMAS108 . seems to be working for me. @jeremy_tammik Id love to see an example of multiple rays per element if you ever decided to do a blog post about it.

 

Heres what worked for me:

using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Adjust Column Heights");

                        if (doc.ActiveView is View3D)
                        {
                            
                            foreach (ElementId elemId in selectedIds)
                            {
                                Element elem = uidoc.Document.GetElement(elemId);

                                //checks if element is column
                                if ((BuiltInCategory)elem.Category.Id.IntegerValue == BuiltInCategory.OST_StructuralColumns)
                                {
                                    allColumns++;

                                    //get column location
                                    XYZ elemLoc = (elem.Location as LocationPoint).Point;

                                    //ray direction for raybounce
                                    XYZ newPP = new XYZ(elemLoc.X, elemLoc.Y, elemLoc.Z + 1);
                                    XYZ rayd = new XYZ(0, 0, 1);

                                    //collect beams and slabs
                                    List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
                                    builtInCats.Add(BuiltInCategory.OST_Floors);
                                    builtInCats.Add(BuiltInCategory.OST_StructuralFraming);
                                    ElementMulticategoryFilter filter = new ElementMulticategoryFilter(builtInCats);

                                    BoundingBoxXYZ elemBB = elem.get_BoundingBox(doc.ActiveView);

                                    XYZ max = elemBB.Max;
                                    XYZ min = elemBB.Min;

                                    Outline myOutLn = new Outline(min, new XYZ(max.X,max.Y,max.Z+100));

                                    BoundingBoxIntersectsFilter invertFilter = new BoundingBoxIntersectsFilter(myOutLn);
                                    FilteredElementCollector collector = new FilteredElementCollector(doc);
                                    IList<Element> el = collector.WherePasses(filter).WherePasses(invertFilter).ToElements();

                                    //new lists for beams and slabs
                                    List<Element> intersectingBeams = new List<Element>();
                                    List<Element> intersectingSlabs = new List<Element>();

                                    if (ColumnAttachment.GetColumnAttachment(elem as FamilyInstance, 1) != null)
                                    {
                                        //change color of columns to green
                                        Color color = new Color((byte)0, (byte)255, (byte)0);
                                        OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                                        ogs.SetProjectionLineColor(color);
                                        doc.ActiveView.SetElementOverrides(elem.Id, ogs);
                                    }
                                    else
                                    {
                                        //add elements to list
                                        foreach (Element e in el)
                                        {
                                            BoundingBoxXYZ eBB = e.get_BoundingBox(uidoc.Document.ActiveView);
                                            if (e.Category.Name == "Structural Framing")
                                            {
                                                intersectingBeams.Add(e);
                                            }
                                            else if (e.Category.Name == "Floors")
                                            {
                                                intersectingSlabs.Add(e);
                                            }
                                        }
                                        if (intersectingBeams.Any())
                                        {
                                            Element lowestBottomElem = intersectingBeams.First();
                                            foreach (Element beam in intersectingBeams)
                                            {
                                                BoundingBoxXYZ thisBeamBB = beam.get_BoundingBox(uidoc.Document.ActiveView);
                                                BoundingBoxXYZ currentLowestBB = lowestBottomElem.get_BoundingBox(uidoc.Document.ActiveView);
                                                if (thisBeamBB.Min.Z < currentLowestBB.Min.Z)
                                                {
                                                    lowestBottomElem = beam;
                                                }
                                            }
                                            ColumnAttachment.AddColumnAttachment(doc, elem as FamilyInstance, lowestBottomElem, 1, ColumnAttachmentCutStyle.None, ColumnAttachmentJustification.Minimum, 0);
                                            successColumns++;
                                        }
                                        else if (intersectingSlabs.Any())
                                        {
                                            Element lowestBottomElem = intersectingSlabs.First();
                                            foreach (Element slab in intersectingSlabs)
                                            {
                                                BoundingBoxXYZ thisSlabBB = slab.get_BoundingBox(uidoc.Document.ActiveView);
                                                BoundingBoxXYZ currentLowestBB = lowestBottomElem.get_BoundingBox(uidoc.Document.ActiveView);
                                                if (thisSlabBB.Min.Z < currentLowestBB.Min.Z)
                                                {
                                                    lowestBottomElem = slab;
                                                }
                                            }
                                            ColumnAttachment.AddColumnAttachment(doc, elem as FamilyInstance, lowestBottomElem, 1, ColumnAttachmentCutStyle.None, ColumnAttachmentJustification.Minimum, 0);
                                            successColumns++;
                                        }
                                        else
                                        {
                                            //change color of columns to red
                                            Color color = new Color((byte)255, (byte)0, (byte)0);
                                            OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                                            ogs.SetProjectionLineColor(color);
                                            doc.ActiveView.SetElementOverrides(elem.Id, ogs);

                                        }

                                    }

                                                                      
                                }
                            }
                        }
                        else
                        {
                            TaskDialog.Show("Revit", "Run Script in 3D View.");
                        }

                        TaskDialog.Show("Columns Changed", string.Format("{0} of {1} Columns Changed", successColumns, allColumns));
                        tx.Commit();
                    }
0 Likes
Message 13 of 17

jeremy_tammik
Autodesk
Autodesk
Accepted solution

There is nothing special about multiple rays per element at all.

 

In your code above, you shoot a ray upwards parallel to the Z axis from the element location point:

 

  // ray direction for raybounce
  XYZ newPP = new XYZ(elemLoc.X, elemLoc.Y, elemLoc.Z + 1);
  XYZ rayd = new XYZ(0, 0, 1);

 

You can define any other source point you like, e.g., each of the four bottom corner points in turn, and also any other direction you like, and simply repeat the same process using the same reference intersector in the same view by repeatedly calling its Find method with the new source point and direction vector:

 

https://www.revitapidocs.com/2021.1/6abd0586-5d7e-68c6-2e64-46199f457499.htm

 

I hope this clarifies.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 14 of 17

zrodgersTSSSU
Advocate
Advocate

@jeremy_tammik I finally figured it out using the ray projection method as well. Thanks to all your responses i realized i was super over complicating it in my head. Thank you again for all your help

 

Here is the working code with ray projection as well:

using (Transaction tx = new Transaction(doc))
                {
                    tx.Start("Attach Columns Tops");

                    foreach (ElementId elemId in selectedIds)
                    {

                        Element elem = uidoc.Document.GetElement(elemId);
                        if ((BuiltInCategory)elem.Category.Id.IntegerValue == BuiltInCategory.OST_StructuralColumns)
                        {
                            allColumns++;
                            

                            //collect beams and slabs
                            List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
                            builtInCats.Add(BuiltInCategory.OST_Floors);
                            builtInCats.Add(BuiltInCategory.OST_StructuralFraming);
                            ElementMulticategoryFilter filter = new ElementMulticategoryFilter(builtInCats);

                            if (ColumnAttachment.GetColumnAttachment(elem as FamilyInstance, 1) != null)
                            {
                                //removes old column attachement
                                ColumnAttachment.RemoveColumnAttachment(elem as FamilyInstance, 1);
                            }

                            ReferenceIntersector refI = new ReferenceIntersector(filter, FindReferenceTarget.All, (View3D)doc.ActiveView);

                            BoundingBoxXYZ elemBB = elem.get_BoundingBox(doc.ActiveView);

                            //create ray
                            XYZ rayd = new XYZ(0, 0, 1);

                            List<XYZ> points = new List<XYZ>();
                            //get column location
                            XYZ elemLoc = (elem.Location as LocationPoint).Point;
                            XYZ elemCenter = new XYZ(elemLoc.X, elemLoc.Y, elemLoc.Z + 0.1);
                            XYZ b1 = new XYZ(elemBB.Min.X, elemBB.Min.Y, elemBB.Min.Z + 0.1);
                            XYZ b2 = new XYZ(elemBB.Max.X, elemBB.Max.Y, elemBB.Min.Z + 0.1);
                            XYZ b3 = new XYZ(elemBB.Min.X, elemBB.Max.Y, elemBB.Min.Z + 0.1);
                            XYZ b4 = new XYZ(elemBB.Max.X, elemBB.Min.Y, elemBB.Min.Z + 0.1);

                            points.Add(b1);
                            points.Add(b2);
                            points.Add(b3);
                            points.Add(b4);
                            points.Add(elemCenter);

                            ReferenceWithContext refC = null;
                            foreach (XYZ pt in points)
                            {
                                refC = refI.FindNearest(pt, rayd);
                                if (refC != null)
                                {
                                    break;
                                }

                            }

                            if (refC != null)
                            {
                                Reference reference = refC.GetReference();

                                //gets reference element id & Element
                                ElementId refEle = reference.ElementId;
                                Element refElem = uidoc.Document.GetElement(refEle);

                                ColumnAttachment.AddColumnAttachment(doc, elem as FamilyInstance, refElem, 1, ColumnAttachmentCutStyle.None, ColumnAttachmentJustification.Minimum, 0);

                                successColumns++;
                            }

                            else
                            {
                                //change color of columns to red
                                Color color = new Color((byte)255, (byte)0, (byte)0);
                                OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                                ogs.SetProjectionLineColor(color);
                                uidoc.ActiveView.SetElementOverrides(elem.Id, ogs);
                            }


                        }

                    }


                    tx.Commit();
                }
0 Likes
Message 15 of 17

jeremy_tammik
Autodesk
Autodesk

Congratulations on simplifying and solving this. KISS works wonders, doesn't it? Thank you for sharing the two approaches!

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 16 of 17

jeremy_tammik
Autodesk
Autodesk

I cleaned up your two solutions a little bit and added them to The Building Coder samples:

 

https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/C...

 

 

  void AdjustColumnHeightsUsingBoundingBox(
    Document doc,
    IList<ElementId> ids )
  {
    View view = doc.ActiveView;

    int allColumns = 0;
    int successColumns = 0;

    if( view is View3D )
    {
      using( Transaction tx = new Transaction( doc ) )
      {
        tx.Start( "Adjust Column Heights" );

        foreach( ElementId elemId in ids )
        {
          Element elem = doc.GetElement( elemId );

          // Check if element is column

          if( (BuiltInCategory) elem.Category.Id.IntegerValue 
            == BuiltInCategory.OST_StructuralColumns )
          {
            allColumns++;

            FamilyInstance column = elem as FamilyInstance;

            // Collect beams and slabs within bounding box

            List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
            builtInCats.Add( BuiltInCategory.OST_Floors );
            builtInCats.Add( BuiltInCategory.OST_StructuralFraming );
            ElementMulticategoryFilter beamSlabFilter 
              = new ElementMulticategoryFilter( builtInCats );

            BoundingBoxXYZ bb = elem.get_BoundingBox( view );
            Outline myOutLn = new Outline( bb.Min, bb.Max + 100 * XYZ.BasisZ );
            BoundingBoxIntersectsFilter bbFilter 
              = new BoundingBoxIntersectsFilter( myOutLn );

            FilteredElementCollector collector 
              = new FilteredElementCollector( doc )
                .WherePasses( beamSlabFilter )
                .WherePasses( bbFilter );

            List<Element> intersectingBeams = new List<Element>();
            List<Element> intersectingSlabs = new List<Element>();

            if( ColumnAttachment.GetColumnAttachment( 
              column, 1 ) != null )
            {
              // Change color of columns to green

              Color color = new Color( (byte) 0, (byte) 255, (byte) 0 );
              OverrideGraphicSettings ogs = new OverrideGraphicSettings();
              ogs.SetProjectionLineColor( color );
              view.SetElementOverrides( elem.Id, ogs );
            }
            else
            {
              foreach( Element e in collector )
              {
                if( e.Category.Name == "Structural Framing" )
                {
                  intersectingBeams.Add( e );
                }
                else if( e.Category.Name == "Floors" )
                {
                  intersectingSlabs.Add( e );
                }
              }
              if( intersectingBeams.Any() )
              {
                Element lowestBottomElem = intersectingBeams.First();
                foreach( Element beam in intersectingBeams )
                {
                  BoundingBoxXYZ thisBeamBB = beam.get_BoundingBox( view );
                  BoundingBoxXYZ currentLowestBB = lowestBottomElem.get_BoundingBox( view );
                  if( thisBeamBB.Min.Z < currentLowestBB.Min.Z )
                  {
                    lowestBottomElem = beam;
                  }
                }
                ColumnAttachment.AddColumnAttachment( 
                  doc, column, lowestBottomElem, 1, 
                  ColumnAttachmentCutStyle.None, 
                  ColumnAttachmentJustification.Minimum, 
                  0 );
                successColumns++;
              }
              else if( intersectingSlabs.Any() )
              {
                Element lowestBottomElem = intersectingSlabs.First();
                foreach( Element slab in intersectingSlabs )
                {
                  BoundingBoxXYZ thisSlabBB = slab.get_BoundingBox( view );
                  BoundingBoxXYZ currentLowestBB = lowestBottomElem.get_BoundingBox( view );
                  if( thisSlabBB.Min.Z < currentLowestBB.Min.Z )
                  {
                    lowestBottomElem = slab;
                  }
                }
                ColumnAttachment.AddColumnAttachment( 
                  doc, column, lowestBottomElem, 1, 
                  ColumnAttachmentCutStyle.None, 
                  ColumnAttachmentJustification.Minimum, 
                  0 );
                successColumns++;
              }
              else
              {
                // Change color of columns to red

                Color color = new Color( (byte) 255, (byte) 0, (byte) 0 );
                OverrideGraphicSettings ogs = new OverrideGraphicSettings();
                ogs.SetProjectionLineColor( color );
                view.SetElementOverrides( elem.Id, ogs );
              }
            }
          }
        }
        tx.Commit();
      }
      TaskDialog.Show( "Columns Changed",
        string.Format( "{0} of {1} Columns Changed",
        successColumns, allColumns ) );
    }
    else
    {
      TaskDialog.Show( "Revit", "Run Script in 3D View." );
    }
  }

  void AdjustColumnHeightsUsingReferenceIntersector(
    Document doc,
    IList<ElementId> ids )
  {
    View3D view = doc.ActiveView as View3D;

    if( null == view )
    {
      throw new Exception( 
        "Please run this command in a 3D view." );
    }

    int allColumns = 0;
    int successColumns = 0;

    using( Transaction tx = new Transaction( doc ) )
    {
      tx.Start( "Attach Columns Tops" );

      foreach( ElementId elemId in ids )
      {
        Element elem = doc.GetElement( elemId );

        if( (BuiltInCategory) elem.Category.Id.IntegerValue 
          == BuiltInCategory.OST_StructuralColumns )
        {
          allColumns++;

          FamilyInstance column = elem as FamilyInstance;

          // Collect beams and slabs

          List<BuiltInCategory> builtInCats = new List<BuiltInCategory>();
          builtInCats.Add( BuiltInCategory.OST_Floors );
          builtInCats.Add( BuiltInCategory.OST_StructuralFraming );
          ElementMulticategoryFilter filter 
            = new ElementMulticategoryFilter( builtInCats );

          // Remove old column attachement

          if( ColumnAttachment.GetColumnAttachment( column, 1 ) != null )
          {
            ColumnAttachment.RemoveColumnAttachment( column, 1 );
          }

          BoundingBoxXYZ elemBB = elem.get_BoundingBox( view );

          XYZ elemLoc = (elem.Location as LocationPoint).Point;
          XYZ elemCenter = new XYZ( elemLoc.X, elemLoc.Y, elemLoc.Z + 0.1 );
          XYZ b1 = new XYZ( elemBB.Min.X, elemBB.Min.Y, elemBB.Min.Z + 0.1 );
          XYZ b2 = new XYZ( elemBB.Max.X, elemBB.Max.Y, elemBB.Min.Z + 0.1 );
          XYZ b3 = new XYZ( elemBB.Min.X, elemBB.Max.Y, elemBB.Min.Z + 0.1 );
          XYZ b4 = new XYZ( elemBB.Max.X, elemBB.Min.Y, elemBB.Min.Z + 0.1 );

          List<XYZ> points = new List<XYZ>( 5 );
          points.Add( b1 );
          points.Add( b2 );
          points.Add( b3 );
          points.Add( b4 );
          points.Add( elemCenter );

          ReferenceIntersector refI = new ReferenceIntersector(
            filter, FindReferenceTarget.All, view );

          XYZ rayd = XYZ.BasisZ;
          ReferenceWithContext refC = null;
          foreach( XYZ pt in points )
          {
            refC = refI.FindNearest( pt, rayd );
            if( refC != null )
            {
              break;
            }
          }

          if( refC != null )
          {
            Reference reference = refC.GetReference();
            ElementId id = reference.ElementId;
            Element e = doc.GetElement( id );

            ColumnAttachment.AddColumnAttachment( 
              doc, column, e, 1, 
              ColumnAttachmentCutStyle.None, 
              ColumnAttachmentJustification.Minimum, 
              0 );

            successColumns++;
          }
          else
          {
            // Change color of columns to red

            Color color = new Color( (byte) 255, (byte) 0, (byte) 0 );
            OverrideGraphicSettings ogs = new OverrideGraphicSettings();
            ogs.SetProjectionLineColor( color );
            view.SetElementOverrides( elem.Id, ogs );
          }
        }
      }
      tx.Commit();
    }
  }

 

 

I see that you are not actually retrieving the bottom four corners of the column, but the bottom four corners of its bounding box.

 

They will coincide if the column is axis aligned. If not, the bounding box corners will be slightly outside the column, so you may hit and attach to a slab that actually does not touch the column at all, since it is just outside one of its corners...

 

Would you like to test whether my code does the same as yours, as I hope and expect?

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 17 of 17

zrodgersTSSSU
Advocate
Advocate

Thanks Jeremy! And ill run it next week when i get back from vacation!!

0 Likes