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:

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;
}