having trouble programmatically placing doors and windows in walls, via an addin

having trouble programmatically placing doors and windows in walls, via an addin

Anonymous
Not applicable
3,193 Views
15 Replies
Message 1 of 16

having trouble programmatically placing doors and windows in walls, via an addin

Anonymous
Not applicable

I am attemtping to programmatically place walls, and then place doors and windows in those walls.

I am getting confused about how to generate a FamilySymbol for a door.  I am assuming that window insertion into walls is similar in technique.

code is below:

 

using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB;
using Autodesk.Revit.Creation;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

[TransactionAttribute( TransactionMode.Manual )]
[RegenerationAttribute( RegenerationOption.Manual )]
public class RevitDataPlugin : IExternalCommand {
    public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ) {
        //Get application and document objects
        UIApplication uiApp = commandData.Application;
        var doc = uiApp.ActiveUIDocument.Document;

        using ( Transaction trans = new Transaction( doc ) ) {
            trans.Start( "WallDataParser" );

            Level level = Level.Create( doc, 0.0 );
            XYZ start = new XYZ( 0.0, 0.0, 0.0 );
            XYZ end = new XYZ( 10.0, 0.0, 0.0 );
            Line wallLine = Line.CreateBound( start, end );
            Wall wall = Wall.Create( doc, wallLine as Line, level.Id, true );

            XYZ doorPoint = new XYZ( 5.0 , 0.0, 0.0 );

            ElementId doorCategoryId = new ElementId( BuiltInCategory.OST_Doors );
          
            FamilySymbol doorSymbol = null; // TODO: how?

            doc.Create.NewFamilyInstance( doorPoint, doorSymbol, wall, Autodesk.Revit.DB.Structure.StructuralType.NonStru​ctural );

            doc.Regenerate();

            trans.Commit();
        }

        return Result.Succeeded;
    }
}

Accepted solutions (1)
3,194 Views
15 Replies
Replies (15)
Message 2 of 16

BobbyC.Jones
Advocate
Advocate

Are you familiar with the concept of the FilteredElementCollector?  

--
Bobby C. Jones
Message 3 of 16

Anonymous
Not applicable

I was not, but I think I understand it's use now. the following code is what I have come up with so far, however it fails with a symbol not active.

 

using System;
using System.Collections.Generic;
//using System.IO;
//using System.Linq;

using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.Creation;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

[TransactionAttribute( TransactionMode.Manual )]
[RegenerationAttribute( RegenerationOption.Manual )]
public class RevitDataPlugin : IExternalCommand {
    private List<FamilySymbol> doorFamilies = new List<FamilySymbol>();

    public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ) {
        //Get application and document objects
        UIApplication uiApp = commandData.Application;
        var doc = uiApp.ActiveUIDocument.Document;

        using ( Transaction trans = new Transaction( doc ) ) {
            trans.Start( "WallDataParser" );

            PrepareDoorFamilies( commandData );

            Level level = Level.Create( doc, 0.0 );
            XYZ start = new XYZ( 0.0, 0.0, 0.0 );
            XYZ end = new XYZ( 10.0, 0.0, 0.0 );
            Line wallLine = Line.CreateBound( start, end );
            Wall wall = Wall.Create( doc, wallLine as Line, level.Id, false );

            XYZ doorPoint = new XYZ( 5.0 , 0.0, 0.0 );

            ElementId doorCategoryId = new ElementId( BuiltInCategory.OST_Doors );
            //Opening opening = wall.Document.Create.NewOpening( wall, pntStart, pntEnd );

            FamilySymbol doorSymbol = doorFamilies[0]; // TODO: how?

            doc.Create.NewFamilyInstance( doorPoint, doorSymbol, wall, Autodesk.Revit.DB.Structure.StructuralType.NonStru​ctural );

            doc.Regenerate();

            trans.Commit();
        }

        return Result.Succeeded;
    }

    private void PrepareDoorFamilies( ExternalCommandData commandData ) {
        UIApplication uiApp = commandData.Application;
        var doc = uiApp.ActiveUIDocument.Document;

        // prepare families
        FilteredElementIterator familyIter = new FilteredElementCollector( doc ).OfClass( typeof( Family ) ).GetElementIterator();

        while ( familyIter.MoveNext() ) {

            Family doorFamily = familyIter.Current as Family;

            if ( null == doorFamily.FamilyCategory ) { // some family.FamilyCategory is null
                continue;
            }

            if ( doorFamily.FamilyCategory.Name != doc.Settings.Categories.get_Item( BuiltInCategory.OST_Doors ).Name ) { // FamilyCategory.Name is not 'Doors'
                continue;
            }

            foreach ( ElementId elementId in doorFamily.GetFamilySymbolIds() ) {
                // store the created family
                doorFamilies.Add( ( FamilySymbol )( doc.GetElement( elementId ) ) );
            }

        }
    }
}

0 Likes
Message 4 of 16

Anonymous
Not applicable
mind you a good but of the code in PrepareDoorFamilies was pulled from the demos of the api
0 Likes
Message 5 of 16

BobbyC.Jones
Advocate
Advocate

Oh, how unfortunate and confusing!  Here's a quick way to get Ids of all door family symbols.

 

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace Revit.Examples
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class TestCommand : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            var collector = new FilteredElementCollector(commandData.Application.ActiveUIDocument.Document);

            var doorFamilySymbolIds = collector.
                OfClass(typeof (FamilySymbol)).
                OfCategory(BuiltInCategory.OST_Doors).
                ToElementIds();

            return Result.Succeeded;
        }
    }
}
--
Bobby C. Jones
0 Likes
Message 6 of 16

BobbyC.Jones
Advocate
Advocate
Accepted solution

but of course, after reading a little closer, you don't give a crap about family symbol Ids, and you need to keep from crashing with the symbol not active exception.

 

using System.Linq;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace DWH.Revit.Schedules.Commands
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class TestCommand : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            var collector = new FilteredElementCollector(commandData.Application.ActiveUIDocument.Document);

            var doorFamilySymbols = collector.
                OfClass(typeof (FamilySymbol)).
                OfCategory(BuiltInCategory.OST_Doors).
                OfType<FamilySymbol>();

            var firstDoorSymbol = doorFamilySymbols.FirstOrDefault();

            if (firstDoorSymbol == null)
            {
                message = "No door families loaded.";

                return Result.Failed;
            }

            if (!firstDoorSymbol.IsActive)
            {
                firstDoorSymbol.Activate();
            }

            //Do your thing with the door symbol.

            return Result.Succeeded;
        }
    }
}
--
Bobby C. Jones
Message 7 of 16

Anonymous
Not applicable

thanks! this little project is my first real foray into C#, so it's been a bit rough, though I have been learning a lot! much appreciated!

0 Likes
Message 8 of 16

BobbyC.Jones
Advocate
Advocate
I thought it might be and I despise those examples that obfuscate the use of the Revit API in unnecessary language constructs. I'm glad I could help and I hope things are a little clearer. Scour the SDK docs and the www to learn all you can about Filters and the FilteredElementCollector; you'll use them a lot. Good luck and come back when you get stuck!
--
Bobby C. Jones
Message 9 of 16

Anonymous
Not applicable

though I do have one issuse with your solution: all doors are null! instead of

FamilySymbol doorSymbol = doorFamilySymbols.FirstOrDefault();

I replaced it with

 

FamilySymbol doorSymbol = null, window = null;
foreach ( FamilySymbol door in doorFamilySymbols ) {
    if ( door == null ) {
        continue;
    } else {
        doorSymbol = door ;

        if ( !doorSymbol.IsActive ) {
            doorSymbol.Activate();
        }

        break;
     }
}

 but the null-ness persists!

 

0 Likes
Message 10 of 16

BobbyC.Jones
Advocate
Advocate
Does your project have any door families loaded?
--
Bobby C. Jones
0 Likes
Message 11 of 16

Anonymous
Not applicable

no I do not, how would I do so?

0 Likes
Message 12 of 16

Anonymous
Not applicable

no it doesn't I'm trying to place one 😛 how would I load it? using loadFamily?

0 Likes
Message 13 of 16

BobbyC.Jones
Advocate
Advocate
Yes, if the family you want isn't loaded, then LoadFamily will load it. Also note that LoadFamily provides you a Family object which has a very convenient GetFamilySymbolIds() method.
--
Bobby C. Jones
0 Likes
Message 14 of 16

BobbyC.Jones
Advocate
Advocate
And alternatively, if you only want to load a single type instead of them all, you can use LoadFamilySymbol().
--
Bobby C. Jones
0 Likes
Message 15 of 16

Anonymous
Not applicable

any ideas on how to load the default families in the arch-template? I cannot find them in the filesystem, so i assume they are in the document itself.

0 Likes
Message 16 of 16

BobbyC.Jones
Advocate
Advocate

Well, two things come to mind immediately. First, you can right click on the Families node in the Project Browser and save families from inside a project to individual .rfa family files, or right click on any single non-system family to save a single file. Second, if you're **** bent on doing all via code, you could look into the ElementTransformUtils.CopyElements() method to copy families from one project to another.

--
Bobby C. Jones
0 Likes