A reader sent the image on the right and asked: “can we make door with specific distance to face of wall like 20 cm without every time need to adjust distance in temporary dimension ?”
This seemed like a good excuse to stop writing code dealing with Family Parameters (I was getting tired of writing it, were you getting tired of reading about it?).
publicvoid DoorWallOffset()
{
UIDocument uidoc = this.ActiveUIDocument;
Document doc = uidoc.Document;
// establish an offset of 20cm that will be applied to the door and wall// Revit's internal units for distance is feetdouble doorToWallDistance = 20 / (12 * 2.54); // convert 20 cm to 1 fttry// try/catch block with PickObject is used to give the user a way to get out of the infinite loop of while (true)// PickObject throws an exception when user aborts from selection
{
while (true)
{
FamilyInstance door = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element, "Select a door. ESC when finished.").ElementId) as FamilyInstance;
double doorWidth = door.Symbol.get_Parameter(BuiltInParameter.DOOR_WIDTH).AsDouble();
Wall sideWall = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element, "Select a wall. ESC when finished.").ElementId) as Wall;
double sideWallWidth = sideWall.Width;
// get the curve that defines the centerline of the side wall
LocationCurve sideWallLocationCurve = sideWall.Location as LocationCurve;
Curve sideWallCurve = sideWallLocationCurve.Curve;
// get the curve that defines the centerline of the wall that hosts the door
Wall hostWall = door.Host as Wall;
LocationCurve hostWallLocationCurve = hostWall.Location as LocationCurve;
Curve hostWallCurve = hostWallLocationCurve.Curve;
// find the point of intersection of these two wall curves (intersectionXYZ)// and the position of this point on the wall that hosts the door (intersectionParam)
IntersectionResultArray ira = new IntersectionResultArray();
SetComparisonResult scr = sideWallCurve.Intersect(hostWallCurve, out ira);
var iter = ira.GetEnumerator();
iter.MoveNext();
IntersectionResult ir = iter.Current as IntersectionResult;
XYZ intersectionXYZ = ir.XYZPoint;
double intersectionParam = hostWallCurve.Project(intersectionXYZ).Parameter;
// find the position of the door in its host wall
LocationPoint doorPoint = door.Location as LocationPoint;
XYZ doorXYZ = doorPoint.Point;
double doorParam = hostWallCurve.Project(doorXYZ).Parameter;
// compute the translation vector between the edge of the door closest to the wall and the side face of the wall
XYZ translation = null;
XYZ doorEdgeXYZ = null;
XYZ intersectionOffsetXYZ = null;
if (intersectionParam > doorParam)
{
intersectionOffsetXYZ = hostWallCurve.Evaluate(intersectionParam - doorToWallDistance - sideWallWidth/2, false);
doorEdgeXYZ = hostWallCurve.Evaluate(doorParam + doorWidth/2, false);
translation = intersectionOffsetXYZ.Subtract(doorEdgeXYZ);
}
else
{
intersectionOffsetXYZ = hostWallCurve.Evaluate(intersectionParam + doorToWallDistance + sideWallWidth/2, false);
doorEdgeXYZ = hostWallCurve.Evaluate(doorParam - doorWidth/2, false);
translation = doorEdgeXYZ.Subtract(intersectionOffsetXYZ).Negate();
}
// Move the doorusing (Transaction t = new Transaction(doc,"move door"))
{
t.Start();
ElementTransformUtils.MoveElement(doc,door.Id,translation);
t.Commit();
}
}
}
catch{}
}
People worry about this too early. In preliminary design the walls are not usually the correct (or final) thickness. We should just “agree we need a door here” in that stage of design. If we fuss with it “now”, we just end up adjusting the placement of doors again later, if we ever actually do revisit this. The “value” “we” use is also usually a minimum requirement or ideal value, big enough to allow for framing and trimming the door, particularly. I think a cooler tool would be one that adjust door positions relative to adjacent walls later, after the walls are the correct thickness, either by picking or just broadly all doors closer than “x” distance from the adjacent wall.
I’m not sure I understand the difference between this tool and a cooler one that could be used later after the walls are the correct thickness. In the video all the walls are the Generic 8″ type, but this tool works just as well with any wall types of any thickness.
Also, the concept of “adjacent wall” is trivial to us humans, but is fairly complicated to figure out with the API. That is why I went with this approach of having the user select each door and wall.
Harry On the view range API you wrote If you change the 3d section box of say the 1st floor it works great Then right click on the view cube and say orient to 1st floor the 3d section box has a zero height Dies the API change this? Any way to make it make view range as the developers intended? Thx Marcello
I don’t think I am seeing the problem. Maybe I am doing something different? The macro sets the Plan View’s view range as follows. – All four planes (top, cut, bottom, depth) are set to the plan view’s level – The view depth offset is set to the height of the bottom of the section box. – The offsets for the other 3 planes are all set to the top of the section box The result should be no different than what you would get from setting these manually with the UI.
// Set all planes of the view range to use the plan view’s level viewRange.SetLevelId(PlanViewPlane.TopClipPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.CutPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.BottomClipPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.ViewDepthPlane, level.Id);
// Set the view depth offset to the difference between the bottom of the section box and // the elevation of the level viewRange.SetOffset(PlanViewPlane.ViewDepthPlane, minZ – level.Elevation );
// Set all other offsets to to the difference between the top of the section box and // the elevation of the level viewRange.SetOffset(PlanViewPlane.TopClipPlane, maxZ – level.Elevation); viewRange.SetOffset(PlanViewPlane.CutPlane, maxZ – level.Elevation); viewRange.SetOffset(PlanViewPlane.BottomClipPlane, maxZ – level. Elevation);
People worry about this too early. In preliminary design the walls are not usually the correct (or final) thickness. We should just “agree we need a door here” in that stage of design. If we fuss with it “now”, we just end up adjusting the placement of doors again later, if we ever actually do revisit this. The “value” “we” use is also usually a minimum requirement or ideal value, big enough to allow for framing and trimming the door, particularly. I think a cooler tool would be one that adjust door positions relative to adjacent walls later, after the walls are the correct thickness, either by picking or just broadly all doors closer than “x” distance from the adjacent wall.
Comment by steve — February 6, 2013 @ 5:07 pm
Hi Steve,
I’m not sure I understand the difference between this tool and a cooler one that could be used later after the walls are the correct thickness. In the video all the walls are the Generic 8″ type, but this tool works just as well with any wall types of any thickness.
Also, the concept of “adjacent wall” is trivial to us humans, but is fairly complicated to figure out with the API. That is why I went with this approach of having the user select each door and wall.
Regards,
Harry
Comment by harrymattison — February 6, 2013 @ 5:15 pm
beautiful!
Comment by David — February 6, 2013 @ 5:54 pm
Harry On the view range API you wrote If you change the 3d section box of say the 1st floor it works great Then right click on the view cube and say orient to 1st floor the 3d section box has a zero height Dies the API change this? Any way to make it make view range as the developers intended? Thx Marcello
Sent from my iPhone
Comment by M S — February 7, 2013 @ 11:32 am
I don’t think I am seeing the problem. Maybe I am doing something different? The macro sets the Plan View’s view range as follows. – All four planes (top, cut, bottom, depth) are set to the plan view’s level – The view depth offset is set to the height of the bottom of the section box. – The offsets for the other 3 planes are all set to the top of the section box The result should be no different than what you would get from setting these manually with the UI.
// Set all planes of the view range to use the plan view’s level viewRange.SetLevelId(PlanViewPlane.TopClipPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.CutPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.BottomClipPlane, level.Id); viewRange.SetLevelId(PlanViewPlane.ViewDepthPlane, level.Id);
// Set the view depth offset to the difference between the bottom of the section box and // the elevation of the level viewRange.SetOffset(PlanViewPlane.ViewDepthPlane, minZ – level.Elevation );
// Set all other offsets to to the difference between the top of the section box and // the elevation of the level viewRange.SetOffset(PlanViewPlane.TopClipPlane, maxZ – level.Elevation); viewRange.SetOffset(PlanViewPlane.CutPlane, maxZ – level.Elevation); viewRange.SetOffset(PlanViewPlane.BottomClipPlane, maxZ – level. Elevation);
Regards, Harry http://boostyourbim.wordpress.com https://twitter.com/BoostYourBIM https://www.facebook.com/BoostYourBim
Comment by harrymattison — February 9, 2013 @ 9:11 am
Harry Some people have asked me when you plan to put up the analytical adjustment app on the App Store ? Thx Marcello
Sent from my iPhone
Comment by M S — February 8, 2013 @ 1:15 pm
I submitted it to Autodesk a while back. Hopefully it will be published next week.
Comment by harrymattison — February 8, 2013 @ 1:39 pm
What need to be changed in this to center the door between two walls?
Comment by Korey — February 18, 2013 @ 9:57 pm