Hi,
we have a plugin, that should adjust walls lines slightly (move them, rotate them a bit and also should adjust the length of the walls a bit).
With wall.Location.Move( xyzTranalation ) and wall.Location.Rotate(...) we could adjust the location and rotation of the walls, but not the length of the walls. So we decided to follow the approach, that is suggested on buildingcoder 10years ago:
https://thebuildingcoder.typepad.com/blog/2010/08/edit-wall-length.html
// get the current wall location LocationCurve wallLocation = myWall.Location as LocationCurve; // get the points XYZ pt1 = wallLocation.Curve.get_EndPoint( 0 ); XYZ pt2 = wallLocation.Curve.get_EndPoint( 1 ); // change one point, e.g. move 1000 mm on X axis pt2 = pt2.Add( new XYZ( 0.01 ), 0, 0 ) ); // create a new LineBound Line newWallLine = app.Create.NewLineBound( pt1, pt2 ); // update the wall curve wallLocation.Curve = newWallLine;
This seems to work fine for single walls. But fails in many cases the wall have hosted elements like windows and even in complex scenarios with multiple walls (Note: the movement is just very less about some mm!)
To show you, what I mean, I wrote a short macro embedded in the rvt that is attached.
The macro "LocationLineReset" just moves the wall inside the rvt by approx. 3mm using the suggested method from buildingcoder
The result is the following:
This seem like a not expected behavior. The windows is now located outside the wall although the wall have moved just about 3mm. Is this a bug?
If I use the second macro "ShiftWall", which just does a wall.LocationCurve.Move( new XYZ(0.01, 0.01,0) ) which is an equivalent translation to the former marco, the result is fine.
If their would be a method to adjust the length of the wall different to resetting the wall.LocationCurve.Curve = Line.CreateBound( ... ) like mentioned on the buildingcoder page, this would solve our issue as well. Is their any such method? I couldn't find a solution neighter in API forum, buildincoder nor google.
Thanks
Harald
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
Dear Harald,
Thank you for your interesting observation and careful analysis.
I looked at your macros and can reproduce what you say.
Besides the macro you list, LocationLineReset, there is another one that slightly moves the existing location line instead of creating a new one, ShiftWall.
That latter macro completes successfully:
public void LocationLineReset() { doc = this.Application.ActiveUIDocument.Document; Wall wall = doc.GetElement( new ElementId( 305891 ) ) as Wall; TransactionStatus status; using ( Transaction trans = new Transaction( doc, "bla" ) ) { trans.Start(); LocationCurve locationCurve = wall.Location as LocationCurve; Line wallLine = locationCurve.Curve as Line; XYZ startPoint = wallLine.GetEndPoint(0); XYZ endPoint = wallLine.GetEndPoint(1); XYZ minimalMoveVector = new XYZ( 0.01 /* =~ 3mm*/, 0.01, 0.0); startPoint += minimalMoveVector; endPoint += minimalMoveVector; locationCurve.Curve = Line.CreateBound( startPoint, endPoint ); status = trans.Commit(); } if( status != TransactionStatus.Committed ) MessageBox.Show( "Commit failed" ); } public void ShiftWall() { doc = this.Application.ActiveUIDocument.Document; Wall wall = doc.GetElement( new ElementId( 305891 ) ) as Wall; TransactionStatus status; bool bSuccess = false; using ( Transaction trans = new Transaction( doc, "bla" ) ) { trans.Start(); XYZ minimalMoveVector = new XYZ( 0.01 /* =~ 3mm*/, 0.01, 0.0); bSuccess = wall.Location.Move( minimalMoveVector ); status = trans.Commit(); } if( status == TransactionStatus.Committed && bSuccess) MessageBox.Show( "Shift succeeded" ); }
I would assume that during the process of resetting the wall location line from scratch, the window position gets completely lost.
When you simply perform a small adjustment to the existing location line, the window position is retained and adjusted accordingly.
Therefore, I would suggest using the latter approach whenever possible.
You could even make use of the latter approach in several steps, adjust first one and then the other location line endpoint.
I hope this enables you to handle all required situations.
Best regards,
Jeremy
Rereading your question in more details, I now address the question you raise at the end:
> Is there any method to adjust the length of the wall except resetting the `wall.LocationCurve.Curve` by creating a new curve using `Line.CreateBound`? That would solve our issue as well.
Yes, absolutely. You can modify just one of the line endpoints without changing the other one, and you can also change both endpoints at the same time by moving them by different translation vectors...
... or so I thought, until this very moment.
Now I looked a the Revit API documentation Curve and Line member methods, expecting to point out the SetEndPoint methods to you, only to discover they do not exist:
https://www.revitapidocs.com/2020/92a388f3-4949-465c-b938-2906ff6bdf5b.htm
Oh dear.
In that case, you really do have to create a new curve from scratch, and the problem you describe arises.
The only other way I could think of to try to modify an existing curve's length is to change its start and end parameters.
In theory, this can be achieved by calling MakeBound. However, all my attempts to use that method to modify the wall length had no result. Here is the final attempt:
public void ShortenWall() { Document doc = this.Application.ActiveUIDocument.Document; Wall wall = doc.GetElement( new ElementId( 305891 ) ) as Wall; TransactionStatus status; using ( Transaction trans = new Transaction( doc ) ) { trans.Start( "Shorten Wall"); LocationCurve lc = wall.Location as LocationCurve; Line ll = lc.Curve as Line; double pstart = ll.GetEndParameter(0); double pend = ll.GetEndParameter(1); double pdelta = 0.05 * (pend - pstart); lc.Curve.MakeBound(pstart + pdelta, pend - pdelta); // no observable change to wall (wall.Location as LocationCurve).Curve.MakeUnbound(); (wall.Location as LocationCurve).Curve.MakeBound( // no observable change to wall pstart + pdelta, pend - pdelta); status = trans.Commit(); } if( status == TransactionStatus.Committed) MessageBox.Show( "Shorten Wall succeeded" ); }
Sorry for the bad news.
I can raise an issue with the development team for this for you and see what they have to say about it.
Best regards,
Jeremy
You can adjust the curve of a wall with hosted elements, if the "curve definition" stays the same, i.e. just changing the start- and end parameters.
LocationCurve lc = wall.Location as LocationCurve; Curve ll = lc.Curve; double pstart = ll.GetEndParameter(0); double pend = ll.GetEndParameter(1); double pdelta = 0.001 * (pend - pstart); ll.MakeUnbound(); ll.MakeBound(pstart + pdelta, pend - pdelta); lc.Curve = ll;
Great! Brilliant! So my code was just lacking the assignment! Thank you!
Thank you and Jeremy for solving the issue!
Just a minor question, can we expect that the wall line parameter scales the position of the start/end point uniformly to feet? E.g. if we want to adjust the length of the wall by 0.1 feet, can we always do the following:
double pstart = ll.GetEndParameter(0); double pend = ll.GetEndParameter(1); ll.MakeUnbound(); ll.MakeBound( pstart, pend + 0.1 /* moves always the end point by 0.1 feet */); lc.Curve = ll;
In my example it did, but I am not sure if this is an invariant we can rely on?
Thanks again
see the remarks in the online documentation of the GetEndParameter method:
https://www.revitapidocs.com/2016/0f4b2c25-35f8-4e3c-c71a-0d41fb6935ce.htm
Can't find what you're looking for? Ask the community or share your knowledge.