ObjectARX & Dummies

Course Index

*Course support: Click here!
*Course and User samples: Download here!

Sunday, March 27, 2005

Class 8 - Selection Sets

Hello,

On this class we will cover the first ways we can interact with user to allow our application to get information from drawing screen You probably will need to use this method inside your application.

Introduction

This is one of the most important ways to interact with user because it will allow you to get information from drawing screen through selected entities. Some times you will request user to select entities individually and sometimes you will select them using a filter.

A selection set is a group of entities which are currently selected by an user or by an application. The most important concept involved when selecting entities from screen is that AutoCAD will return their names through a type called ads_name. This type contains the entity name (which is valid only on the current session) and it can be converted to ObjectId using the acdbGetObjectId() global function:

Acad::ErrorStatus acdbGetObjectId (AcDbObjectId& objId, const ads_name objName);

This function receives the ads_name and convert it to an AcDbObjectId. Most of selection set functions will still use the ads_name as parameters and on theses cases you don't need to convert it. The ads_name can store several entities or just one. This will depend on how you or the user has performed the selection.

The selection is made using a function called acedSSGet() which will apply a selection or prompt the user to do that. The function signature is:
int acedSSGet (const ACHAR *str, const void *pt1, const void *pt2,
const struct resbuf *entmask, ads_name ss);
How to use

It receives a selection option, two points, a mask and returns the resulting selection set. After use the selection set it needs to be released and this is done through the acedSSFree() function The selection option will instruct AutoCAD interface to do one of the following methods:

Selection Code

Description

NULL

Single-point selection (if pt1 is specified)
or user selection (if pt1 is also NULL)

#

Nongeometric (all, last, previous)

:$

Prompts supplied

.

User pick

:?

Other callbacks

A

All

B

Box

C

Crossing

CP

Crossing Polygon

:D

Duplicates OK

:E

Everything in aperture

F

Fence

G

Groups

I

Implied

:K

Keyword callbacks

L

Last

M

Multiple

P

Previous

:S

Force single object selection only

W

Window

WP

Window Polygon

X

Extended search (search whole database)


This way we can perform the selection by several ways. Some examples are presented below:
ads_point pt1, pt2;
ads_name ssname;
pt1[X] = pt1[Y] = pt1[Z] = 0.0;
pt2[X] = pt2[Y] = 5.0; pt2[Z] = 0.0;
// Get the current PICKFIRST or ask user for a selection
acedSSGet(NULL, NULL, NULL, NULL, ssname);
// Get the current PICKFIRST set
acedSSGet(_T("I"), NULL, NULL, NULL, ssname);
// Repeat the previous selection set
acedSSGet(_T("P"), NULL, NULL, NULL, ssname);
// Selects the last created entity
acedSSGet(_T("L"), NULL, NULL, NULL, ssname);
// Selects entity passing through point (5,5)
acedSSGet(NULL, pt2, NULL, NULL, ssname);
// Selects entities inside the window from point (0,0) to (5,5)
acedSSGet(_T("W"), pt1, pt2, NULL, ssname);

Using Selection filters

Filters are a powerful way to speed up selection sets and avoid runtime operations to verify entities. You can use single filters or composed filters. Each filter is specified through a structure called resbuf. A resbuf is a linked list which store several types of information and may contains several items. To use a filter we need to construct it and pass it as a parameters of acedSSGet() method. The selection is performed but each selected entity will need to respect the filter. There are a lot of filters we can create and the SDK documentation cover all of them. The most used examples are presented below:
struct resbuf eb1, eb2;
TCHAR sbuf1[10], sbuf2[10];
ads_name ssname1, ssname2;
eb1.restype = 0; // Entity name filter
_tcscpy(sbuf1, _T("CIRCLE"));
eb1.resval.rstring = sbuf1;
eb1.rbnext = NULL;
// Retrieve all circles
acedSSGet(_T("X"), NULL, NULL, &eb1, ssname1);
eb2.restype = 8; // Layer name filter
_tcscpy(sbuf2, _T("0"));
eb2.resval.rstring = sbuf2;
eb2.rbnext = NULL;
// Retrieve all entities on layer 0
acedSSGet(_T("X"), NULL, NULL, &eb2, ssname2);

Modifying entities through a selection set

To modify entities inside a selection set we need to walk through selection items, get each one, convert the ads_name to an ObjectId, open the entity for write, modify it and then close it. This operation can also be done using a transaction which is, in long operations, much better.

To show you how to walk through a selection set I will present a short code to select all CIRCLE entities inside the drawing and then change its color to red. The operation is pretty simple and is done this way:

// Construct the filter
struct resbuf eb1;
TCHAR sbuf1[10];
eb1.restype = 0; // Entity name
_tcscpy(sbuf1, _T("CIRCLE"));
eb1.resval.rstring = sbuf1;
eb1.rbnext = NULL;

// Select All Circles
ads_name ss;
if (acedSSGet(_T("X"), NULL, NULL, &eb1, ss) != RTNORM){
acutRelRb(&eb1);
return;
}

// Free the resbuf
acutRelRb(&eb1);

// Get the length (how many entities were selected)
long length = 0;
if ((acedSSLength( ss, &length ) != RTNORM) (length == 0)) {
acedSSFree( ss );
return;
}

ads_name ent;
AcDbObjectId id = AcDbObjectId::kNull;

// Walk through the selection set and open each entity
for (long i = 0; i < length; i++) {
if (acedSSName(ss,i,ent) != RTNORM) continue;
if (acdbGetObjectId(id,ent) != Acad::eOk) continue;
AcDbEntity* pEnt = NULL;
if (acdbOpenAcDbEntity(pEnt,id,AcDb::kForWrite) != Acad::eOk)
continue;
// Change color
pEnt->setColorIndex(1);
pEnt->close();
}

// Free selection
acedSSFree( ss );


I have used some new functions (like acdbOpenAcDbEntity) that are also part of ObjectARX SDK. Pay attention to the memory releases regarding to selection set and resbuf types. Note that I have used also a function called acedSSLength() to get the length of selection set.
The acedSSName() function get an at the passed index. If we have more than one entity selected this loop will get every single entity into this selection set.

See you next class.

60 Comments:

  • Hi Fernando,

    There is a logical operator missing where reads:

    // Get the length (how many entities were selected)
    long length = 0;
    if ((acedSSLength( ss, &length ) != RTNORM) (length == 0)) {

    acedSSFree( ss );
    return;

    }

    It has to be something like:

    if ((acedSSLength( ss, &length ) != RTNORM) || (length == 0)) {

    acedSSFree( ss );
    return;

    }

    Regards,
    Luis.

    BTW, do you happen to have some sample about on how to compare let say "POINT"s and being able to delete them if they are duplicated?

    Also, what do I need to do in order to use, this:
    if (acedSSLength(ss, &length) != RTNORM)
    return BAD;

    I get an error if I use "BAD" on the return statement... I was just trying to use the samples on the ARX Dev help

    By Anonymous Anonymous, at 8:11 PM  

  • Hi Luis,

    Thank you. I have updated the sample. Sometimes Blog HTML editor eats some chars...

    Regarding to point comparison, be careful on doing this. Each point coodinate is a double which does not have a exact value. The 0(zero) can be sometimes 0.0 or 0.00000001, etc. This will depend on your code implementation and compiler settings. To avoid problems you should use AcGe library point comparison functions that allows you to pass a tolerance to compare point's coordinates. Another approach is to create your own comparison function. It is up to you!

    Regarding to the BAD symbol, it is not defined in ObjectARX samples or SDK. You just need to define it or return your own error code. From SDK documentation:

    "Note The ObjectARX library doesn't define the values GOOD and BAD, which appear as return values in the code samples throughout this guide (especially in error-handling code). You can define them if you want, or substitute a convention that you prefer."

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 8:50 PM  

  • Hi Fernando,
    How do I get the block name of a block selected by the user. I am using the acedSSGet() function to allow the user to select a block. Also, if the user selects a multi line text, then I want to know the string value of the text.

    regards,

    Jatin.

    By Anonymous Anonymous, at 6:21 AM  

  • Hi Jatin,

    Block entities are reflex of their parent BlockTableRecord. So the block name is the name of the entity's parent BTR. To get it you need to first get its ObjectId which is stored inside the block entity (AcDbBlockReference).

    Call the blockId() method over the block entity and open it (for read) as an AcDbBlockTableRecord. Then use the method:

    Acad::ErrorStatus getName( char*& pName) const;

    It will return the name of your block.

    Regarding to the multiline text, it is an AcDbMText entity. There is a method called:

    char* contents() const;

    For further information, take a look at these entity's classes.

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 8:53 AM  

  • Hi Fernando,
    I am a newbie and so difficult to understand your explanation. Can I send you part of my code on your yahoo Id. Maybe you can add a couple of lines/comments to that so that it will make sense to me. My id is kulkarni.jatin@rediffmail.com


    Regards,
    Jatin

    By Anonymous Anonymous, at 5:49 PM  

  • Hi
    I have a problem with selection set using acedSSGet.
    What I'm trying to do is check whether there is 1 or more entities in
    certain area. I've read documentation and figuread out that it would be
    best to choose either "W" or "C" parameter. I don't know if I'm getting
    it right but I think that when I use "W" the whole entity must be
    selected [like in AutoCAD2007 selecting the right direction] and in "C"
    anything that passes through selection area will be selected [like
    selecting the left direction in autocad].

    That's the theory.

    I wrote something like this:
    pt1[X] = 1.0; pt1[Y] = 131.0; pt1[Z] = 171.0; //temp2
    pt2[X] = -1.0; pt2[Y] = 19.0; pt2[Z] = 169.0; //temp2
    if (acedSSGet(_T("C"), pt1, pt2, NULL, ssname)!= RTNORM){...} //temp2

    in order to select anything that passes through point 0,130,170 or
    0,20,170
    [the idea is that at the beginning there is one entity, which is then
    cloned and mirrored - I want to check if there is one: then I can do
    the operations or if there are 2 entities then I should do nothing]

    I want to check point 0, 130,170 [which should be crossed by one
    entity] and 0,20,170 [the cloned one].
    But the interesting part is that when I count selected entities:
    if ((acedSSLength( nazwa, &length ) != RTNORM) || (length == 0)) {...}
    I get 3 [sic!] of them.
    I have no idea where the other 2 came from and what they are.

    When I was trying to do it using point which should belong to both
    original and cloned one:
    pt1[X] = 30.0; pt1[Y] = 75.0; pt1[Z] = 225.0;
    if (acedSSGet(NULL, pt1, NULL, NULL, ssname)!= RTNORM){ ...}
    it found 1 entity, but when I copied in autocad using _copy it didn't
    find anything.

    Could you tell me if I'm doing it the wrong way? Or how could I do
    it?

    Thanks in advance
    Marek

    By Anonymous Anonymous, at 7:59 AM  

  • Hi Marek,

    Your code fragment looks fine but your error maybe is coming from another part of your application.

    Could you build a separate sample with only this tasks and check if the error is still there?

    Generally this selection set problem is caused by a wrong filter and due that you receive 2 extra objects that are Layout1 and Layout2 database objects.

    Regards,
    Fernando.

    By Blogger Fernando Malard, at 8:31 AM  

  • please how to select enity on screen by using object id

    By Anonymous Anonymous, at 8:43 AM  

  • Hi,

    What do you mean with "select entity on screen" ?

    Would you like to highlight the entity or just open the entity and get/set information?

    Regards.

    By Blogger Fernando Malard, at 8:59 AM  

  • Hi fernando
    Please how to determine wither the entity is selected with grips point (not highlight ),

    Regards,
    M.S

    By Anonymous Anonymous, at 4:21 AM  

  • Hi M.S,

    You need to use a Windows Hook funcion to do that. Something like:


    BOOL GripHook (MSG *pMsg)
    {
    static bool signal = false;
    if (!signal)
    {
    signal = true;
    struct resbuf *grip = NULL, *ents = NULL;
    if acedSSGetFirst(&grip, &ents) == RTNORM)
    {
    // Use resbuf info here
    }
    signal = false;
    }
    return (FALSE) ;
    }


    To make the Hook to work, at your entrypoint, on AcRx::kInitAppMsg handler:

    acedRegisterFilterWinMsg (GripHook);


    To remove the Hook, inside your AcRx::kUnloadAppMsg handler:

    acedRemoveFilterWinMsg (GripHook);

    I don't know exactly how the resbuf information about grips are organized but it should be somewhere inside AutoCAD LISP or ObjectARX documentation.

    Hope this help.
    Fernando.

    By Blogger Fernando Malard, at 7:26 PM  

  • Hello

    I need to select some entities but i want to show a customized dialog like:
    "Select lines or [All/Single width/Double width]: "
    so that the command prompt accepts keywords or a selection set.
    (I tried acedSSGet, and acedEntSel but none of them works as i'd like)

    Regards, Alonso

    By Anonymous Anonymous, at 7:05 AM  

  • Hello Alonso,

    Keyword prompts are handled by two methods used together: acedInitGet() and acedGetKword(). Below is a simple example of a Yes/No prompt using keywords.

    TCHAR yesNo[8]={_T("")};
    acedInitGet(0, _T("Yes No"));
    acedGetKword(_T("\nProceed? Yes/No [Yes]: "), yesNo);

    if (!_tcsicmp(yesNo, _T("")) || !_tcsnicmp(yesNo,_T("Yes"),_tcslen(yesNo)))
    YourMethod1();
    else
    YourMethod2();

    More information at ObjectARX documentation of these methods.

    Regards.

    By Blogger Fernando Malard, at 8:36 AM  

  • Thx for your answer, but thats not what i wanted to know.

    If i use acedSSGet(..) how can i change the default promt from
    "Select objects:" to
    "Select lines [All/Single width/Double width]: "
    ?

    Regards, Alonso

    By Anonymous Anonymous, at 8:50 AM  

  • Hi Alonso,

    I'm afraid this is not possible. The standard "Select Objects" prompt can not be changed as far as I know.

    You will need to create your own command or use a commandWillStart() to handle something before the command loop starts.

    Sorry about that.

    By Blogger Fernando Malard, at 9:10 AM  

  • Hello!
    What is wrong with this code???:

    ads_name entName;
    AcDbObjectId BlockId= AcDbObjectId::kNull;
    //if (acedSSGet(_T("I"), NULL, NULL, NULL, entName) != RTNORM)
    if (acedSSGet(NULL, NULL, NULL, NULL, entName) != RTNORM)
    {
    acutPrintf(_T("\nNothing selected"));
    return;
    }


    Acad::ErrorStatus es;
    AcDbEntity* pEnt=NULL;
    //AcDbEntity* pBlockEnt;

    es = acdbGetObjectId(BlockId, entName);

    es = acdbOpenAcDbEntity(pEnt, BlockId, AcDb::kForWrite);
    if(es != Acad::eOk)
    {
    AfxMessageBox(_T("Error selection! Please restart the command!"), MB_OK);
    return;
    }

    I allways get an
    "
    Unhandled exception at 0x620.... in acad.exe: 0xC0054...: Access violation reading location 0x0030....
    "

    After selecting the entity, entName, BlockId are all OK, but
    acdbGetObjectId give me the error..
    Got crazy..

    By Blogger Bordei, at 5:57 PM  

  • Hello Bordei,

    The problem is that ads_name when used with acedSSGet() method represents a selection set and it may contain several entities even when you select just one.

    As a selection set it need to be traversed following its length and for each postion you need to use the acedSSName() method to get the entity name to get its AcDbObjectId through acdbGetObjectId().

    See this page's example showing how to get the selection set length and how to traverse all its entities.

    Best Regards.

    By Blogger Fernando Malard, at 8:53 PM  

  • I have no words to thank you!!
    :-)

    Kind regards!
    Ioan

    By Blogger Bordei, at 7:01 AM  

  • Hello Fernando!

    I'm using acedSSGet("_CP", in my Application. Unfortunately this function
    catches only Objects that are visible on Acad - screen. If the "_CP"-Polygon
    is outside the visible area, the function did not work. I do not like to make a window zoom to MIN/MAN rectangle area. Is there any other way in ARX to catch all (not only the visible) objects in a Polygon?

    Best regards!
    Ioan

    By Anonymous Anonymous, at 12:16 PM  

  • Hello Ioan,

    This is an AutoCAD normal behavior to speed up selection sets.

    If you want to select regions out of visible screen you will need to create your own selection routine which will search inside ModelSpace.

    This will be certainly slow and I would recommend you to perform a ZOOM Window around your polygon, select your entities and get back to the last ZOOM window.

    Sorry about the bad news.
    Regards,

    By Blogger Fernando Malard, at 3:04 PM  

  • Fernando,

    Thanks for all your previous help.
    I want to specify an iverse selection. Say I want to select all the entities that are NOT circles. I tried the following:

    struct resbuf *entFilter = NULL;
    entFilter = acutBuildList(-4, "<"NOT", RTDXF0, "CIRCLE", -4, "NOT>", RTNONE);
    acedSSGet(_T("X"), NULL, NULL, entFilter, setName);

    But it yields an empty selection. What am I missing?

    Dawie

    By Anonymous Anonymous, at 8:22 AM  

  • Dawie,

    Strange, your code seems to be ok except from an extra " before the first NOT.

    One other thing missing is the UNICODE macro _T() before all strings.

    By Blogger Fernando Malard, at 8:58 AM  

  • So it should work.

    The extra " is to get my submition to work with HTLM.

    By Anonymous Anonymous, at 6:00 AM  

  • Hi Fernando,

    your page is a great help for me.
    But, how to select all lines with xdata?

    I tried:

    acutBuildList(RTDXF0, _T("LINE"), -3, _T("KNOTEN"), _T("ZONE"), RTNONE);

    acutBuildList(RTDXF0, _T("LINE"), -3, _T("ZONE"), RTNONE);

    My xdata there:
    (-3 (EXTEND (1002 . {) (1011 -2.22572e+006 -3.72234e+006 0.0) (1010 0.0 0.0 0.0) (1005 . 109C5D2) (1000 . 0) (1002 . }) ) (ZONE (1002 . {) (1005 . 10998AA) (1000 . 1) (1002 . })) (KNOTEN (1002 . {) (1000 . 1) (1002 . })))

    I just getting errors like:

    Invalid type in acutBuildList() arg #4

    Regards,
    Soeren.

    By Anonymous Anonymous, at 3:55 PM  

  • Hi Soeren,

    You are missing the RTSTR before your strings. Try again with:

    acutBuildList(RTDXF0, _T("LINE"), -3, _T("KNOTEN"), RTSTR,_T("ZONE"), RTNONE);

    Regards.

    By Blogger Fernando Malard, at 5:30 PM  

  • Hi Fernando,

    I select a polyline via Editor.GetEntity and would like to display all vertexes just like when selecting the polyline by mouseclick.
    Is there something like "Displaygrippoints" ?

    By Anonymous Mark, at 7:06 AM  

  • Hello Mark,

    I think you may use two approaches:

    -Use Entity Overrule through .NET. Take a look at this article:

    Overrule

    -Use acedGrDraw() method to draw temporary graphics at your screen emulating the grip's drawing

    Regards,

    By Blogger Fernando Malard, at 8:33 AM  

  • 1. Overrule is not an option as I have to be compatible with ACAD 2008.

    2. The .NET counterpart of acedGrDraw is Editor.DrawVector.
    With this function I can draw a rectangle, but how can I fill it ?.

    By Anonymous Mark, at 9:18 AM  

  • Mark,

    You are correct about 2008.

    Well, the acedGrDraw() is very limited so to draw a rectangle you will need to draw 4 lines, etc. Maybe by using acedGrText() you can draw some special ASCII char with a painted square or something like that.

    By Blogger Fernando Malard, at 9:34 AM  

  • Hhhmmm,

    that doesn't sound very good.

    I would like to call worldDraw directly because it has handy functions such as geometry().polygon, but I did not find a way to call it.

    By Anonymous Mark, at 11:15 AM  

  • Mark,

    You cannot call worldDraw() yourself from outside a custom entity class tree. It is an internal method called by AutoCAD which you can intercept and do your custom drawing.

    Further, it is possible to draw custom graphics by using InputPoint (take a look at the SDK documentation about InputPointManager). It allows you to create the graphics direct into AutoCAD screen during your commands. You can capture the current selected entity, read its data and draw something. The major feature is that this method receives a drawing context and thus you may use the AcGi drawing primitives. It is very useful for creating cursors, custom symbols, etc.

    Regards.

    By Blogger Fernando Malard, at 11:23 AM  

  • Yes,

    We can then use DrawContext.Geometry()
    Still cumbersome, but better than nothing.

    Thanks

    By Anonymous Mark, at 3:05 PM  

  • Fernando,

    How do you get AutoCAD's current selection set? I tried to use acedSSGet() with "P", but it will give me the previous selection set even if there is nothing selected in AutoCAD when I call the function. I even tried acedGetCurrentSelectionSet(), but it gives me the same result.

    Johan

    By Anonymous Anonymous, at 11:10 AM  

  • Johan,

    The acedGetCurrentSelectionSet() method will only return you the current selection set if your custom command adds the ACRX_CMD_USEPICKSET flag.

    This flag will avoid AutoCAD to clear preselected entities when your command is fired.

    So, with this flag, before you call your custom command you will be able to select the entities and they will be returned by the acedGetCurrentSelectionSet() method from inside your custom command.

    Regards,

    By Blogger Fernando Malard, at 9:39 AM  

  • Hi Fernando,
    can you help me to convert an int
    to AcDbObjectId. I just succeeded
    to convert AcDbObjectId to int
    via acutsprintf for storing the Id.
    Now I need something for reverse.
    Thank you.

    Regards Frank

    By Anonymous Anonymous, at 2:37 PM  

  • Hello Frank,

    Sorry about not getting back before.

    You can use the AcDbObjectId methods called:

    asOldId() and setFromOldId()

    They will allow you to convert from and to a LONG.
    Make sure you call isValid() after converting to make sure the ObjectId is valid into current database context.

    Regards,

    By Blogger Fernando Malard, at 12:47 PM  

  • Hi Fernado,

    I am using RealDWG library where "acedSSGet" & other selection set functions are not available. Can you please suggest any other way to select entities within a specified boundary ?

    Or any approach to implement it ?

    Thanks
    Sandy

    By Blogger netSurfer, at 10:44 AM  

  • Hello Sandy,

    RealDWG does not allow any interface interaction. All acedXXX methods are meant to be used only with AutoCAD as the host runtime environment.

    Regards,

    By Blogger Fernando Malard, at 12:18 AM  

  • hi,

    I am new to LISP and ObjectARX programming...

    I am getting issues while selecting object in LISP and executing command (which uses object selected in LISP) in C++ as follows -:

    LISP code
    ----------------------
    (while (null en)
    (setq en (entsel))
    );while

    (command "MYCOMMAND")
    ----------------------

    CPP code (based on objectARX 2009) of "MYCOMMAND"
    ----------------------
    ads_name mSelectionSet;
    const TCHAR* sSelectionMode = _T("_I")
    int iStatus = acedSSGet(sSelectionMode, NULL, NULL,NULL, mSelectionSet);
    ----------------------

    (Tried with selection mode = "_I" \ "P") thinking that I have selected object in LISP.

    but get iStatus = -5001 & mSelectionSet holds garbage values after execution of "acedSSGet"

    So thought that selection set is not created in LISP so changed LISP code as follows -:

    LISP code
    ----------------------
    (while (null en)
    (setq en (entsel))
    );while

    (setq ss (ssadd (en) ss ))

    (command "MYCOMMAND")
    ----------------------

    In this case "MYCOMMAND" is not executed and saw following error at AutoCAD command prompt
    ----------------------
    Error: bad function: ( (195.785 26.4755 0.0))
    ----------------------

    Is it possible to select object in LISP code & use that in CPP code?
    If yes, How? via "Selection Set"? Please reply how to add selected entity in the selection set and how can that be accessed in CPP code?

    Is there some other way to access object in CPP code where selection is made using LISP functions?

    Any help is highly apprecited!

    thanks and regards
    ND

    By Anonymous Anonymous, at 9:09 AM  

  • Hello ND.

    It should be possible but I have never tried this.

    Try to use the following function from inside your C++ code:

    acedGetCurrentSelectionSet()

    Maybe it will work better than acedSSGet()

    Regards.

    By Blogger Fernando Malard, at 8:15 AM  

  • hi,

    Thanks a lot for your help!
    But sorry to say that using "acedGetCurrentSelectionSet" did not resolve my issue.

    However from other sources, I found how to get object ID associated to the entiry selected in LISP. It is as follows -:
    In LISP we select entity and assigne some name to that (say "EN" ) as
    ---
    (while (null en)
    (setq EN (entsel))
    );while

    (command "MYCOMMAND")
    ---

    In C++ code for "MYCOMMAND"
    ---
    const ACHAR* sname = L"EN";
    struct resbuf* value = NULL;
    struct resbuf* Head = NULL;

    if( acedGetSym(sname, &value))
    {
    Head = value;

    while(value != NULL)
    {
    if(value->restype != RTENAME)
    {
    value = value->rbnext;
    continue;
    }

    AcDbObjectId objectId;
    if(acdbGetObjectId
    (objectId,
    value->resval.rlname )
    != Acad::eOk)
    {
    break;
    }

    value = value->rbnext;
    }

    if(Head)
    acutRelRb(Head);
    }
    ---

    Thanks a lot for your help.
    Your blog is very good for ObjectARX learners like me.

    thanks and regards
    ND.

    By Anonymous Anonymous, at 5:17 AM  

  • Hi ND,

    Thank you for sharing the solution.

    Regards.

    By Blogger Fernando Malard, at 8:22 AM  

  • is it possible to select object using ObjectID

    By Anonymous Anonymous, at 4:34 AM  

  • If you mean by creating a selection set, it is something like this:


    // Suppose you have an ObjectIdArray of existing entities

    AcDbObjectIdArray selImport;

    // Prepare selection set
    ads_name lstSelecionSet;
    acedSSAdd(NULL, NULL, lstSelecionSet);

    for (int i = 0; i < selImport.length(); i++)
    {
    // add to selection set
    ads_name objEntityName;
    acdbGetAdsName(objEntityName, selImport[i]);

    acedSSAdd(objEntityName, lstSelecionSet, lstSelecionSet);
    }

    // After using the selection set you need to release it
    acedSSFree(lstSelecionSet);

    By Blogger Fernando Malard, at 8:01 AM  

  • I want to select an entity using its objectID, i m selecting entity by using it's point3d



    OuterObjectPoint3d = New Point3d(tempOuterEntity.GeomExtents.MaxPoint.X, tempOuterEntity.GeomExtents.MaxPoint.Y, tempOuterEntity.GeomExtents.MaxPoint.Z)

    if any other entity is exist at that place or intersect that line then i m unable to select that entity so i want to select that entity using it's object id.

    i want to create a function that will perform subtraction based on parameters of outerObjectID and innerObjectID

    my function work properly if no any adjacent entity exist or no intersection is found but if any intersection found then it give message duplicate object found

    please help me.

    By Blogger SPSharma, at 9:15 AM  

  • hi...
    How to read polyline?
    I have read Line,circle succesfully.
    Thanking You!!
    Snehal

    By Blogger SNEHA, at 12:47 PM  

  • Sneha,

    Polylines are different. To get their vertexes you will need to open the entity itself then traverser its vertexes by using a vertex iterator.

    The process is similar for 2D and 3D polylines (I don't know which one you need):

    void PolyPoints(AcDbObjectId plineId)
    {
    AcDb2dPolyline* pPline = NULL;
    acdbOpenObject(pPline, plineId, AcDb::kForRead);

    AcDbObjectIterator* pVertIter= pPline->vertexIterator();
    pPline->close();

    for (int vertexNumber = 0; !pVertIter->done(); vertexNumber++, pVertIter->step())
    {
    AcDbObjectId vertexObjId = pVertIter->objectId();
    AcDb2dVertex *pVertex = NULL;
    acdbOpenObject(pVertex, vertexObjId, AcDb::kForRead);

    AcGePoint3d location = pVertex->position();
    pVertex->close();

    }
    delete pVertIter;
    }

    This code is just a example for 2D polylines and you should add error checking and also support for 3D polylines if you will.

    Cheers.

    By Blogger Fernando Malard, at 2:41 PM  

  • Hi,
    struct resbuf eb1;
    TCHAR sbuf1[10];
    eb1.restype = 0; // Entity name
    _tcscpy(sbuf1, _T("POLYLINE"));
    eb1.resval.rstring = sbuf1;
    eb1.rbnext = NULL;

    // Select All Circles
    ads_name ss;
    if (acedSSGet(_T("X"), NULL, NULL, &eb1, ss) != RTNORM){

    acutRelRb(&eb1);
    return;

    }



    but,acedSSGet does not return RTNORM,so how can I get ads_name of polyline entity.And is there any method for rectangle,like AcDbLine for line.

    By Blogger SNEHA, at 3:21 AM  

  • SNEHA,

    The "POLYLINE" entity name corresponds to a 3D Polyline. The 2D Polyline is represented by the "LWPOLYLINE" entity name.

    Further, the rectangle is not an entity it is just a LWPOLYLINE created by a specific command.

    To know the exact entity name create it with the AutoCAD commands and then perform a LIST command over it and look what is written on first line right beside the Layer text.

    Regards,

    By Blogger Fernando Malard, at 10:15 AM  

  • Hi....
    Thank you so much!!!
    your answer helps me a lot.I have done it successfully!

    By Blogger SNEHA, at 2:46 AM  

  • Hi,


    AcDb2dPolyline* pPline = NULL;
    acdbOpenObject(pPline, plineId, AcDb::kForRead);

    AcDbObjectIterator* pVertIter= pPline->vertexIterator();
    pPline->close();

    for (int vertexNumber = 0; !pVertIter->done(); vertexNumber++, pVertIter->step())
    {
    AcDbObjectId vertexObjId = pVertIter->objectId();
    AcDb2dVertex *pVertex = NULL;
    acdbOpenObject(pVertex, vertexObjId, AcDb::kForRead);

    AcGePoint3d location = pVertex->position();
    pVertex->close();

    }
    delete pVertIter;






    i have tried this code,but i got exception at
    AcDbObjectIterator* pVertIter= pPline->vertexIterator();
    this line.
    Can u give me any suggestion plz?

    By Blogger smita, at 5:33 AM  

  • smita,

    You need to close your polyline only after you delete the iterator. Try to move the following line:

    pPline->close();

    to the end of your code.
    It should do the trick.

    Regards,

    By Blogger Fernando Malard, at 9:16 AM  

  • Hi,
    There is no exception at pPline->close() or delete VertIter.
    There is exception when i try to use any method of pPline,like pPline->vertexIterator(); or pPline->getEndPoint();
    Thank you for reply..........

    By Blogger smita, at 6:33 AM  

  • smita,

    Any call to an entity method requires it is on opened state because AutoCAD pointers are dynamic. If you try to call any entity method after calling close() through the same pointer it will crash AutoCAD.

    Regards.

    By Blogger Fernando Malard, at 10:06 AM  

  • hi...


    AcDb2dPolyline* pPline = NULL;
    acdbOpenObject(pPline, plineId, AcDb::kForRead);

    AcDbObjectIterator* pVertIter= pPline->vertexIterator();


    there is exception at

    AcDbObjectIterator* pVertIter= pPline->vertexIterator();
    this line only.we haven't close entity before this line.
    plz help me out.
    thank you!

    By Blogger smita, at 12:11 PM  

  • smita,

    Check the returned status from acdbOpenObject() method. Further, check if the entity wasn't left opened by a previous routine inside your application.

    It must work, something seems to be wrong with other portion of your code.

    Regards.

    By Blogger Fernando Malard, at 2:17 PM  

  • Hi Fernando

    I'm trying to use an open and not intersecting polyline to select objects using the mode of fence, but acedSSGet function returns an error code -5001 (Some other error.) I used the example code slightly modified by me (below). What is wrong there?

    Regards.
    badziewiak




    resbuf*
    ptArrayToResbuf(const AcGePoint3dArray& ptArray)
    {
    resbuf* ptList = NULL; // overall list
    resbuf* lastRb = NULL; // place holder to end of list
    resbuf* rb;
    int len = ptArray.length();
    for (int i=0;iresval.rpoint );
    if (ptList == NULL) {
    ptList = rb;
    lastRb = rb;
    }
    else {
    lastRb->rbnext = rb;
    lastRb = rb;
    }
    }
    return ptList;
    }

    bool fenceSelect( const AcGePoint3dArray& ptArray, ads_name& ss, const resbuf* filter )
    {
    // NOTE: flags not allowed on this type of selection
    resbuf* ptList = ptArrayToResbuf(ptArray);
    if (ptList == NULL)
    return false;

    int result = acedSSGet(_T("_F"), ptList, NULL, filter, ss);
    acutRelRb(ptList);
    return result == RTNORM;
    }

    //CUT...

    AcGePoint3dArray arPunkty;
    for( int i = 0; i < wPlinia->numVerts(); i++ )
    {
    AcGePoint2d p2d;
    ErrorStatus eS = wPlinia->getPointAt( i, p2d );
    if( eS != eOk )
    {
    acdbFail( L"\nGet polylinie point failed!" );
    acutPrintf( L" Error code: %d", eS );
    eS = wPlinia->close();
    return;
    } //if( eS != eOk )
    arPunkty.append( AcGePoint3d( p2d.x, p2d.y, 0 ) );
    } //for( int i = 0; i < wPlinia->numVerts(); i++ )
    ads_name ss;
    if( !fenceSelect( arPunkty, ss, NULL ) )
    {
    acedPrompt( L"\nNothing selected!" );
    ErrorStatus eS = wPlinia->close();
    return;
    } //if( !fenceSelect( arPunkty, NULL ) )

    acedSSSetFirst( ss, NULL );
    acedSSFree( ss );
    ErrorStatus eS = wPlinia->close();
    return;

    By Anonymous Anonymous, at 7:52 PM  

  • This comment has been removed by the author.

    By Blogger Fernando Malard, at 11:41 AM  

  • Hi Fernando,
    Is there a way to create a selection set picking enities from multiple layers using the acedSSGet(_T("X") function?

    The goal would be to create a selection set of, let's say, 2 layers. Layer 0 and Layer 1.

    Thanks
    Robert

    By Anonymous robert f, at 4:42 PM  

  • Hi robert,

    Did you try to use the Layer filter?

    eb2.restype = 8; // Layer name filter

    Take a look at this page's examples...it should work.

    Cheers,

    By Blogger Fernando Malard, at 12:07 PM  

Post a Comment

<< Home