2015 New API Usage : AcGiGeometry::edge
In this blog post , I will illustrate a simple usage of our new AutoCAD2015 APIAcGiGeometry::edge(const AcArray<AcGeCurve2d*>& edges) this API essentially defines a boundary of a fill ,can be used to display hatch – either pattern based , or solid hatches or gradients.
In my example ,I have created a custom entity deriving from AcDbPolyline and drawing a hatch in my graphics database, to define the boundary of my hatch. I have extracted line segments from my custom entity and passing those to edge API.
Code Snippet:
Adesk::Boolean ADSKMyEntity::subWorldDraw (AcGiWorldDraw *pWd)
{
assertReadEnabled () ;
/*Purpose is to diplay the hatch using new API AcGiGeometry::edge
on the my entity[ADSKMyEntity] deriving from polyline */
Adesk::Boolean result = Adesk::kFalse;
AcArray<AcGeCurve2d*> geCurves;
double hatchDev = 0.0;
hatchDev =
pWd->deviation(kAcGiMaxDevForCurve, AcGePoint3d::kOrigin);
AcGiFill acgiSolidFill;
acgiSolidFill.setDeviation(hatchDev);
int nSegs = -1;
AcGeLineSeg2d line;
AcGeLineSeg2d *pLine;
nSegs = this->numVerts() ;
for(int i = 0; i < nSegs; i++)
{
if(this->segType(i) == AcDbPolyline::kLine)
{
this->getLineSegAt(i, line);
pLine = new AcGeLineSeg2d(line);
geCurves.append(pLine);
}
}
pWd->subEntityTraits().setFill(&acgiSolidFill);
/* geCurves represents boundary of hatch*/
result = pWd->geometry().edge(geCurves);
return result;
}
{
assertReadEnabled () ;
/*Purpose is to diplay the hatch using new API AcGiGeometry::edge
on the my entity[ADSKMyEntity] deriving from polyline */
Adesk::Boolean result = Adesk::kFalse;
AcArray<AcGeCurve2d*> geCurves;
double hatchDev = 0.0;
hatchDev =
pWd->deviation(kAcGiMaxDevForCurve, AcGePoint3d::kOrigin);
AcGiFill acgiSolidFill;
acgiSolidFill.setDeviation(hatchDev);
int nSegs = -1;
AcGeLineSeg2d line;
AcGeLineSeg2d *pLine;
nSegs = this->numVerts() ;
for(int i = 0; i < nSegs; i++)
{
if(this->segType(i) == AcDbPolyline::kLine)
{
this->getLineSegAt(i, line);
pLine = new AcGeLineSeg2d(line);
geCurves.append(pLine);
}
}
pWd->subEntityTraits().setFill(&acgiSolidFill);
/* geCurves represents boundary of hatch*/
result = pWd->geometry().edge(geCurves);
return result;
}
You can download full sample project ADSKEntity
05/16/2014
We're hiring
The ADN team is hiring an API evangelist based in our San Francisco office. Please spread the word. Experience with AutoCAD APIs - or any other Autodesk technology - is not required (but would be a bonus).
Autodesk is hiring an API evangelist! If you’re a software engineer who’s enthusiastic about new technologies, enjoys interacting with others and sharing this enthusiasm, and loves to evangelize code –then this is the job for you!
Autodesk is in the process of launching a large number of new cloud services – all of which are designed as platforms for developers to build upon. We need to tell the world about these new APIs. As the successful candidate, you will join the Developer Technical Services team (our developer evangelist team at Autodesk, and part of our Cloud Platforms Division).
Responsibilities:
- Working directly with third party developers to help them solve their problems using our APIs.
- Acting as developer advocate to our internal software development teams – helping them understand the APIs our developer community needs to be successful.
- Evangelizing our new technology through conferences, hackathons, meetups, blogging, webcasts, social media, and whatever other communication channels you dream up.
To be successful you will have the following attributes:
- You’re a gifted programmer who is excited about learning new technology and teaching others. (You already know deep in your heart if you’re a natural programmer – if you don’t then you’re not).
- You have a good grounding in web programming technologies, including JavaScript, REST and HTML5.
- You have a good grounding in, or are willing to learn, mobile platform programming technologies, such as Java and Objective-C.
- You’re intelligent and inquisitive, and enjoy solving problems.
- You enjoy interacting with people – including one-on-one conversations and presenting to large audiences at conferences.
- You enjoy writing – including blogging, tweeting, and other social media outlets.
05/15/2014
Zoom to a Window in Editor using CommandASync
In this post, I will illustrate a sample based on AutoCAD 2015 API
Editor.CommandAsync.
Problem: Can I zoom to particular window in an Editor as long as I press esc or cancel to quit?
Answer: Yes, with help of CommandAsync, you can achieve this task.
#region "send Zoom command by callback function"
private static bool ZoomExit = false;
//declare the callback delegation
delegate void Del();
private static Del _actionCompletedDelegate;
// Exit function,check if Zoom command is esc\cancelled
static void
MdiActiveDocument_CommandCancelled(object sender,CommandEventArgs e)
{
ZoomExit = true;
}
[CommandMethod("TestZoom")]
public static void TestZoom()
{
var ed = Application.DocumentManager.MdiActiveDocument.Editor;
var doc = Application.DocumentManager.MdiActiveDocument;
//esc event
doc.CommandCancelled += MdiActiveDocument_CommandCancelled;
// start Zoom command
Editor.CommandResult cmdResult1 =
ed.CommandAsync(new object[]{
"_.ZOOM", Editor.PauseToken, Editor.PauseToken});
// delegate callback function, wait for interaction ends
_actionCompletedDelegate = new Del(CreateZoomAsyncCallback);
cmdResult1.OnCompleted(new Action(_actionCompletedDelegate));
ZoomExit = false;
}
// callback function
public static void CreateZoomAsyncCallback()
{
var ed = Application.DocumentManager.MdiActiveDocument.Editor;
//if Zoom command is running
if (!ZoomExit)
{
// AutoCAD hands over to the callback function
Editor.CommandResult cmdResult1 =
ed.CommandAsync(new object[]{
"_.ZOOM", Editor.PauseToken, Editor.PauseToken});
// delegate callback function, wait for interaction ends
_actionCompletedDelegate = new Del(CreateZoomAsyncCallback);
cmdResult1.OnCompleted(new Action(_actionCompletedDelegate));
}
else
{
ed.WriteMessage("Zoom Exit");
return;
}
}
#endregion
private static bool ZoomExit = false;
//declare the callback delegation
delegate void Del();
private static Del _actionCompletedDelegate;
// Exit function,check if Zoom command is esc\cancelled
static void
MdiActiveDocument_CommandCancelled(object sender,CommandEventArgs e)
{
ZoomExit = true;
}
[CommandMethod("TestZoom")]
public static void TestZoom()
{
var ed = Application.DocumentManager.MdiActiveDocument.Editor;
var doc = Application.DocumentManager.MdiActiveDocument;
//esc event
doc.CommandCancelled += MdiActiveDocument_CommandCancelled;
// start Zoom command
Editor.CommandResult cmdResult1 =
ed.CommandAsync(new object[]{
"_.ZOOM", Editor.PauseToken, Editor.PauseToken});
// delegate callback function, wait for interaction ends
_actionCompletedDelegate = new Del(CreateZoomAsyncCallback);
cmdResult1.OnCompleted(new Action(_actionCompletedDelegate));
ZoomExit = false;
}
// callback function
public static void CreateZoomAsyncCallback()
{
var ed = Application.DocumentManager.MdiActiveDocument.Editor;
//if Zoom command is running
if (!ZoomExit)
{
// AutoCAD hands over to the callback function
Editor.CommandResult cmdResult1 =
ed.CommandAsync(new object[]{
"_.ZOOM", Editor.PauseToken, Editor.PauseToken});
// delegate callback function, wait for interaction ends
_actionCompletedDelegate = new Del(CreateZoomAsyncCallback);
cmdResult1.OnCompleted(new Action(_actionCompletedDelegate));
}
else
{
ed.WriteMessage("Zoom Exit");
return;
}
}
#endregion
05/13/2014
Autodesk Exchange Apps Webinar May 22nd: Learn about exciting new features that bring new opportunities
Without a doubt, Autodesk Exchange Apps is now the best and easiest way for developers to reach Autodesk customers. With over 1,860,000 visitors and over 620,000 downloads, customers continue to demonstrate how much they have come to rely upon Autodesk Exchange Apps to find the tools that help increase their productivity.
With 18 Autodesk Exchange Apps stores now up and riunning and our recent and upcoming enhancements, there is opportunity for any type – and price – of app. Exchange Apps now offers multiple ways of delivering apps to customers:
- Desktop apps
- Web services
- Give-aways to generate leads for your development services
- High price, mid-range, low-priced per unit or monthly subscription
If you develop apps but haven't yet put your toe in the water with Exchange Apps, the Autodesk Developer Network (ADN) team is ready to help you.
You're invited to attend a webinar on May 22nd, hosted by Jim Quanci and Stephen Preston.
As they present and demo the latest trends and features, you'll learn how you can leverage this growing platform, publisher and customer community. You'll learn the tricks of the trade when publishing on Exchange Apps, get ideas on how to be successful and learn about the ability to expand your geographic reach by publishing localised apps in addition to English language ones.
Here's what you need to know:
Webinar details:
- Date: Thursday, May 22nd, 2014
- Time: 8 a.m. PDT – 11 a.m. EDT – 4 p.m. BST – 5 p.m. CET
- Duration: Approximately one hour
- Open to anyone interested in publishing apps on Autodesk Exchange Apps
Registration: Reserve your place by May 20th by sending an email to adn-training-worldwide@autodesk.com with 'Exchange Apps webinar' as the subject. Make sure you include:
- Your full name
- Email address
- Company name
If you are interested in the webinar but time zones or work commitments prevent you from attending, we invite you to register anyway, so that we can send you the link to the recording after the event.
Note: If you want a head start in learning how to publish apps, visit www.autodesk.com/developapps. If you have any questions, send an email to appsinfo@autodesk.com.
05/09/2014
Autodesk University Call for Proposals
In case you missed the announcement, here is a reminder that the AU Call for Proposals is now open. You have until May 23rd to submit your proposa for a class, lab, panel or roundtable session. Click on the image below to go to the Call for Proposals website.
05/01/2014
Non-DWG window in AutoCAD 2015 using .Net
AutoCAD 2015 enables the creation of Non-DWG document window. The Non-DWG document window appears as a tab just as any other drawing window.
In this blog post, I have attached a C# project to create a Non-DWG document window and demonstrate its usage.
To try it :
1. Build the sample project using Visual Studio 2012 with .Net framework set to 4.5.
2. Start AutoCAD 2015 and netload the dll.
3. Run "MyWnd" command. This command creates a Non-DWG document window that accepts user input for the radius of a smiley.
4. Create another drawing and run the "InsertSmiley" command. This command creates a smiley based on the radius value provided in the Non-DWG document window.
Now, here is a brief description of the steps to create a Non-DWG document window using .Net :
Step-1. Create a WPF usercontrol and customize it as you would create it usually.
Step-2. Create a custom document class. This class will be used to hold the data that are specific to this document window.
Step-3. Create a custom document window class derived from WPFDocumentWindow.
- Override the "OnCreate" method to know when the document window is created.
- Override the "OnLoad" method to associate the custom document with our document window class
- Override the "OnActivate" method to know when the document window gets activated.
Step-4. Create an instance of the custom document window class and add it to the DocumentWindowCollection using Application.DocumentWindowCollection.AddDocumentWindow.
In the attached sample, the steps to associate a custom document have been commented. AutoCAD 2015 at present becomes unstable if a custom document is associated with the custom document window. This behavior has been logged in our internal database for our engineering team to analyze.
So the attached sample project retrieves the document data by directly accessing the usercontrol for the "InsertSmiley" command to access.
Here is the sample project :
Coordinates of Points in a Point Cloud entity
For a PointCloud entity created using a PCG file, a simple way to get the coordinates of the points would be insert a spatial filter using the "acdbModifyPointCloudDataView" method. For the PointCloud entity created using RCP file, the way to insert a spatial filter is to use the "AcDbPointCloudEx::addSpatialFilter" method. While creating a spatial filter would still provide access to the point coordinates, the other method is to use the "AcDbPointCloudEx::traverseAllPointData" method.
Here is a sample code to identify the coordinates of the point using the "traverseAllPointData" method :
#include "AcPointCloud.h"
#include "AcDbPointCloudEx.h"
#include "AcDbPointCloudApi.h"
class MyPointCloudProcessor
: public IAcDbPointCloudPointProcessor
{
public:
MyPointCloudProcessor(){}
virtual ~MyPointCloudProcessor(){}
virtual ProcessSate process(
const IAcDbPointCloudDataBuffer* buffer)
{
const AcGePoint3d *pts = buffer->points();
for(int cnt = 0; cnt < buffer->numPoints(); cnt++)
{
AcGePoint3d pt = pts[cnt];
// Get the pt coordinates
}
return ProcessSate::Continue;
}
};
static void AdskMyTestCommand()
{
ads_point pt;
ads_name name;
if (acedEntSel
( L"Select a point cloud",
name, pt) != RTNORM)
return;
AcDbObjectId id;
if (acdbGetObjectId(id, name) != Acad::eOk)
return;
AcDbEntityPointer pEntity(id, AcDb::kForWrite);
if (pEntity.openStatus() != Acad::eOk)
return;
AcDbPointCloudEx *pPtCloud
= AcDbPointCloudEx::cast(pEntity);
if(pPtCloud == NULL)
return;
MyPointCloudProcessor *pPCProcessor
= new MyPointCloudProcessor();
// The last parameter is the Level of Detail.
// There is currently no way to get the maximum LOD value
// from a pointcloud entity.
// You can pass a value between 1 and 100 depending
// on the Level of detail required.
pPtCloud->traverseAllPointData(pPCProcessor, NULL,
IAcDbPointCloudDataBuffer::DataType::kColor, 2);
if(pPCProcessor != NULL)
{
delete pPCProcessor;
pPCProcessor = NULL;
}
}
#include "AcDbPointCloudEx.h"
#include "AcDbPointCloudApi.h"
class MyPointCloudProcessor
: public IAcDbPointCloudPointProcessor
{
public:
MyPointCloudProcessor(){}
virtual ~MyPointCloudProcessor(){}
virtual ProcessSate process(
const IAcDbPointCloudDataBuffer* buffer)
{
const AcGePoint3d *pts = buffer->points();
for(int cnt = 0; cnt < buffer->numPoints(); cnt++)
{
AcGePoint3d pt = pts[cnt];
// Get the pt coordinates
}
return ProcessSate::Continue;
}
};
static void AdskMyTestCommand()
{
ads_point pt;
ads_name name;
if (acedEntSel
( L"Select a point cloud",
name, pt) != RTNORM)
return;
AcDbObjectId id;
if (acdbGetObjectId(id, name) != Acad::eOk)
return;
AcDbEntityPointer pEntity(id, AcDb::kForWrite);
if (pEntity.openStatus() != Acad::eOk)
return;
AcDbPointCloudEx *pPtCloud
= AcDbPointCloudEx::cast(pEntity);
if(pPtCloud == NULL)
return;
MyPointCloudProcessor *pPCProcessor
= new MyPointCloudProcessor();
// The last parameter is the Level of Detail.
// There is currently no way to get the maximum LOD value
// from a pointcloud entity.
// You can pass a value between 1 and 100 depending
// on the Level of detail required.
pPtCloud->traverseAllPointData(pPCProcessor, NULL,
IAcDbPointCloudDataBuffer::DataType::kColor, 2);
if(pPCProcessor != NULL)
{
delete pPCProcessor;
pPCProcessor = NULL;
}
}
Recognising Cancel when using acedCommandC
Sending commands to AutoCAD command line now has two variants of the earlier acedCommand method. The acedCommandS is simpler to use and suitable when all the parameters (a.k.a tokens) that are required by AutoCAD to complete the command execution are known without a need for user input. When using acedCommandS by providing all the parameters, there is no possibility of cancelling the command.
acedCommandC is to be used when you need AutoCAD to pause for some user input while is command is run by AutoCAD. In this case, there is a possibility of user cancelling the command without providing the input. To identify this condition, here is a code snippet that uses the "acedCmdCWasCancelled" and "acedCallBackOnCancel" methods. Also, due to the asynchronous nature of acedCommandC, the completion of the command can only be identified from the callback method provided to acedCommandC as in this code snippet.
#include "acedCmdNF.h"
static void AdskMyTestCommand()
{
ads_point pt1;
int rt = ads_getpoint(
NULL,
_T("\nSelect first point: "), pt1);
int rs = acedCommandC
(
&MyCallback,
NULL,
RTSTR,
_T("_line"),
RT3DPOINT,
pt1,
RTNONE
);
acutPrintf(ACRX_T("\nAfter acedCommandC call.
acedCommandC is asynchronous..."));
}
static int MyCallback(void * pData)
{
if (acedCmdCWasCancelled())
{
acutPrintf(ACRX_T("\nCommand was cancelled..."));
return 0;
}
if(isLineActive())
{
int rs = acedCommandC
(
&MyCallback,
NULL,
RTSTR,
PAUSE,
RTNONE
);
acedCallBackOnCancel();
return 1;
}
CallWhenLineDone();
return 0;
}
static void CallWhenLineDone()
{
acutPrintf(ACRX_T("\nCommand completed."));
}
static Adesk::Boolean isLineActive()
{
struct resbuf rb;
acedGetVar(_T("CMDNAMES"),&rb);
if (_tcsstr(rb.resval.rstring, _T("LINE")))
return Adesk::kTrue;
return Adesk::kFalse;
}
static void AdskMyTestCommand()
{
ads_point pt1;
int rt = ads_getpoint(
NULL,
_T("\nSelect first point: "), pt1);
int rs = acedCommandC
(
&MyCallback,
NULL,
RTSTR,
_T("_line"),
RT3DPOINT,
pt1,
RTNONE
);
acutPrintf(ACRX_T("\nAfter acedCommandC call.
acedCommandC is asynchronous..."));
}
static int MyCallback(void * pData)
{
if (acedCmdCWasCancelled())
{
acutPrintf(ACRX_T("\nCommand was cancelled..."));
return 0;
}
if(isLineActive())
{
int rs = acedCommandC
(
&MyCallback,
NULL,
RTSTR,
PAUSE,
RTNONE
);
acedCallBackOnCancel();
return 1;
}
CallWhenLineDone();
return 0;
}
static void CallWhenLineDone()
{
acutPrintf(ACRX_T("\nCommand completed."));
}
static Adesk::Boolean isLineActive()
{
struct resbuf rb;
acedGetVar(_T("CMDNAMES"),&rb);
if (_tcsstr(rb.resval.rstring, _T("LINE")))
return Adesk::kTrue;
return Adesk::kFalse;
}
Non-DWG window in AutoCAD 2015
AutoCAD 2015 enables the creation of Non-DWG document window. The Non-DWG document window appears as a tab just as any other drawing window.
In this blog post, I have attached a C++ project to create a Non-DWG document window and demonstrate its usage.
To try it :
1. Build the sample project using Visual Studio 2012 with Platform Toolset v110.
2. Start AutoCAD 2015 and load the arx module.
3. Run "ShowMyWnd" command. This command creates a Non-DWG document window that accepts user input for the dimensions of a chain link as shown here :
4. Create another drawing and run the "InsertLink" command. This command creates a chain link based on the values provided in the Non-DWG document window.
Now, here is a brief description of the steps to create a Non-DWG document window using C++ :
Step-1. Create a dialog class derived from CDialog. An MFC dialog can be created using the resource view of Visual Studio as usual.
Step-2. Create a custom document class derived from AcRxObject. This class will be used to hold the data that are specific to this document window.
Step-3. Create a custom document window class derived from AcApDocWindow
Step-3. Create a custom document window class derived from AcApDocWindow
- Override the "onCreate" method to instantiate the dialog that is to be shown.
- Override the "onLoad" method to associate the custom document created in step-2 with our document window class
- Override the "onDestroy" method to perform cleanup such as deleting the dialog instance.
- Override the "subRouteMessage" to perform resizing of the dialog when the document window size changes.
Step-4. Create a custom document window manager reactor derived from AcApDocWindowManagerReactor
- Override the "documentWindowActivated" method to keep our custom document updated with the values provided in the dialog.
- Override the "documentWindowCreated" method to get a pointer to our custom document window after its gets created
- Override the "documentWindowDestroyed" method so we know when our custom document window is no longer valid.
In the attached sample, the steps to associate a custom document have been commented. AutoCAD 2015 at present becomes unstable if a custom document is associated with the custom document window. This behavior has been logged in our internal database for our engineering team to analyze. So the attached sample project now stores the document data in a helper class as static variables for the "InsertLink" command to access.
Here is the sample project :
04/17/2014
Migration After Fiber is Removed in AutoCAD 2015
There’s not that much work needed to port your apps to AutoCAD 2015(Longbow), unless you are using acedCommand or acedCmd.
The following is extracted from our DevDays PPT. If you feel tedious on my repeating the PPT, I’d recommend with the article written by our Blog Master Kean Walmsley :AutoCAD 2015: calling commands, or the video on the migration, or the demosamples codes which is availble at GitHub.
For this release, we’ve re-architected AutoCAD to completely strip out the use of Fibers and Fiber switching. Fibers are an old technology used in Windows that Microsoft stopped supporting several years ago. AutoCAD made heavy use of fibers and they are what allowed users to switch easily between drawings without interrupting commands. You’ve probably all seen this in action in old versions of AutoCAD – start a LINE command in one drawing, switch to another and draw a CIRCLE, then switch back to the first drawing and the LINE command is still active.
But using fibers was causing a lot of problems for us that we were spending more and more effort working around. For example, the .NET Framework has never supported Fiber Switching, and this is why when you switched documents in AutoCAD when debugging a .NET application, you’d often find that Visual Studio would fail to stop at a breakpoint– or it did break, but couldn’t display your code. That was Visual Studio getting confused by AutoCAD switching Fibers. You won’t experience that problem in Longbow now that we’ve removed Fibers. It also allows us to expose more of the ObjectARX SDK to .NET – the most exciting of which is that we now have a .NET version of acedCommand ((command) in LISP). That wasn’t possible before due to the problems caused by Fibers.
Migration in ObjectARX
That means ObjectARX has more significant migration requirements. There are two migration areas of concern: the MDI API and use of acedCommand/acedCmd. Then you’ll have to make changes. How big a change depends on how you’re using it.
If you’re passing a complete set of command tokens to the AutoCAD commandline, then all you have to do is add an ‘S’ to the end of acedCommand or acedCmd. S stands for subroutine. This is when you’re sending an entire command, and not pausing for user input.
If you’re sending a PAUSE, or if you’re sending an incomplete set of command tokens (for example starting a line command and leaving it for the user to finish) then you have a lot more work to do. In this situation, you’ll be using acedCommandC – the coroutine version of the command – and you’ll now have to pass a pointer to a callback function as a command parameter. It’s a lot more complicated – so much so that you might even consider migrating your code that needs this to .NET instead.
Here’s an example of the most basic acedCommand usage – its also the most popular use case – where we’re invoking a complete command in a single call to acedCommand. All you have to do here is change acedCommand to acedCommandS.
void foo(void)
{
acedCommandS(RTSTR,
_T("_Line"),
RTSTR,
_T("0,0"),
RTSTR,
_T("111,111"),
RTSTR, _T(""),
RTNONE);
acutPrintf(_T("\nFinished LINE command - \
control returned to addin\n"));
control returned to addin\n"));
}
But a lot of people use acedCommand like this. Starting a command and then prompting for user input until the command ends. In this case we’re starting the LINE command and issuing PAUSEs to allow the user to keep drawing additional line segments. When we migrate this code for Longbow, we have to use acedCommandC, because acedCommandS doesn’t support partial command token stacks or PAUSEs.
void foo(void){
//Invoke partial command and leave command active.
acedCommandC(RTSTR,
_T("_Line"),
RTSTR,
_T("0,0"),
RTSTR,
_T("111,111"),
RTNONE);
while(isLineActive())
while(isLineActive())
acedCommandC(RTSTR,
PAUSE,
RTNONE);
acutPrintf(_T("\nFinished LINE command - \
acutPrintf(_T("\nFinished LINE command - \
control returned to addin\n"));
}
The migrated code will look something like this. We’ve defined a callback function, which we pass to acedCommandC. Now when AutoCAD is ready to pass control from the user back to you, it will do so by calling the callback function you provided. In this example, the callback function keeps passing itself as a callback until the command ends. If the user cancels the command you invoked using acedCommand, then AutoCAD will also cancel your command that called it. Otherwise, control is handed back to your code when the command invoked by acedCommand ends.
void foo(void){
//Invoke partial command and leave command active.
acedCommandC(&myCallbackFn,
NULL, RTSTR,
_T("_Line"),
RTSTR,
_T("0,0"),
RTSTR,
_T("111,111"),
RTNONE);
//Control is passed to myCallbackFn1 from AutoCAD
}
//Your callback function int myCallbackFn(void * pData){
int nReturn = RTNONE;
//Keep command active until user ends it.
if (isLineActive())
nReturn = acedCommandC(&myCallbackFn,
NULL, RTSTR,
PAUSE, RTNONE);
else
{
//This is never reached if the user cancels the command –
// that cancels your command as well.It is reached if command is ended
//(e.g. by hitting ENTER)
acutPrintf(_T("\nFinished LINE command - \
control returned to addin\n"));
}
return nReturn;
}
Migration in .NET
I would say the most exciting new API in Longbow is the introduction of .NET versions of acedCommand ((command) in LISP). This hasn’t been possible before because of AutoCAD’s use of Fibers – and because the .NET Framework doesn’t support Fibers. So these new APIs – synchronous and asynchronous versions of acedCommand – are now possible for the first time.
acedCommand is probably the most powerful API in ObjectARX. It allows you to embed entire AutoCAD commands within your own commands; and even to invoke partial commands, and then programmatically respond to how the user interacts with those commands. This saves ObjectARX and LISP developers a huge amount of work where otherwise they’d have to reproduce all the native command behavior in their own code – and now .NET developers get the same benefit.
The synchronous version of Command is Editor.Command, the equivalent of the subroutine version of acedCommand. This is how you invoke a complete command from your code. As you can see, the code is very similar to the ObjectARX version – you pass a full set of command tokens to the AutoCAD commandline (the editor), AutoCAD completes the command and immediately returns control back to your code.
//simple use of Editor.Command
//most popular case - invoke a whole command with no user interaction
[CommandMethod(“MyCommand")]
publicstaticvoid MyMethod()
{
Editor ed =
Application.DocumentManager.MdiActiveDocument.Editor;
Application.DocumentManager.MdiActiveDocument.Editor;
ed.Command(newObject[] {
"_.LINE", "0,0,0", "10,10,0", "" });
}
There is also the asynchronous version of Command Editor.CommandAsync. This is the equivalent of the coroutine version of acedCommand. You’ll recall that acedCommandC required you to pass in a reference to a callback function. The .NET version is a little simpler. Because we’re using .NET Framework 4.5, we can make use of the async and await keywords to greatly simplify our asyncronous code. We mark our .NET commandmethod with the async keyword, and we can then use the await keyword inside that method. The await keyword tells AutoCAD where in your code to return control to after it has finished gathering user input. In this example, we’re simply starting the circle comamnd, using a PAUSE to let the user specify the circle center, and then specifying the circle radius in our code.
//Invoke a partial command with user interaction
[CommandMethod("DotNetType2")]
publicstaticasyncvoid DotNetType2()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
//create a circle of radius 2.0 at chosen location.
await ed.CommandAsync("_.CIRCLE");
//wait for user input
await ed.CommandAsync(Editor.PauseToken);
//provide radius input
await ed.CommandAsync(2.0);
}
No comments:
Post a Comment