Rotating Assembly View

Rotating Assembly View

shevyakov.a
Contributor Contributor
1,686 Views
9 Replies
Message 1 of 10

Rotating Assembly View

shevyakov.a
Contributor
Contributor

Hi guys!

 

I have hard times rotating views in Revit 2019.
I've got assemblies in my project that are faced to different directions (N,S,E,W. We can assume, that absolute values of ( X , Y ) are either (0,1) or (1,0) )

 

With single transaction I create multiple sheets with views on them. I try to rotate the view using the subtransaction (it might be the issue).


Initial call:

 using (transaction)
            {
                List<ViewSheet> sheets = new List<ViewSheet>();
                
                transaction.Start();
                Utility.Sheets.CreateSheets(Document, elementId, 9, out sheets);

                //Creating sheets and views
                //sheet 1
                Utility.Sheets.Create3DSheet(Document, elementId, sheets[0]);
                //sheet 2

                Utility.Sheets.CreateCasingDrawing(Document, elementId, sheets[1]);
                //sheet 3


                Document.Regenerate();
                transaction.Commit();

                transaction.Start();
                for (int i = 0; i < sheets.Count; i++)
                {
                    Utility.Sheets.SetSheetParameters(Document, elementId, sheets[i], i+1);
                }
                transaction.Commit();
            }

code snippet from Utility.Sheets.CreateCasingDrawing

ViewSection vsFront2 = AssemblyViewUtils.CreateDetailSection(document, id, orientations[0], viewFront, isAssigned: true);

            ViewSection vsUp2 = AssemblyViewUtils.CreateDetailSection(document, id, AssemblyDetailViewOrientation.HorizontalDetail, viewSection, isAssigned: true);
            

            ViewSection vsLeft2 = AssemblyViewUtils.CreateDetailSection(document, id, orientations[2], viewSection, isAssigned: true);

            ViewSchedule matSched2 = AssemblyViewUtils.CreateSingleCategorySchedule(document, id, scheduleCategoryId: schedTypeElement.Category.Id, schedule, isAssigned: true);

            Viewport.Create(document, sheet.Id, vsFront2.Id, new XYZ(-0.75459, 0.63812, -0.241));
            Viewport.Create(document, sheet.Id, vsUp2.Id, new XYZ(-0.75459, 0.259682048822124, -0.351351502340035));
            Utility.Sheets.RotateHorizontalView(document, vsUp2, orientations[0]);
            Viewport.Create(document, sheet.Id, vsLeft2.Id, new XYZ(-0.108762048822124, 0.634839160104988, -0.225465616797901));


Utility.Sheets.RotateHorizontalView is supposed to do the trick by analyzing the assembly orientation and rotating the Plan view accordingly.

 

So far, I've tried 3 solutions:

1. Directly setting the Cropbox.Transform properties. Ain't working, just like the docs state. (Why do they have public setter though?)
2. https://thebuildingcoder.typepad.com/blog/2013/09/rotating-a-plan-view.html Seems like the thing I'm looking for, except there's no Cropbox Element in Revit 2019. Throws a NullReferenceException, as expected

3. I've modified the 2nd solution and now I'm trying to rotate the OST_Viewer. It executes, though the result is completely different from what I expect.

 

Here're code samples with the results:
Var 1:

SubTransaction rotation = new SubTransaction(document);

            Transform transform = view.CropBox.Transform;
            rotation.Start();
            view.CropBoxActive = true;
            rotation.Commit();


            rotation.Start();
            if (orientation == AssemblyDetailViewOrientation.ElevationLeft)
            {
                transform.BasisX = new XYZ(0, -1, 0);
                transform.BasisY = new XYZ(1, 0, 0);
            }
            if (orientation == AssemblyDetailViewOrientation.ElevationRight)
            {
                transform.BasisX = new XYZ(0, 1, 0);
                transform.BasisY = new XYZ(1, 0, 0);
            }
            if (orientation == AssemblyDetailViewOrientation.ElevationBack)
            {
                transform.BasisX = new XYZ(-1, 0, 0);
                transform.BasisY = new XYZ(0, -1, 0);
            }
            rotation.Commit();

            rotation.Start();
            view.CropBoxActive = false;
            rotation.Commit();

Result: 

 

shevyakova_0-1642379772659.png

(the front view is ok, the cropbox has been activated and not deactivated)

Var3: 

 SubTransaction rotation = new SubTransaction(document);
            //Var 3

            Element cropBoxElement = new FilteredElementCollector(document, view.Id).OfCategory(BuiltInCategory.OST_Viewers).FirstElement();
            XYZ top = view.CropBox.Max;
            XYZ bottom = view.CropBox.Min;
            XYZ center = 0.5 * (bottom + top);
            XYZ centerPlus = new XYZ(center.X, center.Y, center.Z + 1);
            Line axis = Line.CreateBound(center, centerPlus);


            rotation.Start();
            if (orientation == AssemblyDetailViewOrientation.ElevationLeft)
            {
                angle = System.Math.PI / 2;
            }
            if (orientation == AssemblyDetailViewOrientation.ElevationRight)
            {
                angle = 3 * System.Math.PI / 2;
            }
            if (orientation == AssemblyDetailViewOrientation.ElevationBack)
            {
                angle = System.Math.PI;
            }
            ElementTransformUtils.RotateElement(document, cropBoxElement.Id, axis, angle);
            rotation.Commit();

Result: 

shevyakova_1-1642379837101.png

(Instead of the plan, the front view has been transformed)

 

What am I doing wrong? What might be the issue?
I'm clearly making a mistake, I cannot see.

Thanks in advance!

0 Likes
Accepted solutions (1)
1,687 Views
9 Replies
Replies (9)
Message 2 of 10

jeremy_tammik
Alumni
Alumni

Have you tried using the view UpDirection property?

 

https://www.revitapidocs.com/2022/f93840a2-e22b-937f-a10b-a379ebbb2375.htm

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 10

shevyakov.a
Contributor
Contributor
It seems I don't quite get how I can use the readonly property in this case 😞

All of the created plan views have identical UpDirection value,
Direct setting them will cause compilation error,
Using its value to rotate OST_Viewer does no good (as, basically any other rotation).

What I'm trying to do now is reconsidering call hierarchy in my program to rotate OST_Viewer after commiting main transaction , not opening a subtransaction. But I don't know whether it is going to help.

And I still do not have a mere idea where to use UpDirection (if not in calculating rotation axis)
0 Likes
Message 4 of 10

jeremy_tammik
Alumni
Alumni

Oh dear. Maybe it can only be set in 3D views.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 5 of 10

shevyakov.a
Contributor
Contributor
Well, maybe, but I'm confused about the way I should use it

Let me ask a simpler question:
What object (type or category) do I have to access to rotate assembly plan view?
Can you advise any SDK samples with a similar problem? (Simple "RotateFramingObject" rotates element, not the view)
0 Likes
Message 6 of 10

jeremy_tammik
Alumni
Alumni
Accepted solution

First of all, you need to know how to solve this manually in the end user interface. And, above all, is it possible at all? If not, then the API will hardly support it either.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 7 of 10

shevyakov.a
Contributor
Contributor
Excuse me for taking this much time to respond

That's how I do it in Revit user interface:
1. Open a OST_Viewport Element to select the corresponding ViewSection
2. Make Cropbox visible
3. Plain rotate Cropbox ('RO' hotkey)
4. Make Cropbox invisible again, close OST_Viewport

and here's the issue I have:

1. Direct setting of View.Cropbox.Transform is ignored, according to documentation
(https://www.revitapidocs.com/2019/d6246051-ecfb-7388-0429-6ed65de72638.htm)
2. I can't possibly set another properties like View.ViewDirection or View.UpDirection because they don't have public setters
3. Passing the Cropbox Element (OST_Viewer category) into ElementTransformUtils.RotateElement() returns Rotation of OST_Viewport Element instead (initial post -> var3 -> result)

So far, I've been unable to solve this on my own 😞
0 Likes
Message 8 of 10

shevyakov.a
Contributor
Contributor
Figured it out, finally!

Missed some important details 'bout creating multiple sections, cropbox visibility etc.
0 Likes
Message 9 of 10

jeremy_tammik
Alumni
Alumni

Congratulations on solving it! 

 

Would you like to share the working code?

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 10 of 10

shevyakov.a
Contributor
Contributor

Yep. It's not a big deal, actually) Hopefully, it will help someone)

 

/// <summary>
        /// Method for rotating plan view.
        /// It rotates plan view according to the Front view orientation
        /// </summary>
        /// <param name="document">Active runtime document</param>
        /// <param name="viewSection">View to rotate</param>
        /// <param name="orientation">Front view orientation</param>

        public static void RotatePlanView(Document document, ViewSection viewSection, AssemblyDetailViewOrientation orientation)
        {
            View view = (View)viewSection;
            double rotationalAngle = 0;
            string horizontalViewName = "sampleName";

            //we're working inside an ongoing transaction, so we're creating a subtransaction
            SubTransaction rotation = new SubTransaction(document);

            //The following FilteredElementCollector overload searches for visible elements.
            //The CropBox is invisible by default, so, we have to set visibility first

            rotation.Start();
            view.CropBoxVisible = true;
            rotation.Commit();

            //We select the cropbox element. 
            IList<Element> visibleElementsOnView = new FilteredElementCollector(document, view.Id).OfCategory(BuiltInCategory.OST_Viewers).WhereElementIsNotElementType().ToElements();
            Element cropBoxElement = visibleElementsOnView.Where(o => o.Name == horizontalViewName).FirstOrDefault();

            //We are about to rotate plan view in XY plane about the cropbox center
            BoundingBoxXYZ cropBoxBounding = cropBoxElement.get_BoundingBox(view);
            XYZ top = cropBoxBounding.Max;
            XYZ bottom = cropBoxBounding.Min;
            XYZ cropBoxCenter = 0.5 * (bottom + top);
            XYZ cropBoxCenterUp = new XYZ(cropBoxCenter.X, cropBoxCenter.Y, cropBoxCenter.Z + 1 );
            Line rotationalAxis = Line.CreateBound(cropBoxCenter, cropBoxCenterUp);

            //Just choosing the proper angle and perform rotation
            rotation.Start();
            if (orientation == AssemblyDetailViewOrientation.ElevationLeft)
            {
                rotationalAngle = (System.Math.PI / 2);
            }
            else if (orientation == AssemblyDetailViewOrientation.ElevationRight)
            {
                rotationalAngle = (3 * System.Math.PI / 2);
            }
            else if (orientation == AssemblyDetailViewOrientation.ElevationBack)
            {
                rotationalAngle = System.Math.PI;
            }
            ElementTransformUtils.RotateElement(document, cropBoxElement.Id, rotationalAxis, rotationalAngle);
            rotation.Commit();

            //Setting cropbox visibility back to defaults
            rotation.Start();
            view.CropBoxVisible = false;
            rotation.Commit();
        }