On the last class I have presented how to perform selection sets. This class I will show how can you interact with AutoCAD using global functions and acquiring information such as numbers, coordinates, system variables and much more.
Invoking Commands
ObjectARX provide us two global functions that allows us to invoke registered commands. This functionality is very handy and will help users to perform quick operations that don't require complex procedures. Even this method is quite simple you should avoid using it in complex and huge operations. This method may also create problems when dealing with events handling.
The two provided functions are acedCmd() and acedCommand(). The first one invokes the command through a passed in resbuf list which will inform all command parameters. The second function will receive a variable number of parameters which will reproduce the way you fire the command from the prompt interface. Below are these functions signature:
int acedCmd(const struct resbuf * rbp);
int acedCommand(int rtype, ... unnamed);
To build the resbuf list when using acedCmd() there is a utility function called acutBuildList() which constructs this linked list easily. You just need to pass paired values with codes that describe the types and end the list with a 0 or RTNONE value. Another good practice is to clear the command prompt, calling acedCommand(RTNONE) , after issued the command. Don't forget to free memory used, when using resbuf pointers, through the acutRelRb() utility function to avoid memory leaks. There are several ways to use theses functions and I will show some of them below:
acedCmd():
a) Moving the last created entity based on (0,0,0):
ads_point pt;
pt[0] = pt[1] = pt[2] = 0.0;
struct resbuf *Mv;
Mv = acutBuildList(RTSTR,_T("_MOVE"),RTSTR,_T("_LAST"),RTSTR,_T(""),
RTPOINT,pt,RTSTR,PAUSE,0);
acedCmd(Mv);
acedCommand(RTNONE);
acutRelRb(Mv);
b) Calling a "redraw" native command:
acedCommand():struct resbuf *cmdlist;
cmdlist = acutBuildList(RTSTR, _T("_REDRAW"), 0);
acedCmd(cmdlist);
acedCommand(RTNONE);
acutRelRb(cmdlist);
a) Calling a ZOOM command and pausing for user input:
acedCommand(RTSTR, _T("Zoom"), RTSTR, PAUSE, RTNONE);
b) Creating both a Circle and a Line entities:
System VariablesacedCommand(RTSTR, _T("circle"), RTSTR, _T("10,10"),RTSTR, PAUSE,
RTSTR, _T("line"), RTSTR, _T("10,10"), RTSTR, _T("20,20"),
RTSTR, _T(""), 0);
Your application will probably need to access AutoCAD system variables that can be read or write. ObjectARX provide two functions to deal with these variables using the resbuf structure to access and/or modify values. The function are called acedGetVar() and acedSetVar() and below are their signatures:
int acedGetVar(const ACHAR * sym,struct resbuf * result);
int acedSetVar(const ACHAR * sym,const struct resbuf * val);
The first parameter is the variable name the second the resbuf pointer to set / get information. The following example show how to change the FILLET radius which is stored through a system variable:
It is very important that you specify the correct type of resbuf item acquired.struct resbuf rb, rb1;
acedGetVar(_T("FILLETRAD"), &rb);
rb1.restype = RTREAL;
rb1.resval.rreal = 1.0;
acedSetVar(_T("FILLETRAD"), &rb1);
In this case, the FILLET radius is a real number which is RTREAL type.
User Input Functions
There are additional global functions to allow interaction with users via command prompt interface. Each of these functions could be used alone or with other ones. The following table shows what each function does:
acedGetInt | Gets an integer value |
acedGetReal | Gets a real value |
acedGetDist | Gets a distance |
acedGetAngle | Gets an angle (oriented to 0 degrees specified by the ANGBASE) |
acedGetOrient | Gets an angle (oriented to 0 degrees at the right) |
acedGetPoint | Gets a point |
acedGetCorner | Gets the corner of a rectangle |
acedGetKword | Gets a keyword |
acedGetString | Gets a string |
Each of these functions returns a int number as a result code that could be one of the following:
RTNORM | User entered a valid value |
RTERROR | The function call failed |
RTCAN | User entered ESC |
RTNONE | User entered only ENTER |
RTREJ | AutoCAD rejected the request as invalid |
RTKWORD | User entered a keyword or arbitrary text |
AutoCAD allows you to prevent invalid values when user respond to your input functions. This feature can be made through the acedInitGet() function which can receive one or a combination of the following values:
RSG_NONULL | Disallow null input |
RSG_NOZERO | Disallow zero values |
RSG_NONEG | Disallow negative values |
RSG_NOLIM | Do not check drawing limits, even if LIMCHECK is on |
RSG_DASH | Use dashed lines when drawing rubber-band line or box |
RSG_2D | Ignore Z coordinate of 3D points (acedGetDist() only) |
RSG_OTHER | Allow arbitrary input—whatever the user enters |
The following example shows how to acquire a value greater than zero:
int age = -1;
acedInitGet(RSG_NONULL RSG_NOZERO RSG_NONEG, NULL);
acedGetInt(_T("How old are you? "), &age);
86 comments :
Hi,
Saying about interacting with AutoCAD I would indicate the Jig class. Sometimes it’s pretty handy.
I would like to set all the system variables in AutoCAD using arx, so that all users in the network of our company use the same settings. Can you please help me on that.
Thanks
Hello,
There are two utility functions to handle this: acedSetVar() and acedGetVar().
A simple example would be disable OSNAP during some operation and enable it back with old setup:
struct resbuf OldOsnap, NewOsnap;
// Get current OSNAP
acedGetVar("OSMODE", &OldOsnap);
// Chage OSNAP settings
NewOsnap.restype = RTSHORT;
NewOsnap.resval.rint = 0;
acedSetVar("OSMODE", &NewOsnap);
// Do something...
// Get back the old OSNAP
acedSetVar("OSMODE", &OldOsnap);
Regards,
Fernando.
Hi,
My application is accepting list of files from user. and according to
need it opens the files automatically to accept user input by selecting
entites.
it have a function
AcApDocument * asOpenFile(CString FileToOpen)
which checkes wheather the file is already open. if not then, the files
is opened.
it works well but after switching 3-4 drawings while executing
executeInApplicationContext()
normally execution control comes out..
but 3-4 times execution control stuck their, untill, user manually
switch to previous drawing.
when I used
acDocManager->setCurDocument()
it gives fatal error "Command can not be nested more than 4 times" and
crashes
this are the procedures
void asOpenSelFile(void* pData)
{
Acad::ErrorStatus es = Acad::eOk;
if(acDocManager->isApplicationContext())
es = acDocManager->appContextOpenDocument((const char *)pData);
}
AcApDocument * asOpenFile(CString FileToOpen)
{
char* pStr = NULL;
AcApDocument *pDoc = NULL;
if(!asGetDocFromFilename(FileToOpen, pDoc))
{
pStr = FileToOpen.GetBuffer(FileToOpen.GetLength());
//Problem sentence
acDocManager->executeInApplicationContext(asOpenSelFile, (void *)pStr);
//--------------------------------------------------------------------------
ShowMessage(gpAsdkAppDocGlobals->m_sDocIniCommand);
FileToOpen.ReleaseBuffer();
asGetDocFromFilename(FileToOpen, pDoc);
}
else
{
acDocManager->sendStringToExecute(acDocManager->mdiActiveDocument(),
"\003\003\003", false, true);
acDocManager->activateDocument(pDoc);
}
return pDoc;
}
Thanks in advance
Abhay
Hello Abhay,
Could you build a sample with this code, reproducing the problem, and send me at fpmalard@yahoo.com.br ?
This way I can help you faster.
Regards,
Fernando.
Hi,
When I use the acedGetPoint() function the AutoCAD hangs. This is the exact line.
acedGetPoint(NULL, "Enter Start Point", startPt);
acedGetPoint(startPt, "Enter Start Point", endPt);
I am using AutoCAD 2000 and Visual Studio 6. Why does the AutoCAD hang ?
Jatin.
Hi Jatin,
I don't think this is the culprit.But acedGetPoint() should be something like:
ads_point pt1;
int res = acedGetPoint(NULL,"Message",pt1);
if (res == RTNORM)
{
...
}
Maybe you need to check what is happening before your code reach this point.
Regards,
Fernando.
Hi,
Here is the code.
AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
AcDbObjectId lineId;
ads_point startPt, endPt;
AcGePoint3d geStartPt, geEndPt;
switch(msg) {
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
acedGetPoint(NULL, "Enter Start Point", startPt);
acedGetPoint(startPt, "Enter Start Point", endPt);
geStartPt[0] = startPt[0];
geStartPt[1] = startPt[1];
geStartPt[2] = startPt[2];
geEndPt[0] = endPt[0];
geEndPt[1] = endPt[1];
geEndPt[2] = endPt[2];
lineId = createLine(geStartPt, geEndPt);
break ;
case AcRx::kUnloadAppMsg:
acutPrintf("\nYour simple ARX application has been unloaded\n");
break ;
}
return AcRx::kRetOK;
}
When the code executes, I get the prompt at command line "Enter start point". But the AutoCAD hangs and I cannot enter the point or do anything else. I feel sure that the function acedGetPoint() is causing the problem. The createLine() function is never called because the AutoCAD hangs before it.
regards,
Jatin.
Hello Jatin,
The problem is because you are running an user interaction function from inside kInitAppMsg. According to SDK manual, during this message callback:
"Don't expect device drivers to be initialized, any user interface resources to be active, applications to be loaded in a particular order, AutoLISP to be present, or any databases to be open. Calls involving any of these assumptions will result in an error condition, sometimes fatal. AcDb and AcGi libraries are generally not yet active, although related AcRx and other structures are in place.
"
The right thing to do is to register a command and map this command to a function that will execute your procedures.
Regards,
Fernando.
Hi,
Thanks very much. But I dont know how to register a command and map it to a function. Can you please tell me the details for the same ?
Hi,
You just need to add a new command using the "a>" icon at ARXWizard's toolbar.
Check the Lab1 sample at:
http://arxdummies.blogspot.com/2005/03/lab-1-creating-and-editing-entities.html
Regards,
Fernando.
Hi Fernando,
Thanks once again. The ARX Wizard installation does'nt have ArxWizards.msi file in the ObjARXWiz folder. There is a file named WizardSetup.exe but running this file does'nt include any ToolBar to the Visual Studio. I am using ObjectARX for AutoCAD 2000. How do I get the ObjectARX Wizard working ?
Jatin.
Hi Jatin,
Yes, on 2000 the ARXWizard installer is an EXE file.
It should create a new toolbar (but if I remember correctly it is initally hidden so you have to enable it through a right click at VStudio toolbars).
It should also create a new project type option at VStudio new project dialog "ObjectARX...".
Could you check this?
Regards,
Fernando.
Hi Fernando,
I have registerd the command through the wizard and its working fine. Thanks for all the help.
regards,
Jatin.
I registered my command in aoutocad and from command handler function i am making two consecutive calls to acedcommands.
It fails (with error message out of memory.)on second calls if i follow a specific flow in my application.But for other work flow it forks fine.
I tried out by replacing second call to acedCommands with sendStringToExecute and it works.
I want to know the reason behind this behaviour.
Thanks.
Without looking at your code is hard to say what is going on.
It is possible to post your code here or send me through my e-mail?
Try to place the following call to acedCommand, between your two existing command calls, like this:
acedCommand(RTNONE);
Check if this will solve the problem. If not, please give me more details.
Fernando.
Hello:
You mentioned that "
I tried out by replacing second call to acedCommands with sendStringToExecute and it works."
Is it possible to paste a couple of code to illustrate your method please?
Cheers
Hello
How can I make a global variable similar to Autocad system variables, that can be seen from every object in Autocad?
Hello,
You may use a custom Object inside NOD (Named Object Dictionary). This object, derived from AcDbObject, can be stored there and may contain everything you want.
Next, create some commands to read/write these object´s properties.
Another approach is to use AcDbXRecord object and attach it to a specific extension dictionary.
In both above solutions your data will persist inside each DWG file.
In fact the best solution will depend on the use this variable will require.
All these options are well explained on ObjectARX samples.
Regards,
Fernando.
Hi Fernando,
In my application I have to DWG file opened.
I need to read some information from two DWG without change current document.
pdocMgr = acDocManager ;
pAcDoc = acDocManager->document(pDataBase);
acDocManager->activateDocument(pAcDoc);
I use activateDocument to be able to use global function just like
acedSSSetFirst(NULL, NULL);
I can’t use these function to second DWG without using activeDocument
-ActiveDocument take long time when interchangeable between two DWG
Best Regards
M.S
Hi M.S,
Every acedXXXXX() like function interact with AutoCAD interface and thus within the current document context.
Every document has its own command heap, memory buffer, AcDbDatabase, etc.
I'm afraid activateDocument() is the only way to go.
Regards,
Fernando.
Hi Fernando
Thanks a lot
Best Regards,
M.S
Dear fernando,
when I use activateDocument fucnction the next line of code does not execute until activate last document.
why? what is the solution???
and may case "Command may be nested more than 4 deep" error??
Do you have any idea???
Regards,
M.S
Dear Fernanod,
I have this code
AcDbVoidPtrArray *m_pDBArray = acdbActiveDatabaseArray();
if(m_pDBArray->length() >= 2)
{
AcDbDatabase *pDb1 = (AcDbDatabase *)(m_pDBArray->at(0));
AcDbDatabase *pDb2 = (AcDbDatabase *)(m_pDBArray->at(1));
AcApDocument *pDoc0;
AcApDocManager *doc_manager = acDocManagerPtr();
pDoc0 = doc_manager->curDocument();
AcDbDatabase *pDbTemp0 = pDoc0->database();
if(pDbTemp0 == pDb1)
{
AcApDocument *pDoc;
pDoc = doc_manager->document(pDb2);
Acad::ErrorStatus error11= doc_manager->activateDocument(pDoc);
acutPrintf("\n1");
acutPrintf("\n2");
acutPrintf("\n3");
}
else if(pDbTemp0 == pDb2)
{
AcApDocument *pDoc;
pDoc = doc_manager->document(pDb1);
Acad::ErrorStatus error11= doc_manager->activateDocument(pDoc);
acutPrintf("\n11");
acutPrintf("\n12");
acutPrintf("\n13");
}
}
else
{
acutPrintf("\n Number of DWG less than 2");
}
I have a problem when use this code no acutPrintf execute until reactivate document (manually by click on DWG)
Do you have any idea
Regards,
M.S
Hi M.S,
Try to use sendStringToExecute() method. Be aware that there is a stack of commands associated with each document and these commands may not execute at the prompt in time and order you expect.
Take a look at MDI documentation for further information.
Regards,
Fernando.
Thanks fernando
M.S
Hi fernando,
I have one question.
How to disable printing from AutoCAD?
Regards,
M.S
Hi M.S,
Could you explain better?
Do you mean disable all printing commands or just some specific entities printing?
Fernando.
Hi fernando,
I need to disable printing commands
(Disable print command in File Menu)
M.S,
During your kLoadDwgMsg you can undefine native AutoCAD commands and then redefine, if you want, with the same name or leave them undefined.
To do that, use the following function to disable print command:
ads_queueexpr( "(command \"_.undefine\" \"print\")" );
You can do the same for any other AutoCAD native command.
Hope this help.
Fernando.
Hi Fernando,
ads_queueexpr( "(command \"_.undefine\" \"print\")" );
Generat Compile Error :undeclared identifier ads_queueexpr
I use ARX wizard is any Header File to include.
Hi M.S,
It is undocumented.
Put this:
extern "C" int ads_queueexpr(const char*);
on the CPP where are your trying to use it.
Regards,
Fernando.
Hi Fernando,
Yes It Work Thank You very Much
I Have Other Question on print(plot)
I try to add AcplReactotPlot but when I load it to AutoCad I Got
FATAL ERROR: Class 'cstmPlotR' parent named 'AcPlotReactor' not Found
Do you have any idea.
Tanks again
Best Regards,
M.S
Hello,
Take a look at this sample:
ObjectARX 2007\samples\editor\AsdkPlotAPI
It shows everything you need.
Regards.
Hi Fernando,
I have 3 Question.
1) Is any way to rename comand.
Such as rename line command to DrawLine.
2) Is any way to cancel Running Event.
Such as Print Command.
3) Is any way to get event for command
Regards,
M.S
Hi M.S,
1)You need to undefine the existing command and add yours with the same name. There is no way to redefine a command.
2)Use AcApDocManagerReactor to handle the docLockModeChanged() event. Inside this method, check you want and call the veto() method if you want to cancel the command.
3)Take a look at AcEdEditorReactor class. It will implement command events such as commandoWillStart(), commandEnded(), etc.
Regards.
Thank You Frenando
M.S
Hy.
Is it possible to get a list of the system variables (or at least those that get saved in the DWG) ?
I'd like to be able to get a list with all variables and then use acedGetVar and acedSetVar using the list, is it possible somehow ?
Hi AlbuEmil,
I'm afraid you can't.
System variables were implemented through different classes because some are per DWG and some are per AutoCAD instance.
For instance, part of them are inside AcDbDatabase and part inside AcDbAppSystemVariables.
Regards,
Hello Fernando!
I try to insert a block in the current document (an empty dwg file) If the UCS is World, using acedGetPoint() I have no problem with block positioning. But if I change the UCS position, the insertion point of the block is still related to the WUCS .I do not understand what is wrong, as I've read in documentation about acedGetPoint(..) that "the coordinates of the point stored in result are expressed in terms of the current UCS"... But on my screen is still based on the WUCS!!
Do I have to make a transformation from the current UCS into the World UCS and after the insertion to restore the ucs back to the last user? Is this really necessary?
Any idea?
Kind regards!
Ioan
Hello Ioan,
acedGetPoint() returns the point on the current UCS:
"The coordinates of the point stored in result are expressed in terms of the current UCS."
Internally ObjectARX deal on almost its methods within WCS. You will need to convert using these functions to go from/to:
bool acdbWcs2Ucs(ads_point p, ads_point q, bool vec);
bool acdbUcs2Wcs(ads_point p, ads_point q, bool vec);
Try to get your point and convert before create the entity.
Hello Fernando!
I would like to know which is the fast way to scale an entire drawing (database).
Best regards!
Ioan
Hello Ioan,
Basically I would do the following:
- Create a 3D Matrix to scale:
double dFac = 1.5; // Your scale
AcGePoint3d ptCenter(0,0,0); // Scale point reference
AcGeMatrix3d scaleMat;
scaleMat.setToScaling(dFac,ptCenter);
- After this, step through an AcDbBlockTableRecord entries and open each one;
- For each AcDbBlockTableRecord, step through its entities;
- For each AcDbEntity, call the transformBy() method passing in your transformation matrix;
* If you want only to transform Model Space you only need to traverse its entities.
That's it.
As usual.. the fastest response in the world to ARX questions! :-)
So there is no other way to avoid individual scaling? In fact this is the real question: there is no global function to automatically scaling the entire ModelSpace entities?
Thank you Fernando!
Ioan
Ioan,
I really don't know a single call function that can do the magic.
If there is one, it would probably do the same way you will need to do.
Note that the overall result of the scaling process can affect entities depending on the center point specified.
Regards,
Hello Fernando!
Thank you for the valuable informations posted here!
But I'm a little bit confused:
Which are the differences between the
bool acdbWcs2Ucs(ads_point p, ads_point q, bool vec);
bool acdbUcs2Wcs(ads_point p, ads_point q, bool vec);
and
int acedTrans(const ads_point pt, const struct resbuf * from, const struct resbuf * to, int disp, ads_point result);
It seems that both set of functions do the same thing but in practice I got different results combined with the scale problem:
Which is the correct transformation function, to make a correct scale operations on all drawing elements, when the UCS is not set to the default WCS to get the right scale point supposed that the scale point is the drawing origin (0,0,0)?
Hello,
The default AutoCAD blank drawing has both WCS and UCS with the same initial configuration.
In this case, both functions will transform from one system to another with the same configurations and thus result to nothing.
To be able to see the difference between these two methods you need to change the current UCS and choose a different origin and axis.
Major ObjectARX API methods work based only on WCS which is the global coordinate system that is always static. In this case the result of using these functions need to be adjusted with the proper tranformation to allow you to reach the desired results.
Hope this explain why are you getting the same results.
Regarding to the scale I recommend you to build the scale matrix from the 0,0,0 point. In fact the result over objects placed far from this point will result a movement away from the 0,0,0.
If you think better there is no way to scale a drawing without moving the entities but if you want to scale each single entity from its center we will need to calculate each entity center. This can be done by getting the entity extents and by calculation this bouding box center.
Hope this help.
Regards,
Hi Guys,
I would like to use the "-Boundary" command and pass in a coordinate, but I want the routine to return the AcDbObjectId of the created boundary. Is this posible?
You will need to use acedEntLast() method which will return the last created entity after the Boundary command.
Something like this:
ads_name ent;
AcDbObjectId id = AcDbObjectId::kNull;
if (acdbEntLast(ent) == RTNORM)
{
if (acdbGetObjectId (id,ent) == Acad::eOk)
{
// Here you can open the object
}
}
Regards.
Actually is acdbEntLast() not aced.
Hi,
I have a similar problem to what Abhay had. I try to open a new drawing and I want it to become the current document. I use
acDocManager->executeInApplicationContext(newSyncDocHelper, (void *)pData);
void newSyncDocHelper( void *pData)
{
if (acDocManager->isApplicationContext())
{
acDocManager->appContextNewDocument((const TCHAR *)pData)
}
executeInApplicationContext does not return before the user clicks on the original drawing first.
Any thoughts?
Dawie
Dawie,
You need to explicity lock the document you want to make current after executing the appContextNewDocument() method.
Take a look at Document Locking notes at SDK Documentation.
Regards.
Fernando,
My document opens and it is current now, but the problem is that executeInApplicationContext() does not return the control back to its caller function before the user clicks on the original drawing. The caller function needs to continue, because I have some things that has to be loaded into the new drawing. Clear as mud?
Dawie
Try to lock the document and make it current.
Hello Fernando,
Trying to break an entity (LWpolyline) with acedCommand i get a message "No object found".
When i feed the same ads_name to acedCommand "Move" it is accepted but nothing moves.
Here's what i tried;
if (pEnt->upgradeOpen() != Acad::eOk)
acutPrintf (_T("\nNew Entity not Write"));
acedCommand(RTSTR, _T("break"), RTENAME, en, RTSTR, _T("f"), RTPOINT, pt1, RTPOINT, pt1, 0);
//error: no object foud. Also "RTLB entity & point RTLE" doesn't work.
acedCommand(RTSTR, _T("move"), RTENAME, en, RTSTR, _T(""), RTPOINT, _T("10,10"), RTPOINT, _T("30,30"), 0);
//a test with fake points. No error but nothing moves.
acedCmd doesn't help me out either.
Any idea?
Regards,
Frank Nauwelaerts
Hello Frank,
You cannot run a native command with the entity on AcDb::kForWrite opened state. It need to be closed because the command will need to open it for write.
Try to call the commands with the entity closed and probably they will work just fine.
Regards.
Hi Fernando,
Right!
Makes perfect sense.
At first it used to be kForRead to check if entity isKindOf curve. Now i've closed the pointer before acedCommand.
Seems to work all right.
Thanks,
Frank Nauwelaerts
Hi Fernando Malard
I've read about the using of acedCommand function in creating specific entities , but i would like to create "text" on the table,
this is my source code , i don't know how to continue with the entry ->Justify/Style 、height、rotation degree and "text content"
acedCommand(RTSTR, ("text"), RTSTR, PAUSE,RTNONE);
I also want to create a text ex:"test" in the right location if AutoCAD user click on that location , could i do that ?
plz give some suggestions , many thanks
Hello,
Don't do that, acedCommand/sendStringToExecute are just the last resource solutions for things you can't do directly to the AutoCAD's database.
To create a text entity directly to database use the AcDbText entity class which will allow you to set all desired parameters plus the text contents.
Something like this:
// CODE BEGIN
AcDbText* pText = new AcDbText();
pText->setTextString(_T("MyText"));
pText->setHeight(10.0);
pText->setRotation(0.0);
pText->setNormal(AcGeVector(0,0,1));
pText->setPosition(AcGePoint3d(0,0,0));
pText->setAlignmentPoint(AcGePoint3d(0,0,0));
pText->setColorIndex(3);
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead);
AcDbBlockTableRecord *pBlockTableRecord = NULL;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);
pBlockTable->close();
AcDbObjectId textId;
pBlockTableRecord->appendAcDbEntity(textId, pText);
pBlockTableRecord->close();
pText->close();
// CODE END
Hope this help.
hi again Fernando
im forgot to tell you im using VC 6 to build ARX 2000 for AutoCAD 2000, there is something wrong when compiling this code you gave me, is there some head files that i must include ?
the error messages are like this
Acdbtext 'ptext ... and some syntax errors
sry about my noob in VC 6 , but this is very important for me.
Thanks for your reply ~!
Brilliant Fernando this is works , the acdbtext works fine after include some headers,
thank you a lot
Hello Fernando
//this is my code
void test()
{
double r,d;
d = 150;
r = d/3;
acedCommand(RTSTR,"CIRCLE",RTSTR,"100,100",RTREAL,r,0);
acutPrintf("\ng01");
struct resbuf *rb , *rb2 ;
int rc;
int rc2;
rc = acedGetSym("var", &rb);
rc2 = acedGetSym("var2", &rb2);
rb = acutBuildList(RTREAL, 3.12,0);
rb2 = acutBuildList(RTREAL,6.66,0);
rc = acedPutSym("var", rb);
rc2 = acedPutSym("var2", rb2);
} //end code
I want to put the r 、 d value directly into the var 、var2 variables , do i have any alternative method to make it work ? for example , if i determined some int or char value in the specific definition , how do i make acedgetsym and command "!" to show the value r & d
Here is the code that you show to me,yes i've also tried and it works fine ,but how do i make the "my text" result to connect the acedgetsym and acedputsym function so im able to type "!sym" to see the string "my text"
plz help Mr Fernando
Jimmy,
The only way to send/receive AutoLISP symbols is through acedPutSym()/acedGetSym().
Take a look at your ObjectARX documentation and search for "AutoLISP Symbols".
There are examples of Put/Get methods.
Regards,
Fernando.
Hello Fernando!
Could you indicate (at least the pseudo-code) how to start aa ARX routine which moves a point on an arc. The animation (the point moving on the arc) must be visible on the screen.
Best wishes!
Krom
Hello Krom,
You can access the AcDbArc curve parameters and calculate the point position by an increment you set.
To do that use the getPointAtParam() method which will return the point over the arc. The AcDbArc class is derived from AcDbCurve which implements all the parametric curve stuff.
The full arc length in terms of parameters can be calculated by acquiring the start and end parameters.
For each step get your existing AcDbPoint entity and set its new position.
It should work...
Hello Fernando!
Thank you for your fast response!
I can calculate with no problems all the intermediary positions on the arc, but my problem is how to "move" the point to create the animated illusion. All I'm asking is the pseudo-code from Arx point of view: for example I do not know if I can move the point or the point must be deleted and recreate after. Which is the fastest and safe solution?
Best wishes!
Krom
Krom,
AutoCAD is not a multithread environment so any parallel processing it risky.
One thing you could do is to set a Windows Timer and from time to time draw a temporary X mark at the current point position by using the acedGrDraw() method.
Sorry, I can't think an easier solution for that.
Regards.
First of all, thank you for this excellent resource site! It's much appreciated.
I have a question that I'm hoping you can help me with.
I'm developing a plugin using ObjectARX that produces a PDF file containing hyperlinks.
Rather than write an entire PDF exporter from scratch, I'm exporting the file from Autocad and then adding the link in as a separate step. It's working great, but the interface is a bit awkward -- the user exports the PDF file, then runs a command (provided by my plugin) that prompts them to enter the name of the file they just exported. They end up having to specify the PDF filename twice, once for the exporter and once for my plugin. I'd like to streamline the process.
I can think of two ways of doing it. The first is to have my plugin prompt the user for a filename to save the PDF file to, then invoke the PDF exporter from my plugin and do my post-processing. The second is to have my plugin run the PDF exporter, and somehow retrieve the name of the exported file.
For the first approach, I would have to pass a filename (and possibly other settings) to the exportpdf command. For the second approach, I would have to retrieve the filename that the user gave to the PDF exporter.
Is there a way to do either of those using ObjectARX? I've checked the documentation, and I haven't found anything useful so far.
Thanks in advance for any help.
Bernie,
I think the best and most reliable way to do that is by monitoring the plot reactor.
Take a look at the AcPublishReactor and AcPublishUIReactor classes. They both deal with some information packages that may contain the information you want:
AcPublishReactorInfo
AcPublishUIReactorInfo
There should be something else available at the AcPl classes which is the Plotting branch into ARX class tree.
Regards.
Thanks very much, Fernando. I'll give that a try.
hi Fernando,
I like the result buffer very convenient.
Is there any idea of storing objectID in result buffer?
Hello,
You can always store it as an "old ID" which can be obtained with the method asOldId() inside AcDbObjectId class.
The only problem is that it is not valid across AutoCAD sessions. It is safe to use AcDbHandle which stays the same during the DWG existence.
Take a look at the ARX docs about entity relationship and handles.
Regards.
Hello Fernando!
Your blog is very helpful for me!
I have a function in LISP. It's name for example: "ReadFile".
I can invoke it in AutoCad's command line by writing:
(ReadFile "c:\file.txt").
Now, I have a ObjectArx application.
I can invoke simply commands like _circle from ObjectArx application:
acedCommand(RTSTR, _T("_circle"), RTSTR, _T("10,10"),RTSTR , _T("10") ,RTSTR, _T(""), 0);
but I don't know how to invoke: (ReadFile "c:\file.txt") ?
Best Regards!
Peter
Ps. Fernando rules! :)
Hi Peter,
Use sendStringToExecute() method and pass your LISP expression.
Cheers.
Hello Fernando,
I have build my arx application in 32 bit machine/compiler. It works fine. Now I want to use my 32 bit arx on 64 bit machine/AutoCAD. I tried to do appload but it says "Unable to load application". What is the easiest way to use the application in 64 bit AutoCAD? Do it need to completely port it using 64 bit Visual studio with 64 bit settings or is there some other way?
Thanks
Hello,
AutoCAD 32-bit is locked to work only into 32 machines even being theoretically possible to do it. There are some tricks to force it to work but I woudn't recommend you to go that way.
To properly make your application compatible with x64 machines you need to port your code making it suitable for x64 compilation. The ObjectARX SDK comes with appropriate files for both platforms and your compilation platforms need to target the appropriate files as well.
You will end up with multiple configurations at your project like Debug32, Debug64, Release32, Release64.
Note that x64 compiled code won't work into 32bit AutoCAD as well.
Take a look at the ObjectARX documentation for further information.
Regards,
Hi Fernando!
- I want export PDF file silent in my code.
( path of PDF file i already have)
.
Before I do save automatic drawing by:
resbuf _new_result;
_new_result.restype=RTSHORT;
_new_result.resval.rint=0;
ads_setvar(L"CMDECHO",&_new_result);
ads_setvar(L"FILEDIA",&_new_result); acedCommand(RTSTR,L"_qsave",RTSTR,filePath,RTNONE);
but I can't do same with _EPDF.
thanks !
Hi minhnv,
You need to use the "-EXPORT" command...here is a sample LISP expression to export the current Display to a my.pdf file into your C:\ drive:
(command "_-EXPORT" "_PDF" "_D" "_NO" "C:\\my.pdf")
Hope it helps you.
Regards,
Hi,
How can I use the methods acedcmd() and acedCommand() for insert command. I want to bring a block to my model space so I need to use insert command. How I use acedCommand for it?
Thanks
Hello,
These methods are not valid after AutoCAD 2015 when fibers were removed.
Take a look at this article (there is a handy tutorial video at this page too):
http://adndevblog.typepad.com/autocad/2014/04/migration-after-fiber-is-removed-in-autocad-2015.html
Regards,
Hello,
I'm newbie with c++ and I've a question for pro..
can we get the value of a variable create in LISP ?
Lisp example: (setq item1 "test")
then capture the item1 value in c++ ?
any samples wil;l be appreciated. Thank you.
Mike
Hello,
You can use the acedGetSym() and acedPutSym() methods from C++.
Take a look at this blog post:
http://adndevblog.typepad.com/autocad/2012/08/setget-autolisp-symbol.html
Regards,
Thank you for knowledge sharing
i need some more information
I have created mfc application(Add-in) for BricsCAD Application. The main starting dll is loading by a registry rest project dlls are dynamically loading. Now I want to load that same mfc application(Add-in) for AutoCAD. So can you tell how to do?
Hi Akash,
BricsCAD does have BRX programming environment which mimics AutoCAD ObjectARX API.
These APIs comprehend C++ and .NET programming languages and .NET seems to be quite different on both platforms.
From the extent I know about BRX C++, it should match most of ObjectARX C++ features so it would be just a matter of rename the classes.
I never created ObjectARX+BRX applications into a single solution in Visual Studio but it supposed to be viable once you can use conditional definitions in C++ to tweak class names.
If you create all your MFC as a pure DLL without using any of BRX or ObjectARX specific classes, it could be shared by both when running into Windows systems.
Anyway, I think it is feasible but unfortunately I don't have any sample code to share.
Best Regards,
Post a Comment