API wishlist surveys for Autodesk products

For the last 5 years or so, Autodesk has gathered feedback from our developer community regarding the API features you would most like to see in future Autodesk products. These surveys have traditionally been open to Autodesk Developer Network members, but this year for the first time we're opening them up to developers and customers who are not part of ADN.

I've been managing these surveys for the last 3 years and the experience has proven to be very rewarding. Every year we see a number of items get knocked off the various lists: our Engineering teams really appreciate the feedback and respond to it.

So, please do take the time to respond to the surveys for the products in which you're interested. If you (optionally) provide your email address when filling out a survey, you'll get the results of that survey emailed to you, once it has closed and the results have been compiled.

AutoCAD®
AutoCAD® Architecture
AutoCAD® MEP
AutoCAD® Civil 3D®
AutoCAD® Map 3D
Revit®
Autodesk® Inventor®

The surveys will remain open until May 1st, 2008. Thank you in advance for your feedback!

April 21, 2008 in AutoCAD, AutoCAD .NET, ObjectARX | Permalink | Comments (4) | TrackBack

Automatic closing of AutoCAD objects with ObjectARX SmartPointers

Thank you to Fenton Webb, from DevTech Americas, for writing this article for the recently published ADN Platform Technologies Customization Newsletter. This article also talks about the new AcDbSmartObjectPointer class referenced in this overview of the new APIs in AutoCAD 2009.

Those of us who regular create ObjectARX code to manipulate the AutoCAD drawing database are fully aware of the mechanism for opening an object for read (to simply access data held inside it) or write (to update it with new data). Oh and I almost forgot - followed by a call to close() when you are done.

But here lies a very common problem illustrated by that last sentence; the problems start when you accidentally forget to close an object once you are finished with it. AutoCAD follows a strict set of rules which allows the checking-in/out of data inside of AutoCAD and these rules must be adhered to. If not, then AutoCAD will abort in order to do its best to save the previous valid state of the database.

“You must be very careful to close your objects when you are finished with them”. It’s very easy for me to say that, but even I, the person shaking his finger saying those infamous words will fail to remember my own advice time and time again, this is why using ObjectARX SmartPointers is a MUST.

So let’s look at this thing in ObjectARX called SmartPointers.

What are they? First take a look at the MSDN article on “Template Classes” as this explains the basic concept. Leading on from that article, and now in my own words, ObjectARX SmartPointers are C++ template classes which wrap an underlying AutoCAD AcDbObject derived class pointer, and simply provides automatic closure of that pointer, if valid, on destruction of the ObjectARX SmartPointer class (so the end of a function or closing brace “}”).

A question that often arises is on the usage of this class, in particular the way to access the member functions. The template class itself has been implemented so that if you reference a member function with the dot “.” operator

line.openStatus()

then, you reference the ObjectARX SmartPointer specific functions. If you reference a member function with the arrow “->” operator

line->setStartPoint()

Then, because the arrow operator has been overridden to return the underlying AcDbObject pointer, you simply reference the underlying AcDbObject derived class, in this case the AcDbLine::setStartPoint().

So how do we use them then…? Let’s start by showing old ObjectARX code which adds an AcDbLine to the Current Space using open and close.

// create a new line

AcDbLine *line = new AcDbLine();


// set the properties for it

line->setStartPoint(AcGePoint3d(10,10,0));

line->setEndPoint(AcGePoint3d(20,30,0));


// now add it to the current space

AcDbBlockTableRecord *curSpace = NULL;


// open the current space for write

Acad::ErrorStatus es =

  acdbOpenObject(

    (AcDbBlockTableRecord *&)curSpace,

    curDoc()->database()->currentSpaceId(),

    AcDb::kForWrite

  );


// if ok      

if (es == Acad::eOk)

{

  // add it to the space

  es = curSpace->appendAcDbEntity(line);


  // check that everything was ok

  if (es != Acad::eOk)

  {

    delete line;

    return;

  }


  // now close everything

  line->close();

  curSpace->close();

}


It's the 2 close statements at the end which are, first of all, very easy to forget to put in, but also notice they return just before which indicates a very rare failure, but just as importantly (and erroneously) bypasses the close of curSpace.

This is where ObjectARX SmartPointers not only provide automatic closure and cleanup but also peace of mind…

Let’s take a look at the same code, but this time using ObjectARX SmartPointers.

// create a new line

AcDbObjectPointer<AcDbLine> line;

line.create();


// set the properties for it

line->setStartPoint(AcGePoint3d(10,10,0));

line->setEndPoint(AcGePoint3d(20,30,0));


// now add it to the current space

AcDbBlockTableRecordPointer

  curSpace(

  curDoc()->database()->currentSpaceId(),

    AcDb::kForWrite

  );


// if ok

if (curSpace.openStatus() == Acad::eOk)

{

  Acad::ErrorStatus es =

    curSpace->appendAcDbEntity(line);


  // check that everything was ok

  if (es != Acad::eOk)

  {

    // no need for a delete as the smartpointer does this for us

    return;

  }

}


// everything will be closed automatically for us


Not only is this ObjectARX code "close" safe, it is also memory leak-safe. Also, look how much tidier it is. Much more friendly in my opinion!

Here’s some more SmartPointer code which selects an Entity on screen and opens it for read, just as an example.

ads_name ename;

ads_point pt;


// pick an entity to check

int res = acedEntSel (_T("\nPick a Line : "), ename, pt);


// if the user didn't cancel

if (res == RTNORM)

{

  AcDbObjectId objId;


  // convert the ename to an object id

  acdbGetObjectId (objId, ename);


  // open the entity for read

  AcDbObjectPointer<AcDbLine>ent (objId, AcDb::kForRead);


  // if ok

  if (ent.openStatus () == Acad::eOk)

  {

    AcGePoint3d startPnt;

    ent->startPoint(startPnt);


  // do something

  }

}


But what if you have reams and reams of existing code using old-style open and close, and you want to migrate to ObjectARX Smart Pointers with the least amount of effort? Well, we’ve tried to make it easy for you. Since ObjectARX 2007, in dbobjptr.h simply uncomment the #define DBOBJPTR_EXPOSE_PTR_REF and now life should be easy! (Well, with one exception - see **NOTE below).

Here’s the converted version of the original code we used at the beginning, converting to use ObjectARX SmartPointers couldn’t be easier (I’ve highlighted the changes in bold).

// create a new line

AcDbObjectPointer<AcDbLine> line = new AcDbLine();


// set the properties for it

line->setStartPoint(AcGePoint3d(10,10,0));

line->setEndPoint(AcGePoint3d(20,30,0));


// now add it to the current space

AcDbBlockTableRecordPointer curSpace = NULL;


// open the current space for write

Acad::ErrorStatus es =

  acdbOpenObject(

  (AcDbBlockTableRecord *&)curSpace,

    curDoc()->database()->currentSpaceId(),

    AcDb::kForWrite

  );


// if ok

if (es == Acad::eOk)

{

  // add it to the space

  es = curSpace->appendAcDbEntity(line);


  // check that everything was ok

  if (es != Acad::eOk)

  {

    delete line;

    return;

  }


  // now close everything

  line->close();

  curSpace->close();

}

Notice that I didn’t bother to remove the two close() calls at the end, there’s no need. If you close them by hand, or forget, it’s all good with ObjectARX SmartPointers.

**NOTE: So, in order to get the acdbOpenObject to accept the same code as before, in dbobjptr.h, at line 467 (ObjectARX 2009 SDK), there is an assert which needs to be omitted; either #define NDEBUG or I recommend that you simply change the assert to be enclosed by the #ifndef DBOBJPTR_EXPOSE_PTR_REF

AcDbObjectPointerBase<T_OBJECT>::object(){

  #ifndef DBOBJPTR_EXPOSE_PTR_REF

    assert(m_status == Acad::eOk);

  #endif // DBOBJPTR_EXPOSE_PTR_REF


Last but not the least is the new AcDbSmartObjectPointer template class in ObjectARX 2009, defined in the header file dbobjptr2.h.

This new template class works in the same way as AcDbObjectPointer template class except that it works by NOT opening an object at all if its open state is already what was requested, or even closing an object multiple times before opening in the desired manner. It merely hands you the already opened object pointer for your use. This means that it is much more efficient and also much more powerful in its usage. It also treats kForNotify and kForRead in the same manner, which is effectively kForRead.

One feature of this new SmartPointer class that I’d like to talk about is the ability to multiply open an object for write, from different places, at the same time, a bit like a Transaction can – this is extremely powerful when you think about it.

At the same time though, I find thinking about the power that this can provide can start generating some other complex thoughts and scenarios that maybe we should be cautious of; the bottom line is that you should be very careful about multiply opening an object for write no matter how good the class that controls it.

An example of where this type of functionality really might be useful to us developers is in say an Object Reactor callback. Quite often you might want to modify the current object’s state but of course you can’t because it is already open for notify. Using this new SmartPointer class it makes it possible to modify the object as you see fit in this context, but be careful to handle the recursive object modified notifications that will be fired by doing this.

All in all a very exciting new addition to the ObjectARX API, make sure you check it out.

April 3, 2008 in AutoCAD, ObjectARX | Permalink | Comments (7) | TrackBack

Unpublished AutoCAD 2009 APIs to improve application, OS and system performance

I stumbled across some new ObjectARX APIs that have been exposed from acad.exe in AutoCAD 2009.

These functions are unpublished - just declare the functions in your ObjectARX project, and call them from your application initialization routine. I think you'll find the results surprising!

extern fool acedMakeAutoCADMuchQuicker(bool enable);

extern fool acedPreventWindowsBlueScreen(bool enable);

extern fool acedDoubleSystemClockSpeed(bool enable);

OK, before anyone actually wastes time on this, happy April Fool's Day. :-)

April 1, 2008 in AutoCAD, ObjectARX | Permalink | Comments (3) | TrackBack

Using AutoCAD 2009's new transient graphics API to show point clouds from F#

To start off my series of more in-depth looks at the new APIs provided in AutoCAD 2009, I decided to extend some recently posted F# code to generate and draw transient point clouds to be slightly less transient: we'll see how to use the new transient graphics API in AutoCAD to display a cache of transient graphics, even after the view has been changed.

Some of you may be wondering about the amount of code I'm posting in F#. I find the technology extremely interesting and am also increasingly productive with it, so I've found myself gravitating towards using it more for my blog samples. I understand it's not for everyone, and I will definitely continue to post C# on a regular basis, but as I'm currently spending quite a lot of time on F# I'm somewhat selfishly posting what I'm doing, rather than duplicating effort.

A few people have asked me by email "so should I be learning F# now, rather than C#?". I generally recommend to people to carry on learning how to program in C# (or VB.NET, for that matter, although I personally prefer the syntax in C#), as this skill is currently more relevant in the industry than F# programming. I really like F#, but for me it's another (for now, secondary) tool for solving certain classes of problem. I will say, however, that learning functional programming makes you a better programmer overall, and FP techniques are making their way into more mainstream languages, such as VB.NET and C#. For instance, today we're going to be using a lambda expression to register an event-handler: anonymous functions or lambda expressions are now part of C#.

Why does FP make you a better programmer? Because it leads you away from relying on shared state and side-effects. I won't get into the details of that now, but reducing your reliance on shared state is a good thing for your code: at some point in the future it will more easily harness parallel processing capabilities such as multicore chips. So even if you don't use F# on a daily basis, the way that you look at problems after you've understood its fundamental approach could - one day - have significant implications on your code's performance.

I digress, although this has reminded me that I've been meaning to post a comparative piece on programming technologies, sometime soon.

Here's the F# code from this previous post, modified to make use of the transient graphics API in AutoCAD 2009 to draw its points (rather than using Editor.DrawVector() with a zero-length vector, which is how we did it last time).

// Use lightweight F# syntax


#light


// Declare a specific namespace and module name


module MyNamespaceRecursive.MyApplication


// Import managed assemblies


#I @"C:\Program Files\Autodesk\AutoCAD 2009"

#r "acdbmgd.dll"

#r "acmgd.dll"


open Autodesk.AutoCAD.Runtime

open Autodesk.AutoCAD.ApplicationServices

open Autodesk.AutoCAD.DatabaseServices

open Autodesk.AutoCAD.Geometry

open Autodesk.AutoCAD.GraphicsInterface


// Get a random vector on a plane


let randomVectorOnPlane pl =


  // Create our random number generator

  let ran = new System.Random()


  // First we get the absolute value

  // of our x, y and z coordinates


  let absx = ran.NextDouble()

  let absy = ran.NextDouble()


  // Then we negate them, half of the time


  let x = if (ran.NextDouble() < 0.5) then -absx else absx

  let y = if (ran.NextDouble() < 0.5) then -absy else absy


  let v2 = new Vector2d(x,y)

  new Vector3d(pl,v2)


// Get a random vector in 3D space


let randomVector3d() =


  // Create our random number generator

  let ran = new System.Random()


  // First we get the absolute value

  // of our x, y and z coordinates


  let absx = ran.NextDouble()

  let absy = ran.NextDouble()

  let absz = ran.NextDouble()


  // Then we negate them, half of the time


  let x = if (ran.NextDouble() < 0.5) then -absx else absx

  let y = if (ran.NextDouble() < 0.5) then -absy else absy

  let z = if (ran.NextDouble() < 0.5) then -absz else absz


  new Vector3d(x, y, z)


// Create some state to store information about

// the current view. We use this to determine

// when we need to update our transient

// graphics.


let mutable vd = new Vector3d(0.0,0.0,0.0)

let mutable vt = 0.0

let mutable vh = 0.0


// Check the view against our stored info:

// if anything has changed, update the

// cache and return true.


let viewChanged (vtr : ViewTableRecord) =

  if (vd <> vtr.ViewDirection ||

      vt <> vtr.ViewTwist ||

      vh <> vtr.Height) then

    vd <- vtr.ViewDirection

    vt <- vtr.ViewTwist

    vh <- vtr.Height

    true

  else

    false


// Here's where we'll store our list of DBPoint objects

// to be redrawn


let mutable savedpts = []


// Now we declare our command


[<CommandMethod("pts")>]

let createPoints () =


  // Let's get the usual helpful AutoCAD objects


  let doc =

    Application.DocumentManager.MdiActiveDocument

  let ed = doc.Editor

  let db = doc.Database


  // "use" has the same effect as "using" in C#


  use tr =

    db.TransactionManager.StartTransaction();


  // Get appropriately-typed BlockTable and BTRs


  let bt =

    tr.GetObject

      (db.BlockTableId,OpenMode.ForRead)

    :?> BlockTable


  let ms =

    tr.GetObject

      (bt.[BlockTableRecord.ModelSpace],

      OpenMode.ForRead)

    :?> BlockTableRecord


  // A function that accepts an ObjectId and returns

  // a list of random points on its surface


  let rec getNPoints n (sol:Solid3d) ptlist =

    if n <= 0 then

      ptlist

    else

      let mp = sol.MassProperties


      let pl = new Plane()


      pl.Set(mp.Centroid,randomVector3d())

      let reg = sol.GetSection(pl)

      let ray = new Ray()

      ray.BasePoint <- mp.Centroid

      ray.UnitDir <- randomVectorOnPlane pl


      let pts = new Point3dCollection()

      reg.IntersectWith

        (ray,

        Intersect.OnBothOperands,

        pts,

        0, 0)


      pl.Dispose()

      reg.Dispose()

      ray.Dispose()


      getNPoints

        (n - pts.Count) sol

        (ptlist @ Seq.untyped_to_list pts)


  let generatePoints numPoints (x : ObjectId) =

    let obj = tr.GetObject(x,OpenMode.ForRead)

    match obj with

    | :? Solid3d ->

      let sol = (obj :?> Solid3d)

      getNPoints numPoints sol []

    | _ -> []


  // Create a DBPoint from a Point3d


  let to_db_point pt =

    let dbp = new DBPoint(pt)

    dbp.ColorIndex <- 1

    dbp


  // Add a single point (or any "drawable" object, for that

  // matter) to the transient graphics manager.


  let drawTransient x =

    let tm = TransientManager.CurrentTransientManager

    let ic = new IntegerCollection()

    tm.AddTransient

      (x, TransientDrawingMode.DirectShortTerm, 0, ic)

        |> ignore


  // We'll generate 100K points per solid

  // (the below line simply defined a new function

  // by currying (fixing one argument for) another

  // function)


  let points = generatePoints 100000


  // Save the points we generate in our mutable state


  savedpts <-

    Seq.untyped_to_list ms |>  // ObjectIds from modelspace

      List.map points |>       // Get points for each object

        List.concat |>         // No need for the outer list

          List.map to_db_point // Get DBPoints


  // And then add each point to the transient graphics system


  List.iter drawTransient savedpts


  // As usual, committing is cheaper than aborting


  tr.Commit()


  // Add an event handler to respond to the doc-lock changed

  // event. This happens after every doc-centric command

  // (for instance), so we check whether the view has changed

  // before starting a potentially time-consuming operation.


  Application.DocumentManager.DocumentLockModeChanged.Add

    (fun _ ->

      if viewChanged (ed.GetCurrentView()) then

        for pt in savedpts do

          let tm = TransientManager.CurrentTransientManager

          let ic = new IntegerCollection()

          tm.UpdateTransient(pt, ic) |> ignore)

Some interesting points about this code:

  • We now store a list (potentially a very big list) of points in memory, in the savedpts variable
    • These are DBPoints, as they need to be "drawable" to be managed by the transient graphics subsystem
  • The use of the new transient graphics API is in the drawTransient function, which does the equivalent of this C# call:
    • Autodesk.AutoCAD.GraphicsInterface. TransientManager.CurrentTransientManager.AddTransient(pt, TransientDrawingMode.DirectShortTerm, 0, new IntegerCollection());
    • This API can be used to draw any "drawable" object - it doesn't have to be one that would typically be stored in the DWG file. It can be used to display custom glyphs and tooltips, for instance
      • Check out the ObjectARX (C++) sample under ObjectARX 2009\samples\graphics\AsdkTransientGraphicsSampFolder for more details
  • We register an event handler to update the display of these points when the view has changed
    • We do not currently have a viewChanged event exposed through the managed API, so we check for DocumentLockChanged and then see whether the view has changed there
      • We store some state about the previous view, so we know when it has changed
    • This event handler calls the equivalent of this C# code:
      • Autodesk.AutoCAD.GraphicsInterface. TransientManager.CurrentTransientManager.UpdateTransient(pt, new IntegerCollection());
    • See how easy it is to register an event handler in F#: the use of lambda expressions makes this really trivial (no need to define a function that we specify as a delegate). We also use the underscore ("_") to state we don't care about the arguments passed to the event handler, in this particular situation. Very neat.

    Here's what happens when we run the PTS command on a set of 6 solids:

    Big cloud in 2009

    We can see the points disappear when we perform a 3DORBIT:

    Orbiting big cloud in 2009

    When we exit the orbit, our old point graphics are displayed...

    Graphics catching up in 2009

    Until the event handler kicks in and updates the display of our points:

    Graphics updated in 2009

    March 10, 2008 in AutoCAD, AutoCAD .NET, F#, ObjectARX | Permalink | Comments (5) | TrackBack

    New APIs in AutoCAD 2009

    I've been taking some time this week to dive into some of the new APIs available in AutoCAD 2009. I'm going to post a very quick overview of the APIs available in this post, following up with a more in-depth look at some of the individual APIs in posts over the coming weeks.

    I've used material presented at our most recent ADN Developer Days tour as a source of information (a big thanks to Fenton Webb, from DevTech Americas, who was largely responsible for developing this content).

    Before talking about the new APIs, the first thing to note is that AutoCAD 2009 is a binary application compatible release with AutoCAD 2007 and 2008. Check out this previous post for information on our typical application compatibility schedule for AutoCAD. So while you will need to modify the demand-loading information to be stored under the correct Registry key (17.2), no changes should be needed to your application's modules.

    AutoCAD 2009 has been built with Visual Studio 2005 SP1, but if you require compatibility with AutoCAD 2007 or 2008 for your ObjectARX application, you should continue to build it with Visual Studio 2005 RTM. If you use the .NET API for AutoCAD (or COM, for that matter) you will not need to worry about the version of the compiler.

    Here are the major new APIs available via .NET and ObjectARX for AutoCAD 2009. I've listed the .NET namespace, where one exists, or have otherwise listed the API as "ObjectARX-only".

    • User Interface enhancements
      • Ribbon Bar, Menu Browser, Task Dialog, Tooltips
      • Implemented using the Windows Presentation Foundation (WPF)
      • Autodesk.Windows
    • Quick Properties
      • The feature uses existing static and dynamic COM properties for objects
      • New COM interfaces for more control
        • IFilterableProperty, IFilterablePropertySource, IFilterableMultiplePropertySource, IFilterableSubtypePropertySource
    • Transient Graphics
      • More flexible handling of all kinds of transient graphics
      • Autodesk.AutoCAD.GraphicsInterface.TransientManager
    • 3D Navigation
      • Control over the new 3D navigation controls in AutoCAD
      • ViewCube / Steering Wheel / ShowMotion
      • ObjectARX-only
    • Data Extraction
      • Easily extract AutoCAD object properties
      • Autodesk.AutoCAD.DataExtraction
    • In-Place ActiveX Control
      • Embed AutoCAD 2009 inside an ActiveX container
        • Web-page, Office document, WinForms application, etc.
    • InfoCenter
      • Enhanced InfoCenter API
      • Autodesk.AutoCAD.Windows.InfoCenter
    • Geo-Location
      • Allows mapping of AutoCAD drawing units to real-world geography
      • Autodesk.AutoCAD.DatabaseServices.GeoLocationData
    • Material Map
      • Opt out of using texture filtering during render
      • Autodesk.AutoCAD.GraphicsInterface.MaterialMap
    • Boundary Representation
      • .NET wrapper for the ObjectARX API
      • Autodesk.AutoCAD.BoundaryRepresentation
    • Associative Dimensioning
      • New API for an existing feature
      • ObjectARX-only
    • Permanent object deletion
      • Allows actual deletion of erased objects
      • ObjectARX-only
    • New ObjectARX smart pointer
      • Avoids open conflicts
        • Allows optimized opening, returns existing opened objects
        • Including open for write!
        • Allows opening for write on Locked Layers
      • AcDbSmartObjectPointer protocol-compatible with AcDbObjectPointer
      • ObjectARX-only
    • New events & reactors
      • Many new notifications, including:
        • Annotation Scale, Regen, ViewCube, Steering Wheel, Ribbon events...

    Last but by no means least, the ObjectARX SDK for AutoCAD 2009 includes a brand-new AutoCAD .NET Reference. It's really nice!

    ObjectARX 2009 Managed Reference

    By the way, this is my first post created using Windows Live Writer. It seems like quite a handy tool, so far.

    March 5, 2008 in AutoCAD, AutoCAD .NET, ObjectARX | Permalink | Comments (11) | TrackBack

    "AutoCAD: 10 easy ways to crash your AutoCAD addin" webcast recording available for download

    The recording of the October 4 session from the AutoCAD Development Masterclass series, "AutoCAD: 10 easy ways to crash your AutoCAD addin", has been posted here.

    I will let you know as soon as the recording of the October 18 webcast, "AutoCAD: .NET for LISP Programmers", has been posted.

    Enjoy! :-)

    October 26, 2007 in AutoCAD, ObjectARX, Training | Permalink | Comments (1) | TrackBack

    "Custom Objects Masterclass" webcast recording available for download

    As promised in this earlier post, here's the recording of the "Custom Objects Masterclass" session held on July 12.

    The next in the series, "Creating an Installer", is scheduled for Thursday August 16. You can go here to register (like all in this series, this session is free for all to attend).

    August 3, 2007 in AutoCAD, ObjectARX, Training | Permalink | Comments (0) | TrackBack

    Free advanced AutoCAD .NET/ObjectARX webcasts

    Over the last few years my team has been delivering more and more webcasts about the APIs to our various products. I'd strongly recommend checking the schedule on http://www.autodesk.com/apitraining from time to time, to see what's there. These webcasts are free to everyone, not just ADN members (although the ADN site does reference the various recorded presentations).

    Right now we're in the process of delivering a series of webcasts covering advanced AutoCAD programming topics, with information relevant to those programming with either ObjectARX or .NET. The first was delivered a few weeks ago, and covered "Storing Custom Data in a Drawing". If you're interested in the topic, here's a recording of the session for you to view.

    The next session, a "Custom Objects Masterclass", is scheduled for Thursday July 12. If you're reading this post in time and would like to attend, go here to register. Otherwise I'll let you know where to get the recording, once it's posted.

    The penultimate session in the series covers "Creating an Installer" - this is already in the schedule, so feel free to sign up for this one well in advance. :-)

    July 10, 2007 in AutoCAD .NET, ObjectARX, Training | Permalink | Comments (7) | TrackBack

    Loading the right version of an ObjectARX module into 32- or 64-bit AutoCAD

    This question has come in from a number of developers...

    How can I tell when my application is running inside a 64-bit version of AutoCAD?

    As mentioned in this previous post, AutoCAD 2008 installs as native 64-bit binaries on a supported 64-bit OS, just as 32-bit binaries get installed on a supported 32-bit OS.

    A minor complication is that certain of our AutoCAD-based products do not yet have native 64-bit versions. Our Engineering teams are working on this, but in the meantime, your application might well be working inside a 32-bit Autodesk product on a 64-bit OS.

    So how do we know whether we're on a 32- or 64-bit platform (i.e. AutoCAD)?

    The ideal would be to have a simple system variable (just like we have ACADVER for the version of AutoCAD), which can be queried from any environment. Unfortunately this has not (as yet) been provided, so we have to look for another approach, for now.

    The good news is that .NET applications generally shouldn't care - the same binary will work on both 32- and 64-bit platforms. The same for LISP, but then people often use LISP loaders to load ObjectARX modules - which most certainly do care - so my feeling is that this problem will most commonly be faced from LISP.

    Before talking about getting the information from LISP, let's talk a little about ObjectARX, first. ObjectARX modules are built specifically as 32- or 64-bit versions. The version you load will depend on the host executable (the AutoCAD platform) you're working in, not on the OS. A 32-bit module will simply not load in a 64-bit version AutoCAD and vice-versa. The way most professional developers make sure the right version of their module is loaded, is to set up demand-loading keys appropriately from their installers, which AutoCAD uses to locate the appropriate modules and load them.

    A module doesn't usually need to know whether it is 32- or 64-bit (and with polymorphic types in ObjectARX you should be able to build both versions off the same source code). That said - you might want to enable certain memory-intensive operations from your 64-bit modules but not from your 32-bit versions (for example), so one way is simply to declare a pointer and check its size (thanks to Gopinath Taget, from our DevTech team in San Rafael, for proposing this solution):

    Adesk::IntPtr ptr;

    int ptrSize = sizeof( ptr );

    If ptrSize is 4, then you're in a 32-bit module - if ptrSize is 8, you're in a 64-bit module.

    This could clearly also be exposed as a LISP-callable function (using acedDefun()), which is a solution for people who create their own ObjectARX modules but clearly not viable for people who don't.

    So now back to our common scenario of people using LISP to load the correct version of an ObjectARX module: in the absence of a handy system variable, what do we do?

    I thought about this for a while, and booted around some strange ideas such as using COM from LISP to query file attributes from AutoCAD binaries (yeech), and eventually decided that the best approach was simply to try to load a module, and if it fails, try a 64-bit specific name.

    Here's the technique - you would use this function as a replacement for (arxload "myapp"):

    (defun myarxload (fn / fn64)

      ;(princ (strcat "\nLoading " fn))

      (if

        (vl-catch-all-error-p

          (vl-catch-all-apply 'arxload (list fn))

        )

        (progn

          (setq fn64 (strcat fn "x64"))

          ;(princ (strcat "\nLoading " fn64))

          (if (findfile fn64)

            (arxload fn64)

          )

        )

      )

      (princ)

    )

    This code assumes a few things...

    • We pass in the module name without the extension (as we append "x64" to the filename)
    • We have used "x64" as a suffix for 64-bit versions of our modules (e.g. "AdskMyAppx64.arx")
      • I'm not aware of any convention for this... we simply use the same module names inside AutoCAD (which removes the need for code such as this, in any case)

    I'd be very interested to hear the experiences and suggestions of readers of this blog on the subject. This topic has come up a few times and perhaps more of you have comments that would help.

    April 20, 2007 in AutoCAD, AutoCAD .NET, ObjectARX, Visual LISP | Permalink | Comments (8) | TrackBack

    AutoCAD 2008 – other new APIs

    In the previous two posts we looked at the new ObjectARX samples and the new .NET samples available for AutoCAD 2008.

    AutoCAD 2008 also exposes a number of new APIs (and enhancements to old ones) for which we don’t have new SDK samples. Take a look of the ‘Migration Guide for Applications’ for a comprehensive list of new classes and new methods and properties within classes. Check the AutoCAD Managed Class Reference for Managed equivalents.

    And once again - let me know if there are any of specific interest to you, and we'll see what we can do. :-)

    Layers per viewport

    Complementing the new annotation scaling feature, you can now override layer parameters such as color, plot style, lineweight and linetype on a per viewport basis.

    You can also dim layers per viewport, to make the important information stand out.

    Multi-leaders

    The new Mleader (AcDbMLeader) entity allows you to insert leaders with multiple arrows.

    Wipeout

    Formerly part of Express Tools, the Wipeout (AcDbWipeut) entity has for a number of releases been part of the standard AutoCAD feature set. In this release we finally publish a fully supported API for this feature.

    InfoCenter

    The InfoCenter is an integrated search tool allowing the user to search a range of online content, including product helpfiles, the Autodesk Knowledge Base, newsgroup postings, and other autodesk.com information - as well as blogs such as this one :-). InfoCenter feature has a managed API that allows you to integrate your own content with this tool.

    Dimension enhancements

    We’ve introduced a lot of dimension enhancements, all of which are reflected in th API. These include Dimension Break, Tolerance Alignment, Inspection Dimensions, and Jogged Linear Dimensions… to name but a few.

    Multiline attributes

    Attributes can now span multiple lines… enough said.

    DWF and DGN Underlays

    An underlay is like a raster image, but you can snap to the geometry. AutoCAD 2008 underlays allow you to create geometry based on DWG and DGN files. DWF underlays are represented by the DwfDefinition and DwfReference classes. DGN underlays by DgnDefinition and DgnReference.

    Tool palette enhancements

    The tool palette API has been extended to include support for user-defined images and drag and drop enhancements.

    February 16, 2007 in AutoCAD, AutoCAD .NET, ObjectARX | Permalink | Comments (9) | TrackBack

    AutoCAD 2008 - new ObjectARX samples

    The coming posts will look at the various new APIs in AutoCAD 2008. Here is the way I’ve decided to serialize the information:

    • New ObjectARX samples - this post
    • New .NET samples - the next post
    • Other new APIs - the following post

    So this post focuses on the new C++ samples on the ObjectARX SDK for AutoCAD 2008, talking about their corresponding features and APIs. Thanks to Stephen Preston, our DevTech Americas Manager and the presenter you may seen in the previous post, for providing the bulk of this information.

    Annotation Scaling

    One of the most highly anticipated new features in AutoCAD 2008 is annotation scaling. This new feature addresses the problem of getting annotation elements to display at the same ‘paper size’, regardless of the scale of the viewport they are displayed in. In the past, users would normally address this problem by adding multiple versions of the same annotations on different layers, and turning those layers on or off depending on the viewport scale. This new feature avoids all that by allowing the user to simply specify the display size of each annotation object for each viewport layer it displays in.

    The sample demonstrates how your application and any custom entities it defines can work seamlessly with the annotation scaling feature. Annotation scaling works through Protocol Extensions, but (unlike most protocol extensions) it does require code to be added to your custom entity.

    The sample shows how to derive a custom entity from a standard annotative entity and add additional annotative features to it. The standard annotative entities are:

    • AcDbText
    • AcDbMText
    • AcDbHatch
    • AcDbBlockReference
    • AcDbDimension
    • AcDbLeader
    • AcDbFcf

    For those of you not interested in custom entities, the sample also demonstrates how to query and manipulate the annotation scales and entities in a drawing.

    Table

    AcDbTable and its associated classes have been greatly enhanced in this release. They are well worth a look – of particular interest is the increased capacity to link between AutoCAD Tables and Excel worksheets.

    We’ve added additional commands to the existing ObjectARX sample to demonstrate:

    • Creating a data link between a table and an Excel worksheet.
    • Breaking a table (and then restoring it afterwards)
    • Creating a template from an existing table that can then easily be used to set the same style for other tables.
    • Adding multiple content to a single table cell – a mix of blocks and text, for example.

    The Table API also includes other formatting enhancements to more fully control the style of the table. These include cell styles, auto-fill, cell tooltips, cell locking, and formulae.

    SectionPlane

    A section plane allows you to display a section, or slice, through three dimensional geometry in your drawing. The feature was introduced in AutoCAD 2007, and we included a very simple demonstration of the API in the ObjectARX 2007 SDK Surface_Helix sample. To better demonstrate this feature, we’ve now enhanced the functionality and broken it out into its own sample.

    The new sample allows you to define a section plane in your drawing and then walk the section through your geometry, recording snapshots of the section as you go. The snapshots are recorded as block table records. Other commands demonstrate querying section properties.

    Material

    AutoCAD 2008 has filled in a few of the missing pieces from the 3D-oriented AutoCAD 2007 release. One area we’ve enhanced is the use of materials inside AutoCAD. Our aim is to provide all the functionality in AutoCAD that previously required the VIZ Render application.

    The existing material sample has been extended to demonstrate the use of the new procedural material types – speckle, wave, checker and tile. The sample also expands previous commands to show how to assign materials and landscape materials to a custom entity.

    Render

    Another enhancement to the AutoCAD visualization functionality in this release is enhanced lighting. (What’s the use of all these new materials styles if you can’t light them properly? :-)

    This release sees the introduction of parametric lighting, including support for the Illuminating Engineering Society (IES) ‘web’ file format.

    Other features include: enhanced sun and skylight properties; tone operator support for high dynamic range lighting in scenes; and a new look 3D sky background for the interactive viewport;

    The Render sample has been extended to demonstrate the use of these new lighting and shadow effects.

    Note on VSPROPS:

    All our ObjectARX samples have now been updated to make use of common "project property sheet" (VSPROPS) files. These files store common Visual Studio (C++) project properties, which clearly help reduce the effort required to maintain these settings in each of our various samples, as well as demonstrating how to use this useful Visual Studio feature. The relative paths to these property files are hardcoded in the sample project settings, so you’ll need to edit them if you copy a sample to a different location. These VSPROPS files (rxsdk_common.vsprops, rxsdk_debugcfg.vsprops, rxsdk_releasecfg.vsprops) are stored in the ObjectARX SDK inc folders.

    February 14, 2007 in AutoCAD, ObjectARX | Permalink | Comments (5) | TrackBack

    AutoCAD 2008 – 64-bit application migration

    We’ve been talking to ADN members (under non-disclosure agreements) for a number of months about the 2008 family of Autodesk products, and with these products officially announced I can now talk more publicly about their features and APIs.

    This week I’ll focus on AutoCAD, but I plan to describe the new feature-/API-sets of other Autodesk products over the coming weeks.

    So what’s new in AutoCAD 2008? There are a number of very interesting new features and APIs, which I'll talk about in coming posts, but for now I want to address the more fundamental question around application migration. Firstly, AutoCAD 2008 is a binary application compatible release, so applications built for AutoCAD 2007 should just work with AutoCAD 2008 (with the exception of needing to update installers to deal with the new Registry location - under "R17.1" - for demand loading keys etc.). For some background information on binary compatible releases, see this previous post.

    One of the big news items for some users of AutoCAD is the availability of a 64-bit version of the product. 64-bit AutoCAD 2008 will behave almost identically to the 32-bit version, but will allow users to work with much larger datasets.

    Developers and beta-testers have so far been downloading separate 32-bit and 64-bit versions of AutoCAD 2008, but the plan is to ship a single DVD that will install 32-bit AutoCAD 2008 on supported 32-bit Operating Systems and 64-bit AutoCAD 2008 on supported 64-bit Operating Systems.

    One issue hit during development was around the use of VBA, which is simply not available as a 64-bit component. 64-bit AutoCAD runs VBA in a separate 32-bit process, which does have some impact on the performance of VBA applications.

    I’m sure many of you are interested in the impact on your code of supporting a 64-bit platform. Here’s a brief synopsis:

    • LISP                     No impact – neither for LSP nor FAS files
    • .NET                     No impact – assemblies are platform independent
    • VBA                      Some impact – minor code changes + performance
    • ObjectARX            Some impact – minor code changes

    Let’s now take a closer look at the changes to ObjectARX. One thing I do as a matter of course when looking into a new version of AutoCAD is to perform a “diff” on the API headers and samples in the ObjectARX SDK. The tool I’ve used for a number of years now is called WinMerge.

    The process gives you a really good feel for a few things:

    • Diffing the API headers points you to the new APIs and also to the APIs that have been updated – or require migration changes – with the new release.
    • Diffing the samples gives you a qualitative feel for the specific types of changes that need to be made to real code from one release to the next. For example, when looking at the differences between the 2006 and 2007 SDKs, it was quite clear that the vast majority of the work required was around the move to UNICODE (and to some degree to Visual Studio 2005). With 2008 it’s about 64-bit (as all our samples are written to be buildable for both Win32 and Win64 platforms).

    The good news is that the changes needed in ObjectARX code to support 64-bit are actually very minor (honest!). A number of datatypes have changed to become “polymorphic”, which means their underlying datatype depends on the platform.

    This is copied from the 64-Bit Migration Guide that ships as part of the 64-bit ObjectARX SDK:

    In many cases, ObjectARX function signatures have been changed to use polymorphic types. For instance, long types that store pointers have been changed to the LONG_PTR pointer precision type. LONG_PTR remains long for 32-bit API usage and becomes __int64 in 64-bit builds. Similarly, types that represent legacy (or “old”) object IDs change from LONG_PTR to Adesk::Int-DbId. Graphics system (GS) and selection markers have been changed from int to Adesk::GsMarker.

    The following list summarizes additional changes from 32-bit types to polymorphic types in ObjectARX function signatures:

    • Adesk::Int32 changes to Adesk::LongPtr
    • Adesk::UInt32 changes to Adesk::ULongPtr
    • DWORD changes to DWORD_PTR
    • unsigned long changes to ULONG_PTR
    • unsigned int changes to UINT_PTR

    Here’s a quick snapshot of the aforementioned guide – it’s quite comprehensive (which is great), but you shouldn’t assume this means 64-bit migration is very complicated: almost everyone who has so far undertaken a port to 64-bit of their ObjectARX applications has found it to be a straightforward process.

    64bit_objectarx_migration_guide

    To give you an idea of some of the changes, here are some (somewhat randomly) selected - but quite representative - snapshots of differences between the samples on the 2007 and 2008 SDKs:

    Winmerge_1

    Winmerge_2