Creating Floors from Project Rooms' Boundaries

Creating Floors from Project Rooms' Boundaries

amrshaalan
Participant Participant
1,865 Views
1 Reply
Message 1 of 2

Creating Floors from Project Rooms' Boundaries

amrshaalan
Participant
Participant

Hello Smiley Happy ,

My name is Amr from Cairo, Egypt. I'm an Architecture Student at the Bachelor's Final Year and I'm an Autodesk Revit User.

Currently I'm working on a series of AddIns to the Revit API to Automate some Processes trying to cut down the time and effort required to accomplish my work and this is my first participation here, I'm posting here after 10 hrs trying to solve the problem by myself in many ways, so I'm hoping that I can find the answer here by the experts.

 

I'm currently working on a plugin that creates all project floors by iterating through all rooms defined in the project and use their boundaries as profiles for the newly generated floors, but it keeps giving me the error in the msg as shown in the image, I attached the MainProgramCode.cs, any help is really appreciated

 

Thanks and Kind Regards Smiley Happy ,

Amr,

Error Message 

 

 

namespace GenerateFloorByRoom
{
    public class FloorData
    {
        List<Room> projectRooms = new List<Room>();   // a list to store all rooms in the project

        private Hashtable floorTypes;
        private List<string> floorTypesName;
        private FloorType floorType;
        private Level level;
        private CurveArray profile;
        private bool structural;
        private const double PRECISION = 0.00000001;
        private Autodesk.Revit.Creation.Application creApp;
        private Document document;

        // a floor type to be used by the new floor instead of the default type
        public FloorType FloorType
        {
            get
            {
                return floorType;
            }
            set
            {
                floorType = value;
            }
        }

        // the Level on which the floors are to be placed
        public Level Level
        {
            get
            {
                return level;
            }
            set
            {
                level = value;
            }
        }

        // an array of planar lines and arcs that represent the horizontal profile of the floor
        public CurveArray Profile
        {
            get
            {
                return profile;
            }
            set
            {
                profile = value;
            }
        }

        // determine wether the floor is structural
        public bool Structural
        {
            get
            {
                return structural;
            }
            set
            {
                structural = value;
            }
        }

        // a list of all Floor Types Name that could be used by the new Floor
        public List<string> FloorTypesName
        {
            get
            {
                return floorTypesName;
            }
            set
            {
                floorTypesName = value;
            }
        }

        public List<Room> GetAllRooms()
        {
            // get the Active Document
            document =Command.uiApp.ActiveUIDocument.Document;
            RoomFilter roomFilter = new RoomFilter();

            FilteredElementIdIterator roomIter =
                (new FilteredElementCollector(document)).WherePasses(roomFilter).GetElementIdIterator();
            roomIter.Reset();

            // try to find all the Rooms in the Project and add it to the List
            while (roomIter.MoveNext())
            {
                object obj = roomIter.Current;

                // find all Rooms on Condition IsLocatedOnLevel
                Room tmpRoom = obj as Room;
                if (null != tmpRoom && null != document.GetElement(tmpRoom.LevelId))
                {
                    projectRooms.Add(tmpRoom);
                    continue;
                }
            }
            return projectRooms;
        }

        // obtain all Data which is necessary for floor generation
        public void ObtainData(ExternalCommandData commandData)
        {
            if (null == commandData)
            {
                throw new ArgumentNullException("commandData");
            }

            UIDocument doc = commandData.Application.ActiveUIDocument;
            document = doc.Document;
            List<Room> rl = new List<Room>(GetAllRooms());
            
            creApp = commandData.Application.Application.Create;
            Profile = creApp.NewCurveArray();

            FilteredElementIterator iter = (new FilteredElementCollector(doc.Document)).OfClass(typeof(FloorType)).GetElementIterator();
            ObtainFloorTypes(iter);
            foreach (Element elem in rl)
            {
                Transaction tran = new Transaction(document, "ElementBatchCreation");
                tran.Start();

                ObtainProfile(rl);
                ObtainLevel(rl);
                document.Regenerate();
                tran.Commit();
            }
            Structural = true;
        }

        // obtain all types that are avilable for floor types in the current document
        private void ObtainFloorTypes(FilteredElementIterator elements)
        {
            floorTypes = new Hashtable();
            FloorTypesName = new List<string>();

            elements.Reset();
            while (elements.MoveNext())
            {
                Autodesk.Revit.DB.FloorType ft = elements.Current as Autodesk.Revit.DB.FloorType;

                if (null == ft || null == ft.Category || !ft.Category.Name.Equals("Floors"))
                {
                    continue;
                }

                floorTypes.Add(ft.Name, ft);
                FloorTypesName.Add(ft.Name);
                FloorType = ft;
            }
        }

        public void ChooseFloorType(string typeName)
        {
            FloorType = floorTypes[typeName] as FloorType;
        }

        private void ObtainLevel(List<Room> rooms)
        {
            Autodesk.Revit.DB.Level temp = null;
            foreach (Room r in rooms)
            {
                if (null == temp)
                {
                    temp = document.GetElement(r.LevelId) as Level;
                    Level = temp;
                }
            }
        }

        // obtain floor profile from each room's boundary
        private void ObtainProfile(List<Room> rooms)
        {
            foreach (Room r in rooms)
            {
                Level l = (r.Level);
                SketchPlane.Create(document, l.LevelId);
                SpatialElementBoundaryOptions bo = new SpatialElementBoundaryOptions();
                IList<IList<BoundarySegment>> segments = r.GetBoundarySegments(bo);
                if (null != segments)  // the Room may not be bound
                {
                    foreach (IList<Autodesk.Revit.DB.BoundarySegment> segmentList in segments)
                    {
                        CurveArray temp = new CurveArray();
                        foreach (Autodesk.Revit.DB.BoundarySegment boundarySegment in segmentList)
                        {
                            Curve c = boundarySegment.GetCurve();
                            temp.Append(c); 
                        }
                        SortCurves(temp);
                    }
                }
            }
        }
        private void SortCurves(CurveArray lines)
        {
            Autodesk.Revit.DB.XYZ temp = lines.get_Item(0).GetEndPoint(1);
            Curve temCurve = lines.get_Item(0);

            Profile.Append(temCurve);

            while (Profile.Size != lines.Size)
            {

                temCurve = GetNext(lines, temp, temCurve);

                if (Math.Abs(temp.X - temCurve.GetEndPoint(0).X) < PRECISION
                    && Math.Abs(temp.Y - temCurve.GetEndPoint(0).Y) < PRECISION)
                {
                    temp = temCurve.GetEndPoint(1);
                }
                else
                {
                    temp = temCurve.GetEndPoint(0);
                }

                Profile.Append(temCurve);
            }
        }
        private Curve GetNext(CurveArray profile, Autodesk.Revit.DB.XYZ connected, Curve line)
        {
            foreach (Curve c in profile)
            {
                if (c.Equals(line))
                {
                    continue;
                }
                if ((Math.Abs(c.GetEndPoint(0).X - line.GetEndPoint(1).X) < PRECISION && Math.Abs(c.GetEndPoint(0).Y - line.GetEndPoint(1).Y) < PRECISION && Math.Abs(c.GetEndPoint(0).Z - line.GetEndPoint(1).Z) < PRECISION)
                    && (Math.Abs(c.GetEndPoint(1).X - line.GetEndPoint(0).X) < PRECISION && Math.Abs(c.GetEndPoint(1).Y - line.GetEndPoint(0).Y) < PRECISION && Math.Abs(c.GetEndPoint(1).Z - line.GetEndPoint(0).Z) < PRECISION)
                    && 2 != profile.Size)
                {
                    continue;
                }

                if (Math.Abs(c.GetEndPoint(0).X - connected.X) < PRECISION && Math.Abs(c.GetEndPoint(0).Y - connected.Y) < PRECISION && Math.Abs(c.GetEndPoint(0).Z - connected.Z) < PRECISION)
                {
                    return c;
                }
                else if (Math.Abs(c.GetEndPoint(1).X - connected.X) < PRECISION && Math.Abs(c.GetEndPoint(1).Y - connected.Y) < PRECISION && Math.Abs(c.GetEndPoint(1).Z - connected.Z) < PRECISION)
                {
                    if (c.GetType().Name.Equals("Line"))
                    {
                        Autodesk.Revit.DB.XYZ start = c.GetEndPoint(1);
                        Autodesk.Revit.DB.XYZ end = c.GetEndPoint(0);
                        return Line.CreateBound(start, end);
                    }
                    else if (c.GetType().Name.Equals("Arc"))
                    {
                        int size = c.Tessellate().Count;
                        Autodesk.Revit.DB.XYZ start = c.Tessellate()[0];
                        Autodesk.Revit.DB.XYZ middle = c.Tessellate()[size / 2];
                        Autodesk.Revit.DB.XYZ end = c.Tessellate()[size];

                        return Arc.Create(start, end, middle);
                    }
                }
            }
            throw new InvalidOperationException("The Room Boundary should be closed.");
        }
        
    }
}

 

0 Likes
Accepted solutions (1)
1,866 Views
1 Reply
Reply (1)
Message 2 of 2

jeremytammik
Autodesk
Autodesk
Accepted solution

Dear Amr,

 

The error message clearly states that Revit cannot compute a plane from the curve array that you provide.

 

Are you sure the curve array is planar?

 

To make sure that you know what you are doing, you can draw model curves from your curve array first, instead of feeding them into further processing.

 

Then you can look at them and maybe see the problem.

 

Here is a really old discussion of debugging form creation that still applies:

 

http://thebuildingcoder.typepad.com/blog/2009/07/debug-geometric-form-creation.html

 

Also, to ensure that the curves really do define a plane, you can project them onto the desired plane; here is an still older post on that:

 

http://thebuildingcoder.typepad.com/blog/2008/12/polygon-transformation.html

 

There are several other posts on The Building Coder that successfully do create rooms.

 

So do the Revit SDK samples ElementsBatchCreation and RoomSchedule.

 

Cheers,

 

Jeremy

 

 

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder