Author Topic: (entprev)  (Read 56678 times)

0 Members and 1 Guest are viewing this topic.

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: (entprev)
« Reply #45 on: November 24, 2013, 09:01:13 AM »
It depends where our entity supplied to function is situated...

You are missing the point - the code is painfully inefficient regardless of the position of the supplied entity in the drawing database.

Think about how the while loop is being evaluated: the code is retrieving a new selection set of all objects in an entire drawing layout every time the index variable is incremented.

Your code is doing the following:

Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
Query the entity at index 0
Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
Query the entity at index 1
Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
....

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
Re: (entprev)
« Reply #46 on: November 24, 2013, 09:08:53 AM »
It depends where our entity supplied to function is situated...

You are missing the point - the code is painfully inefficient regardless of the position of the supplied entity in the drawing database.

Think about how the while loop is being evaluated: the code is retrieving a new selection set of all objects in an entire drawing layout every time the index variable is incremented.

Your code is doing the following:

Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
Query the entity at index 0
Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
Query the entity at index 1
Iterate over the drawing database to retrieve a selection set of all objects in a drawing layout
....


You're right Lee, I overlooked that I have to Setq SSet before while loop... Code updated... Thanks for your revision... Nobody's perfect...

Thanks, M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Stefan

  • Bull Frog
  • Posts: 319
  • The most I miss IRL is the Undo button
Re: (entprev)
« Reply #47 on: November 24, 2013, 10:56:53 AM »
No, Stefan (entnext (entlast)) if (entlast) is polyline entity is very next nested entity to parent (entlast)... In my case where (entlast) is polyline (entnext (entlast)) = VERTEX entity...

caught again... :)
So (entnext <ename>) returns the next entity within model-space, except when <ename> is 2dpolyline, or attributed block. On the other hand, nor a  vertex or an attribute belongs to model-space, but to its owner (2d pline or insert object), so the ActiveX alternative gives different results. It seems to me like an inconsistency, inherited due to "compatibility" with older versions...


Well, I admit that my lisp doesn't meet your criteria, sorry Marko.

LE3

  • Guest
Re: (entprev)
« Reply #48 on: November 24, 2013, 01:18:42 PM »
following this - About Entity Name Functions (AutoLISP):
http://docs.autodesk.com/ACD/2013/ENU/index.html?url=files/GUID-30C33AF6-4BE3-4334-96BD-F929040C31D3.htm,topicNumber=d30e580452

Quote
(defun c:tst  (/ ent e efound)
  (if (setq e (car (entsel)))
    (progn
    (setq ent (entnext))
    (while (not (eq ent e))
      (setq efound ent)
      (setq ent (entnext ent)))
    (if   efound
      (redraw efound 3)))))

LE3

  • Guest
Re: (entprev)
« Reply #49 on: November 24, 2013, 07:32:13 PM »
Here it is an ARX approach:

Code: [Select]
static void GetEntityPreviousFrom(void)
{
ads_name eName;
ads_point pt;   
if (RTNORM != acedEntSel(_T("\nSelect from entity: "), eName, pt)) return;
AcDbObjectId id;
acdbGetObjectId(id, eName); 
AcDbObjectPointer<AcDbEntity> pObj(id, AcDb::kForRead);
if (pObj.openStatus() != Acad::eOk) return;
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
if (pBTR.openStatus() != Acad::eOk) return;
AcDbBlockTableRecordIterator* pIterator = NULL;
if (pBTR->newIterator(pIterator) != Acad::eOk) return;
AcDbEntity* pEnt = NULL;
if (pIterator->seek(pObj) == Acad::eOk)
{
pIterator->step(false, true);
AcDbObjectId objId;
pIterator->getEntityId(objId);
AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
if (pEnt.openStatus() == Acad::eOk) pEnt->highlight();
}
delete pIterator;
}

In case someone wants to tested the command is MyCommand - attached it is a debug version for AutoCAD 2014 only.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: (entprev)
« Reply #50 on: November 25, 2013, 12:03:57 AM »
Awesome idea with the ARX LE! I was wondering if it's possible to directly access the drawing database and simply obtain the previous record. Thanks to you I now know it "is possible".

As for Vovka's code (and others like it), they definitely are the most robust as they actually use entnext to implement the opposite of entnext. And could be adjusted to account for nested entities (as several of the previous posts already indicate). Perhaps it's not a bad idea, especially since entprev would usually be used very seldom (at least I hope so).

Re the "attached" entities (like attributes and vectors) acting differently using ActiveX: Yep that's because the DWG file is still a "flat" database file (i.e. one entity record following another with "special" codes to indicate it's actually owned by some other entity). ActiveX however maps these into an object hierarchy - as if the DWG is actually an object oriented database. That's why you see these differences.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

LE3

  • Guest
Re: (entprev)
« Reply #51 on: November 25, 2013, 09:32:14 AM »
Awesome idea with the ARX LE! I was wondering if it's possible to directly access the drawing database and simply obtain the previous record. Thanks to you I now know it "is possible".
Thank you irneb, and just to try to provide the function that could be used from autolisp (if it is compiled - not tested have not done arx in years now - HTH):
Code: [Select]
static int ads_entpreviousFrom(void)
{
struct resbuf *rb = acedGetArgs();
if (!rb)
{
acutPrintf(_T("\nError: function requires an ENAME argument. \n"));
return RSERR;
}
AcDbObjectId objId;
if (rb && (rb->restype == RTENAME))
{
if (acdbGetObjectId(objId, rb->resval.rlname) == Acad::eOk)
{
AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
if (pObj.openStatus() == Acad::eOk)
{
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
if (pBTR.openStatus() == Acad::eOk)
{
AcDbBlockTableRecordIterator* pIterator = NULL;
if (pBTR->newIterator(pIterator) == Acad::eOk)
{
AcDbEntity* pEnt = NULL;
if (pIterator->seek(pObj) == Acad::eOk) // if found from ename
{
pIterator->step(false, true); // step back
AcDbObjectId objId;
pIterator->getEntityId(objId);
AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
if (pEnt.openStatus() == Acad::eOk)
{
ads_name objName;
if (acdbGetAdsName(objName, objId) == Acad::eOk)
{

acedRetName(objName, RTENAME); // return the previous entity
}
}
}
delete pIterator;
}
}
}
}
}
return (RSRSLT);
}
Quote
Usage: (entpreviousFrom <ename>)
Return: Previous entity or nil

edit: removed the first delete pIterator; line - not required there, and added the latest compiled arx file, including entPreviousFrom function for autoLisp.
« Last Edit: November 25, 2013, 12:59:55 PM by LE »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: (entprev)
« Reply #52 on: November 25, 2013, 04:42:15 PM »
Awesome idea with the ARX LE! I was wondering if it's possible to directly access the drawing database and simply obtain the previous record. Thanks to you I now know it "is possible".
Thank you irneb, and just to try to provide the function that could be used from autolisp (if it is compiled - not tested have not done arx in years now - HTH):
Code: [Select]
static int ads_entpreviousFrom(void)
{
   struct resbuf *rb = acedGetArgs();
   if (!rb)
   {
      acutPrintf(_T("\nError: function requires an ENAME argument. \n"));
      return RSERR;
   }
   AcDbObjectId objId;
   if (rb && (rb->restype == RTENAME))
   {
      if (acdbGetObjectId(objId, rb->resval.rlname) == Acad::eOk)
      {
         AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
         if (pObj.openStatus() == Acad::eOk)
         {
            AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
            if (pBTR.openStatus() == Acad::eOk)
            {
               AcDbBlockTableRecordIterator* pIterator = NULL;
               if (pBTR->newIterator(pIterator) == Acad::eOk)
               {
                  AcDbEntity* pEnt = NULL;
                  if (pIterator->seek(pObj) == Acad::eOk) // if found from ename
                  {
                     pIterator->step(false, true); // step back
                     AcDbObjectId objId;
                     pIterator->getEntityId(objId);
                     AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
                     if (pEnt.openStatus() == Acad::eOk)
                     {
                        ads_name objName;
                        if (acdbGetAdsName(objName, objId) == Acad::eOk)
                        {
                           
                        acedRetName(objName, RTENAME); // return the previous entity
                        }
                     }
                  }
                  delete pIterator;
               }
            }
         }
      }
   }
   return (RSRSLT);
}
Quote
Usage: (entpreviousFrom <ename>)
Return: Previous entity or nil

edit: removed the first delete pIterator; line - not required there, and added the latest compiled arx file, including entPreviousFrom [/b] function for autoLisp.
Louis.
I tried your ARX and entPreviousFrom [/b]function for autoLispbut I think they does not work with nested entity.

LE3

  • Guest
Re: (entprev)
« Reply #53 on: November 25, 2013, 04:53:23 PM »
Did not do the nest part, that might need to be added (and update the function to work with that). if I get a chance will give it a try and posted back any update. Thanks.

Also Marco, if you have a test drawing, that I can use to run my tests.

BTW, No idea if the AcDbBlockTableRecordIterator class, provides the access to nested entities....
« Last Edit: November 25, 2013, 04:58:28 PM by LE »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: (entprev)
« Reply #54 on: November 26, 2013, 03:51:48 AM »
...
Also Marco, if you have a test drawing, that I can use to run my tests.
...
Here is my test drawing, with your function if I "nentsel" the yellow ellipse in the magenta rectangle I get the cyan ellipse
but the entprev entity is a vertex of the yellow ellipse.

BTW: I tried my function with Bricscad 13 and I get strange behavior...

Ciao.

LE3

  • Guest
Re: (entprev)
« Reply #55 on: November 26, 2013, 09:33:16 AM »
Here is my test drawing, with your function if I "nentsel" the yellow ellipse in the magenta rectangle I get the cyan ellipse
but the entprev entity is a vertex of the yellow ellipse.

BTW: I tried my function with Bricscad 13 and I get strange behavior...

Ciao.
Hi Marco,
Thank you for the sample drawing.

My arx function does not handle nested objects, it will need more work to update it.

Also, to make it work on blocks using a nested selection, looks like we simple need to replace this line:
Code: [Select]
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
With:
Code: [Select]
AcDbBlockTableRecordPointer pBTR(pObj->ownerId(), AcDb::kForRead);

I tried your function: ALE_NENTPREVIOUS and returns nil
Quote
Command: (setq entp (ALE_NENTPREVIOUS e))
nil

LE3

  • Guest
Re: (entprev)
« Reply #56 on: November 26, 2013, 10:11:48 AM »
^ continue from previous post...

To get the previous entity from a 2d polyline (in this case).... we need to do something like this - where pObj is the nested selection of a vertex:
Code: [Select]
acutPrintf(_T("\nThe sub entity is of type %s"), pObj->isA()->name());
if (pObj->isKindOf(AcDb2dVertex::desc()))
{
AcDbObjectPointer<AcDb2dPolyline> pPline(pObj->ownerId(), AcDb::kForRead);
if (pPline.openStatus() == Acad::eOk)
{
AcDbObjectIterator* pVertIterator = pPline->vertexIterator();
pVertIterator->setPosition(pObj);
pVertIterator->start(true);
pVertIterator->step(true);
AcDbObjectPointer<AcDb2dVertex> pVertex(pVertIterator->objectId(), AcDb::kForRead);
if (pVertex.openStatus() == Acad::eOk)
{
acutPrintf(_T("\nNested previous vertex [%s] of color [%ld] found... \n"), pVertex->isA()->name(), pVertex->colorIndex()); // debug...
}
delete pVertIterator;
}
}

Then it will do the search and return the previous vertex if any.... will add this once I get a chance to my method/function... Have fun!

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: (entprev)
« Reply #57 on: November 26, 2013, 10:39:30 AM »
...
I tried your function: ALE_NENTPREVIOUS and returns nil
Try this:
Code: [Select]
; Version 3.01 - 2013/11/26
(defun ALE_EntPrevious (EntNam / SelSet EntDat Countr SsLngt EntOut PrnEnt PrnDat TrueFl)
  (if
    (and
      (setq EntDat (entget EntNam))
      (setq TrueFl (= "BLOCK_RECORD" (DXF 0 (setq PrnDat (entget (setq PrnEnt (DXF 330 EntDat)))))))
      (assoc 410 EntDat)
    )
    (progn
      (setq SelSet (ssget "_X")   Countr 0   SsLngt (sslength SelSet))
      (while (> SsLngt Countr)
        (if (eq EntNam (ssname SelSet Countr)) (setq SsLngt 0) (setq Countr (1+ Countr)))
      )
      (setq EntOut (ssname SelSet (1+ Countr))  PrnEnt EntOut)
    )
    (if TrueFl (setq EntOut (DXF 360 PrnDat)) (setq EntOut PrnEnt))
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)

VovKa

  • Water Moccasin
  • Posts: 1631
  • Ukraine
Re: (entprev)
« Reply #58 on: November 26, 2013, 11:36:37 AM »
this will resolve the problem with nentseled vertexes
Code: [Select]
(defun entprev (e / e1 e2)
  (setq e1 (entget (cdr (assoc 330 (entget e))))
e1 (cdr (cond ((assoc 360 (reverse e1)))
      ((assoc -1 e1))
)
   )
  )
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)

Marc'Antonio, why do you use (ssget "_X")?
« Last Edit: November 26, 2013, 01:40:30 PM by VovKa »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: (entprev)
« Reply #59 on: November 26, 2013, 01:00:13 PM »
...
Marc'Antonio, why do you use (ssget "_X")?
Try to bench with my sample DWG, I think it is faster because you do not need
to pass all nested entities.