Get wall openings

Get wall openings

Anonymous
Not applicable
7,894 Views
23 Replies
Message 1 of 24

Get wall openings

Anonymous
Not applicable

Hi!

 

I'm struggeling to get wall openings using the API. What i'm interested in is the coordinates of a rectangular wall opening (see pic).

I've tried FindInserts(), but it's not given that anything is inserted in the opening. 

 

Does anyone have a solution for this?

 

 

Thanks,

Eirik Aasved Holst

 

wallOpenings.jpg

0 Likes
Accepted solutions (1)
7,895 Views
23 Replies
Replies (23)
Message 21 of 24

Anonymous
Not applicable
Thank you Scott, I appreciate the contribution to this discussion and now I have two good solutions to choose from 🙂

Jeremy, thank you for your blog, it is a fantastic resource for beginners in the Revit API like myself.

I think I will stick with the ray shooting approach because of the obvious fact: rays are cool.

Cheers,
Eirik
0 Likes
Message 22 of 24

Anonymous
Not applicable

Another method is by find opening solid points:

 

Opening Solid = Original Wall Solid (without opening) - Current Wall Solid (with opening)

 

Rectangles below represent opening points:

 

OpeningPoints.png

 

            foreach (Element eWall in collWall) {
                Wall wall = eWall as Wall;

                IList<ElementId> ilstElemIdWallInsert = wall.FindInserts(true, true, true, true);
                if (ilstElemIdWallInsert.Count == 0)
                    continue;

                double dblWallWidth = wall.Width;
                BoundingBoxXYZ bbWall = eWall.get_BoundingBox(null);
                double dblWallMinZ = bbWall.Min.Z;
                double dblWallMaxZ = bbWall.Max.Z;
                double dblWallHeight = dblWallMaxZ - dblWallMinZ;

                LocationCurve loccurvWall = eWall.Location as LocationCurve;
                Curve curvLocWall = loccurvWall.Curve;

                if (curvLocWall is Arc) {

                    /* adjust wall location curve to wall bottom */
                    Arc arcLocCurvWall = null;
                    if (!DoubleValuesAreEqual(curvLocWall.GetEndPoint(0).Z, dblWallMinZ)) {
                        XYZ xyzLocCurvWallStart = new XYZ(curvLocWall.GetEndPoint(0).X, curvLocWall.GetEndPoint(0).Y, dblWallMinZ);
                        XYZ xyzLocCurvWallEnd = new XYZ(curvLocWall.GetEndPoint(1).X, curvLocWall.GetEndPoint(1).Y, dblWallMinZ);
                        XYZ xyzLocCurvWallMiddle = new XYZ(curvLocWall.Evaluate(0.5, true).X, curvLocWall.Evaluate(0.5, true).Y, dblWallMinZ);
                        arcLocCurvWall = Arc.Create(xyzLocCurvWallStart, xyzLocCurvWallEnd, xyzLocCurvWallMiddle);
                    }
                    else
                        arcLocCurvWall = curvLocWall as Arc;

                    XYZ xyzArcLocCurvWallCenter = arcLocCurvWall.Center;

                    Solid solidWallWithoutOpening = GetSolidArcWallWithoutOpening(arcLocCurvWall, xyzArcLocCurvWallCenter, dblWallWidth, dblWallHeight);
                    Solid solidWallWithOpening = GetElementSolid(eWall); 
                    /* get all opening including door and window as solid */
                    Solid solidAllOpening = BooleanOperationsUtils.ExecuteBooleanOperation(solidWallWithoutOpening, solidWallWithOpening, BooleanOperationsType.Difference);

                    foreach (ElementId elemid in ilstElemIdWallInsert) {
                        Element eWallInsert = doc.GetElement(elemid);

                        if (eWallInsert is Opening) {
                            BoundingBoxXYZ bb = eWallInsert.get_BoundingBox(null);
                            Solid solidBB = GetBoundingBoxSolid(bb);
                            Solid solidOpening = BooleanOperationsUtils.ExecuteBooleanOperation(solidBB, solidAllOpening, BooleanOperationsType.Intersect);
                            //DrawSolidLines(doc, solidOpening);
                            List<XYZ> lstXYZOpeningPoints = new List<XYZ>();
                            foreach (Face face in solidOpening.Faces) {
                                PlanarFace pf = face as PlanarFace;
                                if (pf != null) {
                                    if (pf.FaceNormal.Z < 0 || pf.FaceNormal.Z > 0) {   /* analyze top or bottom face only */
                                        foreach (EdgeArray edgeLoop in face.EdgeLoops) {
                                            foreach (Edge edge in edgeLoop) {
                                                Curve curv = edge.AsCurve();
                                                /**********************************************************/
                                                /* if face edge is line                                   */
                                                /* if line is horizontal and line length == wall width    */
                                                /* vectornorm1 = line vector                              */
                                                /* vectornorm2 = line from arch center to line start/end  */
                                                /* get middle point of line if vectornorm1 == vectornorm2 */
                                                /**********************************************************/
                                                if (curv is Line && DoubleValuesAreEqual(curv.GetEndPoint(0).Z, curv.GetEndPoint(1).Z) && DoubleValuesAreEqual(curv.Length, dblWallWidth)) {
                                                    XYZ xyzArcLocCurvWallCenterZAdjusted = new XYZ(xyzArcLocCurvWallCenter.X, xyzArcLocCurvWallCenter.Y, curv.GetEndPoint(0).Z);
                                                    XYZ xyzlineCurvNorm = Line.CreateBound(curv.GetEndPoint(0), curv.GetEndPoint(1)).Direction.Normalize();
                                                    XYZ xyzFromCenterNorm = Line.CreateBound(xyzArcLocCurvWallCenterZAdjusted, curv.GetEndPoint(0)).Direction.Normalize();
                                                    XYZ xyzFromCenterNormReverse = xyzFromCenterNorm.Negate();
                                                    if (PointsAreEqual(xyzlineCurvNorm, xyzFromCenterNorm) || PointsAreEqual(xyzlineCurvNorm, xyzFromCenterNormReverse))
                                                        lstXYZOpeningPoints.Add(new XYZ((curv.GetEndPoint(0).X + curv.GetEndPoint(1).X) / 2, (curv.GetEndPoint(0).Y + curv.GetEndPoint(1).Y) / 2, (curv.GetEndPoint(0).Z + curv.GetEndPoint(1).Z) / 2));
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            DrawVerticalPointsAsRectangle(doc, lstXYZOpeningPoints); /* draw rectangle just to show points */
                        }
                    }
                }
                if (curvLocWall is Line) {

                    /* adjust wall location curve to wall bottom */
                    Line lineLocCurvWall = null;
                    if (!DoubleValuesAreEqual(curvLocWall.GetEndPoint(0).Z, dblWallMinZ)) {
                        XYZ xyzLocCurvWallStart = new XYZ(curvLocWall.GetEndPoint(0).X, curvLocWall.GetEndPoint(0).Y, dblWallMinZ);
                        XYZ xyzLocCurvWallEnd = new XYZ(curvLocWall.GetEndPoint(1).X, curvLocWall.GetEndPoint(1).Y, dblWallMinZ);
                        lineLocCurvWall = Line.CreateBound(xyzLocCurvWallStart, xyzLocCurvWallEnd);
                    }
                    else
                        lineLocCurvWall = curvLocWall as Line;

                    XYZ xyzLineWallNorm = lineLocCurvWall.Direction.Normalize();
                    XYZ xyzLineWallNormCross = xyzLineWallNorm.CrossProduct(XYZ.BasisZ);
                    XYZ xyzLineWallNormCrossReverse = xyzLineWallNormCross.Negate();

                    Solid solidWallWithOpening = GetElementSolid(eWall);
                    Solid solidWallWithoutOpening = GetSolidWallWithoutOpening(lineLocCurvWall, xyzLineWallNormCross, xyzLineWallNormCrossReverse, dblWallWidth, dblWallHeight);
                    /* get all opening including door and window as solid */
                    Solid solidAllOpening = BooleanOperationsUtils.ExecuteBooleanOperation(solidWallWithoutOpening, solidWallWithOpening, BooleanOperationsType.Difference);

                    foreach (ElementId elemid in ilstElemIdWallInsert) {
                        Element eWallInsert = doc.GetElement(elemid);

                        if (eWallInsert is Opening) {
                            BoundingBoxXYZ bb = eWallInsert.get_BoundingBox(null);
                            Solid solidBB = GetBoundingBoxSolid(bb);
                            Solid solidOpening = BooleanOperationsUtils.ExecuteBooleanOperation(solidBB, solidAllOpening, BooleanOperationsType.Intersect);
                            List<XYZ> lstXYZOpeningPoints = new List<XYZ>();
                            foreach (Face face in solidOpening.Faces) {
                                PlanarFace pf = face as PlanarFace;
                                if (pf != null) {
                                    if (pf.FaceNormal.Z < 0 || pf.FaceNormal.Z > 0) {   /* analyze top or bottom face only */
                                        foreach (EdgeArray edgeLoop in face.EdgeLoops) {
                                            foreach (Edge edge in edgeLoop) {
                                                Curve curv = edge.AsCurve();
                                                Line line = Line.CreateBound(curv.GetEndPoint(0), curv.GetEndPoint(1));
                                                /*****************************************************************/
                                                /* if face edge line is horizontal and line length == wall width */
                                                /* if line vector = wall line cross product                      */
                                                /*****************************************************************/
                                                if (DoubleValuesAreEqual(line.GetEndPoint(0).Z, line.GetEndPoint(1).Z) && DoubleValuesAreEqual(line.Length, dblWallWidth)) { 
                                                    XYZ xyzLineDirNorm = line.Direction.Normalize();
                                                    if (PointsAreEqual(xyzLineDirNorm, xyzLineWallNormCross) || PointsAreEqual(xyzLineDirNorm, xyzLineWallNormCrossReverse)) {
                                                        lstXYZOpeningPoints.Add(new XYZ((line.GetEndPoint(0).X + line.GetEndPoint(1).X) / 2, (line.GetEndPoint(0).Y + line.GetEndPoint(1).Y) / 2, (line.GetEndPoint(0).Z + line.GetEndPoint(1).Z) / 2));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            DrawVerticalPointsAsRectangle(doc, lstXYZOpeningPoints); /* draw rectangle just to show points */
                        }
                    }
                }
            }
        private Solid GetSolidArcWallWithoutOpening(Arc arcLocCurvWall, XYZ xyzArcLocCurvWallCenter, double dblWallWidth, double dblWallHeight) {
            Line lineCrossStart = Line.CreateBound(xyzArcLocCurvWallCenter, arcLocCurvWall.GetEndPoint(0));
            XYZ xyzLineCrossStartNorm = lineCrossStart.Direction.Normalize();
            XYZ xyzLineCrossStartNormReverse = xyzLineCrossStartNorm.Negate();
            XYZ xyzInnerArcStart = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.GetEndPoint(0), xyzLineCrossStartNormReverse, dblWallWidth / 2);
            XYZ xyzOuterArcStart = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.GetEndPoint(0), xyzLineCrossStartNorm, dblWallWidth / 2);

            Line lineCrossMiddle = Line.CreateBound(xyzArcLocCurvWallCenter, arcLocCurvWall.Evaluate(0.5, true));
            XYZ xyzLineCrossMiddleNorm = lineCrossMiddle.Direction.Normalize();
            XYZ xyzLineCrossMiddleNormReverse = xyzLineCrossMiddleNorm.Negate();
            XYZ xyzInnerArcMiddle = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.Evaluate(0.5, true), xyzLineCrossMiddleNormReverse, dblWallWidth / 2);
            XYZ xyzOuterArcMiddle = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.Evaluate(0.5, true), xyzLineCrossMiddleNorm, dblWallWidth / 2);

            Line lineCrossEnd = Line.CreateBound(xyzArcLocCurvWallCenter, arcLocCurvWall.GetEndPoint(1));
            XYZ xyzLineCrossEndNorm = lineCrossEnd.Direction.Normalize();
            XYZ xyzLineCrossEndNormReverse = xyzLineCrossEndNorm.Negate();
            XYZ xyzInnerArcEnd = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.GetEndPoint(1), xyzLineCrossEndNormReverse, dblWallWidth / 2);
            XYZ xyzOuterArcEnd = GetEndPointBy_StartPoint_NormDir_Distance(arcLocCurvWall.GetEndPoint(1), xyzLineCrossEndNorm, dblWallWidth / 2);

            CurveLoop curveloop = new CurveLoop();
            curveloop.Append(Arc.Create(xyzInnerArcStart, xyzInnerArcEnd, xyzInnerArcMiddle) as Curve);
            curveloop.Append(Line.CreateBound(xyzInnerArcEnd, xyzOuterArcEnd) as Curve);
            curveloop.Append(Arc.Create(xyzOuterArcEnd, xyzOuterArcStart, xyzOuterArcMiddle) as Curve);
            curveloop.Append(Line.CreateBound(xyzOuterArcStart, xyzInnerArcStart) as Curve);

            List<CurveLoop> listcurveloop = new List<CurveLoop>();
            listcurveloop.Add(curveloop);
            Solid solidWallWithoutOpening = GeometryCreationUtilities.CreateExtrusionGeometry(listcurveloop, new XYZ(0, 0, 1), dblWallHeight);
            return solidWallWithoutOpening;
        }

        private Solid GetSolidWallWithoutOpening(Line lineWallLocation, XYZ xyzLineWallNormCross, XYZ xyzLineWallNormCrossReverse, double dblWallWidth, double dblWallHeight) {
            XYZ xyz1 = GetEndPointBy_StartPoint_NormDir_Distance(lineWallLocation.GetEndPoint(0), xyzLineWallNormCross, dblWallWidth / 2);
            XYZ xyz2 = GetEndPointBy_StartPoint_NormDir_Distance(lineWallLocation.GetEndPoint(1), xyzLineWallNormCross, dblWallWidth / 2);
            XYZ xyz3 = GetEndPointBy_StartPoint_NormDir_Distance(xyz2, xyzLineWallNormCrossReverse, dblWallWidth);
            XYZ xyz4 = GetEndPointBy_StartPoint_NormDir_Distance(xyz1, xyzLineWallNormCrossReverse, dblWallWidth);
            CurveLoop curveloop = new CurveLoop();
            curveloop.Append(Line.CreateBound(xyz1, xyz2) as Curve);
            curveloop.Append(Line.CreateBound(xyz2, xyz3) as Curve);
            curveloop.Append(Line.CreateBound(xyz3, xyz4) as Curve);
            curveloop.Append(Line.CreateBound(xyz4, xyz1) as Curve);
            List<CurveLoop> listcurveloop = new List<CurveLoop>();
            listcurveloop.Add(curveloop);
            Solid solidWallWithoutOpening = GeometryCreationUtilities.CreateExtrusionGeometry(listcurveloop, new XYZ(0, 0, 1), dblWallHeight);
            return solidWallWithoutOpening;
        }

        private Solid GetBoundingBoxSolid(BoundingBoxXYZ bb) {
            CurveLoop curveloop = new CurveLoop();
            XYZ xyz1 = new XYZ(bb.Min.X, bb.Min.Y, bb.Min.Z);
            XYZ xyz2 = new XYZ(bb.Max.X, bb.Min.Y, bb.Min.Z);
            XYZ xyz3 = new XYZ(bb.Max.X, bb.Max.Y, bb.Min.Z);
            XYZ xyz4 = new XYZ(bb.Min.X, bb.Max.Y, bb.Min.Z);
            Line line1 = Line.CreateBound(xyz1, xyz2);
            Line line2 = Line.CreateBound(xyz2, xyz3);
            Line line3 = Line.CreateBound(xyz3, xyz4);
            Line line4 = Line.CreateBound(xyz4, xyz1);
            curveloop.Append(line1);
            curveloop.Append(line2);
            curveloop.Append(line3);
            curveloop.Append(line4);
            List<CurveLoop> listcurveLoop = new List<CurveLoop>();
            listcurveLoop.Add(curveloop);
            Solid solidBB = GeometryCreationUtilities.CreateExtrusionGeometry(listcurveLoop, XYZ.BasisZ, bb.Max.Z - bb.Min.Z);
            return solidBB;
        }

        private void DrawVerticalPointsAsRectangle(Document doc,List<XYZ> lstXYZ) {
            lstXYZ = lstXYZ.OrderBy(p => p.Z).ToList();
            XYZ xyz1 = lstXYZ.ElementAt(0);
            XYZ xyz2 = lstXYZ.ElementAt(1);
            XYZ xyz3 = lstXYZ.ElementAt(2);
            XYZ xyz4 = lstXYZ.ElementAt(3);

            Line line1 = Line.CreateBound(xyz1, xyz2);
            Line line2;
            Line line3;
            Line line4;
            if (DoubleValuesAreEqual(xyz2.X, xyz3.X) && DoubleValuesAreEqual(xyz2.Y, xyz3.Y)) {
                line2 = Line.CreateBound(xyz2, xyz3);
                line3 = Line.CreateBound(xyz3, xyz4);
                line4 = Line.CreateBound(xyz4, xyz1);
            }
            else {
                line2 = Line.CreateBound(xyz2, xyz4);
                line3 = Line.CreateBound(xyz4, xyz3);
                line4 = Line.CreateBound(xyz3, xyz1);
            }
            DrawModelLine(doc,line1);
            DrawModelLine(doc,line2);
            DrawModelLine(doc,line3);
            DrawModelLine(doc,line4);
        }

        private XYZ GetEndPointBy_StartPoint_NormDir_Distance(XYZ xyzStart, XYZ xyzDirection, double dblDistance) {
            xyzDirection = xyzDirection / xyzDirection.GetLength();
            XYZ xyzEnd = xyzStart + dblDistance * xyzDirection;
            return xyzEnd;
        }
Message 23 of 24

markjvlampad
Advocate
Advocate

has this been tested for round opening? say windows or round profile?

0 Likes
Message 24 of 24

jeremytammik
Autodesk
Autodesk

Many different approaches for retrieving wall openings have been discussed by The Building Coder, and several have been successfully tested on arbitrary complex shapes:

 

https://www.google.com/search?q=wall+opening&as_sitesearch=thebuildingcoder.typepad.com

 

Please let us know what works for you, and what your final solution looks like.

 



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

0 Likes