Auto Generate 3D Walls from 2D Line floor plan (with a Selection pre-filter)

Darren asks at AUGI “Can Revit Architecture Auto Generate 3D from 2D floor plan?”

Here’s a little macro to do just that. Run the macro, select these 4 lines, and get these 4 walls.

walls from lines

Most of this should look familiar to code I have explained in previous posts.

The new piece is the ISelectionFilter. This applies a pre-filter to PickObjects so that when the user is prompted to select objects, the Select tool will only allow selections that pass the filter. In this case, the filter is defined so that it will return true only when ModelLines are selected. Nothing will be selected if the user clicks the mouse with the cursor over a wall, window, column, or anything else that it not a model line.

public void wallsFromLines()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = new UIDocument(doc);

    // Get "Level 1"
    Level level = (from l in new FilteredElementCollector(doc).OfClass(typeof(Level)) where l.Name == "Level 1" select l).First() as Level;

    // Selection will be restricted to lines only. Attempts to click on other objects will be ignored
    ISelectionFilter lineFilter = new LineSelectionFilter();

    IList<Reference> lineRefs = uidoc.Selection.PickObjects(ObjectType.Element, lineFilter, "Pick lines");

    using (Transaction t = new Transaction(doc,"Create Walls From Lines"))
    {
        t.Start(); 
        foreach (Reference reference in lineRefs)
        {
            ModelLine modelLine = doc.GetElement(reference) as ModelLine;
            doc.Create.NewWall(modelLine.GeometryCurve, level, false); // false indicates that the wall's Structural property is false
        }
        t.Commit();
    }
}
public class LineSelectionFilter : ISelectionFilter
{
    // determine if the element should be accepted by the filter
    public bool AllowElement(Element element)
    {
        // Convert the element to a ModelLine
        ModelLine line = element as ModelLine;
        // line is null if the element is not a model line
        if (line == null)
        {
            return false;
        }
        // return true if the line is a model line
        return true;
    }

    // references will never be accepeted by this filter, so always return false
    public bool AllowReference(Reference refer, XYZ point)
    {return false;}
}

In the real world you may want to do this with many walls and use a filter or some other mechanism instead of selecting them individually. You would also want something more sophisticated to specify the base constraint of the walls instead of having them all at Level 1. Model lines don’t have a Level property, but you can get their Z location from ModelLine.GeometryCurve.Origin and then find a level with the same elevation.

Advertisements

16 thoughts on “Auto Generate 3D Walls from 2D Line floor plan (with a Selection pre-filter)

  1. I read the post at AUGI assuming a DWG source linked file. The trouble with a conventional CAD background is layer inconsistency and two lines for each side of a wall. If someone only sketched a concept with a single line it would be easier, or used a specific layer for the exterior edge of every double line wall. By the time you are very careful doing these things in CAD you could learn to sketch walls in Revit. That’s probably the simplest thing to learn?

    Nice work on the blog so far!!

    • Hi Steve,

      Yes, you are right that when there are two parallel lines for each wall then the add-in code would have to be more sophisticated. For a small # of walls I agree that it would be faster & better to create them from scratch in Revit. There could be some situations where you have so much line data to convert to walls that an improved version of this tool would at least be a good first step in the process.

      Anyway, if nothing else it was a chance to show a bit of the Element Creation API and the cool selection filter.

      Thanks,
      Harry

  2. NewWall is causing error and showing meesage like this
    ‘Autodesk.Revit.Creation.Document’ does not contain a definition for ‘NewWall’ and no extension method ‘NewWall’ accepting a first argument of type ‘Autodesk.Revit.Creation.Document’ could be found (are you missing a using directive or an assembly reference?)

  3. Hi harry , because i am beginner and i need this handy tool, could you please post the code that gets the level of model line and match it to resulting wall.
    as well as there is i put this instead of obsolete one Wall.Create(doc,modelLine.GeometryCurve,level.LevelId ,false) it builds successfully but fail during execution i think it is complaining about Level id which i want to handle it ?
    Thanks in advance,

  4. Well harry, it is fixed now ,I noticed if i named my view level 1 it will be build on the same level !

    i really need to make it build on the same level not level 1. i could not do it because i am just beginner could you please post for us a code that can make it on the same level ?
    what it makes handy it fits my style sometimes i build my skeleton by lines or reference planes i need to get the wall built saving me effort to pick line by line.
    or if i imported autocad drawing with axes only really will be robust (think for a time about it 🙂
    We are waiting the code that get built it on the same level.
    regards from rose,

    • Hi Rose,

      It would be a lot easier for me to understand what you are doing and what result you’d like if you could post some code and perhaps a screenshort.

      Regards
      Harry

    • The variable “level” which is used here to create the walls
      doc.Create.NewWall(modelLine.GeometryCurve, level, false);

      is defined here in the 3rd line of the macro
      Level level = (from l in new FilteredElementCollector(doc).OfClass(typeof(Level)) where l.Name == “Level 1” select l).First() as Level;

      When you changed the value to something other than “Level 1” did you get the desired result?

  5. perhaps i got it we want to start constructing walls from the base constraint of the walls instead of having them all at Level 1.
    code please 🙂

  6. if i changed the code of this line for example Level level = (from l in new FilteredElementCollector(doc).OfClass(typeof(Level)) where l.Name == “Ground″ select l).First() as Level;
    it would not work.

  7. Well, simply changing the view name (variable) either in code or view plan will not solve the problem of error.
    What i really care about is your quote “You would also want something more sophisticated to specify the base constraint of the walls instead of having them all at Level 1. Model lines don’t have a Level property, but you can get their Z location from ModelLine.GeometryCurve.Origin and then find a level with the same elevation”
    We can not do this code as beginner in API.

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