본문 바로가기
Revit/Revit API

[레빗 API 시작하기] Revit Intro Lab5 - ModelCreation

by Crony 2013. 12. 5.

Revit Intro Lab5 - ModelCreation


Revit Intro Lab5 - ModelCreation_번역.docx


이번 Lab에서는 4개의벽에 창과 문을 설치하고 경사지붕을 덮는 간단한 집을 만드는 과정입니다.

기존의 프로젝트를 오픈하여 새로운 클래스를 정의할 새로운 파일을 추가합니다.

네임스페이스는 전과정과 동일하게 IntroCs를 사용합니다.


파일명 :  5_ModelCreation.cs 클래스명 : ModelCreation


추가로 사용될 네임스페이스

Autodesk.Revit.DB.Structure


멤버변수 설정 UiApp UiDoc RvtApp RvtDoc


추가과정

Lab5의 결과와 동일하게 간단한 집을 만드는 과정이지만 다른방식으로 접근하여 집을 완성하는 과정입니다.

작업하는 방식에도 차이가 있듯이 API도 접근방식을 다르게 할수 있다는 것을 보여주는 예입니다.


파일명 : 5_ModelCreationExport.cs 클래스명 : ModelCreationExport


public class ModelCreation : IExternalCommand


1. public void CreateHouse()


2. public List<Wall> CreateWalls()


3. public void AddDoor(Wall HostWall)


4. public void AddWindow(Wall HostWall)


5. public void AddRoof(List<Wall> walls)


public class ModelCreationExport : IExternalCommand


1. public void CreateHouse_v1()

    public static void CreateHouse(Document rvtDoc)


2. public List<Wall> CreateWalls_v1()

    public static List<Wall> CreateWalls(Document rvtDoc)

    public static List<Wall> CreateWalls(Document rvtDoc, XYZ pt1, XYZ pt2)


3. public static void AddDoor(Document rvtDoc, Wall hostWall)


4. public static void AddWindow(Document rvtDoc, Wall hostWall)


5. public static void AddRoof(Document rvtDoc, List<Wall> walls)



using System;

using System.Collections.Generic;

using Autodesk.Revit.ApplicationServices;

using Autodesk.Revit.Attributes;

using Autodesk.Revit.DB;

using Autodesk.Revit.DB.Structure;

using Autodesk.Revit.UI;

using Util;


namespace IntroCs

{

    // Element Creation.

    [Transaction(TransactionMode.Automatic)]

    public class ModelCreation : IExternalCommand

    {

        // Member variables 

        Application RvtApp;

        Document RvtDoc;


        public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData,ref string message,ElementSet elements)

        {

            UIApplication UIApp = commandData.Application;

            UIDocument UIDoc = UIApp.ActiveUIDocument;

            RvtApp = UIApp.Application;

            RvtDoc = UIDoc.Document;


            // 4개의 벽, 창 및 문으로 구성된 간단한 집을 만들어 보자. 

            CreateHouse();


            return Result.Succeeded;

        }


        public void CreateHouse()

        {

            // 직사각형의 프로파일로 구성된 4개의 벽 만들기 

            List<Wall> walls = CreateWalls();


            // 두번째 벽에 문을 추가하기

            AddDoor(walls[0]);


            // 나머지벽에 창문을 추가하기 

            for (int i = 1; i <= 3; i++)

            {

                AddWindow(walls[i]);

            }


            // 벽체 상부에 지붕추가하기(옵션 


            AddRoof(walls);

        }


        /// <summary>

        /// There are five override methods for creating walls. 

        /// We assume you are using metric template, where you have 

        /// "Level 1" and "Level 2" 

        /// cf. Developer Guide page 117 

        /// </summary>

        public List<Wall> CreateWalls()

        {

            // Hard coding 집의 크기 설정하기

            double width = Constant.MmToFeet(10000.0);

            double depth = Constant.MmToFeet(5000.0);


            // 작업할 레벨값이 있는지 확인하기 

            // Note: 다른 템플릿 사용시 아래구문 수정하기 

            Level level1 = (Level)ElementFiltering.FindElement(RvtDoc, typeof(Level), "Level 1", null);

            if (level1 == null)

            {

                TaskDialog.Show("Create walls", "Cannot find (Level 1). Maybe you use a different template? Try with DefaultMetric.rte.");

                return null;

            }


            Level level2 = (Level)ElementFiltering.FindElement(RvtDoc, typeof(Level), "Level 2", null);

            if (level2 == null)

            {

                TaskDialog.Show("Create walls", "Cannot find (Level 2). Maybe you use a different template? Try with DefaultMetric.rte.");

                return null;

            }


            // 벽체의 4개코너위치 설정하기, 5번째 위치는 처음위치를 입력 

            double dx = width / 2.0;

            double dy = depth / 2.0;


            List<XYZ> PtLst = new List<XYZ>(5);

            PtLst.Add(new XYZ(-dx, -dy, 0.0));

            PtLst.Add(new XYZ(dx, -dy, 0.0));

            PtLst.Add(new XYZ(dx, dy, 0.0));

            PtLst.Add(new XYZ(-dx, dy, 0.0));

            PtLst.Add(PtLst[0]);


            // 구조벽체 여부에 대한 값입력 - 비내력벽으로 설정 

            bool isStructural = false;


            // 벽체에 대한 변수 설정 

            List<Wall> walls = new List<Wall>(4);


            // 순환하는 좌표 리스트를 통하여 4개의 벽체를 생성하기 

            for (int i = 0; i <= 3; i++)

            {

                // 2개의 좌표로 Base Curve 생성하기 

                Line baseCurve = Line.CreateBound(PtLst[i], PtLst[i + 1]);

                // Create a wall using the one of overloaded methods. 


                // Create 메소드를 이용하여 벽체 설정하기

                Wall aWall = Wall.Create(RvtDoc, baseCurve, level1.Id, isStructural);


                // Level 2로 상단구속 설정하기 

                aWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(level2.Id);


                // 설정된 값으로 벽체 생성하기 

                walls.Add(aWall);

            }


            // 화면갱신 그리고 벽체요소 결합 처리하기 

            RvtDoc.Regenerate();

            RvtDoc.AutoJoinElements();


            return walls;

        }


        /// <summary>

        // Add a door to the center of the given wall. 

        // cf. Developer Guide p137. NewFamilyInstance() for Doors and Window. 

        /// </summary>

        public void AddDoor(Wall HostWall)

        {

            // Hard coding the door type we will use. 

            // E.g., "M_Single-Flush: 0915 x 2134mm 


            const string doorFamilyName = Util.Constant.DoorFamilyName;

            const string doorTypeName = Util.Constant.DoorTypeName;

            const string doorFamilyAndTypeName = doorFamilyName + ": " + doorTypeName;


            // Get the door type to use. 


            FamilySymbol doorType = (FamilySymbol)ElementFiltering.FindFamilyType(RvtDoc, typeof(FamilySymbol), doorFamilyName, doorTypeName, BuiltInCategory.OST_Doors);

            if (doorType == null)

            {

                TaskDialog.Show(

                  "Add door",

                  "Cannot find (" +

                  doorFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte.");

            }


            // Get the start and end points of the wall. 


            LocationCurve locCurve = (LocationCurve)HostWall.Location;

            XYZ pt1 = locCurve.Curve.GetEndPoint(0);

            XYZ pt2 = locCurve.Curve.GetEndPoint(1);

            // Calculate the mid point. 

            XYZ pt = (pt1 + pt2) / 2.0;


            // we want to set the reference as a bottom of the wall or level1. 


            ElementId idLevel1 = HostWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();


            Level level1 = (Level)RvtDoc.GetElement(idLevel1);


            // Finally, create a door. 


            FamilyInstance aDoor =

              RvtDoc.Create.NewFamilyInstance(

                pt, doorType, HostWall, level1, StructuralType.NonStructural);

        }


        /// <summary>

        /// Add a window to the center of the wall given. 

        /// cf. Developer Guide p137. NewFamilyInstance() for Doors and Window. 

        /// Basically the same idea as a door except that we need to set sill hight. 

        /// </summary>

        public void AddWindow(Wall HostWall)

        {

            // Hard coding the window type we will use. 

            // E.g., "M_Fixed: 0915 x 1830mm 


            const string windowFamilyName = Util.Constant.WindowFamilyName;

            const string windowTypeName = Util.Constant.WindowTypeName;

            const string windowFamilyAndTypeName = windowFamilyName + ": " + windowTypeName;

            double sillHeight = Constant.MmToFeet(915);


            // Get the door type to use. 


            FamilySymbol windowType = (FamilySymbol)ElementFiltering.FindFamilyType(RvtDoc, typeof(FamilySymbol), windowFamilyName, windowTypeName, BuiltInCategory.OST_Windows);

            if (windowType == null)

            {

                TaskDialog.Show(

                  "Add window",

                  "Cannot find (" +

                  windowFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte.");

            }


            // Get the start and end points of the wall. 


            LocationCurve locCurve = (LocationCurve)HostWall.Location;

            XYZ pt1 = locCurve.Curve.GetEndPoint(0);

            XYZ pt2 = locCurve.Curve.GetEndPoint(1);

            XYZ pt = (pt1 + pt2) / 2.0;


            // we want to set the reference as a bottom of the wall or level1. 

            ElementId idLevel1 = HostWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();

            Level level1 = (Level)RvtDoc.GetElement(idLevel1); // since 2013


            // Finally create a window. 


            FamilyInstance aWindow = RvtDoc.Create.NewFamilyInstance(pt, windowType, HostWall, level1, StructuralType.NonStructural);


            aWindow.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).Set(sillHeight);

        }


        /// <summary>

        /// Add a roof over the rectangular profile of the walls we created earlier. 

        /// </summary>

        public void AddRoof(List<Wall> walls)

        {

            // Hard coding the roof type we will use. 

            // E.g., "Basic Roof: Generic - 400mm" 


            const string roofFamilyName = "Basic Roof";

            const string roofTypeName = Util.Constant.RoofTypeName; //  Util.Constant.RoofTypeName 

            const string roofFamilyAndTypeName = roofFamilyName + ": " + roofTypeName;


            // Find the roof type 


            RoofType roofType = (RoofType)ElementFiltering.FindFamilyType(RvtDoc, typeof(RoofType), roofFamilyName, roofTypeName, null);


            if (roofType == null)

            {

                TaskDialog.Show(

                  "Add roof",

                  "Cannot find (" +

                  roofFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte.");

            }


            // Wall thickness to adjust the footprint of the walls 

            // to the outer most lines. 

            // Note: this may not be the best way, 

            // but we will live with this for this exercise. 


            //double wallThickness = walls[0].WallType.CompoundStructure.Layers.get_Item(0).Thickness; // 2011

            double wallThickness = walls[0].Width;


            double dt = wallThickness / 2.0;

            List<XYZ> dts = new List<XYZ>(5);

            dts.Add(new XYZ(-dt, -dt, 0.0));

            dts.Add(new XYZ(dt, -dt, 0.0));

            dts.Add(new XYZ(dt, dt, 0.0));

            dts.Add(new XYZ(-dt, dt, 0.0));

            dts.Add(dts[0]);


            // Set the profile from four walls 


            CurveArray footPrint = new CurveArray();

            for (int i = 0; i <= 3; i++)

            {

                LocationCurve locCurve = (LocationCurve)walls[i].Location;

                XYZ pt1 = locCurve.Curve.GetEndPoint(0) + dts[i];

                XYZ pt2 = locCurve.Curve.GetEndPoint(1) + dts[i + 1];

                Line line = Line.CreateBound(pt1, pt2);

                footPrint.Append(line);

            }


            // Get the level2 from the wall 


            ElementId idLevel2 = walls[0].get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();

            Level level2 = (Level)RvtDoc.GetElement(idLevel2); // since 2013


            // Footprint to morel curve mapping 


            ModelCurveArray mapping = new ModelCurveArray();


            // Create a roof. 


            FootPrintRoof aRoof = RvtDoc.Create.NewFootPrintRoof(footPrint, level2, roofType, out mapping);


            foreach (ModelCurve modelCurve in mapping)

            {

                aRoof.set_DefinesSlope(modelCurve, true);

                aRoof.set_SlopeAngle(modelCurve, 0.5);

            }

        }


    }

}



using System;

using System.Collections.Generic;

using Autodesk.Revit.ApplicationServices;

using Autodesk.Revit.Attributes;

using Autodesk.Revit.DB;

using Autodesk.Revit.DB.Structure;

using Autodesk.Revit.UI;

using Util;

using IntroCs;


namespace IntroCs

{

    [Transaction(TransactionMode.Automatic)]

    public class ModelCreationExport : IExternalCommand

    {

        // Member variables 

        Application _app;

        Document _doc;


        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

        {

            // Get the acess to the top most objects. 

            UIApplication rvtUIApp = commandData.Application;

            UIDocument uiDoc = rvtUIApp.ActiveUIDocument;

            _app = rvtUIApp.Application;

            _doc = uiDoc.Document;


            // Let's make a simple "house" composed of four walls, a window 

            // and a door. 

            CreateHouse(_doc);


            return Result.Succeeded;


        }


        public void CreateHouse_v1()

        {

            // Simply create four walls with rectangular profile. 

            List<Wall> walls = CreateWalls(_doc);


            // Add a door to the second wall 

            AddDoor(_doc, walls[0]);


            // Add windows to the rest of the walls. 

            for (int i = 1; i <= 3; i++)

            {

                AddWindow(_doc, walls[i]);

            }


            // (optional) add a roof over the walls' rectangular profile. 

            AddRoof(_doc, walls);

        }


        public static void CreateHouse(Document rvtDoc)

        {

            // Simply create four walls with rectangular profile. 

            List<Wall> walls = CreateWalls(rvtDoc);


            // Add a door to the second wall 

            AddDoor(rvtDoc, walls[0]);


            // Add windows to the rest of the walls. 

            for (int i = 1; i <= 3; i++)

            {

                AddWindow(rvtDoc, walls[i]);

            }


            // (optional) add a roof over the walls' rectangular profile. 

            AddRoof(rvtDoc, walls);

        }


        /// <summary>

        /// There are five override methods for creating walls. 

        /// We assume you are using metric template, where you have

        /// "Level 1" and "Level 2"

        /// cf. Developer Guide page 117 

        /// </summary>

        public List<Wall> CreateWalls_v1()

        {

            // Hard coding the size of the house for simplicity 

            double width = Constant.MmToFeet(10000.0);

            double depth = Constant.MmToFeet(5000.0);


            // Get the levels we want to work on. 

            // Note: hard coding for simplicity. Modify here you use a different template. 

            Level level1 = ElementFiltering.FindElement(_doc, typeof(Level), "Level 1", null) as Level;

            if (level1 == null)

            {

                TaskDialog.Show("Create walls",

                  "Cannot find (Level 1). Maybe you use a different template? Try with DefaultMetric.rte.");

                return null;

            }


            Level level2 = ElementFiltering.FindElement(_doc, typeof(Level), "Level 2", null) as Level;

            if (level2 == null)

            {

                TaskDialog.Show("Create walls",

                  "Cannot find (Level 2). Maybe you use a different template? Try with DefaultMetric.rte.");

                return null;

            }


            // Set four corner of walls.

            // 5th point is for combenience to loop through.  

            double dx = width / 2.0;

            double dy = depth / 2.0;


            List<XYZ> pts = new List<XYZ>(5);

            pts.Add(new XYZ(-dx, -dy, 0.0));

            pts.Add(new XYZ(dx, -dy, 0.0));

            pts.Add(new XYZ(dx, dy, 0.0));

            pts.Add(new XYZ(-dx, dy, 0.0));

            pts.Add(pts[0]);


            // Flag for structural wall or not. 

            bool isStructural = false;


            // Save walls we create. 

            List<Wall> walls = new List<Wall>(4);


            // Loop through list of points and define four walls. 

            for (int i = 0; i <= 3; i++)

            {

                // Define a base curve from two points. 

                Line baseCurve = Line.CreateBound(pts[i], pts[i + 1]);

                // Create a wall using the one of overloaded methods. 


                //Wall aWall = _doc.Create.NewWall(baseCurve, level1, isStructural); // 2012

                Wall aWall = Wall.Create(_doc, baseCurve, level1.Id, isStructural); // since 2013


                // Set the Top Constraint to Level 2 

                aWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(level2.Id);

                // Save the wall.

                walls.Add(aWall);

            }

            // This is important. we need these lines to have shrinkwrap working. 

            _doc.Regenerate();

            _doc.AutoJoinElements();


            return walls;


        }


        /// <summary>

        /// Second version modified for Revit UI Labs.

        /// </summary>

        public static List<Wall> CreateWalls(Document rvtDoc)

        {

            // Hard coding the lower-left and upper-right corners of walls. 

            XYZ pt1 = new XYZ(Constant.MmToFeet(-5000.0), Constant.MmToFeet(-2500.0), 0.0);

            XYZ pt2 = new XYZ(Constant.MmToFeet(5000.0), Constant.MmToFeet(2500.0), 0.0);


            List<Wall> walls = CreateWalls(rvtDoc, pt1, pt2);


            return walls;

        }


        /// <summary>

        /// Create walls with a rectangular profile from two coner points. 

        /// </summary>

        public static List<Wall> CreateWalls(Document rvtDoc, XYZ pt1, XYZ pt2)

        {

            // Set the lower-left (x1, y1) and upper-right (x2, y2) corners of a house. 

            double x1 = pt1.X;

            double x2 = pt2.X;

            if (pt1.X > pt2.X)

            {

                x1 = pt2.X;

                x2 = pt1.X;

            }


            double y1 = pt1.Y;

            double y2 = pt2.Y;

            if (pt1.Y > pt2.X)

            {

                y1 = pt2.Y;

                y2 = pt1.Y;

            }


            // Set four corner of walls from two croner point.

            // 5th point is for combenience to loop through.  

            List<XYZ> pts = new List<XYZ>(5);

            pts.Add(new XYZ(x1, y1, pt1.Z));

            pts.Add(new XYZ(x2, y1, pt1.Z));

            pts.Add(new XYZ(x2, y2, pt1.Z));

            pts.Add(new XYZ(x1, y2, pt1.Z));

            pts.Add(pts[0]);


            // Get the levels we want to work on. 

            // Note: hard coding for simplicity. Modify here you use a different template. 

            Level level1 = ElementFiltering.FindElement(rvtDoc, typeof(Level), "Level 1", null) as Level;

            if (level1 == null)

            {

                TaskDialog.Show(

                  "Create walls", "Cannot find (Level 1). Maybe you use a different template? Try with DefaultMetric.rte."

                );

                return null;

            }


            Level level2 = ElementFiltering.FindElement(rvtDoc, typeof(Level), "Level 2", null) as Level;

            if (level2 == null)

            {

                TaskDialog.Show(

                  "Create walls", "Cannot find (Level 2). Maybe you use a different template? Try with DefaultMetric.rte."

                );

                return null;

            }


            // Flag for structural wall or not. 

            bool isStructural = false;


            // Save walls we create. 

            List<Wall> walls = new List<Wall>(4);


            // Loop through list of points and define four walls. 

            for (int i = 0; i <= 3; i++)

            {

                // define a base curve from two points. 

                Line baseCurve = Line.CreateBound(pts[i], pts[i + 1]);

                // create a wall using the one of overloaded methods. 

                //Wall aWall = rvtDoc.Create.NewWall(baseCurve, level1, isStructural); // 2012

                Wall aWall = Wall.Create(rvtDoc, baseCurve, level1.Id, isStructural); // since 2013

                // set the Top Constraint to Level 2 

                aWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(level2.Id);

                // save the wall.

                walls.Add(aWall);

            }

            // This is important. we need these lines to have shrinkwrap working. 

            rvtDoc.Regenerate();

            rvtDoc.AutoJoinElements();


            return walls;


        }


        /// <summary>

        /// Add a door to the center of the given wall. 

        /// cf. Developer Guide p137. NewFamilyInstance() for Doors and Window. 

        /// </summary>


        public static void AddDoor(Document rvtDoc, Wall hostWall)

        {

            // Hard coding the door type we will use. 

            // e.g., "M_Single-Flush: 0915 x 2134mm 

            const string doorFamilyName = Util.Constant.DoorFamilyName;

            const string doorTypeName = Util.Constant.DoorTypeName;

            const string doorFamilyAndTypeName = doorFamilyName + ": " + doorTypeName;


            // Get the door type to use. 

            FamilySymbol doorType =

              ElementFiltering.FindFamilyType(

                rvtDoc, typeof(FamilySymbol), doorFamilyName, doorTypeName, BuiltInCategory.OST_Doors

              ) as FamilySymbol;

            if (doorType == null)

            {

                TaskDialog.Show(

                  "Add door", "Cannot find (" + doorFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte."

                );

            }


            // Get the start and end points of the wall. 

            LocationCurve locCurve = (LocationCurve)hostWall.Location;

            XYZ pt1 = locCurve.Curve.GetEndPoint(0);

            XYZ pt2 = locCurve.Curve.GetEndPoint(1);

            // Calculate the mid point. 

            XYZ pt = (pt1 + pt2) / 2.0;


            // One more thing - we want to set the reference as a bottom of the wall or level1. 

            ElementId idLevel1 = hostWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();

            //Level level1 = (Level)_doc.get_Element(idLevel1); // 2012

            Level level1 = rvtDoc.GetElement(idLevel1) as Level; // since 2013


            // Finally, create a door. 

            FamilyInstance aDoor = rvtDoc.Create.NewFamilyInstance(pt, doorType, hostWall, level1, StructuralType.NonStructural);


        }


        /// <summary>

        /// Add a window to the center of the wall given. 

        /// cf. Developer Guide p137. NewFamilyInstance() for Doors and Window. 

        /// Basically the same idea as a door except that we need to set sill hight. 

        /// </summary>


        public static void AddWindow(Document rvtDoc, Wall hostWall)

        {

            // Hard coding the window type we will use. 

            // e.g., "M_Fixed: 0915 x 1830mm 

            const string windowFamilyName = Util.Constant.WindowFamilyName;

            const string windowTypeName = Util.Constant.WindowTypeName;

            const string windowFamilyAndTypeName = windowFamilyName + ": " + windowTypeName;

            double sillHeight = Constant.MmToFeet(915);


            // Get the door type to use. 

            FamilySymbol windowType =

              ElementFiltering.FindFamilyType(

                rvtDoc, typeof(FamilySymbol), windowFamilyName, windowTypeName, BuiltInCategory.OST_Windows

              ) as FamilySymbol;

            if (windowType == null)

            {

                TaskDialog.Show(

                  "Add window", "Cannot find (" + windowFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte.");

            }


            // Get the start and end points of the wall. 

            LocationCurve locCurve = (LocationCurve)hostWall.Location;

            XYZ pt1 = locCurve.Curve.GetEndPoint(0);

            XYZ pt2 = locCurve.Curve.GetEndPoint(1);

            // Calculate the mid point. 

            XYZ pt = (pt1 + pt2) / 2.0;


            // One more thing - we want to set the reference as a bottom of the wall or level1. 

            ElementId idLevel1 = hostWall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();


            //Level level1 = (Level)_doc.get_Element(idLevel1); // 2012

            Level level1 = rvtDoc.GetElement(idLevel1) as Level; // since 2013


            // Finally create a window. 

            FamilyInstance aWindow = rvtDoc.Create.NewFamilyInstance(pt, windowType, hostWall, level1, StructuralType.NonStructural);


            aWindow.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).Set(sillHeight);


        }


        /// <summary>

        /// Add a roof over the rectangular profile of the walls we created earlier.

        /// </summary>


        public static void AddRoof(Document rvtDoc, List<Wall> walls)

        {

            // Hard coding the roof type we will use. 

            // e.g., "Basic Roof: Generic - 400mm"  

            const string roofFamilyName = "Basic Roof";

            const string roofTypeName = Util.Constant.RoofTypeName;

            const string roofFamilyAndTypeName = roofFamilyName + ": " + roofTypeName;


            // Find the roof type

            RoofType roofType =

              ElementFiltering.FindFamilyType(

                rvtDoc, typeof(RoofType), roofFamilyName, roofTypeName, null

              ) as RoofType;

            if (roofType == null)

            {

                TaskDialog.Show(

                  "Add roof", "Cannot find (" + roofFamilyAndTypeName +

                  "). Maybe you use a different template? Try with DefaultMetric.rte.");

            }


            // Wall thickness to adjust the footprint of the walls

            // to the outer most lines. 

            // Note: this may not be the best way. 

            // but we will live with this for this exercise. 

            //Dim wallThickness As Double = _

            //walls(0).WallType.CompoundStructure.Layers.Item(0).Thickness() ' 2011

            double wallThickness = walls[0].WallType.GetCompoundStructure().GetLayers()[0].Width;

            // 2012

            double dt = wallThickness / 2.0;

            List<XYZ> dts = new List<XYZ>(5);

            dts.Add(new XYZ(-dt, -dt, 0.0));

            dts.Add(new XYZ(dt, -dt, 0.0));

            dts.Add(new XYZ(dt, dt, 0.0));

            dts.Add(new XYZ(-dt, dt, 0.0));

            dts.Add(dts[0]);


            // Set the profile from four walls 

            CurveArray footPrint = new CurveArray();

            for (int i = 0; i <= 3; i++)

            {

                LocationCurve locCurve = (LocationCurve)walls[i].Location;

                XYZ pt1 = locCurve.Curve.GetEndPoint(0) + dts[i];

                XYZ pt2 = locCurve.Curve.GetEndPoint(1) + dts[i + 1];

                Line line = Line.CreateBound(pt1, pt2);

                footPrint.Append(line);

            }


            // Get the level2 from the wall

            ElementId idLevel2 = walls[0].get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();


            //Level level2 = (Level)_doc.get_Element(idLevel2); // 2012

            Level level2 = rvtDoc.GetElement(idLevel2) as Level; // since 2013


            // Footprint to morel curve mapping  

            ModelCurveArray mapping = new ModelCurveArray();


            // Create a roof.

            FootPrintRoof aRoof = rvtDoc.Create.NewFootPrintRoof(footPrint, level2, roofType, out mapping);


            //  Set the slope 

            foreach (ModelCurve modelCurve in mapping)

            {

                aRoof.set_DefinesSlope(modelCurve, true);

                aRoof.set_SlopeAngle(modelCurve, 0.5);

            }


            // Added. 

            rvtDoc.Regenerate();

            rvtDoc.AutoJoinElements();

        }

    }

}