How to get the extents when exporting an image from a view using C# API?

How to get the extents when exporting an image from a view using C# API?

peter.kolbe
Enthusiast Enthusiast
3,061 Views
10 Replies
Message 1 of 11

How to get the extents when exporting an image from a view using C# API?

peter.kolbe
Enthusiast
Enthusiast

Using this post
https://forums.autodesk.com/t5/revit-api-forum/how-to-export-an-image-from-a-specific-view-using-rev...
I'm able to create PNG images and store them in the local file system. The images will be created from 2D floor plans.
Now I want to know, what are the extents of the result image in local coordinates (not the count of pixel. this is an input value).
Is there a way to get that size? Or is there a way to calculate it? Or what elements will be used to create the image and is there a calculation for the border around the elements?
Thank you!
Peter

Accepted solutions (2)
3,062 Views
10 Replies
Replies (10)
Message 2 of 11

jeremytammik
Autodesk
Autodesk
Accepted solution

Dear Peter,

 

I don't know what you mean by 'local' coordinates.

 

Do you mean the internal Revit model coordinates?

 

You can map between the Windows screen device pixel coordinates and the internal Revit model coordinates using functionality on the Revit API UIView class:

 

https://apidocs.co/apps/revit/2019/2a070256-00f0-5cab-1412-bee5bbfcfc5e.htm

 

For instance, I used that to implement my own tooltips that grab information from the Revit model:

 

http://thebuildingcoder.typepad.com/blog/2012/10/uiview-windows-coordinates-referenceintersector-and...

 

http://thebuildingcoder.typepad.com/blog/2017/01/uiview-windows-coordinate-referenceintersector-tool...

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 11

BenoitE&A
Collaborator
Collaborator
Accepted solution

Funny, we are just working on that.

To export you will need a ImageExportOptions object, which has a property named HLRandWFViewsFileType.

And that property can be turned on PNG. This is answer 1.

The ImageExportOptions object has another property called ExportRange. Check the values, one of them is VisibleRegionOfCurrentView. If you modify the crop region of your view you are able to export exactly what you want. This is answer 2.

And I have a bonus : to export properly you should consider changing the scale of your ViewPlan. If it is 1:100 the annotations will be very large, but if you turn it to 1:20... they will be smaller... Bonus !

I think you owe me a triple Accept As Answer 😉

 

Benoit


Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 4 of 11

peter.kolbe
Enthusiast
Enthusiast

Hi Jeremy,

correct, I'm searching for "internal Revit model coordinates".

And it looks like that the UIView.GetZoomCorners() will return these values.

In my app there is the 3D view open and I calculate all the floor views, which should be exported as PNG.
When runing code like this

uiDoc.ActiveView = view;
UIView uiView = GetActiveUiView(uiDoc);
uiView.ZoomToFit();
IList<XYZ> zoomCorners = uiView.GetZoomCorners();
ExportToImage(doc, pngFile);

The variable zoomCorners contains values, when the 2D floor plans were open and active previously. Otherwise the zoom corner values are all equal to zero.
Do you have a hint, how to get the floor plans active and visible, so that the GetZoomCorners() will return the expected values, also if these views were not opened before running my App command?
Thank you for your help!

Best regards,
Peter

 

0 Likes
Message 5 of 11

BenoitE&A
Collaborator
Collaborator

And there is another property of the view called Crop Region which is much better than using the Zoom.

You should check !!


Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 6 of 11

peter.kolbe
Enthusiast
Enthusiast

Hello Benoit,

just for completeness, here is my ExportToImage() and it contains the properties, you mentioned:

static Result ExportToImage(Document doc, string pngFilename)
{
    Result r = Result.Failed;
    using (Transaction tx = new Transaction(doc))
    {
        tx.Start("Export Image");
        ImageExportOptions img = new ImageExportOptions();
        img.ZoomType = ZoomFitType.FitToPage;
        img.PixelSize = 6400;
        img.ImageResolution = ImageResolution.DPI_300;
        img.FitDirection = FitDirectionType.Horizontal;
        img.ExportRange = ExportRange.CurrentView;
        img.HLRandWFViewsFileType = ImageFileType.PNG;
        img.FilePath = pngFilename;
        img.ShadowViewsFileType = ImageFileType.PNG;
        doc.ExportImage(img);
        tx.RollBack();
        r = Result.Succeeded;
    }
    return r;
}

But there is the same problem as I answered to Jeremy, the result value are invalid as long as the floor plan view were inactive and invisible. Otherwise when I open the views before running the command, the values will be returned.

What else do I have to do then 

uiDoc.ActiveView = view;

before accessing the uiView?

Thank you!
Best regards,
Peter

0 Likes
Message 7 of 11

BenoitE&A
Collaborator
Collaborator

Indeed you have to activate the view.

Be careful you can only activate it OUTSIDE a transaction.

 

Benoit


Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 8 of 11

yafim.simanovsky
Participant
Participant

Hi,

In relation to the partial solutions provided above, I tried the following code to switch to all floorplans in the document one after the other in a loop:

 

// initialize app and uiapp objects
Application app = document.Application;
UIApplication uiapp = new UIApplication(app);
UIDocument uidoc = uiapp.ActiveUIDocument;
UIView uiview = null;

IList<Element> elementSet;

/// Find all instances in the document by using category filter
FilteredElementCollector collector = new FilteredElementCollector(document);
elementSet = collector.OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType().ToElements();


IList<ElementId> ImageExportList = new List<ElementId>();
            foreach (View view in elementSet)
            {
                if (view.ViewType.ToString() == "FloorPlan")
                {
                    uiapp.ActiveUIDocument.RequestViewChange(view);

                    IList<UIView> uiviews = uidoc.GetOpenUIViews();
                    foreach (UIView uv in uiviews)
                    {
                        if (uv.ViewId.Equals(view.Id))
                        {
                            uiview = uv;
                            break;
                        }
                    }
                }
            }

 

The loop works fine the first time, meaning that it switches from the open Level 0 view to Level 1 view in a new viewtab in Revit, but then it fails saying that:

 


Cannot make a template view active.
Parameter name: view

 

What am I missing here..?

Thanks!

0 Likes
Message 9 of 11

jeremytammik
Autodesk
Autodesk

The message tells you the problem:

 

You are apparently trying to activate a template view.

 

You need to eliminate or skip template views from your iteration.

 

The view has an IsTemplate property:

 

https://www.revitapidocs.com/2020/bd7d3469-dc89-93b7-1cb8-848fd4f38d65.htm

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 10 of 11

BenoitE&A
Collaborator
Collaborator

Funny indeed, a Template View is not a Type in Revit.

So you should add here :

foreach (View view in elementSet)
{
    if(view.isTemplate)
         continue;
    if (view.ViewType.ToString() == "FloorPlan")
    {

Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 11 of 11

yafim.simanovsky
Participant
Participant

Thanks for both of you, indeed I was missing this small step 🙂

0 Likes