@jeremytammik
I was able to dimensions to openings by using the following block of code, however i was never able to create a stable and reliable function to dimensions to "Rectangular Straight wall Openings" "Windows" and "Doors"
Here are my functions (sections that are commented out aren't working)
public void CollectEmbedsAndOpenings()
{
//BoundingBoxIsInsideFilter bbfilter = new BoundingBoxIsInsideFilter(Outline);
FilteredElementCollector collector = new FilteredElementCollector(document, EmbedView.Id);
//collects all elements in the bounding box filter
//collector.WherePasses(bbfilter);
Embeds = new List<Embed>();
NFEmbeds = new List<Embed>();
FFEmbeds = new List<Embed>();
Openings = new List<Opening>();
foreach (Element ele in collector)
{
if(ele.Name.StartsWith("EM"))
{
Embed embed = new Embed(ele);
Embeds.Add(embed);
if (transform.Inverse.OfPoint(embed.LocationPoint.Point).Z < 0)
{
embed.NearFace = true;
}
else
{
embed.NearFace = false;
};
if(embed.NearFace == true)
{
NFEmbeds.Add(embed);
}else
{
FFEmbeds.Add(embed);
}
}
if (ele.Name == "Rectangular Straight Wall Opening")
{
Opening opening = new Opening(ele);
//non visible elements needs to be turned on to access data from openings
Options opt = new Options();
opt.IncludeNonVisibleObjects = true;
opt.ComputeReferences = true;
GeometryElement geomElem = ele.get_Geometry(opt);
foreach (GeometryObject geomObj in geomElem)
{
Solid geomSolid = geomObj as Solid;
if (null != geomSolid)
{
List<PlanarFace> faces = new List<PlanarFace>();
foreach (PlanarFace geomPFace in geomSolid.Faces)
{
faces.Add(geomPFace);
}
List<PlanarFace> HorizontalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal, transform.BasisX))
.OrderBy(x => transform.Inverse.OfPoint(x.Origin).X).ToList();
List<PlanarFace> VerticalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal, transform.BasisY))
.OrderBy(x => transform.Inverse.OfPoint(x.Origin).Y).ToList();
//Left Reference
opening.LeftReference = HorizontalFaces.Last().Reference;
//Right Reference
//Creator.CreateModelLine(document, transform.Origin, HorizontalFaces.Last().Origin);
opening.RightReference = HorizontalFaces.First().Reference;
//Bottom Reference
//Creator.CreateModelLine(document, transform.Origin, VerticalFaces.First().Origin);
opening.BottomReference = VerticalFaces.First().Reference;
//Top Reference
//Creator.CreateModelLine(document, transform.Origin, VerticalFaces.Last().Origin);
opening.TopReference = VerticalFaces.Last().Reference;
opening.BottomLeftPoint = new XYZ(HorizontalFaces.Last().Origin.X, HorizontalFaces.Last().Origin.Y, VerticalFaces.First().Origin.Z);
}
}
Openings.Add(opening);
}
//if (ele.Category.Equals(BuiltInCategory.OST_Doors))
//{
// Opening opening = new Opening();
// opening.centerPoint = ele.Location as LocationPoint;
// opening.height = ele.get_Parameter(BuiltInParameter.DOOR_HEIGHT).AsDouble();
// opening.boundingBox = element.get_BoundingBox(view3d);
// //non visible elements needs to be turned on to access data from openings
// Options opt = new Options();
// opt.IncludeNonVisibleObjects = true;
// opt.ComputeReferences = true;
// GeometryElement geomElem = ele.get_Geometry(opt);
// foreach (GeometryObject geomObj in geomElem)
// {
// Solid geomSolid = geomObj as Solid;
// if (null != geomSolid)
// {
// List<PlanarFace> faces = new List<PlanarFace>();
// foreach (PlanarFace geomPFace in geomSolid.Faces)
// {
// faces.Add(geomPFace);
// }
// List<PlanarFace> HorizontalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal, transform.BasisX))
// .OrderBy(x => transform.Inverse.OfPoint(x.Origin).X).ToList();
// List<PlanarFace> VerticalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal, transform.BasisY))
// .OrderBy(x => transform.Inverse.OfPoint(x.Origin).Y).ToList();
// //Left Reference
// opening.leftReference = HorizontalFaces.Last().Reference;
// //Right Reference
// //Creator.CreateModelLine(document, transform.Origin, HorizontalFaces.Last().Origin);
// opening.rightReference = HorizontalFaces.First().Reference;
// //Bottom Reference
// //Creator.CreateModelLine(document, transform.Origin, VerticalFaces.First().Origin);
// opening.bottomReference = VerticalFaces.First().Reference;
// //Top Reference
// //Creator.CreateModelLine(document, transform.Origin, VerticalFaces.Last().Origin);
// opening.topReference = VerticalFaces.Last().Reference;
// opening.bottomLeftPoint = new XYZ(HorizontalFaces.Last().Origin.X, HorizontalFaces.Last().Origin.Y, VerticalFaces.First().Origin.Z);
// }
// }
// Openings.Add(opening);
//}
}
}
public void GetWallReferences()
{
Options opt = new Options();
opt.IncludeNonVisibleObjects = false;
opt.ComputeReferences = true;
opt.DetailLevel = ViewDetailLevel.Fine;
GeometryElement geomElem = wall.get_Geometry(opt);
foreach (GeometryObject geomObj in geomElem)
{
Solid geomSolid = geomObj as Solid;
if (null != geomSolid)
{
List<PlanarFace> faces = new List<PlanarFace>();
foreach (PlanarFace geomPFace in geomSolid.Faces)
{
faces.Add(geomPFace);
}
List<PlanarFace> HorizontalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal,transform.BasisX))
.OrderBy(x => transform.Inverse.OfPoint(x.Origin).X).ToList();
List<PlanarFace> VerticalFaces = faces.Where(x => Util.IsParallel(x.FaceNormal, transform.BasisY))
.OrderBy(x => transform.Inverse.OfPoint(x.Origin).Y).ToList();
//Left Reference
wallLeftReference = HorizontalFaces.Last().Reference;
//Right Reference
//Creator.CreateModelLine(document, transform.Origin, HorizontalFaces.Last().Origin);
wallRightReference = HorizontalFaces.First().Reference;
//Bottom Reference
//Creator.CreateModelLine(document, transform.Origin, VerticalFaces.First().Origin);
wallBottomReference = VerticalFaces.First().Reference;
//Top Reference
//Creator.CreateModelLine(document, transform.Origin, VerticalFaces.Last().Origin);
wallTopReference = VerticalFaces.Last().Reference;
}
}
}
I also tries Ray casting.
/// <summary>
/// Casts a ray and finds all the openings in the panel that it collides with. (Not Currently Used)
/// </summary>
/// <param name="wall"></param>
/// <param name="view"></param>
/// <param name="vertical"></param>
/// <param name="offset"></param>
/// <param name="start"></param>
/// <returns></returns>
private List<Reference> GetWallReferences(Wall wall, View3D view, bool vertical, bool start)
{
UV offsetOutHorizontal = new UV();
UV offsetOutVertical1 = new UV();
UV offsetOutVertical2 = new UV();
IList<ReferenceWithContext> refs = null;
ReferenceIntersector intersector = new ReferenceIntersector(wall.Id, FindReferenceTarget.Face, view);
if (vertical == false)
{
offsetOutHorizontal = _buffer * new UV(wallDirection.X, wallDirection.Y);
XYZ rayStartHorizontal = new XYZ(wallStartPoint.X - offsetOutHorizontal.U, wallStartPoint.Y - offsetOutHorizontal.V, elevation + _buffer);
refs = intersector.Find(rayStartHorizontal, wallDirection);
//Creator.CreateModelLine(document, rayStartHorizontal, rayStartHorizontal + wallLength * wallDirection);
}
else if (vertical == true & start == true)
{
offsetOutVertical1 = _buffer * new UV(wallDirection.X, wallDirection.Y);
XYZ rayStartVertical1 = new XYZ(wallStartPoint.X + offsetOutVertical1.U, wallStartPoint.Y + offsetOutVertical1.V, elevation - _buffer);
refs = intersector.Find(rayStartVertical1, wallDirectionVertical);
//Creator.CreateModelLine(document, rayStartVertical1, rayStartVertical1 + wallHeight * wallDirectionVertical);
}
else if (vertical == true & start == false)
{
offsetOutVertical2 = _buffer * new UV(wallDirection.X, wallDirection.Y);
XYZ rayStartVertical2 = new XYZ(wallEndPoint.X - offsetOutVertical2.U, wallEndPoint.Y - offsetOutVertical2.V, elevation - _buffer);
refs = intersector.Find(rayStartVertical2, wallDirectionVertical);
//Creator.CreateModelLine(document, rayStartVertical2, rayStartVertical2 + wallHeight * wallDirectionVertical);
}
if (vertical == true)
{
List<Reference> faceReferenceList = new List<Reference>(refs
.Where<ReferenceWithContext>(r => HelperClass.IsSurface(
r.GetReference()))
.Where<ReferenceWithContext>(r => r.Proximity
< wallHeight + 2 * _buffer)
.Select<ReferenceWithContext, Reference>(r
=> r.GetReference()));
return faceReferenceList;
}
else
{
List<Reference> faceReferenceList = new List<Reference>(refs
.Where<ReferenceWithContext>(r => HelperClass.IsSurface(
r.GetReference()))
.Where<ReferenceWithContext>(r => r.Proximity
< wallLength + _buffer + _buffer)
.Select<ReferenceWithContext, Reference>(r
=> r.GetReference()));
return faceReferenceList;
}
}
my opening class:
public class Opening
{
public Element Element { get; set; }
public LocationPoint CenterPoint { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public Reference LeftReference { get; set; }
public Reference RightReference { get; set; }
public Reference TopReference { get; set; }
public Reference BottomReference { get; set; }
public XYZ BottomLeftPoint { get; set; }
public Opening(Element Element)
{
this.Element = Element;
this.CenterPoint = Element.Location as LocationPoint;
this.Height = Element.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
}
}
Here is what the addon currently produces (notice no dimension to the door or window created opening)

Edit:
Here is how i use the references in my dimension class:
if (dimloc == DimLocation.OPENINGVERTICAL)
{
if (Openings.Count > 0)
{
refs.Append(wallBottomReference);
refs.Append(wallTopReference);
foreach (Opening op in Openings)
{
if (transform.Inverse.OfPoint(op.BottomLeftPoint).Y > Util._eps)
{
refs.Append(op.BottomReference);
}
refs.Append(op.TopReference);
}
XYZ dimStart = transform.OfPoint(new XYZ(wallLength / 2 + offset, 0, 0));
XYZ dimEnd = transform.OfPoint(new XYZ(wallLength / 2 + offset, wallHeight, 0));
dimensionLine = Line.CreateBound(dimStart, dimEnd);
Dimension dim = document.Create.NewDimension(EmbedView, dimensionLine, refs);
}
}