Selecting the edge of a nested solid in ObjectARX

This entry was contributed by Adam Nagy, a member of DevTech EMEA based in Prague.

The question is really a combination of two problems:

  1. Selecting a subentity
  2. Selecting a nested entity

Selecting a subentity

First we should clarify what a subentity is:

A subentity is a pseudo entity which is a logical part of a real entity. In our sample drawing the solid is the real entity [AcDb3dSolid] and the edge is the pseudo entity (there is no AcDbEdge class). In AutoCAD we rely on IDs called GS (short for graphics system) markers to get to these subentities.

The ObjectARX help file contains a small piece of sample code showing how to highlight one of a solid's internal edges. Unfortunately, it does not work in shaded mode – always the face will be selected - and it will not find the subentity in the case of a nested entity.

Selecting a nested entity

Again, let's start by defining things:

For the purposes of this article, we're defining a nested entity as an entity that is placed inside a block [AcDbBlockTableRecord] other than one of the internal layout blocks [e.g. Model Space].

We can use a standard function such as acedNEntSelP() to select a nested entity, which gives back the bottommost selected entity and all its nesting entities – you can find information about it in the ObjectARX help file. But what about the GS markers we need?

The two combined

We really need a function that can select the bottommost nested entity and also gives back the [correct] GS marker of the subentity.

Fortunately, there is such a function, the undocumented brother of acedNEntSelP(). It does exactly what we need and is called acedNEntSelPEx(). It gives back the correct GS marker (even in shaded mode), provides the list of nesting entities and gives back the selected bottommost nested entity. Not only does it select edges and return the GS marker as we have seen, it also picks through spaces. e.g. say you are in paper space with no model space selected, from that mode you can use this function to select an entity in model space.

In the attached drawing we have the following structure:

SolidBlock2 -> SolidBlock -> Solid

[SolidBlock2 contains a reference to SolidBlock, which contains the Solid entity].

When using acedNEntSelPEx() [or acedNEntSelP()], we will get back a result buffer that contains the selected entity's nesting entities in the same order as getSubentPathsAtGsMarker() needs them – starting from the directly nesting entity going upwards until we reach the top-most nesting entity that contains all the others. In case where we select the solid in SolidBlock2 in our sample drawing, the path is:

  1. SolidBlock reference
  2. SolidBlock2 reference [which contains SolidBlock]

Now we just have to create an array filled with the above entities in the same order, but starting with the solid entity itself:

  1. Solid entity
  2. SolidBlock reference
  3. SolidBlock2 reference

We call the getSubentPathsAtGsMarker() function of the topmost nesting entity [SolidBlock2 reference] with the GS marker and the array we just created, and voilá, we get the correct subentity path that we need to highlight the subentity.

The attached project for Visual Studio 2005 (using ObjectARX 2007) contains both the help file code [in the "HelpfileSelect" command] and the rewritten code [in the "MySelect" command]:

Download ArxSelectEdge.zip

10 responses to “Selecting the edge of a nested solid in ObjectARX”

  1. I found your article while searching for info about nested entities. I have a similar problem that has me puzzled. I'm coding in VB.net using VS2005 and AutoCAD 2007.

    I have a 3dface inserted in a block and this block is inserted several times in other blocks. I am trying to determine the objectID for the block insert of the 3dface. I can easily get the handle for the top level block or the handle for the 3dface but the Xdata I'm looking for is in the block insert of the 3dface. I can even get the handle of the 3dface block but I don't know how to get the objectID for the inserted 3dface block I picked in the graphics window.

    Any help would be greatly appreciated as I can find very little help for VB.net and the AutoCAD API. Thnak you.

  2. Hi Kean:

    thanks for nice code, but how to selecting the face of a solid3d in ObjectARX or .NET?
    thanks.

  3. Hi ahlzl,

    Try looking into AcEdSolidSubentitySelector::selectFaces().

    I haven't used it myself, but it should do what you want (from ObjectARX).

    Regards,

    Kean

  4. successful!
    thanks again.

  5. Since two days I try to get this working.
    I m using VS2017 and the SDK for Autocad 2019.x64
    I created a new Project with the Wizard.
    And I added the code from you.
    But the undocumented Function is always underlined green.
    What am I doing wrong?
    A other undocumented function from another post from you "Cancelling an active command in AutoCAD"
    i got running in seconds. And it is not underlined in green.

    1. Hi Tim,

      I'm no longer working with AutoCAD (and don't have time to provide support, in any case): I suggest posting to the ObjectARX discussion group to see if someone there can help (ideally Adam, who created the sample project).

      Best,

      Kean

    2. Hi Tim,

      I wrote that 14 years and 14 AutoCAD releases ago, when AutoCAD did not even have a 64 bit version. My guess is that maybe the signature changed because of that.
      A much more recent article is using TCHAR instead of ACHAR - maybe that's all you need?
      adndevblog.typepad.com/autocad/2013/01/select-the-edge-of-a-nested-solid.html
      I have not touched AutoCAD for quite a while either, so if that is not the issue, please check on the ObjectARX forum as @keanw:disqus suggested.

      Cheers,
      Adam

    3. Thx for your answers. I don`t think that it is a TCHAR / ACHAR Problem.
      It is because the Function Definition of acedNEntSelPEx could not be found.

      error LNK2019: unresolved external symbol "int __cdecl acedNEntSelPEx(wchar_t const *,__int64 * const,double * const,int,double (* const)[4],struct resbuf * *,unsigned int,int *)" (?acedNEntSelPEx@@YAHPEB_WQEA_JQEANHQEAY03NPEAPEAUresbuf@@IPEAH@Z)...

      Maybe an entry point issue. But I have no idea how to solve that.
      I hope for a flash of thought. Otherwise I will post to the ObjectARX discussion group.

      1. Ah - you may need to scan through the relevant DLLs using "dumpbin /exports" to find the new signature (or if it's there at all). I'd start with any DLLs you find with an aced prefx.

        Kean

        1. now i got it 🙂
          the trick was to use intptr_t* like Abhay Joshi said here:
          adndevblog.typepad....
          And I have now managed to implement this correctly.
          Thanks again for the support 🙂

          extern int acedNEntSelPEx(const ACHAR *str, ads_name entres,
          ads_point ptres, int pickflag,
          ads_matrix xformres,
          struct resbuf **refstkres,
          unsigned int uTransSpaceFlag,
          intptr_t* gsmarker);
          ...

          static void
          highlightTest()
          {
          AcDbObjectId objId;
          AcGePoint3d pt3d;
          intptr_t marker
          ...

          static Acad::ErrorStatus
          getObjectAndGsMarker(AcDbObjectId& objId, AcGePoint3d& pt3d, ads_matrix& mx, resbuf*& rbChain, intptr_t& marker)
          ...

          static void
          highlightEdge(const AcDbObjectId& objId, AcGePoint3d& pt3d, ads_matrix& mx, resbuf*& rbChain, intptr_t marker)
          ...

Leave a Reply to Kean Walmsley Cancel reply

Your email address will not be published. Required fields are marked *