Rotating a Plan View

Rotating a Plan View

grahamcook
Advocate Advocate
1,750 Views
9 Replies
Message 1 of 10

Rotating a Plan View

grahamcook
Advocate
Advocate

Hi

I'm having a problem (or a misunderstanding) with rotating views using the
ElementTransformUtils.RotateElement method.  The simplified sample code below will work but only if i add 2 to the Id value of the newly created view.  So if newViewPlan.Id is the view I'm rotating, what element is newViewPlan.Id + 2 referring to?  I stumbled on this "solution" after comparing the element Id's of the new view during code execution and after.

 

[RegenerationAttribute(RegenerationOption.Manual)]
[Transaction(TransactionMode.Manual)]
public class rotateElem2 : IExternalCommand
{
    UIApplication uiapp;
    UIDocument uidoc;
    Autodesk.Revit.ApplicationServices.Application app;
    Document doc;

    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
        uiapp = commandData.Application;
        uidoc = uiapp.ActiveUIDocument;
        app = uiapp.Application;
        doc = uidoc.Document;

        using (Transaction trans = new Transaction(doc, "Rotate View"))
        {
            trans.Start();

            // create new plan view of the first level found
            ViewFamilyType vft = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
                                .Cast<ViewFamilyType>()
				.FirstOrDefault<ViewFamilyType>(x => ViewFamily.FloorPlan == x.ViewFamily);

            Level firstLevel = new FilteredElementCollector(doc).OfClass(typeof(Level))
                                .Cast<Level>().FirstOrDefault<Level>();

            ViewPlan newViewPlan = ViewPlan.Create(doc, vft.Id, firstLevel.Id);

            // create rotation axis
            Line lineAsAxis = app.Create.NewLineBound(new XYZ(0, 0, 0), new XYZ(0, 0, 1));

            // rotate 45 deg (in radians)
            double rad = 45 / 57.2957795;

            // this line doesn't work or at least executes but doesn't do anything
            // ElementTransformUtils.RotateElement(doc, newViewPlan.Id, lineAsAxis, rad);

            // If you add 2 to the Id of newViewPlan then the new view gets rotated ???
            int id = newViewPlan.Id.IntegerValue + 2;
            ElementTransformUtils.RotateElement(doc, new ElementId(id), lineAsAxis, rad);

            trans.Commit();
        }

        return Result.Succeeded;
    }

}

 

0 Likes
1,751 Views
9 Replies
Replies (9)
Message 2 of 10

Revitalizer
Advisor
Advisor

Dear grahamcook,

 

in your posting you mentioned that your yiewplan gets rotated when using an ElementId which value is increased by 2.

 

I remember a TBC entry that handles about the relationship between views and viewers/viewports:

http://thebuildingcoder.typepad.com/blog/2011/11/undocumented-elementid-relationships.html

 

I fact there is a difference between the view itself and the viewer element that relates to this view.

In your case, in the end, you rotated the viewer element, I think that's the way it will work.

 

But of course you should search for another way to get the relating viewer element than just increasing the view's id by 2.

Maybe they are "connected" by a pair of parameters, by properties that refer to each other in a unique way ?

If you find such a unique relation, the TBC posting I mentioned above could be updated by this result.

 

 

Cheers,

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 3 of 10

grahamcook
Advocate
Advocate

Thanks for that insight Revitalizer.  Much appreciated.  So as you say its a case of figuring out how to get a handle on the "viewer" to the new plan view (other than incrementing the Id by 2).  I added the following line to the code to see if i could get any clues.  It returns an Autodesk.Revit.DB.Element object of the "viewer" in question:

 

object obj = App.activeDoc.GetElement(new ElementId(id));

 

But didn't give me any clues other than both the view and the viewer share the same name.  Looped through all the parameters in the new view as well but nothing stands out.

0 Likes
Message 4 of 10

Revitalizer
Advisor
Advisor

Hi grahamcook,

 

in the Revit 2013 API, there is a new class named ViewPort which has a ViewId property.


I think that's the relation we are looking for.

 

 

Best regards,

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 5 of 10

grahamcook
Advocate
Advocate

Thanks Revitalizer.

 

To test that theory i inserted the code below into the routine to iterated over all Viewports looking for an Id match on both Id and viewId.  Unfortunately there was no match on any of the Viewports.  Unless i missed something of course.

 

FilteredElementIterator viewPortItr = new FilteredElementCollector(doc).OfClass(typeof(Viewport)).GetElementIterator();
while (viewPortItr.MoveNext())
{
    Viewport vPort = viewPortItr.Current as Viewport;

    // check against newViewPlan.Id.IntegerValue + 2
    if (vPort.Id.IntegerValue == newViewPlan.Id.IntegerValue + 2)
    {
        MessageBox.Show("Match on vPort.Id");
    }

    if (vPort.ViewId.IntegerValue == newViewPlan.Id.IntegerValue)
    {
        MessageBox.Show("Match on vPort.ViewId");
    }

// also try the + 2 value
    if (vPort.ViewId.IntegerValue == newViewPlan.Id.IntegerValue + 2)
    {
        MessageBox.Show("Match on vPort.ViewId + 2");
    }


}

 

0 Likes
Message 6 of 10

Revitalizer
Advisor
Advisor

Hi grahamcook,

 

I see a variable called newViewPlan in your code.

As long as this viewplan has not been placed onto a sheet, there is no ViewPort for this.

ViewPort is the representing element on a sheet, after placing a view on this sheet.

 

Ah, in fact there are three different elements.

A view is an abstract element which is steered by an viewer element.

Between those, there is an undocumented relation.

 

A ViewPort is a third element, only residing on sheets.

This viewport has properties which refer to the (abstract) view, but not the viewer element.

 

Viewer element can be a section line, for example. The element you use to move a section manually, etc.

 

Best regards,

Revitalizer




Rudolf Honke
Software Developer
Mensch und Maschine





0 Likes
Message 7 of 10

Anonymous
Not applicable

Hi Revitalizer,

 

Simple revit 2016 api question hopefully. I would like to know how I can detect if a user has selected the viewport and rotated the viewport boundary. I don't need to know how to detect if a user has rotated the viewport by setting the enumerated values, viewport.Rotate = none, clockwise, anticlock as I already have that mystery sorted. Users would normally activate the viewport on a sheet, select the viewport boundary and rotate that sucker.

 

Regards,

Toiler

0 Likes
Message 8 of 10

grahamcook
Advocate
Advocate

Toiler

 

If I was looking at ways of solving that problem I would look at the IUpdater interface.

 

IUpdater Knowledge Article

 

But this won't tell you if the view port has been rotated, just that it has been modified in some way.  I guess in order to determine if it has been rotated you would need to store the current (or old) rotation against the viewport object using eStorage and check if the value has changed in the updater (when it is fired).  Then update the eStorage value with the new value to keep everything aligned.

 

http://thebuildingcoder.typepad.com/blog/2011/04/extensible-storage.html

 

Hope that helps.

 

Graham Cook.

Message 9 of 10

Anonymous
Not applicable

Thanx Graham,

I will attempt to get this functional. Is this something that has been added to the revit api wish list, as I would have thought it important for development of sheet/ view related add-ins. 

 

0 Likes
Message 10 of 10

Anonymous
Not applicable

See below for how I obtain the cropBox of a view for the purposes of rotation.

I find it to be quite reliable and using it I have found that the Id+2 trick isn't very reliable as sometimes it is Id +1

Although I guess you could use the same match criteria (Same name and TypeId)from my code to test a small range of Ids starting with Id+1 up to say +10, it might be quicker.

public static Element GetViewUiCropBox(View view)
{
	Element cropBox = null;

	if(view != null)
	{
		Document dbDoc = view.Document;
		ElementId typeId = view.GetTypeId();

		cropBox = new FilteredElementCollector(dbDoc).WherePasses(new ElementIsElementTypeFilter(true))
			.Where(x => x.GetTypeId() == typeId && x.Name == view.Name && x.Id != view.Id).FirstOrDefault();
	}

	return cropBox;
}