During development of the ViewPortMaster, I faced the problem of, how to align viewports with defined frames in the model space. Most of the properties, like Height, Width, Insertion point, Scale, can be set with the put functions of VLA-Object ->> autodesk ActiveX resources. Unfortunately there is no property of the view center point. In this post I’m going to show you two different ways of how to manage it. First thought was, why not to use DXF codes with ordinary entget, entmod. Cool, according to autodesk DXF resources the view center point is exposed in group code 12 . Unfortunately it’s impossible to modify the viewport’s DXF codes, so I had to work around and I found that routine:
(setq paperObjects (vla-get-PaperSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) (vlax-for x paperObjects (if (= (vla-get-ObjectName x) "AcDbViewport") (progn (vla-put-DisplayLocked x :vlax-false) (vla-put-MSpace (vla-get-ActiveDocument (vlax-get-acad-object)) :vlax-true) (vla-put-ActivePViewport (vla-get-ActiveDocument (vlax-get-acad-object)) x) (vla-ZoomCenter (vlax-get-acad-object) (vlax-3d-point vpC) 1.0 );vla-zoomcenter (vla-put-MSpace (vla-get-ActiveDocument (vlax-get-acad-object)) :vlax-false) (vla-put-DisplayLocked x :vlax-true) );progn );if );vlax-for
where: vpC – view center point e.g. ‘(0 100 0) The routine iterates over all VLA-Objects from current layout. When it finds AcDbViewport object it unlocks the viewport’s display, puts the model space and the viewport active and then sets the view center point vpC. It looks quite simple and works fine but that way also has some disadvantages. Synchronizing many viewports takes a long time, and what is more important, execution of it with the :vlr-LayoutSwitched reactor sometimes make errors.
Those two functions: vla-get-PaperSpace, vla-put-MSpace are problematic in AutoCad (in BricsCad/ZWcad works fine), so I had to find another way. I started digging into resources and voila! I found that forum thread: cadtutor thread. There is the editable xData named “ACAD” attached to the every viewport and it contains my Holy Grail 🙂 The xData cannot be modify by entmod but can be by ActiveX methods vla-GetXData; vla-PutXData. Let’s get xData from the viewport and look closer to values:
(setq vpObj (vlax-ename->vla-object (car entsel))) (vla-GetXData vpObj "ACAD" 'XDataType 'XDataValue)
After extracting raw data from variant values we get:
|4||1010||0.0 0.0 0.0|
|5||1010||0.0 0.0 1.0|
(vlax-safearray-put-element XDataValue 8 xCord) (vlax-safearray-put-element XDataValue 9 yCord) (vla-SetXData vpObj XDataType XDataValue)
xCord, yCord – real values
Looks simple, right? But there are two catches:
- If you’d like to change xData of any viewport in current layout, first you need to switch off that viewport’s display, and switch it on after you save the new xData to see the changes: (vla-put-ViewPortOn vpObj :vlax-false/:vlax-true)
- If you’d like to change xData of viewport which is not inserted in the current layout you don’t need to switch display on/off, but you need to remember to set system variable LAYOUTREGENCTL to 0 which controls caching of viewports in layouts. If you change the viewport’s xData, it’s cached and you switch layout to see the changes, you will not see any and additionally all xData changes will be lost.
That’s all about it. Most of the post’s content is quite easy to find in forums but I think it’s worth to put all together and make it public. In the next post I will explain how to find a proper 8th and 9th values of xData when the viewport is twisted, it took a while to find out :). Have a question? Leave a comment.