Creating a mass from Toposurface geometry

Following up this suggestion from Julien, here’s a look at how to create a massing family with geometry built from the mesh of a toposurface.

public void topoToMass()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = this.ActiveUIDocument;
    Application app = this.Application;

    TopographySurface topo = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element)) as TopographySurface;

    Mesh mesh = topo.get_Geometry(new Options()).First(q => q is Mesh) as Mesh;

    Document famDoc = app.NewFamilyDocument(@"C:\ProgramData\Autodesk\RAC 2014\Family Templates\English_I\Conceptual Mass\Mass.rft");

    using (Transaction t = new Transaction(famDoc,"Create massing surfaces"))
    {
        t.Start();

        for (int i = 0; i < mesh.NumTriangles; i++)
        {
            MeshTriangle mt = mesh.get_Triangle(i);
            makeForm(famDoc, mt.get_Vertex(0), mt.get_Vertex(1), mt.get_Vertex(2));

            if (i > 0 && i % 100 == 0)
            {
                TaskDialog td = new TaskDialog("Form Counter");
                td.CommonButtons = TaskDialogCommonButtons.Yes|TaskDialogCommonButtons.No;
                td.MainInstruction = i + " out of " + mesh.NumTriangles + " triangles processed. Do you want to continue?";
                if (td.Show() == TaskDialogResult.No)
                    break;
            }
        }
        t.Commit();
    }
    famDoc.LoadFamily(doc);
}

private Form makeForm(Document doc, XYZ pt1, XYZ pt2, XYZ pt3)
{
    Form form = null;

    XYZ u = pt2.Subtract(pt1);
    XYZ v = pt3.Subtract(pt1);
    double area = u.CrossProduct(v).GetLength()/2;
    if (area < 10)
        return null;

    ReferenceArray ra = new ReferenceArray();
    ra.Append(MakeCuveByPoints(doc, pt1, pt2).GeometryCurve.Reference);
    ra.Append(MakeCuveByPoints(doc, pt2, pt3).GeometryCurve.Reference);
    ra.Append(MakeCuveByPoints(doc, pt3, pt1).GeometryCurve.Reference);

    form = doc.FamilyCreate.NewFormByCap(true, ra);

    return form;
}

private CurveByPoints MakeCuveByPoints(Document doc, XYZ ptA, XYZ ptB)
{
    ReferencePointArray rpa = new ReferencePointArray();
    rpa.Append(doc.FamilyCreate.NewReferencePoint(ptA));
    rpa.Append(doc.FamilyCreate.NewReferencePoint(ptB));
    return doc.FamilyCreate.NewCurveByPoints(rpa);
}

17 thoughts on “Creating a mass from Toposurface geometry

  1. Hi, this looks extremely useful thanks for sharing the code. I am unable to run the code though, it always throws an exception when I go to load the family ‘famDoc.LoadFamily(doc);’? Do you know whats going wrong and how I can fix it? The exception is ‘Revit encountered a System.Runtime.InteropServices.SEHException: External component has thrown an exception.’

    The code is exactly like your sample except that the path to ‘Mass.rft’ is different on my computer (using Revit 2014 in Australia); theres no ‘C:\ProgramData\Autodesk\RAC 2014\Family Templates\English_I\Conceptual Mass\Mass.rft’ but I do have ‘C:\ProgramData\Autodesk\RVT 2014\Family Templates\English\Conceptual Mass\Metric Mass.rft’ which is what I am using. Maybe this is the cause of the error?

  2. Harry,

    I was running in to the same issue as above. It turns out the problem was the LoadFamily was returning this error if you didn’t have SP2 installed. Installed that and the program runs without a hitch.

  3. Hi Harry,

    I have a question. Is there any way where we can code the api so that it is placed exactly on the topo-surface. I might need to create the mass and discard the topo-surface. Please advise.

    Thanks

    Ani

    • The easiest way would be to use the Element.Location property, but that property has no data for a toposurface. Perhaps it would work to match the BoundingBox.Min or Max points for the topo and family instance.

  4. Hello,

    I have been trying to get this macro to work in Revit 2014 (service pack 3) and I keep getting the error “Revit failed to execute topoToMass”
    Here is the full code I am compiling: http://pastebin.com/cPHpmiHk

    Your help is very much appreciated to help me figure what I am missing or have left out.

    I am working on a project with a very large site and a lot of topography that I need to convert to roads (slabs). I want to convert the Revit Toposurface to a mass and then apply a slab to the surface of the mass. The roads have parts of the project under them so I need to make the roads with slabs in Revit.

    Thank you!

    Ry

      • Hello,

        Thanks for the quick reply. The error message displays:
        —–
        Revit failed to execute topoToMass.

        A problem has been detected.

        Autodesk.Revit.Exceptions.ArgumentException: Input
        templateFileName doesn’t exist.
        at MacroModule.executeMacro_(MacroModule* , AString*
        macroName)
        at MacroModule.executeMacro(MacroModule* , AString* )
        at
        UIMacroGeneralManager.runMacro(UIMacroGeneralManager* ,
        MacroModule* pModule, AString* macroName)
        —–

        I did try to go through the code to figure it out but keep getting this same error message each time. The only line of code I changed from your code above was the location of the conceptual mass folder on my system. This leads me to believe that I must have something wrong in the format or possibly the other code above the macro script.

        Your help is very much appreciated. Thank you!

  5. Hello Harry,

    That was it actually! There was a tiny bit of the code that was off. On my system the template file is named: Metric Mass.rft

    In your example code it was just Mass.rft

    Note to others who may try to use the sample code. Be sure to check the whole template file path as well as the template file name. On my system the full path with template file location is: C:\ProgramData\Autodesk\RVT 2014\Family Templates\English\Conceptual Mass\Metric Mass.rft

    I fixed the template path to make sure it was correct and forgot to check the actually template file name.

    Thanks again for your help to get it working.

    Now I need to deal with being able to create a slab from the mass that I created from the toposurface. Harry, do you know of a better way to do that? I am now finding that the toposurface may be too complex to make a slab from the mass. Might work if I take the topography into Rhino and tweak it in there and then bring it back into Revit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s