Boost Your BIM – making Revit even better

January 13, 2014

Creating a mass from Toposurface geometry

Filed under: Massing, Site — Harry Mattison @ 1:37 pm

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);
}
About these ads

9 Comments »

  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?

    Comment by Sam — February 1, 2014 @ 5:39 am

    • What line of code is throwing that exception?

      Comment by harrymattison — February 1, 2014 @ 5:10 pm

      • Hi :), the last line in ‘topoToMass()’, which is, ‘famDoc.LoadFamily(doc);’.

        Comment by Sam — February 1, 2014 @ 7:33 pm

        • What happens if you modify the API code to save the family instead of loading it? Can you manually open and load that family?

          >

          Comment by harrymattison — February 1, 2014 @ 7:46 pm

          • If I do that and save the family to a .rfa. Then open the .rfa it looks correct, just like your example. See the image (the top image is the TS I selected and the bottom is the mass created): http://i58.tinypic.com/5yaweu.jpg

            I guess my options are either to:
            - Save the family to a file, read that family in using LoadFamily() or LoadFamilySymbol(), then delete the .rfa
            - Regenerate the family document before calling load family. That might work, I’ll give it a try.

            Comment by Sam — February 2, 2014 @ 12:08 am

      • Also I am running the addin in a ‘Construction Revit Project’ not a ‘Family Project’ or MEP or etc. Maybe that affects it?

        Comment by Sam — February 1, 2014 @ 7:35 pm

  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.

    Comment by Tom Harkins — February 24, 2014 @ 2:24 pm

  3. This is exactly what I need to do How do I utilize it?

    Comment by Michael — March 18, 2014 @ 2:32 pm


RSS feed for comments on this post. TrackBack URI

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

The WordPress Classic Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 972 other followers