Is there a way to find which framing members are attached to a wall or column?

Is there a way to find which framing members are attached to a wall or column?

ehall8CEK4
Contributor Contributor
181 Views
1 Reply
Message 1 of 2

Is there a way to find which framing members are attached to a wall or column?

ehall8CEK4
Contributor
Contributor

Title has the question. I just want to be able to get the instances of beams that are framing into a wall/column so I can parse them for associated level/beam type/etc.  If possible it would be nice to know where in the wall they're framed into as well.

0 Likes
182 Views
1 Reply
Reply (1)
Message 2 of 2

ctm_mka
Collaborator
Collaborator

Not directly no. Ive been working on this exact same thing. The short version, Solid intersection tests with the beam geometry. First part is creating a solid from the beam. This is annoying but here's two methods to do this.

Option 1, creating a scale solid from the beams instance geometry. Important to note, this is the joined geometry of the beam, aka the visible part in 3D, which by itself intersects nothing, thus we need to scale it a bit. Downside, because it scales in all axis, it may grab things you dont want, so you will need to test for that as well:

public Solid ScaledSolid(Element elem)
{
    List<BuiltInCategory> wallsandfloor = new List<BuiltInCategory>() { BuiltInCategory.OST_Walls, BuiltInCategory.OST_Floors };
    Options geomtopts = new Options();
    GeometryElement geoelem = elem.get_Geometry(geomtopts);
    Solid bmsolid = geoelem.Where(x => x.Id > -1 && x.GraphicsStyleId.IntegerValue != -1).FirstOrDefault() as Solid;
    XYZ bmorign = bmsolid.ComputeCentroid();
    Transform scale = Transform.CreateTranslation(new XYZ(0, 0, 0)).ScaleBasis(1.1);
    Solid tempsolid = SolidUtils.CreateTransformed(bmsolid, scale);
    XYZ temporigin = tempsolid.ComputeCentroid();
    Transform shift = Transform.CreateTranslation(bmorign - temporigin);
    Solid finalsolid = SolidUtils.CreateTransformed(tempsolid, shift);
    //using (Transaction tr2 = new Transaction(_doc))
    //{
    //    tr2.Start("temp solid");
    //    DirectShape ds = DirectShape.CreateElement(_doc, new ElementId(BuiltInCategory.OST_GenericModel));
    //    ds.SetShape(new GeometryObject[] { finalsolid });
    //    tr2.Commit();
    //}
    return finalsolid;

Second, more complicated but gets around the issue of grabbing extra things. This creates a solid from the beams family geometry. This creates a more complete representation of the beam at its true size and length. Downsize, lots of transforms:

 public Solid CreateBeamSolid(Element elem)
 {
     Line bmline = (elem.Location as LocationCurve).Curve as Line; //location/analytical line for the path of sweep
     FamilyInstance fisnt = elem as FamilyInstance;//get instance to grab defined depth of beam and the family symbol
     double ht = fisnt.Symbol.LookupParameter("h").AsDouble();
     FamilySymbol fysmb = fisnt.Symbol;
     double angleYZ = VertAngle(bmline.GetEndPoint(0), bmline.GetEndPoint(1), bmline.Direction);
     //if the Z property the direction of the beam line is greater than 0, and the beam has not been mirrored, flip teh calc'd angle
     if (bmline.Direction.Z > 0 && !fisnt.FacingFlipped && !fisnt.HandFlipped)
     {
         angleYZ = -angleYZ;
     }
     Options geomtopts = new Options(); //options needed to get beam geometry, even though im not really doing anything with it.
     GeometryElement geoelem = fysmb.get_Geometry(geomtopts); //this gets the geometry of beam, we are grabbing from teh family symbol to get the true unjoined geometry values
     Solid symbSolid = geoelem.Where(x => x.Id > -1 && x.GraphicsStyleId.IntegerValue != -1).FirstOrDefault() as Solid; //get the solid from the geometry note, this is only 5 feet long in the fam defintion so we cant really use it as is
     List<PlanarFace> symbfaces = (from PlanarFace face in symbSolid.Faces //get list of planar faces from beam solid
                                   select face).ToList();
     PlanarFace symbPface = symbfaces.FirstOrDefault(x => x.FaceNormal.IsAlmostEqualTo(new XYZ(1, 0, 0)));//take the first face with min area, this is the cross section
     XYZ newOrigin = new XYZ(symbPface.Origin.X, symbPface.Origin.Y, symbPface.Origin.Z + ht / 2);//create new point at top of symbol geometry, so we dont need to shift after we create sweep
     //since the family defintion is at 0,0,0 we need to create a few translations for the solid
     Transform loopshift = Transform.CreateTranslation(bmline.GetEndPoint(0) - newOrigin);//tranform for move
     Transform looprotateZ = Transform.CreateRotationAtPoint(XYZ.BasisZ, HorizAngle(bmline.Direction, new XYZ(0, 0, 0)), bmline.GetEndPoint(0));//transform for rotate horizontal at start
     Transform looprotateX = Transform.CreateRotationAtPoint(fisnt.FacingOrientation, angleYZ, bmline.GetEndPoint(0));//transform for rotate vertically, perp to beam at start
     Solid symbMove = SolidUtils.CreateTransformed(symbSolid, loopshift);//move the beam
     Solid symbRotateHoriz = SolidUtils.CreateTransformed(symbMove, looprotateZ);//first rotation
     Solid symbRotateVert = SolidUtils.CreateTransformed(symbRotateHoriz, looprotateX);//secondroation
     List<PlanarFace> solfaces = (from PlanarFace face in symbRotateVert.Faces //grab the faces again from the translated solid
                                  select face).ToList();
     //grb the face where the distance from origin to end point is less than half the beam depth, this is the curve loop we want for the sweep
     PlanarFace solFace = solfaces.FirstOrDefault(x => ht / 2 >= solfaces.Min(y => y.Origin.DistanceTo(bmline.GetEndPoint(0))));
     CurveLoop sourceloop = solFace.GetEdgesAsCurveLoops().FirstOrDefault(); //get teh curve loop defining this face.
     CurveLoop offsetloop = CurveLoop.CreateViaOffset(sourceloop, 0.25, solFace.FaceNormal);//offset teh loop by 3"
     CurveLoop pathloop = new CurveLoop();//curveloop neeed for path of sweep   
     pathloop.Append(bmline); //add line to curveloop
     IList<CurveLoop> finalloop = new List<CurveLoop>
     {
         offsetloop //add teh offset loop to the loop list, this is the "sweep sketch"
     };
     //Solid temp = GeometryCreationUtilities.CreateSweptGeometry(pathloop, 0, bmline.GetEndParameter(0), finalloop);
     //using (Transaction tr2 = new Transaction(_doc))
     //{
     //    tr2.Start("temp solid");
     //    DirectShape ds = DirectShape.CreateElement(_doc, new ElementId(BuiltInCategory.OST_GenericModel));
     //    ds.SetShape(new GeometryObject[] { temp });
     //    tr2.Commit();
     //}
     return GeometryCreationUtilities.CreateSweptGeometry(pathloop, 0, bmline.GetEndParameter(0), finalloop); //create the sweep!
 }

Part 2, the Solid Intersection:

I use a FilteredElementCollector with the ElementIntersectSolidFIlter and a few other filters to get what i need, in this case beams, columns, walls and floors:

public List<Element> SolidIntersectTest(Element elem, Solid bmsolid, bool filter)
{
    //separate cat lists for filtered element collection becuase different options needed
    List<BuiltInCategory> wallsandfloor = new List<BuiltInCategory>() { BuiltInCategory.OST_Walls, BuiltInCategory.OST_Floors };
    List<BuiltInCategory> bmsandcols = new List<BuiltInCategory>() { BuiltInCategory.OST_StructuralColumns, BuiltInCategory.OST_StructuralFraming };
  
    List<ElementId> excludelist = new List<ElementId>()
    {
        elem.Id
    };
    if (filter)
    {
      List<Element> testcoll = new FilteredElementCollector(_doc, GlobalVars.Active.Id)
            .Excluding(excludelist)
             .WherePasses(new ElementMulticategoryFilter(bmsandcols))
             .WherePasses(new StructuralMaterialTypeFilter(StructuralMaterialType.Steel, true))
             .WherePasses(new ElementIntersectsSolidFilter(bmsolid)).ToList();
       testcoll.AddRange(new FilteredElementCollector(_doc, GlobalVars.Active.Id)
            .WherePasses(new ElementMulticategoryFilter(wallsandfloor))
            .WherePasses(new ElementIntersectsSolidFilter(bmsolid)).ToList());
        return testcoll;
    }
    else
    {
        List<Element> testcoll = new FilteredElementCollector(_doc, GlobalVars.Active.Id)
                            .Excluding(excludelist)
                             .WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_StructuralFraming))
                             .WherePasses(new StructuralMaterialTypeFilter(StructuralMaterialType.Steel, true))
                             .WherePasses(new ElementIntersectsSolidFilter(bmsolid)).ToList();
        return testcoll;
    }
   
}

Lastly, you may have noticed that these are all separate methods. Because i use them alot in my applications, it gets called like this (bmelem is the beam, as element):

List<Element> testcoll = _utils.SolidIntersectTest(bmelem, _utils.ScaledSolid(bmelem), true);
0 Likes