July 22, 2013

Software Rental and Remote Access

Here are a couple of new things that I became aware of today. I thought I would post links here in case others have not heard of these yet.

FAQ for Autodesk® Software Rental

You have to be on subscription to take advantage of the following Autodesk® Exchange application:
Autodesk® Remote

July 16, 2013

ActiveX and AutoLISP Programming Tip 1

When trying to make use of the AutoCAD® ActiveX® access to the object model through the AutoLISP® "VL" commands, the vlax-dump-object function will likely become one of your best friends. The Help sections on the object model are certainly useful, but as you test bits of code to verify that they work, I have found the vlax-dump-object function invaluable in helping me to understand exactly what properties are available for a given object.

For example, I was trying to update a subroutine I had written some years back that returned certain information about the current AutoCAD® Architecture drawing, including the drawing scale. This was before drawing scale had been added as a feature to the "vanilla" AutoCAD® software, and I had been using a DXF "hack" to get the current drawing scale from (namedobjdict) > AEC_VARS dictionary > AEC_VARS_DWG_SETUP dictionary > 40 group. In more recent releases, the CANNOSCALEVALUE system variable will give you the current annotation scale in a drawing. When Model Space is active in a Layout Viewport, however, it is possible for the viewport scale (magnification relative to Paper Space, which is presumed to be 1:1 when plotted) to be different from the annotation scale, and I wanted to be able to report both scales. By using the vlax-dump-object function in the Visual LISP Console for the ActivePViewport object, I was able to quickly see which properties changed when I changed settings in the drawing, which helped me to understand that the inverse of the CustomScale property of the ActivePViewport object would give me the scale factor for the viewport magnification, and also allow me to sidestep dealing with the enum values reported by the StandardScale (Viewport magnification) and StandardScale2 (viewport annotation scale).

Another thing that I was able to discover by using the vlax-dump-object function was that the Paper Space Viewport does not report all of the properties that other Layout Viewports report. For example, a Layout Viewport object scaled to 1/4" = 1'-0", saved to variable objVpA, might have the following properties, which can be examined using vlax-dump-object:
_$ (vlax-dump-object objVpA)
; IAcadPViewport: IAcadPViewport Interface
; Property values:
;   Application (RO) = #
;   ArcSmoothness = 10000
;   Center = (17.8157 11.25 0.0)
;   Clipped (RO) = 0
;   CustomScale = 0.0208333
;   Direction = (0.0 0.0 6889.41)
;   DisplayLocked = 0
;   Document (RO) = #
;   GridOn = -1
;   Handle (RO) = "E84"
;   HasExtensionDictionary (RO) = -1
;   HasSheetView (RO) = 0
;   Height = 22.5
;   Hyperlinks (RO) = #
;   LabelBlockId = 0
;   LabelBlockId32 = 0
;   Layer = "G-Anno-Nplt-N"
;   LayerPropertyOverrides (RO) = 0
;   LensLength = 50.0
;   Linetype = "ByLayer"
;   LinetypeScale = 1.0
;   Lineweight = -1
;   Material = "ByLayer"
;   ModelView = nil
;   ObjectID (RO) = 60
;   ObjectID32 (RO) = 60
;   ObjectName (RO) = "AcDbViewport"
;   OwnerID (RO) = 61
;   OwnerID32 (RO) = 61
;   PlotStyleName = "ByLayer"
;   ShadePlot = 0
;   SheetView = nil
;   SnapBasePoint = (0.0 0.0)
;   SnapOn = 0
;   SnapRotationAngle = 0.0
;   StandardScale = 26
;   StandardScale2 = 7
;   Target = (1690.27 1160.54 0.0)
;   TrueColor = #
;   TwistAngle = 0.0
;   UCSIconAtOrigin = -1
;   UCSIconOn = -1
;   UCSPerViewport = -1
;   ViewportOn = -1
;   Visible = -1
;   VisualStyle = 1
;   Width = 35.3685

For the Paper Space Viewport object for that same Layout, vlax-dump-object returns the following:
_$ (vlax-dump-object objVpA)
; IAcadPViewport: IAcadPViewport Interface
; Property values:
;   Application (RO) = #
;   ArcSmoothness = 10000
;   Center = (24.3525 19.3312 0.0)
;   Clipped (RO) = 0
;   CustomScale = 1.0
;   Direction = (0.0 0.0 1.0)
;   DisplayLocked = 0
;   Document (RO) = #
;   GridOn = 0
;   Handle (RO) = "1FB"
;   HasExtensionDictionary (RO) = 0
;   HasSheetView (RO) = 0
;   Height = 36.5272
;   Hyperlinks (RO) = #
;   LabelBlockId = Exception occurred
;   LabelBlockId32 = ; error: Exception occurred: 0xC0000005 (Access Violation)
; warning: unwind skipped on exception
; error: Exception occurred: 0xC0000005 (Access Violation)
; error: Exception occurred: 0xC0000005 (Access Violation)
; error: Exception occurred: 0xC0000005 (Access Violation)

The LabelBlockID property is apparently unavailable for a Paper Space Viewport and the LabelBlockId32 property is not only unavailable, but trying to get the value causes an error that terminates the vlax-dump-object function. You can get to the properties that occur alphabetically after those two, one at a time, by using the vlax-get-property function. My routine presumes that Paper Space is plotted at 1:1 and any annotation would be scaled accordingly, so it sets the scale factors for both the viewport and the annotation at 1.0 without extracting any data from the drawing.

July 04, 2013

ActiveX Access to ACA/AMEP Drawing Settings

Since the 2010 releases, the AEC data stored in "dictionaries" has not been accessible through AutoLISP® entities/entity data, as it had been previously, through statements such as:
(cdr (assoc 350 (member '(3 . "AEC_VARS") (entget (namedobjdict)))))

I recently had the time and opportunity to investigate the use of the Visual LISP® functions to access the drawing data to access the data previously available through entity data.

The keys to getting ACA or AMEP data are understanding the Object Model, so that you know which Application holds the data of interest, a willingness to explore the Object Model, so you can find things that are exposed in locations other than what the object model suggests, and knowing that the "undocumented" vla-GetInterfaceObject function can be used to access those Applications and thereby the Object Model elements defined/stored therein.

The Help menu (in recent releases, in the upper right corner of the ACA/AMEP window, to the right of the InfoCenter and to the left of the Minimize/Maximize/Close buttons) has a choice called AutoCAD® Architecture Developer Help (in ACA) or AutoCAD® MEP Developer Help (in AMEP) that will open "local" Help files that explain the Object Models and available objects, methods and properties. AMEP users will need to see the ACA file, which can also be found under the installation directory (C:\Program Files\Autodesk\AutoCAD 2014\Help\adtauto.chm for my installation of the 2014 Building Design Suite). The AMEP file can also be found in the same folder (absauto.chm).

The loading of the Application objects is version-dependent, so the first step on my journey was to write a subroutine to return the proper string indicating the version of the release of ACA/AMEP running. Because many of the routines I am trying to update were written in the ADT 3.3/2004 time frame, I have chosen to include releases back to that time in this function. Unfortunately, I no longer have access to many of those releases to verify the AEC version numbers, so some of the return values in the routine are based on my best guess. If anyone is still running any of the the releases marked "verify", please do verify the values before trying to use the following code. And if you do, and are so inclined, I would appreciate a comment to this post either verifying that I guessed correctly or providing the right values. The subroutine initially tests to see if ACA or AMEP is running, and returns nil if aecarchbase.dbx or aecarchbasenn.dbx is not loaded, where nn is a two-digit number indicating a specific release from 2007 or earlier. If it is not loaded, then the subroutine ends with a warning to the user and returns nil, since there is little point looking for information that does not exist. The calling routine will have to determine how to handle the return of a nil value.
(defun AECAPPVER (            ; No arguments.
                   / ;_ Local variable:  
                     sacdvr   ; String stored in ACADVER system variable.
                 ) ;_ End arguments and local variables.
  (setq sacdvr (getvar "ACADVER"))
  ;; Return appropriate string:
  (cond                       ; cond A.
         (member "aecarchbase.dbx" (arx))
         (member "aecarchbase50.dbx" (arx))
                              ; DBX file name not verified for 2007.
         (member "aecarchbase47.dbx" (arx))
         (member "aecarchbase45.dbx" (arx))
                              ; DBX file name not verified for 2005.
         (member "aecarchbase40.dbx" (arx))
                              ; DBX file name not verified for 2004.
         (member "aecarchbase30.dbx" (arx))
                              ; DBX file name not verified for 3.3.
       ) ;_ End or.
     ) ;_ End not.
      ;; ACA or AMEP is not running.
          "Unsupported version of AutoCAD Architecture/MEP is running."
          "\nACADVER = "
          "\n\nPlease notify the CAD/BIM IT Staff."
         ) ;_ End strcat.
      ) ;_ End alert.
      nil                     ; Return nil.
    ) ;_ End condition A.1.
    ((= "15.06" sacdvr)       ; ADT 3.3.
      ".3.0"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.2.
    ((= "16.0" sacdvr)        ; ADT 2004.
      ".4.0"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.3.
    ((= 16.1 (atof sacdvr))   ; ADT 2005.
      ".4.5"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.4.
    ((= 16.2 (atof sacdvr))   ; ADT 2006.
      ".4.7"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.5.
    ((= 17.0 (atof sacdvr))   ; ADT 2007.
      ".5.0"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.6.
    ((= 17.1 (atof sacdvr))   ; ADT 2008.
      ".5.5"                  ; Return string.
    ) ;_ End condition A.7.
    ((= 17.2 (atof sacdvr))   ; ADT 2009.
      ".5.7"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.8.
    ((= 18.0 (atof sacdvr))   ; ADT 2010.
      ".6.0"                  ; Return string.
    ) ;_ End condition A.9.
    ((= 18.1 (atof sacdvr))   ; ADT 2011.
      ".6.5"                  ; Return string.
    ) ;_ End condition A.10.
    ((= 18.2 (atof sacdvr))   ; ADT 2012.
      ".6.7"                  ; VERIFY THIS RETURN STRING!
    ) ;_ End condition A.11.
    ((= 19.0 (atof sacdvr))   ; ADT 2013.
      ".7.0"                  ; Return string.
    ) ;_ End condition A.12.
    ((= 19.1 (atof sacdvr))   ; ADT 2014.
      ".7.5"                  ; Return string.
    ) ;_ End condition A.13.
    (T                        ; Unsupported version running.
         "Unsupported version of AutoCAD is running."
         "\nACADVER = " sacdvr "."
         "\n\nPlease notify the CAD/BIM IT Staff."
       ) ;_ End strcat.
     ) ;_ End alert.
     nil                       ; Return nil.
    ) ;_ End condition A.13.
  ) ;_ End cond A.

With the subroutine above loaded, you can access the AecArchBaseApplication with this code
  (strcat "AecX.AecArchBaseApplication" (aecappver))

I will post more of my findings as I develop them.

Backstory Behind This Post:
Many years back, I did a lot of customization in AutoCAD® using AutoLISP, and was particularly pleased when the Visual LISP was introduced, as I made extensive use of the Visual LISP interactive development environment (VLIDE). While perhaps somewhat less slick that the equivalent setup for Visual Basic, it none the less made writing, testing and debugging a LISP routine or project much easier than using Notepad or a DOS text editor. I never really worked with the Visual LISP commands that were added to the AutoLISP arsenal at that time, however, and the time I had for customization dwindled with increasing project responsibilities and with attempting to master Architectural Desktop/AutoCAD Architecture.

I did, however, manage to find time to write a few customizations that accessed ACA settings (such as the drawing scale - before AutoCAD added that feature, Annotation Plot Size, current Layer Key Style, etc.) via DXF access to the dictionaries where that data was stored. There was little to no documentation on the structure of those dictionaries, but by working with what there was and trial and error, I was able to find the locations of various settings. My routines only read these values, and then acted accordingly; changing the values through ENTMOD was not supported and actively discouraged by Autodesk staffers. These routines stopped working in the 2010 release, because the dictionary contents were no longer exposed to DXF "hacking".

My on-the-job responsibilities shifted last year, as I moved out of the Project Architect roll and into the CAD/BIM Manager roll. I had reason to get back into customization, as I was looking for a way to expedite the processing of AutoCAD files exported from Revit, which tend to have a lot of entity-level settings (in particular, color) and which then tend not to work well for the disciplines that remain in CAD, as they are used to externally referencing the background drawings and controlling the appearance and plotting of the elements therein via layer settings. While working on that task, I had reason to become more familiar with the capabilities in the Visual LISP commands, and was reminded that I had a number of routines that no longer worked in versions more recent than 2009. I am using the rehabilitation of these routines as a pretext to become more familiar with the Visual LISP commands and the ACA Object Model, as I suspect that these skills will continue to have some relevance, at least until the day that our work is all Revit and no AutoCAD.