Here is a query from the Autodesk Revit API discussion forum dealing with the rotation of a plan view:
Question: I am trying to create rotated duplicates of existing views using the Revit 2013 API.
I managed to create the view, both as dependent and not. After this I activate the view crop box and make it visible.
I then create a rotation transformation. When I debug it, I can see that the transformation and rotation of the bounding box is ok.
I try to set the rotated bounding box as the crop box. However, this does not work, and all I get is the standard identity matrix.
I have a right handed rotation, and use basis Z as the rotation axis. I have a reference to a transaction inside the method, but have also tried to encapsulate the specific part into a sub transaction.
This way of doing things is according to the Revit 2013 API documentation. It states that the bounding box can be rotated, then used as section box/crop box, and provides to following example code for this:
private void RotateBoundingBox( View3D view3d ) { BoundingBoxXYZ box = view3d.SectionBox; if( !box.Enabled ) { TaskDialog.Show( "Revit", "The View3D section box is not enabled." ); return; } // Create a rotation transform Transform rotate = Transform.get_Rotation( XYZ.Zero, XYZ.BasisZ, 2 ); // Transform the SectionBox // with the rotation transfrom box.Transform = box.Transform.Multiply( rotate ); view3d.SectionBox = box; }
I tried to use it like this:
ViewPlan rotatedView = doc.GetElement( viewToDuplicate.Duplicate( ViewDuplicateOption.AsDependent ) ) as ViewPlan; rotatedView.CropBoxActive = true; rotatedView.CropBoxVisible = true; BoundingBoxXYZ box = rotatedView.CropBox; XYZ originOfRotation = 0.5 * (box.Max - box.Min); XYZ axizOfRotation = XYZ.BasisZ; Transform rotate = Transform.get_Rotation( originOfRotation, axizOfRotation, Math.PI ); box.Transform = box.Transform.Multiply( rotate ); rotatedView.CropBox = box;
I also tried using the ElementTransformUtils.RotateElement method.
Both approaches yield no result.
Manually I make sure the plan is situated to 'Project north', show the crop box, select it, rotate it and the view is rotated accordingly.
The desired result is a dependent view rotated at the point of creation. I need to create several views at once, e.g. 4-8 differently rotated ones of the same plan, to create evacuation plans.
Let me reiterate my requirement and manual solution:
For creating evacuation plans for a floor, I need to create rotated dependent views so that the person looking at the plan on the inside of a door sees the situation the same way as the corridor outside.
I can achieve it manually like this:
This is obviously a very time consuming operation.
I have already implemented methods to create the fire and evacuation plans.
The issue I am now dealing with is the rotation of the crop region.
I do get the transformation, but I am not able to apply it to the crop region. Something fails and the transformation remains unchanged.
How can I fix this, please?
Answer: Yes, rotating a view in the user interface is perfectly straightforward, just as you say:
In the API, the issue is also clear: The element to rotate is not the view, but rather the crop box element associated to it.
If it is visible, it can be found using a filtered element collector taking document and view element id arguments.
Here is a macro that works based on your sample code:
public void CreateDuplicatedRotatedCroppedView( Document doc ) { View activeView = doc.ActiveView; View duplicated = null; using( Transaction t = new Transaction( doc ) ) { t.Start( "Duplicate View" ); duplicated = doc.GetElement( activeView.Duplicate( ViewDuplicateOption.WithDetailing ) ) as View; t.Commit(); } Element cropBoxElement = null; using( TransactionGroup tGroup = new TransactionGroup( doc ) ) { tGroup.Start( "Temp to find crop box element" ); using( Transaction t2 = new Transaction( doc, "Temp to find crop box element" ) ) { // Deactivate crop box t2.Start(); duplicated.CropBoxVisible = false; t2.Commit(); // Get all visible elements; // this excludes hidden crop box FilteredElementCollector collector = new FilteredElementCollector( doc, duplicated.Id ); ICollection<ElementId> shownElems = collector.ToElementIds(); // Activate crop box t2.Start(); duplicated.CropBoxVisible = true; t2.Commit(); // Get all visible elements excluding // everything except the crop box collector = new FilteredElementCollector( doc, duplicated.Id ); collector.Excluding( shownElems ); cropBoxElement = collector.FirstElement(); } tGroup.RollBack(); } using( Transaction t3 = new Transaction( doc ) ) { BoundingBoxXYZ bbox = duplicated.CropBox; XYZ center = 0.5 * ( bbox.Max + bbox.Min ); Line axis = Line.CreateBound( center, center + XYZ.BasisZ ); t3.Start( "Rotate crop box element" ); ElementTransformUtils.RotateElement( doc, cropBoxElement.Id, axis, Math.PI / 6.0 ); t3.Commit(); } }
There are several noteworthy points in here.
All the transactions could be assimilated into one group, if desired.
The crop box element is retrieved using a clever trick: first hide it, retrieve the set V of all visible elements, unhide it and again retrieve all visible elements, this time excluding the set V. Clever, huh?