TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: ribarm on November 21, 2013, 03:32:16 PM

Title: (entprev)
Post by: ribarm on November 21, 2013, 03:32:16 PM
As opposed to (entnext), I wrote this little sub-function, but I don't know jet where can I use it but for checking purposes... :loco:
Maybe someone may find it useful...

Code: [Select]
(defun entprev ( e / ss en ssxelst )
  (if (eq (type e) 'ename)
    (if (setq ss (ssget "_X"))
      (progn
        (setq en (ssname ss (- (sslength ss) 1)))
        (setq ssxelst (cons en ssxelst))
        (while (setq en (entnext en))
          (setq ssxelst (cons en ssxelst))
        )
        (cadr (member e ssxelst))
      )
    )
    (progn (prompt "\n; error: bad argument type: lentityp ")(princ e)(princ))
  )
)

 :wink:
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 05:06:10 AM
   Another approach:
Code: [Select]
; Version 1.00 - 22/11/2013
;
(defun ALE_EntPrevious (EntNam / SelSet Countr SsLngt)
  (if (eq (type EntNam) 'ename)
    (if (setq SelSet (ssget "_X"))
      (progn
        (setq Countr 0   SsLngt (sslength SelSet))
        (while (> SsLngt Countr)
          (if (eq EntNam (ssname SelSet Countr))
            (setq SsLngt 0)
            (setq Countr (1+ Countr))
          )
        )
        (ssname SelSet (1+ Countr))
      )
    )
    (progn (prompt "\n; error: bad argument type: lentityp ")(princ EntNam)(princ))
  )
)
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 05:26:33 AM
Antonio, (ssname) function will return parent entityname instead of nested... My version uses (entnext) to build list of all entity + nested entity names and then it retrieves previous one from supplied entity , wich can be nested too...

Test this with 3d polyline entity or old heavy 2d polyline and see what I am talking about...

M.R.
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 06:29:03 AM
Here is just a slight improvement in that that now list of all entity + nested entity names is shorter - it is proccessed all from beginning till supplied entity is reached and therefore rest of entity names are unneccessary to build into this list... Previous entity name is returned just when our desired entity is reached...

Code: [Select]
(defun entprev ( e / ss en ssxelst )
  (if (eq (type e) 'ename)
    (if (setq ss (ssget "_X"))
      (progn
        (setq en (ssname ss (- (sslength ss) 1)))
        (setq ssxelst (cons en ssxelst))
        (while (and (/= (setq en (entnext en)) nil) (/= en e))
          (setq ssxelst (cons en ssxelst))
        )
        (setq ssxelst (cons en ssxelst))
        (cadr (member e ssxelst))
      )
    )
    (progn (prompt "\n; error: bad argument type: lentityp ")(princ e)(princ))
  )
)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 08:17:42 AM
Try this:
Code: [Select]
; Version 1.00 - 22/11/2013
;
(defun ALE_NEntPrevious (EntNam / SelSet Countr SsLngt EntOut EntNxt)
  (if (eq (type EntNam) 'ename)
    (if (setq SelSet (ssget "_X"))
      (progn
        (setq Countr 0   SsLngt (sslength SelSet))
        (while (> SsLngt Countr)
          (if (eq EntNam (ssname SelSet Countr))
            (setq SsLngt 0   EntOut (ssname SelSet (1+ Countr))  EntNxt EntOut)
            (setq Countr (1+ Countr))
          )
        )
        (while (and EntNxt (setq EntNxt (entnext EntNxt)))
          (if (eq EntNxt EntNam) (setq EntNxt nil) (setq EntOut EntNxt))
        )
        EntOut
      )
    )
    (progn (prompt "\n; error: bad argument type: lentityp ")(princ EntNam)(princ))
  )
)
Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 08:23:17 AM
An alternative method perhaps:
Code - Auto/Visual Lisp: [Select]
  1. ;; entprev  -  Lee Mac 2013-11-22
  2. (defun entprev ( e1 / e2 h1 h2 )
  3.     (setq h1 (cdr (assoc 5 (entget (entnext))))
  4.           h2 (cdr (assoc 5 (entget e1)))
  5.     )
  6.     (if (/= h1 h2)
  7.         (while
  8.             (not
  9.                 (or (= h1 (setq h2 (hex-- h2)))
  10.                     (and (setq e2 (handent h2)) (entnext e2))
  11.                 )
  12.             )
  13.             (setq e2 nil)
  14.         )
  15.     )
  16.     e2
  17. )
  18.  
  19. ;; Decrement Hex  -  Lee Mac 2013-11-22
  20. (defun hex-- ( h )
  21.     (   (lambda ( f ) (vl-list->string (reverse (f (reverse (vl-string->list h))))))
  22.         (lambda ( l )
  23.             (cond
  24.                 (   (null l) nil)
  25.                 (   (= 65 (car l)) (cons 57 (cdr l)))
  26.                 (   (= 48 (car l)) (cons 70 (f (cdr l))))
  27.                 (   (cons (1- (car l)) (cdr l)))
  28.             )
  29.         )
  30.     )
  31. )
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 08:30:41 AM
I think that now Antonio hit the target right into center... Although I am not familiar with Lee's suggestion, I would of course use the code that is better, but unfortunately I don't have benchmarking codes and haven't done this process - I think it will be nice to compare, but I don't know how and with what example...
 :embarrassed:
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 08:32:48 AM
@Lee: Very alternative!  :kewl:

(small drawing)
Benchmark.lsp | © 2005 Michael Puckett | All Rights Reserved

Elapsed milliseconds / relative speed for 4096 iteration(s):

    (LM_ENTPREV KKKK).................1186 / 6.27 <fastest>
    (ALE_NENTPREVIOUS KKKK).....5116 / 1.45
    (ENTPREV KKKK)........................7441 / 1 <slowes
Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 08:36:14 AM
Thank you Marc  8-)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 09:01:44 AM
@Lee I think there is something wrong:

Code: [Select]
Comando: (entget (ALE_nEntPrevious kkkk))
((-1 . <Nome entità: 7ffffb18880>) (0 . "SEQEND") (330 . <Nome entità: 7ffffb18870>) (5 . "5C10") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "$0__NORM") (6 . "Continuous") (-2 . <Nome entità: 7ffffb18870>))

Comando: (entget (entprev kkkk))
((-1 . <Nome entità: 7ffffb18880>) (0 . "SEQEND") (330 . <Nome entità: 7ffffb18870>) (5 . "5C10") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "$0__NORM") (6 . "Continuous") (-2 . <Nome entità: 7ffffb18870>))

Comando: (entget (lm_entprev kkkk))
((-1 . <Nome entità: 7ffffb18980>) (0 . "VERTEX") (330 . <Nome entità: 7ffffb18870>) (5 . "5C20") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "$0__NORM") (6 . "Continuous") (100 . "AcDbVertex") (100 . "AcDb2dVertex") (10 502.003 -324.114 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0713466) (91 . 0) (70 . 0) (50 . 5.68134))


Just a little improvement:

Code: [Select]
(defun ALE_NEntPrevious (EntNam / SelSet Countr SsLngt EntOut EntNxt)
  (if (eq (type EntNam) 'ename)
    (if (setq SelSet (ssget "_X"))
      (progn
        (setq 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))  EntNxt EntOut)
        (while (and EntNxt (setq EntNxt (entnext EntNxt)))
          (if (eq EntNxt EntNam) (setq EntNxt nil) (setq EntOut EntNxt))
        )
        EntOut
      )
    )
    (progn (prompt "\n; error: bad argument type: lentityp ")(princ EntNam)(princ))
  )
)
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 09:15:01 AM
Marc'Antonio, I did few more tests and Lee's code gave me correct results like my, or your code... Can you elaborate your results?... How did you get them?...

M.R.
Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 09:27:30 AM
@Lee I think there is something wrong:

This should fix it:
Code - Auto/Visual Lisp: [Select]
  1. ;; entprev  -  Lee Mac 2013-11-22
  2. (defun entprev ( e1 / e2 h1 h2 )
  3.     (setq h1 (cdr (assoc 5 (entget (entnext))))
  4.           h2 (cdr (assoc 5 (entget e1)))
  5.     )
  6.     (if (/= h1 h2)
  7.         (while
  8.             (not
  9.                 (or (= h1 (setq h2 (hex-- h2)))
  10.                     (and (setq e2 (handent h2)) (entnext e2))
  11.                 )
  12.             )
  13.             (setq e2 nil)
  14.         )
  15.     )
  16.     (if (and e2 (not (eq e1 (entnext e2))))
  17.         (entnext e2)
  18.         e2
  19.     )
  20. )
  21.  
  22. ;; Decrement Hex  -  Lee Mac 2013-11-22
  23. (defun hex-- ( h )
  24.     (   (lambda ( f ) (vl-list->string (reverse (f (reverse (vl-string->list h))))))
  25.         (lambda ( l )
  26.             (cond
  27.                 (   (null l) nil)
  28.                 (   (= 65 (car l)) (cons 57 (cdr l)))
  29.                 (   (= 48 (car l)) (cons 70 (f (cdr l))))
  30.                 (   (cons (1- (car l)) (cdr l)))
  31.             )
  32.         )
  33.     )
  34. )
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 09:38:49 AM
My test on empty DWG:

draw a line
draw a circle
Comando: PELLIPSE
Digitare nuovo valore per PELLIPSE <0>: 1
draw a ELLISSE
draw a ELLISSE

Comando: (setq kkkk (car (entsel)))  select last ellipse

Comando: !kkkk
<Nome entità: 7ffffb08090>

Comando: (entnext (entprev kkkk))
<Nome entità: 7ffffb18f30>

Comando: (entnext (ALE_NEntPrevious kkkk))
<Nome entità: 7ffffb08090>

Comando: (entnext (LM_entprev1 kkkk))
<Nome entità: 7ffffb18f30>

Comando: (entnext (LM_entprev2 kkkk))
<Nome entità: 7ffffb08010>
Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 09:47:15 AM
I was a little too hasty with my fix, try this:
Code - Auto/Visual Lisp: [Select]
  1. ;; entprev  -  Lee Mac 2013-11-22
  2. (defun entprev ( e1 / e2 h1 h2 )
  3.     (setq h1 (cdr (assoc 5 (entget (entnext))))
  4.           h2 (cdr (assoc 5 (entget e1)))
  5.     )
  6.     (if (/= h1 h2)
  7.         (while
  8.             (not
  9.                 (or (= h1 (setq h2 (hex-- h2)))
  10.                     (and (setq e2 (handent h2)) (entnext e2))
  11.                 )
  12.             )
  13.             (setq e2 nil)
  14.         )
  15.     )
  16.     (while (and e2 (not (eq e1 (entnext e2))))
  17.         (setq e2 (entnext e2))
  18.     )
  19.     e2
  20. )
  21.  
  22. ;; Decrement Hex  -  Lee Mac 2013-11-22
  23. (defun hex-- ( h )
  24.     (   (lambda ( f ) (vl-list->string (reverse (f (reverse (vl-string->list h))))))
  25.         (lambda ( l )
  26.             (cond
  27.                 (   (null l) nil)
  28.                 (   (= 65 (car l)) (cons 57 (cdr l)))
  29.                 (   (= 48 (car l)) (cons 70 (f (cdr l))))
  30.                 (   (cons (1- (car l)) (cdr l)))
  31.             )
  32.         )
  33.     )
  34. )

Thanks for testing Marc  :-)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 22, 2013, 09:54:23 AM
Now I think is OK:

Code: [Select]
(defun c:Test ( )
(setq kkkk (car (entsel)))
(princ "\nkkkk              ") (princ kkkk)
(princ "\nALE_NEntPrevious  ") (princ (entnext (ALE_NEntPrevious kkkk)))
(princ "\nLM_entprev3       ") (princ (entnext (LM_entprev3 kkkk)))
(princ "\nentprev           ") (princ (entnext (entprev kkkk)))
(princ)
)
Code: [Select]
Selezionare oggetto:
kkkk              <Nome entità: 7ffffb081b0>
ALE_NEntPrevious  <Nome entità: 7ffffb081b0>
LM_entprev3       <Nome entità: 7ffffb081b0>
entprev           <Nome entità: 7ffffb080d0>
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 10:02:34 AM
Yes, there is still something wrong...

Code: [Select]
Command: !e
<Entity name: 7ffffb05c60>
Command: (entnext e)
<Entity name: 7ffffb05c80>
Command: (entprev e)
<Entity name: 7ffffb05c50>
Command: (entprev (entnext e))
nil
Command: (entnext (entprev e))
<Entity name: 7ffffb05c60>

Why is this :
Code: [Select]
Command: (entprev (entnext e))
nil

M.R. (It seems that you're right Antonio something's wrong...)
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 10:09:27 AM
It seems that only my version works correct with this trick :

Code: [Select]
Command: (entprev (entnext e))
<Entity name: 7ffffb05c60>
Command: (entnext (entprev e))
<Entity name: 7ffffb05c60>

But its the slowest variant... :cry:
Title: Re: (entprev)
Post by: LE3 on November 22, 2013, 10:14:23 AM
maybe this:
Code: [Select]
(defun lastEnt (/ a b) (if (setq a (entlast)) (while (setq b (entnext a)) (setq a b))) a)
(defun previousEnt (/ le pe) (setq le (lastEnt)) (entdel le) (setq pe (lastEnt)) (entdel le) pe)
Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 10:19:59 AM
Nice idea Luis  :-)
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 10:27:29 AM
I don't see where Luis is supplying entity from witch are result to be retrieved...

And IMO Antonio's code should work, but something's wrong, I just don't see it...
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 10:47:07 AM
I figured why Antonio's code isn't working as it should...

When (entprev (entnext e))
(entnext e) is actually nested entity from entity e, so when supplied this kind of entity, this condition (eq EntNam (ssname SelSet Countr)) will never be true, so (while) loop is continuing to search until all entities from SelSet witch is actually (ssget "_X") are processed, as a result of while loop not finding match, counter is incrementing all the way, and this line (setq EntOut (ssname SelSet (1+ Countr))  EntNxt EntOut) will assign EntOut variable nil, because (ssname SelSet (sslength SelSet)) is always nil - ssname can find entities in range from [0 - (1- (sslength SelSet))]... So EntOut = nil => (entprev (entnext e)) => nil
Title: Re: (entprev)
Post by: LE3 on November 22, 2013, 11:13:37 AM
I don't see where Luis is supplying entity from witch are result to be retrieved...
no problem, was just trying to add something on the plate - eventually if I get a chance will try to write the function with the from entity argument.... but my lisp skills are dead. have fun
Title: Re: (entprev)
Post by: roy_043 on November 22, 2013, 11:15:37 AM
@ Lee Mac:
Test 1.
Create a dwg with 2 entities:
(LM_entprev (entlast)) => nil

Test 2.
Create a dwg with 3 entities and delete the 2nd entity:
(LM_entprev (entlast)) => <Entity name: #>
(entget (LM_entprev (entlast))) => nil

Took me a while to understand your (hex--). Interesting approach.
But why not?:
Code: [Select]
(defun alt_hex-- ( hex / foo)
  (defun foo (lst)
    (cond
       ((null lst) nil)
       ((= 65 (car lst)) (cons 57 (cdr lst)))
       ((= 48 (car lst)) (cons 70 (foo (cdr lst))))
       ((cons (1- (car lst)) (cdr lst)))
    )
  )
  (vl-list->string (reverse (foo (reverse (vl-string->list hex)))))
)

Title: Re: (entprev)
Post by: Lee Mac on November 22, 2013, 11:35:27 AM
@ Lee Mac:
Test 1.
Create a dwg with 2 entities:
(LM_entprev (entlast)) => nil

Test 2.
Create a dwg with 3 entities and delete the 2nd entity:
(LM_entprev (entlast)) => <Entity name: #>
(entget (LM_entprev (entlast))) => nil

I don't have time right now, but I shall investigate your findings - thanks roy  :-)

Took me a while to understand your (hex--). Interesting approach.
But why not?:
Code: [Select]
(defun alt_hex-- ( hex / foo)
  (defun foo (lst)
  ...
)

Thanks - Both methods are equivalent of course, I just like to experiment with different methods in order to discover & demonstrate new ways of doing things.  :-)
Title: Re: (entprev)
Post by: LE3 on November 22, 2013, 01:02:03 PM
I don't see where Luis is supplying entity from witch are result to be retrieved...

ok - played with on my lunch break.... and continued with a similar approach, let's see if works.
Code: [Select]
(defun lastEnt (/ a b) (if (setq a (entlast)) (while (setq b (entnext a)) (setq a b))) a)
(defun previousEnt (/ le pe) (setq le (lastEnt)) (entdel le) (setq pe (lastEnt)) (entdel le) pe)
(defun previousEntFromEnt  (e / a b l pe)
  (setq a e)
  (while (setq b (entnext a))
    (setq l (cons b l))
    (setq a b))
  (foreach i l (entdel i))
  (setq pe (previousEnt))
  (foreach i l (entdel i))
  pe)

test command:
Quote
(defun c:tst  (/ e p)
  (if (setq e (car (entsel)))
    (progn
      (if (setq p (previousEntFromEnt e))
   (redraw p 3)))))
Title: Re: (entprev)
Post by: owenwengerd on November 22, 2013, 01:06:24 PM
I don't have time at the moment to dig out my old code, but I once wrote a version similar to Lee's that was better optimized for sparse handles (i.e. drawings with large handle gaps between consecutive entities) by using a look-ahead (or rather, look-behind in this case) algorithm in the case where the previous handle doesn't exist. The idea was to find an earlier entity without enumerating every single handle in a large gap. Once any previous entity is found, (entnext) could be used to find the "most" previous entity between the found entity and the base entity.
Title: Re: (entprev)
Post by: irneb on November 22, 2013, 03:00:15 PM
My try  :D ... have to keep my hand in
Code - Auto/Visual Lisp: [Select]
  1. (defun hex->dec  (hex / fact)
  2.   (setq fact (expt 16 (strlen hex)))
  3.   (apply '+
  4.          (mapcar (function (lambda (h)
  5.                              (* (cond ((> h 57) (- h 55))
  6.                                       ((> h 47) (- h 48)))
  7.                                 (setq fact (/ fact 16)))))
  8.                  (vl-string->list hex))))
  9.  
  10.  
  11. (defun dec->hex  (dec / d lst)
  12.   (while (> dec 0)
  13.     (setq d   (rem dec 16)
  14.           lst (cons (cond ((> d 9) (+ d 55))
  15.                           (t (+ d 48)))
  16.                     lst)
  17.           dec (lsh dec -4)))
  18.   (vl-list->string lst))
  19.  
  20.  
  21. (defun entprev  (eName / h d en stop found)
  22.   (setq h    (hex->dec (cdr (assoc 5 (entget eName))))
  23.         stop (1- (hex->dec (cdr (assoc 5 (entget (entnext)))))))
  24.   (while (and (not found) (> (setq h (1- h)) stop))
  25.     (if (and (setq en (handent (dec->hex h))) (setq d (entget en)))
  26.       (progn (setq h (hex->dec (cdr (assoc 5 d))))
  27.              (if (eq (entnext en) eName)
  28.                (setq found en)))))
  29.   found)
A bit imperative, but it works.
Title: Re: (entprev)
Post by: VovKa on November 22, 2013, 03:48:51 PM
Code: [Select]
(defun entprev (e / e1 e2)
  (setq e1 (entnext))
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)

be careful with decreasing hex, sometimes handles in custom generated dxfs are total mess
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 03:49:32 PM
Congratulations, Irne... It works, I've checked and it's fast...

(entnext (entprev e)) = e
and also
(entprev (entnext e)) = e, where (entnext e) is nested ename of e (POLYLINE entity)...

Thanks again, M.R. :-)
Title: Re: (entprev)
Post by: ribarm on November 22, 2013, 03:54:19 PM
Code: [Select]
(defun entprev (e / e1 e2)
  (setq e1 (entnext))
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)

be careful with decreasing hex, sometimes handles in custom generated dxfs are total mess

Excellent logic, VovKa, congratulations, too...
Title: Re: (entprev)
Post by: LE3 on November 22, 2013, 04:14:09 PM
Code: [Select]
(defun entprev (e / e1 e2)
  (setq e1 (entnext))
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)

be careful with decreasing hex, sometimes handles in custom generated dxfs are total mess
nice... I tried a similar approach but no luck -- I recall seeing a ent prev function on the old CompuServe forums that was also a simple one... again nice stuff.
Title: Re: (entprev)
Post by: irneb on November 23, 2013, 06:42:46 AM
Good call Vovka. I did know there was some weird situations with the handle. Actually noted some issue with deleted entities as well in an old Augi thread: http://forums.augi.com/showthread.php?92053-Help-Rotation-angle-of-text&p=918573&viewfull=1#post918573

But obviously your brute-force method could become extremely slow on large drawings. That's the main reason for using the handle decrement idea. I wonder if something similar could be achieved using ObjectID's instead? Though I think those are random numbers (i.e. the drawing database has a hash-table index and the ID is the hash code), but would have to check.

Another issue with yours is it won't work inside of block definitions. Neither would the selection set versions. E.g. if the given ename is a nested entity inside a block, entnext gives the next entity inside that block - so you'd expect this entprev to give the previous entity also. Same would go for dictionaries & xrecords.

Perhaps that is the idea Owen mentioned about optimizing: If the given entity is inside a block then only search from that block's nested entities, if outside then skip all entities owned by a block record (which is not too difficult as it's just a dxf code of any one of the nesded entities). Though going through all possibilities could become a bit hairy since Model space and Paper Space tabs are also stored as block definitions, but in their case entnext mashes them up.
Title: Re: (entprev)
Post by: ribarm on November 23, 2013, 09:24:34 AM
Just to make it clear...
Where (entnext) won't enter and return result, (entprev) shouldn't too... (entprev) is opposed function to (entnext)... So if handles are somehow altered by Autodesk intervention in future releases, I think IMO that this VovKa's code is the most acceptable no matter for its brute force slowness on large drawings... (I've tested mine witch is similar to VovKa's in method it is used with difference that my is building list along with checking during while loop on 140000 entities and it returned result in approx. 2-5 sec.)... I doubt that this function will be used in that big drawings, but then again VovKa's code doesn't built list and I suppose it's also therefore faster... So my conclusion is that probably the most adequate answer to this task is VovKa's reply with small intervention for checking argument type at the beginning and error message if argument condition isn't satisfied...

Code - Auto/Visual Lisp: [Select]
  1. (defun entprev (e / e1 e2)
  2.   (if (eq (type e) 'ename)
  3.     (progn
  4.       (setq e1 (entnext))
  5.       (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  6.         (setq e1 e2)
  7.       )
  8.       e1
  9.     )
  10.     (progn (prompt "\n; error: bad argument type: lentityp ")(princ e)(princ))
  11.   )
  12. )
  13.  

You may agree with me or you may not, but I was trying to make some reasonable conclusion...
M.R.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 23, 2013, 01:04:05 PM
I figured why Antonio's code isn't working as it should...

When (entprev (entnext e))
(entnext e) is actually nested entity from entity e, so when supplied this kind of entity, ...
Yes previous version do not works with nested entity (my tests was with entsel not with nentsel).
Try this, MAYBE it is faster if there are many complex entities:

Code: [Select]
; Version 1.10 - 23/11/2013
(defun ALE_NEntPrevious_110 (EntNam / SelSet EntDat Countr SsLngt EntOut EntNxt PrnEnt)
  (if (and (eq (type EntNam) 'ename) (assoc 410 (setq EntDat (entget EntNam))))
    (if (= "BLOCK_RECORD" (DXF 0 (entget (setq PrnEnt (DXF 330 EntDat)))))
      (if (setq SelSet (ssget "_X"))
        (progn
         (setq 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))  EntNxt EntOut)
          (while (and EntNxt (setq EntNxt (entnext EntNxt)))
            (if (eq EntNxt EntNam) (setq EntNxt nil) (setq EntOut EntNxt))
          )
        )
      )
      (progn
        (setq EntOut PrnEnt)
        (while (and PrnEnt (setq PrnEnt (entnext PrnEnt)))
          (if (eq PrnEnt EntNam) (setq PrnEnt nil) (setq EntOut PrnEnt))
        )
      )
    )
  )
  EntOut
)

Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 23, 2013, 01:08:53 PM
...
You may agree with me or you may not, but I was trying to make some reasonable conclusion...
M.R.

IMHO in VovKa's entprev you can put a condition to avoid false results if the entity is the first in the database (no previous).
Title: Re: (entprev)
Post by: VovKa on November 23, 2013, 01:26:16 PM
little improvement (i hope)
Code: [Select]
(defun entprev (e / e1 e2)
  (setq e1 (cdr (assoc 360
       (entget (cdr (assoc 330 (entget e))))
)
   )
  )
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)
test it with nentsel
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 23, 2013, 03:27:19 PM
little improvement (i hope)
Code: [Select]
(defun entprev (e / e1 e2)
  (setq   e1 (cdr   (assoc 360
             (entget (cdr (assoc 330 (entget e))))
      )
      )
  )
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2)
  )
  e1
)
test it with nentsel
I have tested but I had some problems. This is another version with your contribution:
Code: [Select]
; Version 2.00 - 23/11/2013
(defun ALE_NEntPrevious_2 (EntNam / EntNm2 EntDat SsLngt EntOut PrnEnt)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (= "BLOCK_RECORD" (DXF 0 (entget (setq PrnEnt (DXF 330 EntDat)))))
    )
    (setq EntOut (entnext))
    (setq EntOut PrnEnt)
  )
  (while (and EntOut (not (eq EntNam (setq EntNm2 (entnext EntOut)))))
    (setq EntOut EntNm2)
  )
  EntOut
)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 24, 2013, 04:54:01 AM
Last version, less code:
Code: [Select]
; Version 3.00 - 2013/11/24
(defun ALE_EntPrevious (EntNam / SelSet EntDat Countr SsLngt EntOut PrnEnt)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (= "BLOCK_RECORD" (DXF 0 (entget (setq PrnEnt (DXF 330 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)
    )
    (setq EntOut PrnEnt)
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)
Title: Re: (entprev)
Post by: ribarm on November 24, 2013, 06:22:23 AM
I was just going to propse the same, Marc'...

Even more optimized...

Code - Auto/Visual Lisp: [Select]
  1. ; Version 3.00 - 24/11/2013
  2. (defun entprev (EntNam / EntNm2 EntDat SsEnts SsCount EntOut PrnEnt)
  3.   (if
  4.     (and
  5.       (assoc 410 (setq EntDat (entget EntNam)))
  6.       (= "BLOCK_RECORD" (ACET-DXF 0 (entget (setq PrnEnt (ACET-DXF 330 EntDat)))))
  7.     )
  8.     (progn
  9.       (setq SsCount -1)
  10.       (setq SsEnts (ssget "_X" (list (assoc 410 EntDat))))
  11.       (while (not (eq EntNam (setq PrnEnt (ssname SsEnts (setq SsCount (1+ SsCount)))))))
  12.       (setq PrnEnt (ssname SsEnts (1+ SsCount)))
  13.       (setq EntOut PrnEnt)
  14.     )
  15.     (setq EntOut PrnEnt)
  16.   )
  17.   (while (and EntOut (not (eq EntNam (setq EntNm2 (entnext EntOut)))))
  18.     (setq EntOut EntNm2)
  19.   )
  20.   EntOut
  21. )
  22.  

Thanks, Marc'
Title: Re: (entprev)
Post by: Stefan on November 24, 2013, 06:53:57 AM
Another one:
Code - Auto/Visual Lisp: [Select]
  1. (defun entprev (e / owner i prev crt)
  2.   (setq owner (vla-objectidtoobject *acdoc* (vla-get-ownerid (setq e (vlax-ename->vla-object e))))
  3.         i     -1
  4.   )
  5.   (while
  6.     (not
  7.       (=
  8.         (vla-get-objectid e)
  9.         (vla-get-objectid (setq crt (vla-item owner (setq i (1+ i)))))
  10.       )
  11.     )
  12.     (setq prev crt)
  13.   )
  14.   (if
  15.     prev
  16.     (vlax-vla-object->ename prev)
  17.     (not (princ "\nNo previous entity.\n"))
  18.   )
  19. )

Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / e)
  2.   (if
  3.     (and
  4.       (setq e (car (entsel)))
  5.       (setq e (entprev e))
  6.       )
  7.     (sssetfirst nil (ssadd e (ssadd)))
  8.     )
  9.   (princ)
  10.   )
entprev works with (nentsel) too.
Title: Re: (entprev)
Post by: ribarm on November 24, 2013, 07:09:33 AM
Stefan, your version isn't good, although another cunning approach...

Here are results :
Code: [Select]
Command: (entnext (entprev (entlast)))
<Entity name: 7ffff5beb30>
Command: (entlast)
<Entity name: 7ffff5bec40>
Command: (entprev (entnext (entlast)))
; error: ActiveX Server returned the error: unknown name: Item

Tested on 10000 2d Polyline entities... (not LWPOLYLINEs)
M.R.
Title: Re: (entprev)
Post by: Lee Mac on November 24, 2013, 07:56:51 AM
Even more optimized...

You sure about that...?  :?

Your code is retrieving a new selection set (and hence iterating over the entire drawing database) for every iteration of the while loop...  :-o
Quote from: ribarm
Code - Auto/Visual Lisp: [Select]
  1.     (not
  2.         (eq EntNam
  3.             (setq PrnEnt
  4.                 (ssname
  5.                     (setq SsEnts
  6.                         (ssget "_X" (list (assoc 410 EntDat)))
  7.                     )
  8.                     (setq SsCount (1+ SsCount))
  9.                 )
  10.             )
  11.         )
  12.     )
  13. )
Title: Re: (entprev)
Post by: Stefan on November 24, 2013, 08:30:02 AM
Stefan, your version isn't good, although another cunning approach...

Here are results :
Code: [Select]
Command: (entnext (entprev (entlast)))
<Entity name: 7ffff5beb30>
Command: (entlast)
<Entity name: 7ffff5bec40>
Command: (entprev (entnext (entlast)))
; error: ActiveX Server returned the error: unknown name: Item
You are right Marko. I didn't test my lisp on 2dpolylines. My mistake.
About the last error, (entnext (entlast)) is always nil, so (entprev nil) ends with an error as it should be. But you are right again, I should catch this error and print a message instead.
Title: Re: (entprev)
Post by: ribarm on November 24, 2013, 08:30:48 AM
Even more optimized...

You sure about that...?  :?

Your code is retrieving a new selection set (and hence iterating over the entire drawing database) for every iteration of the while loop...  :-o
Quote from: ribarm
Code - Auto/Visual Lisp: [Select]
  1.     (not
  2.         (eq EntNam
  3.             (setq PrnEnt
  4.                 (ssname
  5.                     (setq SsEnts
  6.                         (ssget "_X" (list (assoc 410 EntDat)))
  7.                     )
  8.                     (setq SsCount (1+ SsCount))
  9.                 )
  10.             )
  11.         )
  12.     )
  13. )

It depends where our entity supplied to function is situated... If it's near last entity (ssname ss 0), than this is more optimized - if it's near starting entity (ssname ss (1- (sslength ss)) than this isn't case, but in fact that newer version is searching for parent entity and when it finds it then steps to searching nested it is better structured function than just using (entnext) from starting entity till the previous one... IMO

M.R.
Title: Re: (entprev)
Post by: ribarm on November 24, 2013, 08:33:13 AM
Stefan, your version isn't good, although another cunning approach...

Here are results :
Code: [Select]
Command: (entnext (entprev (entlast)))
<Entity name: 7ffff5beb30>
Command: (entlast)
<Entity name: 7ffff5bec40>
Command: (entprev (entnext (entlast)))
; error: ActiveX Server returned the error: unknown name: Item
You are right Marko. I didn't test my lisp on 2dpolylines. My mistake.
About the last error, (entnext (entlast)) is always nil, so (entprev nil) ends with an error as it should be. But you are right again, I should catch this error and print a message instead.

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...
Title: Re: (entprev)
Post by: Lee Mac 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
....
Title: Re: (entprev)
Post by: ribarm 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.
Title: Re: (entprev)
Post by: Stefan 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.
Title: Re: (entprev)
Post by: LE3 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)))))
Title: Re: (entprev)
Post by: LE3 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.
Title: Re: (entprev)
Post by: irneb 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.
Title: Re: (entprev)
Post by: LE3 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.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi 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.
Title: Re: (entprev)
Post by: LE3 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....
Title: Re: (entprev)
Post by: Marc'Antonio Alessi 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.
Title: Re: (entprev)
Post by: LE3 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
Title: Re: (entprev)
Post by: LE3 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!
Title: Re: (entprev)
Post by: Marc'Antonio Alessi 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
)
Title: Re: (entprev)
Post by: VovKa 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")?
Title: Re: (entprev)
Post by: Marc'Antonio Alessi 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.
Title: Re: (entprev)
Post by: LE3 on November 26, 2013, 01:13:38 PM
Hi Marco,
Tried your latest function and works.

Can you test the latest entPreviousFrom function? and also maybe do a benchmark?

Have not added the part for selection of nested objects inside of blocks.

Here it is the updated function - source code:
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;
ads_name objName;
if (rb && (rb->restype == RTENAME))
{
if (acdbGetObjectId(objId, rb->resval.rlname) == Acad::eOk)
{
AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
if (pObj.openStatus() == Acad::eOk)
{
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)
{
if (acdbGetAdsName(objName, objId) == Acad::eOk)
{
acedRetName(objName, RTENAME); // return the previous entity
}
}
delete pVertIterator;
}
}
else
{
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead); //pObj->ownerId()
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)
{
if (acdbGetAdsName(objName, objId) == Acad::eOk)
{
acedRetName(objName, RTENAME); // return the previous entity
}
}
}
delete pIterator;
}
}
}
}
}
}
return (RSRSLT);
}

Thanks.
Title: Re: (entprev)
Post by: VovKa on November 26, 2013, 01:27:24 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.
but entnext doesn't step into nested objects
Title: Re: (entprev)
Post by: Lee Mac on November 26, 2013, 01:37:25 PM
but entnext doesn't step into nested objects

By 'nested', I think Marc is referring to Attributes & Vertices in this case.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 26, 2013, 01:45:21 PM
but entnext doesn't step into nested objects

By 'nested', I think Marc is referring to Attributes & Vertices in this case.
@Lee: Yes, thanks for your clarification.

@VovKa: the last version do not work on "normal" entities...

@Louis: I have tested your version, it seem works but I can not do do a benchmark, I need a version that accept argument. Also I think it is difficult to compare Lisp and ARX at the same time.

Title: Re: (entprev)
Post by: VovKa on November 26, 2013, 01:50:15 PM
but entnext doesn't step into nested objects

By 'nested', I think Marc is referring to Attributes & Vertices in this case.
now i see, thanks. but in this case (entnext (entprev e)) will not be equal to e
and more (ssget "_X") will iterate through all entities on all layouts
Title: Re: (entprev)
Post by: LE3 on November 26, 2013, 01:52:57 PM
Marco.-

The entPreviousFrom it is an autolisp function and accepts one argument - what do you mean by that accept argument?.

Where: <ename> normal or nested
Usage: (entPreviousFrom <ename>)
Title: Re: (entprev)
Post by: VovKa on November 26, 2013, 01:53:17 PM
@VovKa: the last version do not work on "normal" entities...
yep, thank you
i've fixed it, reverse was missing
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 26, 2013, 02:47:46 PM
...
now i see, thanks. but in this case (entnext (entprev e)) will not be equal to e
and more (ssget "_X") will iterate through all entities on all layouts
(ssget "_X")  make a selection of all entities in all layout:

Command: (setq kkkk (ssget "_X"))
<Selection set: b2>

Command: M
MOVE
Select objects: !kkkk
<Selection set: b2>
2396 found
2395 were not in current space.
1 was the paper space viewport.
Title: Re: (entprev)
Post by: VovKa on November 26, 2013, 03:07:50 PM
Command: (setq kkkk (ssget "_X"))
<Selection set: b2>
Code: [Select]
(sslength kkkk)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 26, 2013, 03:08:34 PM
Marco.-

The entPreviousFrom it is an autolisp function and accepts one argument - what do you mean by that accept argument?.

Where: <ename> normal or nested
Usage: (entPreviousFrom <ename>)
OK Louis, I'm sorry I did not realize... read below...

Code: [Select]
Benchmark.lsp | © 2005 Michael Puckett | All Rights Reserved

>>> from "nested" entity
Elapsed milliseconds / relative speed for 16384 iteration(s):
    (ALE_ENTPREVIOUS KKKK).....1451 / 1.27 <fastest>
    (entpreviousfrom KKKK).....1841 / 1 <slowest>

>>> from "nested" entity
Elapsed milliseconds / relative speed for 16384 iteration(s):
    (entpreviousfrom KKKK).....2418 / 1.18 <fastest>
    (ALE_ENTPREVIOUS KKKK).....2855 / 1 <slowest>

>>> from "nested" entity
Elapsed milliseconds / relative speed for 16384 iteration(s):
    (entpreviousfrom KKKK).....1077 / 1.26 <fastest>
    (ALE_ENTPREVIOUS KKKK).....1357 / 1 <slowest>


>>> from "normal" entity
Elapsed milliseconds / relative speed for 16384 iteration(s):
    (entpreviousfrom KKKK).......1794 / 64.37 <fastest>
    (ALE_ENTPREVIOUS KKKK).....115487 / 1 <slowest>


But from "normal" entity I get wrong results

(defun c:TestL ( / EntRef EntPrv)
(setq EntRef (car (nentsel)))
(princ "\nEntRef         ") (princ EntRef)
(princ "\nentPreviousFrom") (princ (entnext (setq EntPrv (entPreviousFrom EntRef))))
(princ "\nALE_EntPrevious") (princ (entnext (setq EntPrv (ALE_EntPrevious EntRef))))
(princ "\n")
(textpage)(princ)
)

Select object:
EntRef         <Entity name: 7ffffb40240>
entPreviousFrom<Entity name: 7ffffb401f0>
ALE_EntPrevious<Entity name: 7ffffb40240>

Command:  TESTL

Select object:
EntRef         <Entity name: 7ffffb06c00>
entPreviousFrom<Entity name: 7ffffb06c00>
ALE_EntPrevious<Entity name: 7ffffb06c00>

Command:  TESTL

Select object:
EntRef         <Entity name: 7ffffb06bf0>
entPreviousFrom<Entity name: 7ffffb06ae0>
ALE_EntPrevious<Entity name: 7ffffb06bf0>
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 26, 2013, 03:10:42 PM
Command: (setq kkkk (ssget "_X"))
<Selection set: b2>
Code: [Select]
(sslength kkkk)
Command: (sslength kkkk)
2396
Title: Re: (entprev)
Post by: LE3 on November 26, 2013, 03:23:24 PM
Hi Marco,
Thank you a lot for taking the time to run the tests and doing the benchmarking.... for me I guess it is all about my contribution on this thread, was fun but I do not use autolisp nor I work with objectarx anymore or even use AutoCAD nowadays. My sample code is there open, so anyone can use it and update it and make it better!!!.

Have fun!
 :-)
Title: Re: (entprev)
Post by: VovKa on November 26, 2013, 04:49:19 PM
Command: (sslength kkkk)
2396
(ssget "_X") returns entities in the following order:
EntitiesOnLayout1+EntitiesOnLayout2...+...EntitiesOnLayoutN+EntitiesInModelSpace
so if are looking for an entity that is in the model space you will iterate through all layout entities first
Title: Re: (entprev)
Post by: irneb on November 27, 2013, 12:09:38 AM
so if are looking for an entity that is in the model space you will iterate through all layout entities first
I think we might be talking in circles. The OP was about a function which operates in reverse from what entnext does.

So:
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 04:00:23 AM
Command: (sslength kkkk)
2396
(ssget "_X") returns entities in the following order:
EntitiesOnLayout1+EntitiesOnLayout2...+...EntitiesOnLayoutN+EntitiesInModelSpace
so if are looking for an entity that is in the model space you will iterate through all layout entities first
Try my new test DWG and put a counter inside your function:
Code: [Select]
; Version 3.02_Test - 2013/11/27 - no DXF function
(defun ALE_EntPrevious_Test (EntNam / SelSet EntDat Countr SsLngt EntOut PrnEnt PrnDat TrueFl)
  (setq Countr 0);test
  (if
    (and
      (setq EntDat (entget EntNam))
      (setq TrueFl
        (=
          "BLOCK_RECORD"
          (cdr (assoc 0 (setq PrnDat (entget (setq PrnEnt (cdr (assoc 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)
    )
    (setq EntOut (if TrueFl (cdr (assoc 360 PrnDat)) PrnEnt))
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt   Countr (1+ Countr));test
;   (setq EntOut PrnEnt)
  )
  (list EntOut Countr);test
; EntOut
)

(defun c:Test ( / EntRef EntPrv)
  (setq EntRef (car (nentsel)))
  (princ "\nEntRef              ") (princ EntRef)
  (princ "\nALE_EntPrevious_Test") (princ (entnext (car (setq EntPrv (ALE_EntPrevious_Test EntRef)))))
  (princ "  ")(princ (cadr EntPrv))
  (princ "\nVK_entprev1         ") (princ (entnext (car (setq EntPrv (VK_entprev1     EntRef)))))
  (princ "  ")(princ (cadr EntPrv))
  (textpage)(princ)
)

My DWG:
4228 total entities
1414 Model
1406 Layout L1
1406 Layout L2

Code: [Select]
Select the red line on magenta rectangle, is the (entlast) in model space,
results:

Selezionare oggetto:
EntRef              <Nome entità: 7ffffb61930>
ALE_EntPrevious_Test<Nome entità: 7ffffb61930>  2814
VK_entprev1         <Nome entità: 7ffffb61930>  12515
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 04:03:00 AM
I think we might be talking in circles. The OP was about a function which operates in reverse from what entnext does.

So:
  • If supplied argument = nil (unfortunately ALisp doesn't allow for optional arguments in defuns), then get entlast (instead of the 1st entity in the DWG)
  • If supplied argument is an ename of an enetity contained either in the Model Space or any Paper Space then get the previous entity
    • That could be a joined entity like an attribute, not to be confused with nested entities like lines inside blocks.
    • Note entnext runs along all entities in MS/PS1/PS2 ... PSn as if they're all contained in one group (not each separately).
  • If the argument is an entity nested inside a complex entity like a block definition, then get the previous entity inside that block - stop at the block record itself.
Do you think that there is, at this time, a function that meets these three points?
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 04:05:54 AM
Hi Marco,
Thank you a lot for taking the time to run the tests and doing the benchmarking.... for me I guess it is all about my contribution on this thread, was fun but I do not use autolisp nor I work with objectarx anymore or even use AutoCAD nowadays. My sample code is there open, so anyone can use it and update it and make it better!!!.

Have fun!
 :)
Grazie a te, spero di ritrovarti ancora.
Gracias a ti, espero encontrarte de nuevo.  :kewl:
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 05:16:32 AM
Select the red line on magenta rectangle, is the (entlast) in model space,
results:
ssget generates selections set in a reversed order i.e. entlast is the first element. and still your function is iterating 2814 times. why? because it searches though all layouts.

entnext starts from the beginning and steps through all vertexes but doesn't go into layouts.

benchmark both function with (entnext (entnext)) as an argument  :)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 06:25:15 AM
ssget generates selections set in a reversed order i.e. entlast is the first element. and still your function is iterating 2814 times. why? because it searches though all layouts.
> entlast is the first element
I do not think so:
Comando: (setq kkkk (ssget "_X"))
<Selection set: 11b>
Comando: (ssname kkkk 0)
<Nome entità: 7ffffb60c70>
Comando: (entlast)
<Nome entità: 7ffffb61930>
Comando: (ssname kkkk 1)
<Nome entità: 7ffffb449f0>
Comando: (ssname kkkk (1- (sslength kkkk)))
<Nome entità: 7ffffb06700>
Comando: (ssname kkkk (sslength kkkk))
nil

entnext starts from the beginning and steps through all vertexes but doesn't go into layouts.
I think entnext steps through all entities (DWG with only 3 entities):
Code: [Select]
(defun VK_entprev1 (e / e1 e2 Countr)
  (setq Countr 0)
  (setq e1 (entnext))
  (while (and e1 (not (eq e (setq e2 (entnext e1)))))
    (setq e1 e2  Countr (1+ Countr))
    (princ "\n ") (princ (entget e2) )
  )
  (list e1 Countr)
)
>
((-1 . <Nome entità: 7ffffb60d60>) (0 . VERTEX) (330 . <Nome entità: 7ffffb60d50>) (5 . AE8E) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (62 . 2) (100 . AcDbVertex) (100 . AcDb2dVertex) (10 1887.13 222.152 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0465439) (91 . 0) (70 . 0) (50 . 0.0))
 ((-1 . <Nome entità: 7ffffb60d70>) (0 . VERTEX) (330 . <Nome entità: 7ffffb60d50>) (5 . AE8F) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (62 . 2) (100 . AcDbVertex) (100 . AcDb2dVertex) (10 1829.33 165.574 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0601886) (91 . 0) (70 . 0) (50 . 0.0))
...
 ((-1 . <Nome entità: 7ffffb60e50>) (0 . VERTEX) (330 . <Nome entità: 7ffffb60d50>) (5 . AE9D) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (62 . 2) (100 . AcDbVertex) (100 . AcDb2dVertex) (10 1954.41 267.061 0.0) (40 . 0.0) (41 . 0.0) (42 . 0.0465439) (91 . 0) (70 . 0) (50 . 4.25351))
 ((-1 . <Nome entità: 7ffffb60e60>) (0 . SEQEND) (330 . <Nome entità: 7ffffb60d50>) (5 . AE9E) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (62 . 2) (-2 . <Nome entità: 7ffffb60d50>))
 ((-1 . <Nome entità: 7ffffb44a40>) (0 . VIEWPORT) (330 . <Nome entità: 7ffffb44a20>) (5 . 94D4) (100 . AcDbEntity) (67 . 1) (410 . L2) (8 . 0) (100 . AcDbViewport) (10 975.889 259.916 0.0) (40 . 396.146) (41 . 286.588) (68 . 1) (69 . 1) (12 975.889 259.916 0.0) (13 0.0 0.0 0.0) (14 10.0 10.0 0.0) (15 10.0 10.0 0.0) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (42 . 50.0) (43 . 0.0) (44 . 0.0) (45 . 286.588) (50 . 0.0) (51 . 0.0) (72 . 100) (90 . 819232) (281 . 0) (71 . 1) (74 . 0) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (170 . 0) (61 . 5) (348 . <Nome entità: 7ffffb06170>) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))
 ((-1 . <Nome entità: 7ffffbf7cc0>) (0 . CIRCLE) (330 . <Nome entità: 7ffffb44a20>) (5 . B08C) (100 . AcDbEntity) (67 . 1) (410 . L2) (8 . 0) (100 . AcDbCircle) (10 891.453 209.204 0.0) (40 . 33.0551) (210 0.0 0.0 1.0))

benchmark both function with (entnext (entnext)) as an argument
Why?
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 06:49:58 AM
I do not think so:
it's a well known fact

if you want to test (ssget "_X")
create an empty drawing
draw a line
draw a circle
switch to Layout1
draw a polyline
draw a point
switch to Layout2
draw an arc
draw a text
then inspect (ssname "_X") in vlide
you will see that you line is the last element because http://www.theswamp.org/index.php?topic=45732.msg508993#msg508993
Title: Re: (entprev)
Post by: snownut2 on November 27, 2013, 08:16:37 AM
Sorry new to this thread, but I would naturally assume ssget would select items in the same order as the draw order in ACAD essentially by their order in the DB.  So not only would it be dependent on when they where created but also edited or modified, you could also manipulate the order with the "draw order" command. 
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 08:52:32 AM
I do not think so:
it's a well known fact

if you want to test (ssget "_X")
create an empty drawing
draw a line
draw a circle
switch to Layout1
draw a polyline
draw a point
switch to Layout2
draw an arc
draw a text
then inspect (ssname "_X") in vlide
you will see that you line is the last element because http://www.theswamp.org/index.php?topic=45732.msg508993#msg508993 (http://www.theswamp.org/index.php?topic=45732.msg508993#msg508993)

With your DWG
From MSpace:
Code: [Select]
Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfb1a0>) (0 . "TEXT") (330 . <Nome entità: 7ffffbfb060>) (5 . "19C2") (100 . "AcDbEntity") (67 . 1) (410 . "Layout2") (8 . "$XP_COM_NORM") (100 . "AcDbText") (10 10.0 10.0 0.0) (40 . 2.0) (1 . "123") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "$STD_ISO") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . "AcDbText") (73 . 0))

Comando:   <Passaggio a: Layout1>
Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfb050>) (0 . "POINT") (330 . <Nome entità: 7ffffbfe8d0>) (5 . "19AD") (100 . "AcDbEntity") (67 . 1) (410 . "Layout1") (8 . "$XP_COM_NORM") (100 . "AcDbPoint") (10 0.0 0.0 0.0) (210 0.0 0.0 1.0) (50 . 0.0))

Comando:   <Passaggio a: Layout2>
Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfb1a0>) (0 . "TEXT") (330 . <Nome entità: 7ffffbfb060>) (5 . "19C2") (100 . "AcDbEntity") (67 . 1) (410 . "Layout2") (8 . "$XP_COM_NORM") (100 . "AcDbText") (10 10.0 10.0 0.0) (40 . 2.0) (1 . "123") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "$STD_ISO") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . "AcDbText") (73 . 0))

From MSpace:
Comando: _line
Specificare primo punto: 20,20
Specificare punto successivo o [Annulla]: 30,30
Specificare punto successivo o [Annulla]:

Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfbb90>) (0 . "LINE") (330 . <Nome entità: 7ffffbfe820>) (5 . "1A59") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "$COM_NORM") (100 . "AcDbLine") (10 20.0 20.0 0.0) (11 30.0 30.0 0.0) (210 0.0 0.0 1.0))

Comando:   <Passaggio a: Layout1>
Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfb050>) (0 . "POINT") (330 . <Nome entità: 7ffffbfe8d0>) (5 . "19AD") (100 . "AcDbEntity") (67 . 1) (410 . "Layout1") (8 . "$XP_COM_NORM") (100 . "AcDbPoint") (10 0.0 0.0 0.0) (210 0.0 0.0 1.0) (50 . 0.0))

Comando:   <Passaggio a: Layout2>
Comando: (entget (entlast))
((-1 . <Nome entità: 7ffffbfb1a0>) (0 . "TEXT") (330 . <Nome entità: 7ffffbfb060>) (5 . "19C2") (100 . "AcDbEntity") (67 . 1) (410 . "Layout2") (8 . "$XP_COM_NORM") (100 . "AcDbText") (10 10.0 10.0 0.0) (40 . 2.0) (1 . "123") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "$STD_ISO") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . "AcDbText") (73 . 0))
(entlast) > the result may change going from one Layout to another Layout
Title: Re: (entprev)
Post by: LE3 on November 27, 2013, 09:09:52 AM
Hi Marco,
Thank you a lot for taking the time to run the tests and doing the benchmarking.... for me I guess it is all about my contribution on this thread, was fun but I do not use autolisp nor I work with objectarx anymore or even use AutoCAD nowadays. My sample code is there open, so anyone can use it and update it and make it better!!!.

Have fun!
 :)
Grazie a te, spero di ritrovarti ancora.
Gracias a ti, espero encontrarte de nuevo.  :kewl:
Grazie Marco, so che sarà difficile non partecipare...
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 09:11:34 AM
Sorry new to this thread, but I would naturally assume ssget would select items in the same order as the draw order in ACAD essentially by their order in the DB.  So not only would it be dependent on when they where created but also edited or modified,
OK

you could also manipulate the order with the "draw order" command.

I do not think so:
Code: [Select]
(defun C:PrintSS ( / Countr SelSet)
  (setq SelSet (ssget "_X")   Countr 0)
  (repeat (sslength SelSet)
    (princ "\n ") (princ (entget (ssname SelSet Countr)))
    (setq Countr (1+ Countr))
  )
  (princ)
)

Comando: PRINTSS
 ((-1 . <Nome entità: 7ffffbfb050>) (0 . POINT) (330 . <Nome entità: 7ffffbfe8d0>) (5 . 19AD) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . $XP_COM_NORM) (100 . AcDbPoint) (10 0.0 0.0 0.0) (210 0.0 0.0 1.0) (50 . 0.0))
 ((-1 . <Nome entità: 7ffffbfb000>) (0 . POLYLINE) (330 . <Nome entità: 7ffffbfe8d0>) (5 . 19A8) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . $XP_COM_NORM) (100 . AcDb2dPolyline) (66 . 1) (10 0.0 0.0 0.0) (70 . 0) (40 . 0.0) (41 . 0.0) (210 0.0 0.0 1.0) (71 . 0) (72 . 0) (73 . 0) (74 . 0) (75 . 0))
 ((-1 . <Nome entità: 7ffffbfe8e0>) (0 . VIEWPORT) (330 . <Nome entità: 7ffffbfe8d0>) (5 . E) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . 0) (100 . AcDbViewport) (10 128.5 97.5 0.0) (40 . 958.196) (41 . 693.198) (68 . 1) (69 . 1) (12 128.5 97.5 0.0) (13 0.0 0.0 0.0) (14 10.0 10.0 0.0) (15 10.0 10.0 0.0) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (42 . 50.0) (43 . 0.0) (44 . 0.0) (45 . 693.198) (50 . 0.0) (51 . 0.0) (72 . 100) (90 . 819232) (281 . 0) (71 . 1) (74 . 0) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (170 . 0) (61 . 5) (348 . <Nome entità: 7ffffbbc1f0>) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))
 ((-1 . <Nome entità: 7ffffbfb1a0>) (0 . TEXT) (330 . <Nome entità: 7ffffbfb060>) (5 . 19C2) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . $XP_COM_NORM) (100 . AcDbText) (10 10.0 10.0 0.0) (40 . 2.0) (1 . 123) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . $STD_ISO) (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . AcDbText) (73 . 0))
 ((-1 . <Nome entità: 7ffffbfb170>) (0 . ARC) (330 . <Nome entità: 7ffffbfb060>) (5 . 19BF) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . $XP_COM_NORM) (100 . AcDbCircle) (10 20.0 20.0 0.0) (40 . 14.1421) (210 0.0 0.0 1.0) (100 . AcDbArc) (50 . 3.92699) (51 . 4.45059))
 ((-1 . <Nome entità: 7ffffbfb140>) (0 . VIEWPORT) (5 . 19BC) (102 . {ACAD_XDICTIONARY) (360 . <Nome entità: 7ffffbfb150>) (102 . }) (330 . <Nome entità: 7ffffbfb060>) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . 0) (100 . AcDbViewport) (10 31.6168 40.5766 0.0) (40 . 96.4091) (41 . 69.7462) (68 . 1) (69 . 1) (12 31.6168 40.5766 0.0) (13 0.0 0.0 0.0) (14 10.0 10.0 0.0) (15 10.0 10.0 0.0) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (42 . 50.0) (43 . 0.0) (44 . 0.0) (45 . 69.7462) (50 . 0.0) (51 . 0.0) (72 . 100) (90 . 819232) (281 . 0) (71 . 1) (74 . 0) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (170 . 0) (61 . 5) (348 . <Nome entità: 7ffffbbc1f0>) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))
 ((-1 . <Nome entità: 7ffffb05020>) (0 . LINE) (330 . <Nome entità: 7ffffbfe820>) (5 . 1A9A) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbLine) (10 1.0 1.0 0.0) (11 5.0 5.0 0.0) (210 0.0 0.0 1.0))
 ((-1 . <Nome entità: 7ffffbbced0>) (0 . CIRCLE) (330 . <Nome entità: 7ffffbfe820>) (5 . 199D) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbCircle) (10 10.0 10.0 0.0) (40 . 10.0) (210 0.0 0.0 1.0))
 ((-1 . <Nome entità: 7ffffbbcec0>) (0 . LINE) (330 . <Nome entità: 7ffffbfe820>) (5 . 199C) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbLine) (10 0.0 0.0 0.0) (11 10.0 10.0 0.0) (210 0.0 0.0 1.0))


Comando: AI_DRAWORDER ... bla ... bla ...

Comando: PRINTSS
 ((-1 . <Nome entità: 7ffffbfb050>) (0 . POINT) (330 . <Nome entità: 7ffffbfe8d0>) (5 . 19AD) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . $XP_COM_NORM) (100 . AcDbPoint) (10 0.0 0.0 0.0) (210 0.0 0.0 1.0) (50 . 0.0))
 ((-1 . <Nome entità: 7ffffbfb000>) (0 . POLYLINE) (330 . <Nome entità: 7ffffbfe8d0>) (5 . 19A8) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . $XP_COM_NORM) (100 . AcDb2dPolyline) (66 . 1) (10 0.0 0.0 0.0) (70 . 0) (40 . 0.0) (41 . 0.0) (210 0.0 0.0 1.0) (71 . 0) (72 . 0) (73 . 0) (74 . 0) (75 . 0))
 ((-1 . <Nome entità: 7ffffbfe8e0>) (0 . VIEWPORT) (330 . <Nome entità: 7ffffbfe8d0>) (5 . E) (100 . AcDbEntity) (67 . 1) (410 . Layout1) (8 . 0) (100 . AcDbViewport) (10 128.5 97.5 0.0) (40 . 958.196) (41 . 693.198) (68 . 1) (69 . 1) (12 128.5 97.5 0.0) (13 0.0 0.0 0.0) (14 10.0 10.0 0.0) (15 10.0 10.0 0.0) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (42 . 50.0) (43 . 0.0) (44 . 0.0) (45 . 693.198) (50 . 0.0) (51 . 0.0) (72 . 100) (90 . 819232) (281 . 0) (71 . 1) (74 . 0) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (170 . 0) (61 . 5) (348 . <Nome entità: 7ffffbbc1f0>) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))
 ((-1 . <Nome entità: 7ffffbfb1a0>) (0 . TEXT) (330 . <Nome entità: 7ffffbfb060>) (5 . 19C2) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . $XP_COM_NORM) (100 . AcDbText) (10 10.0 10.0 0.0) (40 . 2.0) (1 . 123) (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . $STD_ISO) (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . AcDbText) (73 . 0))
 ((-1 . <Nome entità: 7ffffbfb170>) (0 . ARC) (330 . <Nome entità: 7ffffbfb060>) (5 . 19BF) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . $XP_COM_NORM) (100 . AcDbCircle) (10 20.0 20.0 0.0) (40 . 14.1421) (210 0.0 0.0 1.0) (100 . AcDbArc) (50 . 3.92699) (51 . 4.45059))
 ((-1 . <Nome entità: 7ffffbfb140>) (0 . VIEWPORT) (5 . 19BC) (102 . {ACAD_XDICTIONARY) (360 . <Nome entità: 7ffffbfb150>) (102 . }) (330 . <Nome entità: 7ffffbfb060>) (100 . AcDbEntity) (67 . 1) (410 . Layout2) (8 . 0) (100 . AcDbViewport) (10 31.6168 40.5766 0.0) (40 . 96.4091) (41 . 69.7462) (68 . 1) (69 . 1) (12 31.6168 40.5766 0.0) (13 0.0 0.0 0.0) (14 10.0 10.0 0.0) (15 10.0 10.0 0.0) (16 0.0 0.0 1.0) (17 0.0 0.0 0.0) (42 . 50.0) (43 . 0.0) (44 . 0.0) (45 . 69.7462) (50 . 0.0) (51 . 0.0) (72 . 100) (90 . 819232) (281 . 0) (71 . 1) (74 . 0) (110 0.0 0.0 0.0) (111 1.0 0.0 0.0) (112 0.0 1.0 0.0) (79 . 0) (146 . 0.0) (170 . 0) (61 . 5) (348 . <Nome entità: 7ffffbbc1f0>) (292 . 1) (282 . 1) (141 . 0.0) (142 . 0.0) (63 . 250) (421 . 3355443))
 ((-1 . <Nome entità: 7ffffb05020>) (0 . LINE) (330 . <Nome entità: 7ffffbfe820>) (5 . 1A9A) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbLine) (10 1.0 1.0 0.0) (11 5.0 5.0 0.0) (210 0.0 0.0 1.0))
 ((-1 . <Nome entità: 7ffffbbced0>) (0 . CIRCLE) (330 . <Nome entità: 7ffffbfe820>) (5 . 199D) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbCircle) (10 10.0 10.0 0.0) (40 . 10.0) (210 0.0 0.0 1.0))
 ((-1 . <Nome entità: 7ffffbbcec0>) (0 . LINE) (330 . <Nome entità: 7ffffbfe820>) (5 . 199C) (100 . AcDbEntity) (67 . 0) (410 . Model) (8 . $COM_NORM) (100 . AcDbLine) (10 0.0 0.0 0.0) (11 10.0 10.0 0.0) (210 0.0 0.0 1.0))
Title: Re: (entprev)
Post by: irneb on November 27, 2013, 09:24:47 AM
Selection sets may be influenced by the Layouts, I don't truly know, but that's not the point of this thread is it?

But I do know that entnext and entlast is not affected by them at all. E.g. I started a new blank DWG from acadiso.dwt. Then drew a circle and a line in the model space. Then swapped to Layout 1 and placed a text, selected it copy-pasted into Layout 2. Then swapped back to Model and drew an arc. So the circle is the 1st entity drawn, and the arc the last. And that is exactly what entnext and entlast shows - no matter what layout is current:
Code: [Select]
Command: (setq en (entnext))
<Entity name: 7ffffb95cc0>
Command: (while en (setq ed (entget en) en (entnext en)) (print (strcat (cdr (assoc 0 ed)) " on " (cdr (assoc 410 ed)))))
"CIRCLE on Model"
"LINE on Model"
"VIEWPORT on Layout1"
"MTEXT on Layout1"
"ARC on Model" "ARC on Model"
Command: (setq ed (entget (entlast)))
((-1 . <Entity name: 7ffffb961d0>) (0 . "ARC") (330 . <Entity name: 7ffffb929f0>) (5 . "28D") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbCircle") (10 4054.01 380.296 0.0) (40 . 1618.93) (210 0.0 0.0 1.0) (100 . "AcDbArc") (50 . 1.09233) (51 . 3.0848))
Then swap to a Layout tab and try again
Code: [Select]
Command: CTAB
Enter new value for CTAB <"Model">: Layout1
Restoring cached viewports - Regenerating layout.
Command: (setq en (entnext))
<Entity name: 7ffffb95cc0>
Command: (while en (setq ed (entget en) en (entnext en)) (print (strcat (cdr (assoc 0 ed)) " on " (cdr (assoc 410 ed)))))
"CIRCLE on Model"
"LINE on Model"
"VIEWPORT on Layout1"
"MTEXT on Layout1"
"ARC on Model" "ARC on Model"
Command: (setq ed (entget (entlast)))
((-1 . <Entity name: 7ffffb961d0>) (0 . "ARC") (330 . <Entity name: 7ffffb929f0>) (5 . "28D") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbCircle") (10 4054.01 380.296 0.0) (40 . 1618.93) (210 0.0 0.0 1.0) (100 . "AcDbArc") (50 . 1.09233) (51 . 3.0848))
Exact same result.
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 09:46:06 AM
(entlast) > the result may change going from one Layout to another Layout
that's an old bug
and i think it's somehow bugged because of this:
(http://i.piccy.info/i9/054ab6be2420d9f093ea985ab67733e2/1385563511/8062/407886/Clipboard_1_240.jpg) (http://piccy.info/view3/5504546/45bca6fbd10c3cf8c339f44c24ac1d33/)(http://i.piccy.info/a3/2013-11-27-14-45/i9-5504546/240x171-r/i.gif) (http://i.piccy.info/a3c/2013-11-27-14-45/i9-5504546/240x171-r)
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 09:57:48 AM
My current version, regards the fact that (entnext) is going and inspecting all entities from all Layouts is this version of VovKa's code - only mods is if checking entity is the first one in database - it should return nil...

Code - Auto/Visual Lisp: [Select]
  1. (defun VovKa-MR-entprev (e / e1 e2)
  2.   (if (eq (type e) 'ename)
  3.     (if (eq e (entnext))
  4.       nil
  5.       (progn
  6.         (setq e1 (entnext))
  7.         (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  8.           (setq e1 e2)
  9.         )
  10.         e1
  11.       )
  12.     )
  13.     (progn (prompt "\n; error: bad argument type: lentityp ")(princ e)(princ))
  14.   )
  15. )
  16.  

So, please when benchmarking, take this code in consideration among others that are correct (I don't know much ab. arx and other languages)...

OP, M.R.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 10:10:52 AM
...
"CIRCLE on Model"
"LINE on Model"
"VIEWPORT on Layout1"
"MTEXT on Layout1"
"ARC on Model" "ARC on Model"
...

...and where is "TEXT on Layout2"?

I get this (AutoCAD 2013 Mech.):
Code: [Select]
Comando: (setq en (entnext))
<Nome entità: 7ffffbca340>

Comando: (while en (setq ed (entget en) en (entnext en)) (print (strcat (cdr (assoc 0 ed)) " on " (cdr (assoc 410 ed)))))

"CIRCLE on Model"
"LINE on Model"
"VIEWPORT on Layout2"
"TEXT on Layout2"
"ARC on Model" "ARC on Model"

Comando: (setq ed (entget (entlast)))
((-1 . <Nome entità: 7ffffbca700>) (0 . "ARC") (330 . <Nome entità: 7ffffbaff10>) (5 . "E8") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbCircle") (10 577.904 218.872 0.0) (40 . 60.8391) (210 0.0 0.0 1.0) (100 . "AcDbArc") (50 . 1.47854) (51 . 2.12479))

Comando: CTAB

Digitare nuovo valore per CTAB <"Model">: Layout1
Ripristino finestre memorizzate nella cache in corso - Rigenerazione layout in corso.

Comando: (setq en (entnext))
<Nome entità: 7ffffbca340>

Comando: (while en (setq ed (entget en) en (entnext en)) (print (strcat (cdr (assoc 0 ed)) " on " (cdr (assoc 410 ed)))))

"CIRCLE on Model"
"LINE on Model"
"ARC on Model"
"VIEWPORT on Layout1"
"TEXT on Layout1" "TEXT on Layout1"

Comando: (setq ed (entget (entlast)))
((-1 . <Nome entità: 7ffffbca550>) (0 . "TEXT") (330 . <Nome entità: 7ffffbafed0>) (5 . "CD") (100 . "AcDbEntity") (67 . 1) (410 . "Layout1") (8 . "0") (100 . "AcDbText") (10 -203.743 43.1176 0.0) (40 . 23.0115) (1 . "123") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "Standard") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . "AcDbText") (73 . 0))
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 10:18:07 AM
(entlast) > the result may change going from one Layout to another Layout
that's an old bug
and i think it's somehow bugged because of this:
(http://i.piccy.info/i9/054ab6be2420d9f093ea985ab67733e2/1385563511/8062/407886/Clipboard_1_240.jpg) (http://piccy.info/view3/5504546/45bca6fbd10c3cf8c339f44c24ac1d33/)(http://i.piccy.info/a3/2013-11-27-14-45/i9-5504546/240x171-r/i.gif) (http://i.piccy.info/a3c/2013-11-27-14-45/i9-5504546/240x171-r)
this is mine

Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 10:37:44 AM
...
So, please when benchmarking, take this code in consideration among others that are correct (I don't know much ab. arx and other languages)...

OP, M.R.
Remember that the code in VovKa-MR-entprev do not work if you select
a block (not the attribs).
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 11:29:04 AM
...
So, please when benchmarking, take this code in consideration among others that are correct (I don't know much ab. arx and other languages)...

OP, M.R.
Remember that the code in VovKa-MR-entprev do not work if you select
a block (not the attribs).

Marc'Antonio, can you elaborate that... If I pick normal block in DWG made of normal blocks, it returns previous block of picked one... If I pick attributed block in DWG made of attributed blocks, it returns SEQUEND entity, and that is exactly previous entity of picked one - that is correct...
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 11:40:03 AM
Marc'Antonio, can you elaborate that... If I pick normal block in DWG made of normal blocks, it returns previous block of picked one... If I pick attributed block in DWG made of attributed blocks, it returns SEQUEND entity, and that is exactly previous entity of picked one - that is correct...
Try with "Nentsel":
(entnext (VovKa-MR-entprev (car (nentsel))))
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 12:09:24 PM
Try with "Nentsel":
(entnext (VovKa-MR-entprev (car (nentsel))))

Thats not the point... (entnext) won't work with (car (nentsel))... The function (entprev) should perform exactly the opposite than (entnext)... So (VovKa-MR-entprev) is correct function...
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 12:11:54 PM
This is related to the use of "assoc 360" (my function and VovKa's),  I found a problem with Bricscad:
Code: [Select]
(defun c:TestDxf360 ( / EntNam EntDat PrnEnt PrnDat)
  (setq EntNam (car (nentsel))) ;select a block (not attribs)
  (setq EntDat (entget EntNam))
  (setq PrnEnt (cdr (assoc 330 EntDat)))
  (setq PrnDat (entget (setq PrnEnt (cdr (assoc 330 EntDat)))))
  (princ "\n ")
  (entget (cdr (assoc 360 prndat)))
)
Code: [Select]
;   >>>>>>>>>>>>>>>>>>  Bricscad V14  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Seleziona entità:
;
; ----- LISP : Call Stack -----
; [0]...C:TESTDXF360 <<--
;
; ----- Error around expression -----
(ASSOC 360 PRNDAT)
;
; error : bad argument type <NIL> ; expected ENTITYNAME at [ENTGET]
;   >>>>>>>>>>>>>>>>>>  Bricscad V14  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Code: [Select]
;   >>>>>>>>>>>>>>>>>>  AutoCAD 2013  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Selezionare oggetto:
 ((-1 . <Nome entità: 7ffffb579c0>) (0 . "BLOCK") (330 . <Nome entità: 7ffffb57990>) (5 . "AFEC") (100 . "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbBlockBegin") (70 . 0) (10 0.0 0.0 0.0) (-2 . <Nome entità: 7ffffb579a0>) (2 . "ASSO010L") (1 . ""))
;   >>>>>>>>>>>>>>>>>>  AutoCAD 2013  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 12:24:28 PM
Try with "Nentsel":
(entnext (VovKa-MR-entprev (car (nentsel))))

Thats not the point... (entnext) won't work with (car (nentsel))... The function (entprev) should perform exactly the opposite than (entnext)... So (VovKa-MR-entprev) is correct function...
Marko, entnext works with nentsel
anyway i suggest using this variant http://www.theswamp.org/index.php?topic=45732.msg508956#msg508956
it's faster and works within nested objects if the argument supplied is a part of a complex entity
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 12:27:52 PM
Try with "Nentsel":
(entnext (VovKa-MR-entprev (car (nentsel))))

Thats not the point... (entnext) won't work with (car (nentsel))... The function (entprev) should perform exactly the opposite than (entnext)... So (VovKa-MR-entprev) is correct function...
Hummm...
Try with my last DWG posted (without nentsel):
Comando: (VovKa-MR-entprev (handent "4D3F"))
nil

Comando: (handent "4D3F")
<Nome entità: 7ffffbc9770>

Comando: (ALE_EntPrevious (handent "4D3F"))
(<Nome entità: 7ffffbc9760>

Comando: (entnext (ALE_EntPrevious (handent "4D3F")))
<Nome entità: 7ffffbc9770>
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 12:36:08 PM
...
anyway i suggest using this variant http://www.theswamp.org/index.php?topic=45732.msg508956#msg508956 (http://www.theswamp.org/index.php?topic=45732.msg508956#msg508956)
it's faster and works within nested objects if the argument supplied is a part of a complex entity

>>>    e1 (cdr    (cond ((assoc 360 (reverse e1)))

Yes, now it works.

Ciao.
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 12:38:51 PM
Marko, entnext works with nentsel
anyway i suggest using this variant http://www.theswamp.org/index.php?topic=45732.msg508956#msg508956
it's faster and works within nested objects if the argument supplied is a part of a complex entity

Yes, it seems that you're right again... My apology... But what can we do ab (entprev)... Regularly (entnext <block entity>) won't step inside that <block entity> and find very next nested entity... Only if (entnext <nested entity>) if will find next nested entity...
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 12:48:00 PM
Regularly (entnext <block entity>) won't step inside that <block entity> and find very next nested entity... Only if (entnext <nested entity>) if will find next nested entity...
entprev works the same way
the main condition for entprev function is (eq (entnext (entprev e)) e)
Title: Re: (entprev)
Post by: LE3 on November 27, 2013, 12:59:34 PM
Hi Marco,
Thank you a lot for taking the time to run the tests and doing the benchmarking.... for me I guess it is all about my contribution on this thread, was fun but I do not use autolisp nor I work with objectarx anymore or even use AutoCAD nowadays. My sample code is there open, so anyone can use it and update it and make it better!!!.

Have fun!
 :)
Grazie a te, spero di ritrovarti ancora.
Gracias a ti, espero encontrarte de nuevo.  :kewl:
Grazie Marco, so che sarà difficile non partecipare...

OK I have to fix my code, here it is again - I did not tested a lot, but appears to work, on the vertexes iterator, you cannot set the position of the iterator using an entity for database-resident we need to use the vertex selected objectId, also now it will use the ownerId of the selected object instead of the currentSpaceId:
Code - C++: [Select]
  1. static int ads_entpreviousFrom(void)
  2. {
  3.         struct resbuf *rb = acedGetArgs();
  4.         if (!rb)
  5.         {
  6.                 acutPrintf(_T("\nError: function requires an ENAME argument. \n"));
  7.                 return RSERR;
  8.         }
  9.         AcDbObjectId objId;
  10.         ads_name objName;
  11.         if (rb && (rb->restype == RTENAME))
  12.         {
  13.                 if (acdbGetObjectId(objId, rb->resval.rlname) == Acad::eOk)
  14.                 {
  15.                         AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
  16.                         if (pObj.openStatus() == Acad::eOk)
  17.                         {
  18.                                 if (pObj->isKindOf(AcDb2dVertex::desc()))
  19.                                 {
  20.                                         AcDbObjectPointer<AcDb2dPolyline> pPline(pObj->ownerId(), AcDb::kForRead);
  21.                                         if (pPline.openStatus() == Acad::eOk)
  22.                                         {
  23.                                                 AcDbObjectIterator* pVertIterator = pPline->vertexIterator();
  24.                                                 pVertIterator->start();
  25.                                                 pVertIterator->setPosition(pObj->objectId());
  26.                                                 pVertIterator->step(true);
  27.                                                 AcDbObjectPointer<AcDb2dVertex> pVertex(pVertIterator->objectId(), AcDb::kForRead);
  28.                                                 if (pVertex.openStatus() == Acad::eOk)
  29.                                                 {
  30.                                                         if (acdbGetAdsName(objName, pVertex->objectId()) == Acad::eOk)
  31.                                                         {
  32.                                                                 acedRetName(objName, RTENAME); // return the previous entity
  33.                                                         }
  34.                                                 }
  35.                                                 delete pVertIterator;
  36.                                         }
  37.                                 }
  38.                                 else
  39.                                 {
  40.                                         //AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
  41.                                         AcDbBlockTableRecordPointer pBTR(pObj->ownerId(), AcDb::kForRead);
  42.                                         if (pBTR.openStatus() == Acad::eOk)
  43.                                         {
  44.                                                 AcDbBlockTableRecordIterator* pIterator = NULL;
  45.                                                 if (pBTR->newIterator(pIterator) == Acad::eOk)
  46.                                                 {
  47.                                                         AcDbEntity* pEnt = NULL;
  48.                                                         if (pIterator->seek(pObj) == Acad::eOk) // if found from ename
  49.                                                         {
  50.                                                                 pIterator->step(false, true); // step back
  51.                                                                 AcDbObjectId objId;
  52.                                                                 pIterator->getEntityId(objId);
  53.                                                                 AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
  54.                                                                 if (pEnt.openStatus() == Acad::eOk)
  55.                                                                 {
  56.                                                                         if (acdbGetAdsName(objName, objId) == Acad::eOk)
  57.                                                                         {
  58.                                                                                 acedRetName(objName, RTENAME); // return the previous entity
  59.                                                                         }
  60.                                                                 }
  61.                                                         }
  62.                                                         delete pIterator;
  63.                                                 }
  64.                                         }
  65.                                 }
  66.                         }
  67.                 }
  68.         }
  69.         return (RSRSLT);
  70. }
  71.  

attached it is the arx debug version for autocad 2014 and x64. --- Hope that works and helps. Have fun!
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 01:02:33 PM
entprev works the same way
the main condition for entprev function is (eq (entnext (entprev e)) e)

No, VovKa, if I select with (car (nentsel)) second - next nested entity in block that contains more nested entities, (entprev) won't give that previous nested entity, but if I select that previous - first nested entity with (car (nentsel)), (entnext) returns second nested entity I previously picked... So (entnext) works in space of that block, but (entprev) can't enter that space, because (entnext <parent entity>) returns entity in space of parent entities and this is how (entprev) works, using only parent space...

Beside all this, my further investigations tell me that this issue isn't only related for "INSERT" entities, but also for "DIMENSION" entities - they also have separate space... Just checked, so if we solve problem for "INSERT", that must be applied for "DIMENSION" too...
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 01:40:34 PM
I think, I've solved it... Test it now with : (entprev (car (nentsel)))

Code - Auto/Visual Lisp: [Select]
  1. (defun entprev (e / e1 e2)
  2.   (if (eq (type e) 'ename)
  3.     (if (eq e (entnext))
  4.       nil
  5.       (progn
  6.         (if (not
  7.               (or
  8.                 (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Model_Space")
  9.                 (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Paper_Space")
  10.               )
  11.             )
  12.           (progn
  13.             (setq e1 (cdr (assoc -2 (entget (cdr (assoc 360 (entget (cdr (assoc 330 (entget e))))))))))
  14.             (if (eq e e1) nil
  15.               (progn
  16.                 (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  17.                   (setq e1 e2)
  18.                 )
  19.                 e1
  20.               )
  21.             )
  22.           )
  23.           (progn
  24.             (setq e1 (entnext))
  25.             (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  26.               (setq e1 e2)
  27.             )
  28.             e1
  29.           )
  30.         )
  31.       )
  32.     )
  33.     (entget e)
  34.   )
  35. )
  36.  

M.R.
Title: Re: (entprev)
Post by: VovKa on November 27, 2013, 01:45:22 PM
No, VovKa, if I select with (car (nentsel)) second - next nested entity in block that contains more nested entities, (entprev) won't give that previous nested entity, but if I select that previous - first nested entity with (car (nentsel)), (entnext) returns second nested entity I previously picked... So (entnext) works in space of that block, but (entprev) can't enter that space, because (entnext <parent entity>) returns entity in space of parent entities and this is how (entprev) works, using only parent space...
i think i can not fully understand your explanation.
can you test your drawing with this?
Code: [Select]
(while (setq e (car (nentsel)))
  (princ (if (eq (entnext (entprev e)) e)
   "ok"
   "error"
)
  )
)
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 02:07:55 PM
i think i can not fully understand your explanation.
can you test your drawing with this?
Code: [Select]
(while (setq e (car (nentsel)))
  (princ (if (eq (entnext (entprev e)) e)
   "ok"
   "error"
)
  )
)

I see what you're getting on... Code updated :
- If I pick nested entity that isn't very first one inside block/dimension - it should return "ok"...
- Now changed not to loop forever - If I pick very first entity (entprev e)=nil, so now in both your cases - it should return "ok" (what I ment to say "error") (entprev e)=nil => (eq e (entnext (entprev e))) = nil...
Title: Re: (entprev)
Post by: ribarm on November 27, 2013, 02:38:22 PM
Code updated oce more - changed last line to (entget e)...

So now both versions should break the same way if condition (entnext nil) or (entprev nil) :
Code: [Select]
(while (setq e (car (nentsel)))
  (princ (if (eq (entnext (entprev e)) e)
   "ok"
   "error"
)
  )
)
Code: [Select]
(while (setq e (car (nentsel)))
  (princ (if (eq (entprev (entnext e)) e)
   "ok"
   "error"
)
  )
)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 27, 2013, 05:02:20 PM
I have a built-in part of the code of VovKa "(assoc 360 (reverse EntOut)", now it works in Bricscad:

Code: [Select]
; Version 3.20 - 2013/11/27
(defun ALE_EntPrevious (EntNam / SelSet EntDat Countr EntOut PrnEnt)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (not (wcmatch (cdr (assoc 0 EntDat)) "ATTRIB,VERTEX"))
    )
    (progn
      (setq SelSet (ssget "_X")   Countr 0)
      (while SelSet
        (if (eq EntNam (ssname SelSet Countr))
          (setq EntOut (ssname SelSet (1+ Countr))  PrnEnt EntOut  SelSet nil)
          (setq Countr (1+ Countr))
        )
      )
    )
    (setq
      EntOut (entget (cdr (assoc 330 EntDat)))
      EntOut (cdr (cond ((assoc 360 (reverse EntOut)))
                         ((assoc -1 EntOut))
                  )
             )
    )
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)

But:
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
)

>>> Bricscad command line:
Code: [Select]
: (entprev         EntRef)

; ----- Error around expression -----
(ENTNEXT E1)
;
; error : Unknown Error in Lisp or CAD system or 'Stack Overflow'
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 28, 2013, 02:34:14 AM
...
OK I have to fix my code, here it is again -
...
Luis, if I select a block ATTRIB I get an error:
Code: [Select]
(defun c:Test2 ( / EntRef EntPrv)
(setq EntRef (car (nentsel)))
(princ "\nEntRef         ") (princ EntRef)
(princ "\nALE_EntPrevious") (princ (entnext (setq EntPrv (ALE_EntPrevious EntRef))))
(princ "\nentprev        ") (princ (entnext (setq EntPrv (entprev         EntRef))))
(princ "\nentpreviousFrom") (princ (entnext (setq EntPrv (entpreviousFrom EntRef)))) ; louis
(textpage)(princ)
)
Select object:
EntRef         <Entity name: 7ffffb5fd20>
ALE_EntPrevious<Entity name: 7ffffb5fd20>
entprev        <Entity name: 7ffffb5fd20>
entpreviousFrom; error: bad argument type: lentityp nil
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 28, 2013, 03:01:43 AM
Selection sets may be influenced by the Layouts, I don't truly know, but that's not the point of this thread is it?
But I do know that entnext and entlast is not affected by them at all.
...
perhaps this thread may be interesting:
http://forums.autodesk.com/t5/Visual-LISP-AutoLISP-and-General/Copy-order-of-entities/td-p/1557265/page/3

Do you think that the format for saving a DWG can change the way of operate?
(I normally work with 2013 but save in 2004 version)
Title: Re: (entprev)
Post by: irneb on November 28, 2013, 03:35:13 AM
...and where is "TEXT on Layout2"?
:? oops yes, you're correct! Only the last opened PS tab is iterated by entnext. So it's a situation of the model space object and the current paper space object.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 28, 2013, 06:09:30 AM
Simple DWG, draw: 1 circle on ModelSpace + 1 circle on layout1 + 1 circle on layout2
Code: [Select]
Command: (ale_entprevious (entnext (entnext)))
<Entity name: 7ffffbfc330>

Command: (entprev (entnext (entnext)))
<Entity name: 7ffffbfc330>

Command: CTAB

Enter new value for CTAB <"Layout2">: layout1
Restoring cached viewports - Regenerating layout.

Command: (ale_entprevious (entnext (entnext)))
nil

Command: (entprev (entnext (entnext)))
<Entity name: 7ffffbfc330>

Command: (entnext)
<Entity name: 7ffffbfc330>

Command: CTAB

Enter new value for CTAB <"Layout1">: model
Restoring cached viewports.

Command: (ale_entprevious (entnext (entnext)))
nil

Command: (entprev (entnext (entnext)))
<Entity name: 7ffffbfc330>

Command: (entnext)
<Entity name: 7ffffbfc330>

;;; switch to layout2 then to model

Command: CTAB

Enter new value for CTAB <"Model">: layout2
Restoring cached viewports - Regenerating layout.

Command: CTAB

Enter new value for CTAB <"Layout2">: model
Restoring cached viewports.

Command: (ale_entprevious (entnext (entnext)))
<Entity name: 7ffffbfc330>

Command: (entprev (entnext (entnext)))
<Entity name: 7ffffbfc330>
...and where is "TEXT on Layout2"?
:? oops yes, you're correct! Only the last opened PS tab is iterated by entnext. So it's a situation of the model space object and the current paper space object.
This is the reason why entprev is very fast if there are many layout with many entities.
And, from help:
 "If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in the database.
Code: [Select]
Command: (ale_entprevious (entnext)) => nil
Command: (entprev (entnext))         => <Entity name: 7ffffbf9950>
Title: Re: (entprev)
Post by: irneb on November 28, 2013, 07:07:59 AM
"If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in the database.
Ah! But that's then not strictly true is it? E.g. blank drawing (all VP's deleted) with a circle on Layout2 with Layout1 open. (entnext) will give you the "Viewport" which is actually Layout1's page. But if you later draw a line in model space - that is considered the "1st" (not the VP, nor the circle).

Thus it should rather read as: "If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in either the model space or the current paperspace. If none found in model space, then the paperspace page (not viewport) is the 1st found. If the MS was blank before drawing anything in any PS, then any later entities in MS will be considered prior to the existing entities in the PS. Only after MS contains something is the order of entities constant. If you then delete the MS contents, the VP of PS becomes the 1st entity - even if you then draw something new in MS. When you then swap to a different PS the MS items are interpreted as previous to anything on the new PS (even if they were drawn earlier)"

It seems these edge cases might need lots of checks to get entprev working as an exact inverse of entnext.
Title: Re: (entprev)
Post by: LE3 on November 28, 2013, 12:02:09 PM
Code: [Select]
[quote author=Marc'Antonio Alessi link=topic=45732.msg509089#msg509089 date=1385624054]
Luis, if I select a block ATTRIB I get an error:
entpreviousFrom; error: bad argument type: lentityp nil
[/quote]

Marco,
Looks like we need to add more conditions like what I have in there now and test for the selection type:
Quote
if (pObj->isKindOf(AcDb2dVertex::desc()))

I have a long weekend here, starting today, so I can play with this.

Thanks,
LE!

PS> Can you upload your test drawing with the block? - thanks!
Title: Re: (entprev)
Post by: LE3 on November 28, 2013, 02:03:00 PM
Code: [Select]
[quote author=Marc'Antonio Alessi link=topic=45732.msg509089#msg509089 date=1385624054]
entpreviousFrom; error: bad argument type: lentityp nil

I think I have my code fixed/updated and now will return the previous entity from these type of selections (will uploaded in a while/later need more tests).

please... ignore my previous comment --- all work.
Title: Re: (entprev)
Post by: LE3 on November 28, 2013, 04:42:41 PM
Here it is my latest code:

Code - C++: [Select]
  1. static int ads_EntPreviousFrom(void)
  2. {
  3.         struct resbuf *rb = acedGetArgs();
  4.         if (!rb)
  5.         {
  6.                 acutPrintf(_T("\nError: function requires an ENAME argument. \n"));
  7.                 return RSERR;
  8.         }
  9.         AcDbObjectId objId;
  10.         ads_name objName;
  11.         if (rb && (rb->restype == RTENAME))
  12.         {
  13.                 if (acdbGetObjectId(objId, rb->resval.rlname) == Acad::eOk)
  14.                 {
  15.                         AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
  16.                         if (pObj.openStatus() == Acad::eOk)
  17.                         {
  18.                                 if (pObj->isKindOf(AcDb2dVertex::desc()))
  19.                                 {
  20.                                         AcDbObjectPointer<AcDb2dPolyline> pPline(pObj->ownerId(), AcDb::kForRead);
  21.                                         if (pPline.openStatus() == Acad::eOk)
  22.                                         {
  23.                                                 AcDbObjectIterator* pVertIterator = pPline->vertexIterator();
  24.                                                 pVertIterator->start();
  25.                                                 pVertIterator->setPosition(pObj->objectId());
  26.                                                 pVertIterator->step(true);
  27.                                                 AcDbObjectPointer<AcDb2dVertex> pVertex(pVertIterator->objectId(), AcDb::kForRead);
  28.                                                 if (pVertex.openStatus() == Acad::eOk)
  29.                                                 {
  30.                                                         if (acdbGetAdsName(objName, pVertex->objectId()) == Acad::eOk)
  31.                                                         {
  32.                                                                 acedRetName(objName, RTENAME);
  33.                                                         }
  34.                                                 }
  35.                                                 else if (acdbGetAdsName(objName, pPline->objectId()) == Acad::eOk)
  36.                                                 {
  37.                                                         acedRetName(objName, RTENAME);
  38.                                                 }
  39.                                                 delete pVertIterator;
  40.                                         }
  41.                                 }
  42.                                 else if (pObj->isKindOf(AcDbAttribute::desc()))
  43.                                 {
  44.                                         AcDbObjectPointer<AcDbBlockReference> pRef(pObj->ownerId(), AcDb::kForRead);
  45.                                         if (pRef.openStatus() == Acad::eOk)
  46.                                         {
  47.                                                 AcDbObjectIterator* pAttributeIterator = pRef->attributeIterator();
  48.                                                 pAttributeIterator->start(true);
  49.                                                 pAttributeIterator->setPosition(pObj->objectId());
  50.                                                 pAttributeIterator->step(true);
  51.                                                 AcDbObjectPointer<AcDbAttribute> pAttribute(pAttributeIterator->objectId(), AcDb::kForRead);
  52.                                                 if (pAttribute.openStatus() == Acad::eOk)
  53.                                                 {
  54.                                                         if (acdbGetAdsName(objName, pAttribute->objectId()) == Acad::eOk)
  55.                                                         {
  56.                                                                 acedRetName(objName, RTENAME);
  57.                                                         }
  58.                                                 }
  59.                                                 else if (acdbGetAdsName(objName, pRef->objectId()) == Acad::eOk)
  60.                                                 {
  61.                                                         acedRetName(objName, RTENAME);
  62.                                                 }
  63.                                                 delete pAttributeIterator;
  64.                                         }
  65.                                 }
  66.                                 else
  67.                                 {
  68.                                         AcDbBlockTableRecordPointer pBTR(pObj->ownerId(), AcDb::kForRead);
  69.                                         if (pBTR.openStatus() == Acad::eOk)
  70.                                         {
  71.                                                 AcDbBlockTableRecordIterator* pIterator = NULL;
  72.                                                 if (pBTR->newIterator(pIterator) == Acad::eOk)
  73.                                                 {
  74.                                                         AcDbEntity* pEnt = NULL;
  75.                                                         if (pIterator->seek(pObj) == Acad::eOk)
  76.                                                         {
  77.                                                                 pIterator->step(false, true);
  78.                                                                 AcDbObjectId objId;
  79.                                                                 pIterator->getEntityId(objId);
  80.                                                                 AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
  81.                                                                 if (pEnt.openStatus() == Acad::eOk)
  82.                                                                 {
  83.                                                                         if (acdbGetAdsName(objName, objId) == Acad::eOk)
  84.                                                                         {
  85.                                                                                 acedRetName(objName, RTENAME);
  86.                                                                         }
  87.                                                                 }
  88.                                                         }
  89.                                                         delete pIterator;
  90.                                                 }
  91.                                         }
  92.                                 }
  93.                         }
  94.                 }
  95.         }
  96.         return (RSRSLT);
  97. }
  98.  

I see on my tests that the ALE_EntPrevious and entprev on a drawing with some entities and one dimension, if I select (nested) the mtext of the dimension, and then I get all the previous entities, it will stop (return nil) after an ACAD BLOCK or AcDbBlockBegin and any previous entities won't be scanned.

This (coding) is fun!

Let's see if works (arx attached).

TODO: Next task need to study AcDbDimension(s)... and being able to do the scan back.....the seek() works on the iterator but somehow the step back or something is not working... hmm need to install the arx wizard right since the debug does not work and can't step into each line..... :-(
Title: Re: (entprev)
Post by: ribarm on November 28, 2013, 06:07:11 PM
"If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in the database.
Ah! But that's then not strictly true is it? E.g. blank drawing (all VP's deleted) with a circle on Layout2 with Layout1 open. (entnext) will give you the "Viewport" which is actually Layout1's page. But if you later draw a line in model space - that is considered the "1st" (not the VP, nor the circle).

Thus it should rather read as: "If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in either the model space or the current paperspace. If none found in model space, then the paperspace page (not viewport) is the 1st found. If the MS was blank before drawing anything in any PS, then any later entities in MS will be considered prior to the existing entities in the PS. Only after MS contains something is the order of entities constant. If you then delete the MS contents, the VP of PS becomes the 1st entity - even if you then draw something new in MS. When you then swap to a different PS the MS items are interpreted as previous to anything on the new PS (even if they were drawn earlier)"

It seems these edge cases might need lots of checks to get entprev working as an exact inverse of entnext.

Yes, Irne, (entprev) will be very hard to implement doing exact inverse of (entnext)... So I take back my words... Given the fact that ALISP is equipped with saver function (entlast)... We can easily do it instead (entprev (entprev)) as (entprev (entlast)), due to the fact that I don't know how to construct function (entprev) to perform with and without supplied argument and not to actually change (defun's) names... So if this level of problem can be solved than (entprev) can be exact what should, but as we can see there is (entlast) alternative...
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 30, 2013, 04:54:52 AM
Here it is my latest code:
...
Let's see if works (arx attached).

TODO: Next task need to study AcDbDimension(s)... and being able to do the scan back.....the seek() works on the iterator but somehow the step back or something is not working... hmm need to install the arx wizard right since the debug does not work and can't step into each line..... :(
Sorry for late:
Code: [Select]
Benchmark.lsp | © 2005 Michael Puckett | All Rights Reserved
Elapsed milliseconds / relative speed for 16384 iteration(s):

> Old Polyline
    (entpreviousfrom KKKK).....1607 / 1.31 <fastest>
    (ALE_ENTPREVIOUS KKKK).....2106 / 1 <slowest>

> Entity in block
    (entpreviousfrom KKKK)......2246 / 28.48 <fastest>
    (ALE_ENTPREVIOUS KKKK).....63976 / 1 <slowest>
   
> Attrib in Block
    (entpreviousfrom KKKK).....1092 / 1.53 <fastest>
    (ALE_ENTPREVIOUS KKKK).....1669 / 1 <slowest>

> Line                       ********
    (entpreviousfrom KKKK).......1029 / 167.57 <fastest>
    (ALE_ENTPREVIOUS KKKK).....172428 / 1 <slowest>
   
Yes, if I select a dimension nested entity (maybe the first or the last)
I get an error.

But sometime I get a wrong result similar with entprev (VovKa):   

Code: [Select]
Command: !entref
<Entity name: 7ffffbb3550>

Command: (entnext (ALE_EntPrevious EntRef))
<Entity name: 7ffffbb3550>

Command: (entnext (entprev         EntRef))
<Entity name: 7ffffbb3550>

Command: (entnext (entpreviousFrom EntRef))
<Entity name: 7ffffbb32e0>
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 30, 2013, 04:59:14 AM
...
Yes, Irne, (entprev) will be very hard to implement doing exact inverse of (entnext)...

Do you know a condition for the last ALE_ENTPREVIOUS do not get the exact inverse of (entnext)?
Title: Re: (entprev)
Post by: ribarm on November 30, 2013, 07:58:27 AM
...
Yes, Irne, (entprev) will be very hard to implement doing exact inverse of (entnext)...

Do you know a condition for the last ALE_ENTPREVIOUS do not get the exact inverse of (entnext)?

Marc' I think your version has even advantage in comparison to (entprev) my last version I posted... The only difference I see in obraining result is the case where you actually pick with (ale_entprevious (car (nentsel))) first nested entity in block - it then returns "BLOCK" entity - BlockBegin... And my version (entprev (car (nentsel))) with picked first nested entity returns nil - similar to picking last nested entity inside block or dimension with (entnext (car (nentsel)))... I've checked the cases with paper/model space entities and both version act the same (so I don't know how did you get these results stated in post 109) :
Code: [Select]
Command: CTAB

Enter new value for CTAB <"Layout2">: layout1
Restoring cached viewports - Regenerating layout.

Command: (ale_entprevious (entnext (entnext)))
nil

Command: (entprev (entnext (entnext)))
<Entity name: 7ffffbfc330>
When I checked I get entity name of first imaginary VIEWPORT entity that is base entity of Layout TAB...
I don't quite know how would benchmarking show results between these 2 variants, as I think that your version is better optimized if DWG contains entities consisted from vertices or attribs... We should check comparison of these 2 in large amount of entities with those properties, but for checking choosing just the entity that is in the middle of (ssget "_X") - I mean (ssname (ssget "_X") (1- (fix (/ (sslength (ssget "_X") 2.0))))...

So long from me and thanks Marc' for your inputs... Don't take this too serious this all topic was intended for experimental purposes... I mean should new function be implemented into AutoLisp, this all falls to water as probably fastest solution would be implemented and the one that is seriously tested...

As I did wrote, your version seems to me just fine for now and I should be using it for my purposes if I get the opportunity for using it in the future (until and if Autodesk plans to upgrade existing functions database come into reality)...
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on November 30, 2013, 08:43:02 AM
...
Marc' I think your version has even advantage in comparison to (entprev) my last version I posted... The only difference I see in obraining result is the case where you actually pick with (ale_entprevious (car (nentsel))) first nested entity in block - it then returns "BLOCK" entity - BlockBegin... And my version (entprev (car (nentsel))) with picked first nested entity returns nil - similar to picking last nested entity inside block or dimension with (entnext (car (nentsel)))... I've checked the cases with paper/model space entities and both version act the same (so I don't know how did you get these results stated in post 109) :
...
Marko,

sorry but I never test your functions, I do not like to test functions with the same name of others.
For me "entprev" is the function written by VovKa.

If I test your last version (renamed from entprev to entprevMR):
Code: [Select]
(defun entprevMR (e / e1 e2)
 (if (eq (type e) 'ename)
   (if (eq e (entnext))
     nil
     (progn
       (if (not
             (or
               (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Model_Space")
               (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Paper_Space")
             )
           )
         (progn
           (setq e1 (cdr (assoc -2 (entget (cdr (assoc 360 (entget (cdr (assoc 330 (entget e))))))))))
           (if (eq e e1) nil
             (progn
               (while (and e1 (not (eq e (setq e2 (entnext e1)))))
                 (setq e1 e2)
               )
               e1
             )
           )
         )
         (progn
           (setq e1 (entnext))
           (while (and e1 (not (eq e (setq e2 (entnext e1)))))
             (setq e1 e2)
           )
           e1
         )
       )
     )
   )
   (entget e)
 )
)
Test on my last DWG posted:
Code: [Select]
; select line 1
Comando: (setq EntRef (car (nentsel)))
Selezionare oggetto: <Nome entità: 7ffffb600b0>
Comando: (entprevMR EntRef)
nil                            <<< NOT TRUE


; select line 2 in block
Comando: (setq EntRef (car (nentsel)))
Selezionare oggetto: <Nome entità: 7ffffb18770>
Comando: (entprevMR EntRef)
<Nome entità: 7ffffb18760>
Comando: (entnext (entprevMR EntRef))
<Nome entità: 7ffffb18770>      <<< TRUE


; select OLD polyline 3
Comando: (setq EntRef (car (nentsel)))
Selezionare oggetto: <Nome entità: 7ffffb5fde0>
Comando: (entprevMR EntRef)
; errore: tipo di argomento errato: lentityp nil
Title: Re: (entprev)
Post by: ribarm on November 30, 2013, 10:22:50 AM
Sorry, Marc'... I thought my code will work on old POLYLINE vertices...

Here is the version for tests... Although I think your code will perform faster in the case I described above... (ssname (ssget "_X") (1- (fix (/ (sslength (ssget "_X")) 2.0))))

Code - Auto/Visual Lisp: [Select]
  1. (defun entprev (e / e1 e2)
  2.   (if (eq (type e) 'ename)
  3.     (if (eq e (entnext))
  4.       nil
  5.       (if (wcmatch (cdr (assoc 0 (entget e))) "ATTRIB,VERTEX,SEQEND")
  6.         (progn
  7.           (setq e1 (cdr (assoc 330 (entget e))))
  8.           (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  9.             (setq e1 e2)
  10.           )
  11.           e1
  12.         )
  13.         (if
  14.           (not
  15.             (or
  16.               (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Model_Space")
  17.               (eq (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Paper_Space")
  18.             )
  19.           )
  20.            (progn
  21.              (setq e1 (tblobjname "BLOCK" (vla-get-name (vlax-ename->vla-object (cdr (assoc 330 (entget e)))))))
  22.              (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  23.                (setq e1 e2)
  24.              )
  25.              e1
  26.            )
  27.            (progn
  28.              (setq e1 (cdr (assoc 360 (reverse (entget (cdr (assoc 330 (entget e))))))))
  29.              (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  30.                (setq e1 e2)
  31.              )
  32.              e1
  33.            )
  34.         )
  35.       )
  36.     )
  37.     (entget e)
  38.   )
  39. )
  40.  

My apology for wrong code...
M.R.
Title: Re: (entprev)
Post by: ribarm on November 30, 2013, 12:06:43 PM
According to my tests, now my version works (thanks to some of your excellent lines I've taken from your code) and on XREF's, but your version ALE_entprevious fails - my CAD doesn't finish test...

Of course, test it with (entprev (car (nentsel))) on nested entity from Xref...

M.R.
Title: Re: (entprev)
Post by: ribarm on December 01, 2013, 02:51:24 AM
I've tested my code in various situations and it didn't fail... So if anyone have some spare time for testing, I just can produce situation where it should fail - tried combinations with nested blocks inside xrefs, with nested xrefs... So if it fails, please inform me...

The code for testing is here :
http://www.theswamp.org/index.php?topic=45732.msg509151#msg509151

M.R.
Title: Re: (entprev)
Post by: LE3 on December 01, 2013, 12:04:56 PM
ribarm,

try this one, select with nentsel the mtext from the dimension, then get the previous entity and then pass that previous entity until stop on the first entity (the block with the four attributes):

Sequence:
Quote
(setq EntRef (car (nentsel)))
(setq EntPrv (ENTPREVMR EntRef))
(setq EntPrv (ENTPREVMR EntPrv)) ;;; repeat this until stop on the first entity that will be the last previous one.

Does return the first one after all calls?
Title: Re: (entprev)
Post by: ribarm on December 01, 2013, 05:06:16 PM
Thanks, Luis for your tests, it was really small issue - I should have added SEQEND entity to (wcmatch) function... So I think that should fix it... Maybe I missed something else? Who knows, please inform me again if you find something strange like this issue...

M.R.
Title: Re: (entprev)
Post by: LE3 on December 01, 2013, 09:36:48 PM
Thanks, Luis for your tests, it was really small issue - I should have added SEQEND entity to (wcmatch) function... So I think that should fix it... Maybe I missed something else? Who knows, please inform me again if you find something strange like this issue...

M.R.

Marko,
I tried and still does the same - will give a try tomorrow. Thanks!
Title: Re: (entprev)
Post by: LE3 on December 01, 2013, 09:50:11 PM
This is the latest code on my try-out of using ObjectARX - why ARX? -- it is of what AutoLisp and Vlisp function are made of.

HTH and works.

Code - C++: [Select]
  1. void GetObjectIdFirstEntityOnCurrentSpace(AcDbObjectId& objIdFirst, AcDbObjectId spaceId = acdbCurDwg()->currentSpaceId())
  2. {
  3.         AcDbBlockTableRecordPointer blockTableRecordPointer(spaceId, AcDb::kForRead);
  4.         if (blockTableRecordPointer.openStatus() == Acad::eOk)
  5.         {
  6.                 AcDbBlockTableRecordIterator* it = NULL;
  7.                 if (blockTableRecordPointer->newIterator(it) == Acad::eOk)
  8.                 {
  9.                         it->start();
  10.                         AcDbObjectId objId;
  11.                         if (it->getEntityId(objId) == Acad::eOk) objIdFirst = objId;
  12.                         delete it;
  13.                 }
  14.         }
  15. }
  16.  
  17. void GetPreviousEntityObjectId(AcDbEntity* pObj, AcDbObjectId& objIdOut)
  18. {
  19.         AcDbBlockTableRecordPointer blockTableRecordPointer(pObj->ownerId(), AcDb::kForRead);
  20.         if (blockTableRecordPointer.openStatus() == Acad::eOk)
  21.         {
  22.                 AcDbBlockTableRecordIterator* it = NULL;
  23.                 if (blockTableRecordPointer->newIterator(it) == Acad::eOk)
  24.                 {
  25.                         if (it->seek(pObj->objectId()) == Acad::eOk)
  26.                         {
  27.                                 it->step(false, true);
  28.                                 AcDbObjectId objId;
  29.                                 if (it->getEntityId(objId) == Acad::eOk) objIdOut = objId;
  30.                         }
  31.                         delete it;
  32.                 }
  33.         }
  34. }
  35.  
  36. void GetPreviousEname(AcDbObjectId objIdFirst, AcDbObjectId& id, struct resbuf *rb, ads_name& objName)
  37. {
  38.         if (id.isValid() && objIdFirst != id)
  39.         {
  40.                 if (acdbGetAdsName(objName, id) != Acad::eOk) return;
  41.         }
  42.         else if (id.isValid() && objIdFirst == id)
  43.         {
  44.                 if (acdbGetAdsName(objName, objIdFirst) != Acad::eOk) return;
  45.         }
  46.         else if (id.isNull() && rb->rbnext && rb->rbnext->restype == RTENAME) // null id and has an optional argument?
  47.         {
  48.                 AcDbObjectId objId;
  49.                 if (acdbGetObjectId(objId, rb->rbnext->resval.rlname) != Acad::eOk) return;
  50.                 if (acdbGetAdsName(objName, objId) != Acad::eOk) return;
  51.                 id = objId; // make the id valid
  52.         }
  53. }
  54.  

Code - C++: [Select]
  1. static int ads_EntPreviousFrom(void)
  2. {
  3.         struct resbuf *rb = acedGetArgs();
  4.         if (!rb) return RSERR;
  5.        
  6.         AcDbObjectId objId;
  7.         ads_name objName;
  8.         AcDbObjectId objIdFirst;
  9.         if (rb && rb->restype != RTENAME) { acutPrintf(_T("\nError: function requires an ENAME argument. \n")); return RSERR; }
  10.         if (acdbGetObjectId(objId, rb->resval.rlname) != Acad::eOk) return RSERR;
  11.         AcDbObjectPointer<AcDbEntity> pObj(objId, AcDb::kForRead);
  12.         if (pObj.openStatus() != Acad::eOk) return RSERR;
  13.         GetObjectIdFirstEntityOnCurrentSpace(objIdFirst);
  14.         if (objIdFirst == objId && acdbGetAdsName(objName, objIdFirst) == Acad::eOk)
  15.         {
  16.                 acedRetName(objName, RTENAME);
  17.         }
  18.         else
  19.         {
  20.                 if (pObj->isKindOf(AcDb2dVertex::desc()))
  21.                 {
  22.                         AcDbObjectPointer<AcDb2dPolyline> pPline(pObj->ownerId(), AcDb::kForRead);
  23.                         if (pPline.openStatus() == Acad::eOk)
  24.                         {
  25.                                 AcDbObjectIterator* pVertIterator = pPline->vertexIterator();
  26.                                 pVertIterator->start();
  27.                                 pVertIterator->setPosition(pObj->objectId());
  28.                                 pVertIterator->step(true);
  29.                                 AcDbObjectPointer<AcDb2dVertex> pVertex(pVertIterator->objectId(), AcDb::kForRead);
  30.                                 if (pVertex.openStatus() == Acad::eOk && acdbGetAdsName(objName, pVertex->objectId()) == Acad::eOk)
  31.                                 {
  32.                                         acedRetName(objName, RTENAME);
  33.                                 }
  34.                                 else if (acdbGetAdsName(objName, pPline->objectId()) == Acad::eOk)
  35.                                 {
  36.                                         acedRetName(objName, RTENAME);
  37.                                 }
  38.                                 delete pVertIterator;
  39.                         }
  40.                 }
  41.                 else if (pObj->isKindOf(AcDbAttribute::desc()))
  42.                 {
  43.                         AcDbObjectPointer<AcDbBlockReference> pBlockReference(pObj->ownerId(), AcDb::kForRead);
  44.                         if (pBlockReference.openStatus() == Acad::eOk)
  45.                         {
  46.                                 AcDbObjectIterator* pAttributeIterator = pBlockReference->attributeIterator();
  47.                                 pAttributeIterator->start(true);
  48.                                 pAttributeIterator->setPosition(pObj->objectId());
  49.                                 pAttributeIterator->step(true);
  50.                                 AcDbObjectPointer<AcDbAttribute> pAttribute(pAttributeIterator->objectId(), AcDb::kForRead);
  51.                                 if (pAttribute.openStatus() == Acad::eOk && acdbGetAdsName(objName, pAttribute->objectId()) == Acad::eOk)
  52.                                 {
  53.                                         acedRetName(objName, RTENAME);
  54.                                 }
  55.                                 else if (acdbGetAdsName(objName, pBlockReference->objectId()) == Acad::eOk)
  56.                                 {
  57.                                         acedRetName(objName, RTENAME);
  58.                                 }
  59.                                 delete pAttributeIterator;
  60.                         }
  61.                 }
  62.                 else
  63.                 {
  64.                         AcDbObjectId id;
  65.                         GetPreviousEntityObjectId(pObj, id);
  66.                         if (id.isValid())
  67.                         {
  68.                                 GetPreviousEname(objIdFirst, id, rb, objName);
  69.                                 if (id.isValid())
  70.                                 {
  71.                                         acedRetName(objName, RTENAME);
  72.                                 }
  73.                         }
  74.                         else // use the optional argument if any
  75.                         {
  76.                                 GetPreviousEname(objIdFirst, id, rb, objName);
  77.                                 if (id.isValid())
  78.                                 {
  79.                                         acedRetName(objName, RTENAME);
  80.                                 }
  81.                                 else
  82.                                 {
  83.                                         // is part of a nest object?
  84.                                         // use the method with the optional argument:
  85.                                         // usage:
  86.                                         // (setq data (nentsel))
  87.                                         // (setq e (EntPreviousFrom (car data) (car (last data))))
  88.                                 }
  89.                         }
  90.                 }
  91.         }
  92.         return (RSRSLT);
  93. }
  94.  

Quote
usage:
(EntPreviousFrom <ename> <container ename optional>)
returns: previous ename or nil or first ename on space

(setq e (car (nentsel)))
(setq e (EntPreviousFrom e))

or...

(setq e (car (entsel)))
(setq e (EntPreviousFrom e))

or...

(setq data (nentsel))
(setq e (EntPreviousFrom (car data) (car (last data))))
Title: Re: (entprev)
Post by: ribarm on December 02, 2013, 10:02:32 AM
Marko,
I tried and still does the same - will give a try tomorrow. Thanks!

If you're lazy, maybe this test function can help you... It should give the same results, both for (entnext) and (entprevMR)... Note that both functions won't step inside XREF entities - they will treat them parent entities...

Code - Auto/Visual Lisp: [Select]
  1. (defun entprevMR ( e / e1 e2 )
  2.   (if (eq (type e) 'ename)
  3.     (if (eq e (entnext))
  4.       nil
  5.       (if (wcmatch (cdr (assoc 0 (entget e))) "ATTRIB,VERTEX,SEQEND")
  6.         (progn
  7.           (setq e1 (cdr (assoc 330 (entget e))))
  8.           (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  9.             (setq e1 e2)
  10.           )
  11.           e1
  12.         )
  13.         (if (wcmatch (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Model_Space,*Paper_Space")
  14.           (progn
  15.             (setq e1 (cdr (assoc 360 (reverse (entget (cdr (assoc 330 (entget e))))))))
  16.             (if (eq (cdr (assoc 0 (entget e1))) "BLOCK") (setq e1 (entnext)))
  17.             (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  18.               (setq e1 e2)
  19.             )
  20.             e1
  21.           )
  22.           (progn
  23.             (setq e1 (tblobjname "BLOCK" (vla-get-name (vlax-ename->vla-object (cdr (assoc 330 (entget e)))))))
  24.             (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  25.               (setq e1 e2)
  26.             )
  27.             e1
  28.           )
  29.         )
  30.       )
  31.     )
  32.     (entget e)
  33.   )
  34. )
  35.  
  36. (defun c:test ( / e loop n )
  37.   ;;; last nested or parent entity - e ;;;
  38.   (setq e (entlast))
  39.   (setq loop t)
  40.   (while loop
  41.     (if (entnext e) (setq e (entnext e)) (setq loop nil))
  42.   )
  43.   ;;; test - entprev ;;;
  44.   (setq n 0)
  45.   (while e
  46.     (setq n (1+ n))
  47.     (setq e (entprevMR e))
  48.   )
  49.   (prompt "\nTesting entprev function; Total: ")
  50.   (if (= n 1)
  51.     (progn
  52.       (princ n) (prompt " nested/parent entity")
  53.     )
  54.     (progn
  55.       (princ n) (prompt " nested/parent entities")
  56.     )
  57.   )
  58.   ;;; first parent entity - e ;;;
  59.   (setq e (entnext))
  60.   ;;; test - entnext ;;;
  61.   (setq n 0)
  62.   (while e
  63.     (setq n (1+ n))
  64.     (setq e (entnext e))
  65.   )
  66.   (prompt "\nTesting entnext function; Total: ")
  67.   (if (= n 1)
  68.     (progn
  69.       (princ n) (prompt " nested/parent entity")
  70.     )
  71.     (progn
  72.       (princ n) (prompt " nested/parent entities")
  73.     )
  74.   )
  75.   (princ)
  76. )
  77.  

Marko R.
Title: Re: (entprev)
Post by: ribarm on December 02, 2013, 11:05:26 AM
I had cutoff between different CTABs, so I've changed my function once more - look in my last post... Now (entprevMR) should be OK...

My testings passed... Please verify this...

M.R.
Title: Re: (entprev)
Post by: LE3 on December 02, 2013, 11:58:48 AM
Marko,
Got the chance to run another test and see the image capture below with the output - also using vovka entprev(this one will step to previous ones but after returning nil, it will rewind and return the entities again, yours and marco after returning nil will return an error, since the ename argument will be nil) and marco ALE_EntPrevious all with a call of (car (entsel)) - on the dimension.
The A it is what returns of all previous entities, but I see that the previous of a line it should be the block, but it first returns the attributes then the block (this being the first entity on the drawing).

Let's hope my explanation it is clear as mud.

Using my EntPreviousFrom it return entities on the B side.

Thanks,
Luis.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 03, 2013, 08:15:41 AM
@Marko: your entpreMR seems ok, I have seen the problem with my ALE_EntPrevious and XREF,  I'll see if I can solve. Thank you.

@Louis: do you know how do we get the same result of (ssget "_X"), equal to what you see in this window?



 
Title: Re: (entprev)
Post by: LE3 on December 03, 2013, 08:34:03 AM
@Marko: your entpreMR seems ok, I have seen the problem with my ALE_EntPrevious and XREF,  I'll see if I can solve. Thank you.

@Louis: do you know how do we get the same result of (ssget "_X"), equal to what you see in this window?

Hi Marc'Antonio,

Sorry, I do not understand your question, do you want to use some other function to get the same as using SSGET _X ? or if there is another way to get the same? and in that order?

edit: I see that image capture is taking from the VLIDE under View -> Browse drawing database -> Browse all entities

Here it is 5:30AM - I know in Italy it is 2:30PM --- let me get my first coffee.

Luis.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 03, 2013, 09:50:42 AM
Hi Marc'Antonio,
Sorry, I do not understand your question, do you want to use some other function to get the same as using SSGET _X ? or if there is another way to get the same? and in that order?
edit: I see that image capture is taking from the VLIDE under View -> Browse drawing database -> Browse all entities
Here it is 5:30AM - I know in Italy it is 2:30PM --- let me get my first coffee.

Luis.

Yes. Take the coffee first!

My question:  (ssget "_X") is very slow, is there another method in Visuallisp to obtain the same result?
That is a list of just main entities as can be seen also in Browse drawing database -> Browse all entities?

Ciao.
 
Title: Re: (entprev)
Post by: LE3 on December 03, 2013, 10:02:14 AM
Yes. Take the coffee first!

My question:  (ssget "_X") is very slow, is there another method in Visuallisp to obtain the same result?
That is a list of just main entities as can be seen also in Browse drawing database -> Browse all entities?

Ciao.

Not that I know or aware.

I did a quick method in arx that access directly the database (as they did it for vlide):

Code - C++: [Select]
  1. static void BrowseAllEntities(void)
  2. {
  3.         AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);
  4.         if (pBTR.openStatus() != Acad::eOk) return;
  5.         AcDbBlockTableRecordIterator* it = NULL;
  6.         if (pBTR->newIterator(it) != Acad::eOk) return;
  7.         AcDbObjectId objId;
  8.         ads_name ename;
  9.         for (; !it->done(); it->step())
  10.         {
  11.                 if (it->getEntityId(objId) != Acad::eOk) continue;
  12.                 AcDbObjectPointer<AcDbEntity> pEnt(objId, AcDb::kForRead);
  13.                 if (pEnt.openStatus() != Acad::eOk) continue;
  14.                 if (acdbGetAdsName(ename, pEnt->objectId()) != Acad::eOk) continue;
  15.                 acutPrintf(_T("\n<%s> <Entity name: %8lx> \n"), pEnt->isA()->dxfName(), ename[0]);
  16.         }
  17.         delete it;
  18. }
  19.  

Then on the command line returns, similar to what the vlide does, did not added types:
Quote
<INSERT> <Entity name: FFB06D40>
<LINE> <Entity name: FFB06E30>
<CIRCLE> <Entity name: FFB06E40>
<CIRCLE> <Entity name: FFB06E50>
<DIMENSION> <Entity name: FFB06ED0>
<CIRCLE> <Entity name: FFB04040>
<CIRCLE> <Entity name: FFB04050>

I think that the best way is to create an objectarx solution and add your own methods to handle, this then send those to be use as autolisp functions - to do the work faster - I have no idea or have not tested this approach(es) on c# (thinking if by using c# could be much simpler and accessible since we can do autolisp function with c# btw) --- don't recall seeing a way to iterate the same as in arx....
Title: Re: (entprev)
Post by: LE3 on December 03, 2013, 10:29:28 AM
Yes. Take the coffee first!

My question:  (ssget "_X") is very slow, is there another method in Visuallisp to obtain the same result?
That is a list of just main entities as can be seen also in Browse drawing database -> Browse all entities?

Ciao.

Not that I know or aware.


To add something into my previous post, maybe something like this?

Code - Auto/Visual Lisp: [Select]
  1. (vlax-for item ms (print item))
  2. ;;; or...
  3. (vlax-for item ms (print (vlax-vla-object->ename item)))
  4.  

Quote
Command: 'VLIDE
#<VLA-OBJECT IAcadBlockReference 000000002a374448>
#<VLA-OBJECT IAcadLine 000000002a717b08>
#<VLA-OBJECT IAcadCircle 000000002a717bc8>
#<VLA-OBJECT IAcadCircle 000000002a717988>
#<VLA-OBJECT IAcadDimRotated 000000002a442da8>
#<VLA-OBJECT IAcadCircle 000000002a717a48>
#<VLA-OBJECT IAcadCircle 000000002a7178c8>

or:

<Entity name: 7ffffb06d40>
<Entity name: 7ffffb06e30>
<Entity name: 7ffffb06e40>
<Entity name: 7ffffb06e50>
<Entity name: 7ffffb06ed0>
<Entity name: 7ffffb04040>
<Entity name: 7ffffb04050>
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 03, 2013, 11:36:47 AM
To add something into my previous post, maybe something like this?
Code - Auto/Visual Lisp: [Select]
  1. (vlax-for item ms (print item))
  2. ;;; or...
  3. (vlax-for item ms (print (vlax-vla-object->ename item)))
  4.  
I do not know if your code "...(setq ms (vla-get-modelspace db))..." is faster then  (ssget "_X") because I have to iterate on ModelSpace and all layouts...

In your DWG sample I have created two text one in Layout1  "ThisIsATextOnLayOut1" and one in Layout2 "ThisIsATextOnLayOut2" but I saw that "Browse drawing database -> Browse all entities" shows only the text in the active layout (Layout2 > "ThisIsATextOnLayOut2", see image).

Title: Re: (entprev)
Post by: LE3 on December 03, 2013, 01:05:10 PM
I noticed that on the 'browse all entities" - no idea about the internals on how these guys from basis did back when vlisp was vital lisp.

But anyway, my method that uses the acdbCurDwg()->currentSpaceId() or current space will work better since it will grab the entities on the desired location and also avoiding the use of COM or activex extensions as those from all the vlax-XXXX

There are VLAX- methods for active layout or to get by layout name, too.

But do not know if any of those VLAX- calls are faster or not than the (ssget "_X") all depends in the case you are working.... the ssget "x" will get all, but maybe it will be a need to sort out entities.... difficult to say.


My 0.2 cts.... :)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 03, 2013, 05:14:06 PM
I have tried this version but seems slower, I need a method to stop (vlax-for ObjFor (vla-get-block LayFor) ...
when find the  (equal EntObj ObjFor) condition.
Code: [Select]
; Version 3.30 - 2013/12/03 - not tested on xref
(defun ALE_EntPrevious (EntNam / EntObj SelSet EntDat Countr EntOut PrnEnt *AcAcDwg* *AcDataB* TrueFl)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (not (wcmatch (cdr (assoc 0 EntDat)) "ATTRIB,VERTEX"))
    )
    (progn
      (setq
        *AcAcDwg* (vla-get-ActiveDocument (vlax-get-acad-object))
        *AcDataB* (vla-get-database *AcAcDwg*)
        EntObj    (vlax-ename->vla-object EntNam)
      )
      (vlax-for LayFor (vla-get-Layouts *AcDataB*)
        (vlax-for ObjFor (vla-get-block LayFor)
          (if (equal EntObj ObjFor)
            (setq TrueFl T   EntOut (vlax-vla-object->ename EntOut))
            (or TrueFl (setq EntOut ObjFor))
          )
        )
      )
    )
    (setq
      EntOut (entget (cdr (assoc 330 EntDat)))
      EntOut (cdr (cond ((assoc 360 (reverse EntOut)))
                         ((assoc -1 EntOut))
                  )
             )
    )
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)
Title: Re: (entprev)
Post by: Lee Mac on December 03, 2013, 05:36:42 PM
I need a method to stop (vlax-for ObjFor (vla-get-block LayFor) ...
when find the  (equal EntObj ObjFor) condition.

Not pretty, but should work:
Code: [Select]
(vl-catch-all-apply
    (function
        (lambda ( )
            (vlax-for l (vla-get-layouts *AcDataB*)
                (vlax-for o (vla-get-block l)
                    (if (equal entobj o)
                        (progn
                            (setq entout (vlax-vla-object->ename entout))
                            (exit)
                        )
                        (setq entout o)
                    )
                )
            )
        )
    )
)
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 04, 2013, 05:17:35 AM
I need a method to stop (vlax-for ObjFor (vla-get-block LayFor) ...
when find the  (equal EntObj ObjFor) condition.

Not pretty, but should work: ...

Thanks Lee, I thought (exit) or (quit) but the idea of putting it in a (vl-catch-all-apply ...) I would never come!
Code: [Select]

;Benchmark.lsp | © 2005 Michael Puckett | All Rights Reserved
; On my entprev.dwg:
; select line 1
;Elapsed milliseconds / relative speed for 8192 iteration(s):
;    (ALE_ENTPREVIOUS KKKK)......1076 / 67.53 <fastest>
;    (ENTPREVMR KKKK)...........72665 / 1 <slowest>

; select line 2 in block
;Elapsed milliseconds / relative speed for 512 iteration(s):
;    (ALE_ENTPREVIOUS KKKK).....2589 / 1.62 <fastest>
;    (ENTPREVMR KKKK)...........4196 / 1 <slowest>

; select Attrib in block 2
;Elapsed milliseconds / relative speed for 16384 iteration(s):
;    (ENTPREVMR KKKK)...........2028 / 1.27 <fastest>
;    (ALE_ENTPREVIOUS KKKK).....2574 / 1 <slowest>

; select OLD polyline 3
;Elapsed milliseconds / relative speed for 16384 iteration(s):
;    (ENTPREVMR KKKK)...........1404 / 1.03 <fastest>
;    (ALE_ENTPREVIOUS KKKK).....1451 / 1 <slowest>

; select line 1
;Elapsed milliseconds / relative speed for 8192 iteration(s):
;    (ALE_ENTPREVIOUS KKKK)................1498 / 10.85 <fastest>
;    (ALE_ENTPREVIOUSBYSS KKKK #SSET).....16255 / 1 <slowest>
Code: [Select]
; Version 3.40 - 2013/12/04 - not tested on Xref
;(setq *AcDataB* (vla-get-database (vla-get-ActiveDocument (vlax-get-acad-object))))
;
(defun ALE_EntPrevious (EntNam / EntObj SelSet EntDat EntOut PrnEnt)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (not (wcmatch (cdr (assoc 0 EntDat)) "ATTRIB,VERTEX"))
    )
    (progn
      (setq EntObj (vlax-ename->vla-object EntNam))
      (vl-catch-all-apply ; Lee Mac idea
        (function
          (lambda ( )
            (vlax-for l (vla-get-layouts *AcDataB*)
              (vlax-for o (vla-get-block l)
                (if (equal EntObj o)
                  (progn (setq EntOut (vlax-vla-object->ename EntOut)) (exit))
                  (setq EntOut o)
                )
              )
            )
          )
        )
      )
    )
    (setq
      EntOut (entget (cdr (assoc 330 EntDat)))
      EntOut (cdr (cond ((assoc 360 (reverse EntOut)))
                         ((assoc -1 EntOut))
                  )
             )
    )
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)

; Another attempt - Version 1.00 - 2013/12/04 - not tested on Xref
; (setq #SSet (ssget "_X"))
; (ALE_EntPreviousBySS (car (nentsel)) #SSet)
;
(defun ALE_EntPreviousBySS (EntNam SelSet / SelSet EntDat Countr EntOut PrnEnt)
  (if
    (and
      (assoc 410 (setq EntDat (entget EntNam)))
      (not (wcmatch (cdr (assoc 0 EntDat)) "ATTRIB,VERTEX"))
    )
    (progn
      (setq Countr 0)
      (while SelSet
        (if (eq EntNam (ssname SelSet Countr))
          (setq EntOut (ssname SelSet (1+ Countr))  PrnEnt EntOut  SelSet nil)
          (setq Countr (1+ Countr))
        )
      )
    )
    (setq
      EntOut (entget (cdr (assoc 330 EntDat)))
      EntOut (cdr (cond ((assoc 360 (reverse EntOut)))
                         ((assoc -1 EntOut))
                  )
             )
    )
  )
  (while (and EntOut (not (eq EntNam (setq PrnEnt (entnext EntOut)))))
    (setq EntOut PrnEnt)
  )
  EntOut
)
Title: Re: (entprev)
Post by: ribarm on December 04, 2013, 10:52:00 AM
Marc', can you benchmark also this version... I think it's more optimized for entities near end of ss (ssname (ssget "_X") 0) or (entlast)... It would be nice to see if this version is actually faster than orig. (entprevMR)...

Code - Auto/Visual Lisp: [Select]
  1. (defun entprevMR-SS ( e / i ss e1 e2 )
  2.   (setq i -1)
  3.   (setq ss (ssget "_X"))
  4.   (while (not (or (eq e (ssname ss (setq i (1+ i)))) (eq (cdr (assoc 330 (entget e))) (ssname ss i)))))
  5.   (if (eq (type e) 'ename)
  6.     (if (eq e (entnext))
  7.       nil
  8.       (if (wcmatch (cdr (assoc 0 (entget e))) "ATTRIB,VERTEX,SEQEND")
  9.         (progn
  10.           (setq e1 (cdr (assoc 330 (entget e))))
  11.           (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  12.             (setq e1 e2)
  13.           )
  14.           e1
  15.         )
  16.         (if (wcmatch (cdr (assoc 2 (entget (cdr (assoc 330 (entget e)))))) "*Model_Space,*Paper_Space")
  17.           (progn
  18.             (setq e1 (cdr (assoc 360 (reverse (entget (cdr (assoc 330 (entget e))))))))
  19.             (if (eq (cdr (assoc 0 (entget e1))) "BLOCK") (setq e1 (ssname ss (1+ i))))
  20.             (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  21.               (setq e1 e2)
  22.             )
  23.             e1
  24.           )
  25.           (progn
  26.             (setq e1 (tblobjname "BLOCK" (vla-get-name (vlax-ename->vla-object (cdr (assoc 330 (entget e)))))))
  27.             (while (and e1 (not (eq e (setq e2 (entnext e1)))))
  28.               (setq e1 e2)
  29.             )
  30.             e1
  31.           )
  32.         )
  33.       )
  34.     )
  35.     (entget e)
  36.   )
  37. )
  38.  
  39. (defun c:test ( / e loop n )
  40.   ;;; last nested or parent entity - e ;;;
  41.   (setq e (entlast))
  42.   (setq loop t)
  43.   (while loop
  44.     (if (entnext e) (setq e (entnext e)) (setq loop nil))
  45.   )
  46.   ;;; test - entprev ;;;
  47.   (setq n 0)
  48.   (while e
  49.     (setq n (1+ n))
  50.     (setq e (entprevMR-SS e))
  51.   )
  52.   (prompt "\nTesting entprev function; Total: ")
  53.   (if (= n 1)
  54.     (progn
  55.       (princ n) (prompt " nested/parent entity")
  56.     )
  57.     (progn
  58.       (princ n) (prompt " nested/parent entities")
  59.     )
  60.   )
  61.   ;;; first parent entity - e ;;;
  62.   (setq e (entnext))
  63.   ;;; test - entnext ;;;
  64.   (setq n 0)
  65.   (while e
  66.     (setq n (1+ n))
  67.     (setq e (entnext e))
  68.   )
  69.   (prompt "\nTesting entnext function; Total: ")
  70.   (if (= n 1)
  71.     (progn
  72.       (princ n) (prompt " nested/parent entity")
  73.     )
  74.     (progn
  75.       (princ n) (prompt " nested/parent entities")
  76.     )
  77.   )
  78.   (princ)
  79. )
  80.  

(entprevMR-SS) also passed all my tests...

M.R.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 04, 2013, 03:50:47 PM
Marc', can you benchmark also this version... I think it's more optimized for entities near end of ss (ssname (ssget "_X") 0) or (entlast)... It would be nice to see if this version is actually faster than orig. (entprevMR)...
M.R.
Marko, I am doing tests, (ssget "_X") is very slow, this version use a selset as argument:
; (setq #SSet (ssget "_X"))  <<<<<<< I set only one time! But it is slower again.
; (ALE_EntPreviousBySS (car (nentsel)) #SSet)
Code: [Select]
; select line 1
;Elapsed milliseconds / relative speed for 8192 iteration(s):
;    (ALE_ENTPREVIOUS KKKK)................1498 / 10.85 <fastest>
;    (ALE_ENTPREVIOUSBYSS KKKK #SSET).....16255 / 1 <slowest>
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 04, 2013, 05:20:10 PM
Marc', can you benchmark also this version... I think it's more optimized for entities near end of ss (ssname (ssget "_X") 0) or (entlast)... It would be nice to see if this version is actually faster than orig. (entprevMR)...
M.R.
Code: [Select]
;Benchmark.lsp | © 2005 Michael Puckett | All Rights Reserved
; select line 1
;Elapsed milliseconds / relative speed for 8192 iteration(s):
;    (ALE_ENTPREVIOUS KKKK).......1029 / 568.52 <fastest>
;    (ENTPREVMR-SS KKKK)........585004 / 1 <slowest>
I can not do other tests, to much difference
Code: [Select]

; select line 1
;Elapsed milliseconds / relative speed for 128 iteration(s):
;    (ENTPREVMR KKKK)........1092 / 8.73 <fastest>
;    (ENTPREVMR-SS KKKK).....9531 / 1 <slowest>
I can not do other tests, to much difference

Title: Re: (entprev)
Post by: ribarm on December 04, 2013, 05:55:27 PM
Thanks, Marc' for benchmarking... I thought so that SS version is slower in situations with testing on firstly created entities... I don't know this line in benchmark :
Code: [Select]
; select line 1
Does this mean that you're testing functions on first line in DWG with plenty of them?
Also on what entity is referenced KKKK?
Or you are cycling through all of them similar to my (c:test) function from last to first entity...
Is SS version slower than orig. version in this case from last to first entity?

If KKKK entity is first one (setq KKKK (entnext (entnext))), can you benchmark it with last one (setq KKKK (entlast) loop t) (while loop (if (entnext KKKK) (setq KKKK (entnext KKKK)) (setq loop nil)))...

Or is KKKK actually : (setq KKKK (ssname (ssget "_X") (1- (fix (/ (sslength (ssget "_X")) 2.0)))))
Title: Re: (entprev)
Post by: ribarm on December 04, 2013, 06:58:29 PM
Here are my results between (entprevMR) and (entprevMR-SS) :

Code - Auto/Visual Lisp: [Select]
  1. (defun c:test-benchmark ( / ss e )
  2. ; Results on 10000 PELLIPSE entities ;
  3. ;------------------------------------;
  4.   (setq ss (ssget "_X"))
  5. ;  (setq e (ssname ss (1- (sslength ss))))                  ;;; (entprevMR e) = 0 ;;; (entprevMR-SS e) = 202 ;;;
  6. ;  (setq e (ssname ss (1- (fix (/ (sslength ss) 2.0)))))    ;;; (entprevMR e) = 78 ;;; (entprevMR-SS e) = 125 ;;;
  7. ;  (setq e (ssname ss 0))                                   ;;; (entprevMR e) = 140 ;;; (entprevMR-SS e) = 15 ;;;
  8.                                                             ;;;--------------------------------------------------;;;
  9.                                                             ;;;  (entprevMR e) = 218 ;;; (entprevMR-SS e) = 342  ;;;
  10.                                                             ;;; 342/218 = 1.57 faster (entprevMR)/(entprevMR-SS) ;;;
  11.   (setq t1 (car (_vl-times)))
  12.   (entprev e)
  13.   (setq t2 (car (_vl-times)))
  14.   (princ (- t2 t1))
  15.   (princ)
  16. )
  17.  
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 05, 2013, 03:18:54 AM
Here are my results between (entprevMR) and (entprevMR-SS) :
...
Marko,
I forgot to write (as I did above)   >>>; On my entprev.dwg:
about:
; select line 1
; select line 2 in block
; select Attrib in block 2
; select OLD polyline 3
see figure on my dwg.

About kkkk: it simply a variable, Benchmark is Benchmark.lsp by Michael Puckett:
Code: [Select]
(setq kkkk (car (nentsel)))
(Benchmark '(
   (entprevMR kkkk) ;Marko Ribar
   (ALE_EntPrevious kkkk)
)           )

My 2 cents: the problem un performance is in DWG with many complex entities PEllipse, 3Dline, Blocks with many attribs and when you select a simple entity (line) to avoid to iterate over all sub-entities as in my sample dwg.
Title: Re: (entprev)
Post by: Marc'Antonio Alessi on December 08, 2013, 12:58:57 PM
...
But anyway, my method that uses the acdbCurDwg()->currentSpaceId() or current space will work better since it will grab the entities on the desired location and also avoiding the use of COM or activex extensions as those from all the vlax-XXXX
...
Louis,
I have tested (in my entprev.dwg) your function again and:
Code: [Select]
(defun C:TestentpreviousFrom ( / SelSet Countr EntNam EntPrv Countr)
  (setq EntNam (ssname (ssget "_X") 0) Countr 0)
  (while EntNam
    (if (setq EntPrv (entpreviousFrom EntNam))
      (or
        (eq EntNam (entnext EntPrv))
        (progn (print (cdr (assoc 0 (entget EntNam)))) (princ " Not Eq "))
      )
      (progn (print (cdr (assoc 0 (entget EntNam))))(princ " nil "))
    )
    (setq EntNam (entnext EntNam)  Countr (1+ Countr))
  )
  Countr
)
My fuction return nil only for seqend:
...
"SEQEND"  nil
"SEQEND"  nil 6274

Your function:
....
"SEQEND"  nil
"INSERT"  nil
"SEQEND"  nil
"LWPOLYLINE"  nil
"SEQEND"  nil
"POLYLINE"  nil
"SEQEND"  nil
"LWPOLYLINE"  nil
...
and Not Eq in:
...
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"LWPOLYLINE"  Not Eq
"POLYLINE"  Not Eq
"LWPOLYLINE"  Not Eq
6274

Title: Re: (entprev)
Post by: LE3 on December 08, 2013, 01:25:25 PM
...
But anyway, my method that uses the acdbCurDwg()->currentSpaceId() or current space will work better since it will grab the entities on the desired location and also avoiding the use of COM or activex extensions as those from all the vlax-XXXX
...
Louis,
I have tested (in my entprev.dwg) your function again and:
Code: [Select]
(defun C:TestentpreviousFrom ( / SelSet Countr EntNam EntPrv Countr)
  (setq EntNam (ssname (ssget "_X") 0) Countr 0)
  (while EntNam
    (if (setq EntPrv (entpreviousFrom EntNam))
      (or
        (eq EntNam (entnext EntPrv))
        (progn (print (cdr (assoc 0 (entget EntNam)))) (princ " Not Eq "))
      )
      (progn (print (cdr (assoc 0 (entget EntNam))))(princ " nil "))
    )
    (setq EntNam (entnext EntNam)  Countr (1+ Countr))
  )
  Countr
)
My fuction return nil only for seqend:
...
"SEQEND"  nil
"SEQEND"  nil 6274

Your function:
....
"SEQEND"  nil
"INSERT"  nil
"SEQEND"  nil
"LWPOLYLINE"  nil
"SEQEND"  nil
"POLYLINE"  nil
"SEQEND"  nil
"LWPOLYLINE"  nil
...
and Not Eq in:
...
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"INSERT"  Not Eq
"LWPOLYLINE"  Not Eq
"POLYLINE"  Not Eq
"LWPOLYLINE"  Not Eq
6274

Hi Marco,
The function 'BrowseAllEntities' uploaded as source code where I have the call:
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForRead);

Here:
http://www.theswamp.org/index.php?topic=45732.msg509295#msg509295

It is part of an internal command on my solution not avail and was to demonstrate how the one in visual lisp was made or implemented (I can make that as command to tested if needed).

The latest exported autolisp function of 'EntPreviousFrom' I uploaded a few days ago here:
http://www.theswamp.org/index.php?topic=45732.msg509185#msg509185

And the reason I have done my uploads on separate messages it is to reflect the changes, and in some case anyone one day end up using the code, can do a comparison too.

HTH.

Luis.