By Augusto Goncalves
Here is a collection of lessons learned during this plug-in development. You can see all of that in action with the source code available at Autodesk Labs.
Intersection points between walls
Both Chamfer and Fillet uses a key method for this plug-in: Curve.Intersect. Basically, for a given wall, the command must access its underlying geometry, a curve (e.g. line), and through the Intersect method find the intersection point with another curve. It is very important to notice that LineSegment objects (i.e. finite lines) usually do not intersect each other, so it’s required to use the method Curve.MakeUnbound to create a Line object (i.e. infinite line). Note that this plug-in was designed to work on linear walls with one intersection point between them.
Organize the underlying geometry to if necessary create the third wall with the correct orientation
After access the curves of both walls (e.g. LineSegments), the command store XYZ directional vectors for both walls. All calculations are performed with vectors, which is more consistent. Notice that walls are created following that orientation, which affects the internal/external sides, which ultimately affects hosted elements (e.g. doors, windows).
Chamfer
As a chamfered intersection of walls consist in resizing two walls from its (projected) intersection point, this PIOTM created XYZ vectors from the intersection point to the closest point on the wall, which is used to find the next end point of the walls. Once resized, the new wall is created connecting them.
Fillet
This was the changeling one. To create a fillet with a previously defined radius, the command must calculate the deflection angle formed between the walls. This deflection angle is important because is used to obtain the tangent distance T in the image below. This external tangent length represents the necessary distance between the intersection point and the end point of the selected walls, used to create a curve with the desired radius.
Image adapted from Civil Engineering Terms blog
To find the deflection angle, the command creates two concurrent XYZ vectors, from the farthest point of the walls to the intersection point, and then the Vector.AngleTo method gets the deflection angle. On important trick: the AngleTo method considers the vector orientation and, inside Revit API, is always counterclockwise, that’s why this plug-in recreates the concurrent vectors, which obeys the image above.
Resizing connects/joined walls
Revit does not accept changes on walls curves when the wall end is connected to another wall, so the trick here was call WallUtils.IsWallJoinAllowedAtEnd to check if that end was connected, then, if required, disconnect with a call to WallUtils.DisallowWallJoinAtEnd, followed by a call to connect them back with WallUtils.AllowWallJoinAtEnd.