DirectShape

This element type can store arbitrary geometry obtained from import operations or calculations in either a project or family document.

The DirectShape element and related classes support the ability to store externally created geometric shapes in a Revit document. The geometry can include closed solids or meshes. DirectShape is primarily intended for importing shapes from other data formats such as IFC or STEP where not enough information is available to create a "real" Revit element.

A DirectShape object may be assigned a top-level Model category, such as the Wall category. Sub-categories cannot be assigned to DirectShape elements. The IsValidCategoryId property can test a category id to make sure it is a top-level built-in category and the Category.CategoryType enumerated value will indicated if the category type is Model. Assigning a category will affect how that object is displayed in Revit and will grant the object a collection of available parameters and some limited behaviors.

DirectShape creation

The static CreateElement() method will create a new instance-level DirectShape. It requires the document in which the DirectShape will be added and the id of an appropriate built-in category. DirectShape provides additional fields that may be used by the creating application to manage the DirectShape elements - two string parameters passed to CreateElement(). These fields can be accessed by the application later if necessary to provide context for the source of the created shape.

Once the DirectShape is created, the shape can be set using one of the overloaded SetShape() method. The shape can be set either directly from a ShapeBuilder object or from a list of GeometryObjects. If you are using a ShapeBuilder object to construct geometry for the DirectShape anyway, there may be a slight performance advantage to using the ShapeBuilder input, as Revit will bypass repetitive validation of the input geometry. It is also possible to append additional geometry objects to the DirectShape using versions of the AppendShape() method. Note that AppendShape() will not merge or join the incoming geometry with any geometry already present, the geometry will be stored independently.

DirectShapes accept the following geometry types as input:

In addition, you can specify geometry to be used in a view-specific representation of a DirectShape. This geometry is input along with the input of a DirectShapeTargetViewType. When setting a view-specific shape representation, it will only be used in views of that type. Currently the only view-specific representation supported is for Plan views.

The following example demonstrates how to create a simple DirectShape from a sphere created using the GeometryCreationUtilities class.

Code Region: Create a DirectShape

// Create a DirectShape Sphere
public void CreateSphereDirectShape(Document doc)
{
    List<Curve> profile = new List<Curve>();

    // first create sphere with 2' radius
    XYZ center = XYZ.Zero;
    double radius = 2.0;    
    XYZ profile00 = center;
    XYZ profilePlus = center + new XYZ(0, radius, 0);
    XYZ profileMinus = center - new XYZ(0, radius, 0);

    profile.Add(Line.CreateBound(profilePlus, profileMinus));
    profile.Add(Arc.Create(profileMinus, profilePlus, center + new XYZ(radius, 0, 0)));

    CurveLoop curveLoop = CurveLoop.Create(profile);
    SolidOptions options = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId);

    Frame frame = new Frame(center, XYZ.BasisX, -XYZ.BasisZ, XYZ.BasisY);
    Solid sphere = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curveLoop }, 0, 2 * Math.PI, options);
    using (Transaction t = new Transaction(doc, "Create sphere direct shape"))
    {
        t.Start();
        // create direct shape and assign the sphere shape
        DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel),
                                                    "Application id",
                                                    "Geometry object id");
        ds.SetShape(new GeometryObject[] { sphere });
        t.Commit();
    }
}

The geometry for a DirectShape can also be created using a subclass of the ShapeBuilder class or from a TessellatedShapeBuilder.

ShapeBuilder

ViewShapeBuilder and WireframeBuilder can be used to create geometry to store in a DirectShape class. The ViewShapeBuilder class builds and verifies a view-specific shape representation. It is limited to curve-based representations for plan views. WireframeBuilder constructs a 3D shape representation consisting of points and curves. Both types of ShapeBuilders can be applied to a DirectShape element using the DirectShape.SetShape() or DirectShape.AppendShape() overload that takes a ShapeBuilder parameter.

TessellatedShapeBuilder

TessellatedShapeBuilder can be used create solid, shell, or polymeshes bounded by a set of connected planar facets, created by adding TessellatedFace objects one by one. Faces can only be added to the build while a face set is "open". Use the OpenConnectedFaceSet() method to open a face set. After adding all the TessellatedFaces, call CloseConnecedFaceSet() to close the face set. The builder allows for the possibility of multiple face sets - in such cases the first set should represent the outer 'surface' of a body and all following sets represent interior voids. The builder tries to create a geometry valid in Revit despite inconsistencies or omissions in the input data.

After defining all faces and closing the face set, call the Build() method to build the designated geometrical objects from the stored face sets. The Build() method returns a TessellatedShapeBuilderResult object. The TessellatedShapeBuilderResult.GetGeometricalObjects() method will return a list of GeometryObjects which can be used with the corresponding DirectShape.SetShape() or DirectShape.AppendShape() overload, as shown in the example below.

Code Region: Create a DirectShape using TessellatedShapeBuilder

// Create a pyramid-shaped DirectShape using given material for the faces
public void CreateTessellatedShape(Document doc, ElementId materialId)
{
    List<XYZ> loopVertices = new List<XYZ>(4);

    TessellatedShapeBuilder builder = new TessellatedShapeBuilder();

    builder.OpenConnectedFaceSet(true);
    // create a pyramid with a square base 4' x 4' and 5' high
    double length = 4.0;
    double height = 5.0;

    XYZ basePt1 = XYZ.Zero;
    XYZ basePt2 = new XYZ(length, 0, 0);
    XYZ basePt3 = new XYZ(length, length, 0);
    XYZ basePt4 = new XYZ(0, length, 0);
    XYZ apex = new XYZ(length / 2, length / 2, height);

    loopVertices.Add(basePt1);
    loopVertices.Add(basePt2);
    loopVertices.Add(basePt3);
    loopVertices.Add(basePt4);
    builder.AddFace(new TessellatedFace(loopVertices, materialId));

    loopVertices.Clear();
    loopVertices.Add(basePt1);
    loopVertices.Add(apex);
    loopVertices.Add(basePt2);
    builder.AddFace(new TessellatedFace(loopVertices, materialId));

    loopVertices.Clear();
    loopVertices.Add(basePt2);
    loopVertices.Add(apex);
    loopVertices.Add(basePt3);
    builder.AddFace(new TessellatedFace(loopVertices, materialId));

    loopVertices.Clear();
    loopVertices.Add(basePt3);
    loopVertices.Add(apex);
    loopVertices.Add(basePt4);
    builder.AddFace(new TessellatedFace(loopVertices, materialId));

    loopVertices.Clear();
    loopVertices.Add(basePt4);
    loopVertices.Add(apex);
    loopVertices.Add(basePt1);
    builder.AddFace(new TessellatedFace(loopVertices, materialId));

    builder.CloseConnectedFaceSet();

    TessellatedShapeBuilderResult result = builder.Build(TessellatedShapeBuilderTarget.Solid, TessellatedShapeBuilderFallback.Abort, ElementId.InvalidElementId);

    using (Transaction t = new Transaction(doc, "Create tessellated direct shape"))
    {
        t.Start();
                
        DirectShape ds = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel),
                                                    "Application id",
                                                    "Geometry object id");

        ds.SetShape(result.GetGeometricalObjects());
        t.Commit();
    }
}

The image below is the result of running the example above with a concrete material id specified.

Options

The DirectShapeOptions class is used to control behavior of a DirectShape object. Use DirectShape.SetOptions() to set the options used by a DirectShape object. The GetOptions() method will return the DirectShapeOptions currently used by the DirectShape object.

DirectShape elements, by default, support element references, including dimensions, alignments, and face hosting, as well as snapping. This default behavior can be changed using the DirectShapeOptions.ReferencingOption property. If it is set to NotReferenceable, the geometry may not be used for dimensioning, snapping, alignment, or face-hosting. The element may still be selected by the user for operations which do not reference individual geometry objects.

DirectShape elements also support the ability to participate in room boundary calculations, if they are of an appropriate category for room boundary calculations, and if the associated "Room Bounding" parameter is set to true. The property DirectShapeOptions.RoomBoundingOption identifies whether the DirectShape supports an option for the "Room Bounding" parameter to permit participation in room boundary calculations. The default value is NotApplicable, but this will be changed automatically to SetByParameter for applicable DirectShapes.