Dimension between walls corners using Revit's API

Dimension between walls corners using Revit's API

Anonymous
Not applicable
6,437 Views
27 Replies
Message 1 of 28

Dimension between walls corners using Revit's API

Anonymous
Not applicable

Hi,

 

When you're using Revit's Dimension Tool you can hit tab several times to switch between things to select. One of the options looks like it's the corner of the wall:

End.png

Corner.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

My question is: How do I get these apparent "Intersection of [..." via the API as References? I want to generate a dimension between them with code.

 

 

They don't seem to actually be intersections. The first one doesn't intersect with anything but itself.

 

Any information, including what these dots actually are, would be appreciated!

0 Likes
Accepted solutions (1)
6,438 Views
27 Replies
Replies (27)
Message 21 of 28

dylanj
Contributor
Contributor

@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)

 

Panel.JPG

 

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

 

0 Likes
Message 22 of 28

jeremytammik
Autodesk
Autodesk

Not being a computer myself, I cannot read the code just with my eyes... I would need to step through in the debugger.

 

I am pretty sure that the door and window openings can be included in the dimension strip as well, either by raytracing or geometric analysis of the faces of the wall solid with holes.

 

Would you like to provide a minimal reproducible sample case with a simple minimal model, maybe of a wall with a couple of openings and other features of interest, for people to look, see whether they can solve the complete dimensioning challenge, bite their teeth out on?

 

Cheers,

 

Jeremy

 



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

0 Likes
Message 23 of 28

jeremytammik
Autodesk
Autodesk

Dear @dylanj,

 

Looking at your panel image lacking dimensioning to the door and window edges, I wonder...

 

Couldn't you simply retrieve the wall geometry and determine all vertical faces perpendicular to the wall location line?

 

That should include the right and left hand sides of each opening, shouldn't it?

 

Cheers,

 

Jeremy

 



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

0 Likes
Message 24 of 28

Anonymous
Not applicable
The issue you may face with that is, depending on the LOD of the wall geometry, you may find you have too many dimensions.

If the wall has layers, the end of each layer is a separate face which will be dimensioned to. Likewise, if the window cuts anything more complex than a cube out of the wall, it'll also dimension several places you may not have been expecting.

I had a filter that deleted dimensions with a length of zero from the model as they were made by my program.

Message 25 of 28

jeremytammik
Autodesk
Autodesk

Yup, I can imagine that lots of filtering is needed, and elimination of all distances below a certain threshold.

 

How about providing a sample model to test on, with a description of the exact requirements?

 

Cheers,

 

Jeremy

 



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

0 Likes
Message 26 of 28

dylanj
Contributor
Contributor

@Anonymous@jeremytammik

 

Thomas, I think you may have hit the nail on the head. The wall has three layers and i therefore have a lot more geometry than I originally thought. My openings are always rectangular.

 

I need this amount of detail and dimensions as I am attempting to produce shop drawings. The panels get built from these drawings. The model is usually detailed to LOD 300, but our embeds are to an LOD 350. A second sheet also gets produced for all the structural reinforcement. Here is a simple model of which the image in my previous post is produced from: https://autode.sk/2UjWTnR

 

It will take some work to put together a stripped down version of my add-on, but i may be able to do so over the Christmas holidays if you guys are interested.

 

Edit:

Exact Requirement: 

The wall needs to be constructed off this one drawings. (Tilt-Up Construction)

     • All opening widths/heights & Location on panel.

     • All center of embeds need dimensions for placement, based on the edge of the panel.

 

Edit 2:

@jeremytammik

 

I also considered adding dimensions based on all edges that are perpendicular to panel edges, but i ran into problems as some of my embeds also cut the panel resulting in many false references. I tried filtering by surface area, but i do have instances where opening can be smaller than embeds. In order to come up with a fool-proof solution, I scrapped this idea all together.

 

0 Likes
Message 27 of 28

jeremytammik
Autodesk
Autodesk

Dear Dylan,

 

Thank you for the edited requirement and sample model.

 

I'm interested  🙂

 

Cheers,

 

Jeremy

 



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

0 Likes
Message 28 of 28

matias_m1912
Explorer
Explorer

Hi @dylanj , I'm working in a similar code. I want know if you can share where you declared the "transform".

I will appreciate.

Best regards!  

0 Likes