Author Topic: FYI: enlast is buggy!  (Read 1452 times)

0 Members and 1 Guest are viewing this topic.

roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
FYI: enlast is buggy!
« on: January 09, 2018, 10:16:18 AM »
I do not know if this is common knowledge, I do not remember seeing any posts to this effect, but the entlast function is quite buggy. This applies to both the AutoCAD and the BricsCAD implementation. I have just found out that the BricsCAD team have actually gone out of their way to exactly emulate the quaint AutoCAD behavior.

The problem in a nutshell:
The return value of (entlast) can depend on the layout that was previously active. (There may of course be other issues...)

See the attached test files (Lisp and dwg).

Instead of entlast I advise using something like this:
Code - Auto/Visual Lisp: [Select]
  1. (defun ReliableEntlast ( / ss)
  2.   (if (setq ss (ssget "_L"))
  3.     (ssname ss 0)
  4.   )
  5. )

MP

  • Seagull
  • Posts: 17488
Re: FYI: enlast is buggy!
« Reply #1 on: January 09, 2018, 10:34:47 AM »
In before John. One issue some programmers may miss is that entlast returns the last non deleted primary entity, so while the last entity may be an attribute entlast would return its owner, a block instance.
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9282
Re: FYI: enlast is buggy!
« Reply #2 on: January 09, 2018, 10:35:55 AM »
Somewhat related topic, if anyone wants to add/adjust/correct/etc. any section of theSwamp's Autolisp help file they will need to follow some simple HTML editing sytaxs rules so here is some basic info about the process. Here is a section (the HTML source) for the ADD function so you can see the HTML tags I added/used.

Below that is the CSS for the file so they can see what classes they can use.

Aside from that Mark or I will have to do the final editing because the file resides in my home directory on TheSwamps server. So, if you provide a code snip like the ADD example below it can be added to the file.

Code - HTML5: [Select]
  1. <h3 class="String" id="+">+ (add)</h3>
  2.  
  3. Returns the sum of all numbers
  4.  
  5. (+ [number number] ...)
  6.  
  7. <span class="ArgumentsIdentifier">Arguments</span>
  8.  
  9. number
  10.  
  11. A number.
  12.  
  13. <span class="ReturnsIdentifier">Return Values</span>
  14.  
  15. The result of the addition. If you supply only one number argument, this
  16. function returns the result of adding it to zero. If you supply no arguments,
  17. the function returns 0.
  18.  
  19. <span class="ExamplesIdentifier">Examples</span>
  20.  
  21. (+ 1 2) returns 3
  22.  
  23. (+ 1 2 3 4.5) returns 10.5
  24.  
  25. (+ 1 2 3 4.0) returns 10.0
  26.  
  27. <span class="PreProc">-------------------------------------------------------------------------------</span>

Code - CSS: [Select]
  1. <style type="text/css">
  2. <!--
  3. pre {
  4.     color:#333333;
  5.     background-color:#fffffc;
  6.     margin-left:7px;
  7.     margin-right:7px;
  8.     margin-top:0;
  9.     margin-bottom:0;
  10.     border:none;
  11.     padding:0;
  12.     text-indent:0;
  13.     font-family:'Courier New', monospace;
  14.     font-size:12px;
  15. }
  16. body {
  17.     color:#333333;
  18.     background-color:#fffffc;
  19. }
  20. .heading {
  21.     color: #000044;
  22.     font-size:22px;
  23.     font-weight:bold;
  24.     font-style: italic;
  25. }
  26. .Ignore {
  27.     color: #202020;
  28. }
  29. .Statement {
  30.     color: #7e8aa2;
  31. }
  32. .Todo {
  33.     color: #C82536;
  34.     font-size:14px;
  35.     font-style: italic;
  36.     font-weight: bold;
  37.     text-decoration: underline;
  38. }
  39. .Special {
  40.     color: #B22222;
  41. }
  42. .Identifier {
  43.     color: #000044;
  44. }
  45. .ArgumentsIdentifier {
  46.     font-family:'Courier New', monospace;
  47.     font-size:14px;
  48.     font-weight:bold;
  49.     font-style:italic;
  50.     text-decoration: underline;
  51. }
  52. .ReturnsIdentifier {
  53.     font-family:'Courier New', monospace;
  54.     font-size:14px;
  55.     font-weight:bold;
  56.     font-style:italic;
  57.     text-decoration: underline;
  58. }
  59. .ExamplesIdentifier {
  60.     font-family:'Courier New', monospace;
  61.     font-size:14px;
  62.     font-weight:bold;
  63.     font-style:italic;
  64.     text-decoration: underline;
  65. }
  66. .PreProc {
  67.     color: #000000;
  68. }
  69. .String {
  70.     color: #000044;
  71.     font-size:22px;
  72.     font-style: italic;
  73. }
  74. -->
  75. </style>

“Common sense is not so common.” ~Voltaire

--> Donate to TheSwamp.org <--


roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
Re: FYI: enlast is buggy!
« Reply #4 on: January 09, 2018, 01:07:17 PM »
@Marc'Antonio Alessi: Thanks for confirming this.

Note that entnext (no doubt a close cousin of entlast) is also buggy.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1019
  • Marco
Re: FYI: enlast is buggy!
« Reply #5 on: January 09, 2018, 01:33:28 PM »
@Marc'Antonio Alessi: Thanks for confirming this.

Note that entnext (no doubt a close cousin of entlast) is also buggy.
:yes: :)

ribarm

  • Water Moccasin
  • Posts: 2175
  • Marko Ribar, architect
Re: FYI: enlast is buggy!
« Reply #6 on: January 09, 2018, 01:42:35 PM »
Now you got me... Is this OK?

Code - Auto/Visual Lisp: [Select]
  1. (defun c:elast ( / tmp )
  2.   (setq tmp (entlast))
  3.   (if (entnext tmp)
  4.     (while (setq tmp (entnext tmp))
  5.       (setq el tmp)
  6.     )
  7.     (setq el tmp)
  8.   )
  9.   (prompt "\nLast entity name is stored in variable \"el\"... You can call it with !el...")
  10.   (princ)
  11. )
  12.  
:thinking:
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Water Moccasin
  • Posts: 2175
  • Marko Ribar, architect
Re: FYI: enlast is buggy!
« Reply #7 on: January 09, 2018, 02:53:50 PM »
I guess it's wrong... Why simple when it can be more complex... DUH...

Code - Auto/Visual Lisp: [Select]
  1. (defun c:elast ( / tmp )
  2.   (if (and (ssget "_L") (setq tmp (ssname (ssget "_L") 0)))
  3.     (if (and (entnext tmp) (wcmatch (cdr (assoc 0 (entget (entnext tmp)))) "ATTRIB,VERTEX"))
  4.       (progn
  5.         (while (/= (cdr (assoc 0 (entget (setq tmp (entnext tmp))))) "SEQEND")
  6.           (setq el tmp)
  7.         )
  8.         (if (= (cdr (assoc 0 (entget tmp))) "SEQEND")
  9.           (setq el tmp)
  10.         )
  11.       )
  12.       (setq el tmp)
  13.     )
  14.     (progn
  15.       (setq tmp (entlast))
  16.       (if (and tmp (entnext tmp) (wcmatch (cdr (assoc 0 (entget (entnext tmp)))) "ATTRIB,VERTEX"))
  17.         (progn
  18.           (while (/= (cdr (assoc 0 (entget (setq tmp (entnext tmp))))) "SEQEND")
  19.             (setq el tmp)
  20.           )
  21.           (if (= (cdr (assoc 0 (entget tmp))) "SEQEND")
  22.             (setq el tmp)
  23.           )
  24.         )
  25.         (setq el tmp)
  26.       )
  27.     )
  28.   )
  29.   (if el
  30.     (prompt "\nLast entity name is stored in variable \"el\"... You can call it with !el...")
  31.   )
  32.   (princ)
  33. )
  34.  
  35. (defun c:EntlastTest ( / el )
  36.   (setvar 'ctab "Model")
  37.   (c:elast)
  38.   (print (vlax-ename->vla-object el))
  39.   (setvar 'ctab "Layout1")
  40.   (setvar 'ctab "Model")
  41.   (c:elast)
  42.   (print (vlax-ename->vla-object el))
  43.   (setvar 'ctab "Layout2")
  44.   (setvar 'ctab "Model")
  45.   (c:elast)
  46.   (print (vlax-ename->vla-object el))
  47.   (princ)
  48. )
  49.  
« Last Edit: January 09, 2018, 04:41:55 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
Re: FYI: enlast is buggy!
« Reply #8 on: January 09, 2018, 04:06:19 PM »
I have upgraded a library function to this:
Code - Auto/Visual Lisp: [Select]
  1. (defun KGA_Sys_Entlast ( / enm ss tmp)
  2.   (if (setq ss (ssget "_L"))
  3.     (progn
  4.       (setq enm (ssname ss 0))
  5.       (while
  6.         (and
  7.           (setq tmp (entnext enm))
  8.           (not (vlax-erased-p tmp))                                      ; Required: entnext is also buggy.
  9.           (vl-position (vle-entget 0 tmp) '("ATTRIB" "SEQEND" "VERTEX")) ; Required: entnext is also buggy.
  10.         )
  11.         (setq enm tmp)
  12.       )
  13.     )
  14.   )
  15.   enm
  16. )

Vle-entget is a built-in function in BricsCAD. You can probably guess what it returns.

@ribarm: (ssget "_L") can return nil...

EDIT: Improved version of KGA_Sys_Entlast.
« Last Edit: January 14, 2018, 03:41:41 PM by roy_043 »

roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
Re: FYI: enlast is buggy!
« Reply #9 on: January 09, 2018, 04:13:28 PM »
Maybe this can help: https://www.theswamp.org/index.php?topic=45732.msg509031#msg509031
Thanks for that link. I'll study the topic. I vaguely remember reading only parts of it in the past. :roll:

ribarm

  • Water Moccasin
  • Posts: 2175
  • Marko Ribar, architect
Re: FYI: enlast is buggy!
« Reply #10 on: January 09, 2018, 04:43:02 PM »
@ribarm: (ssget "_L") can return nil...

code corrected above...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1019
  • Marco
Re: FYI: enlast is buggy!
« Reply #11 on: January 11, 2018, 04:48:25 AM »
Maybe this can help: https://www.theswamp.org/index.php?topic=45732.msg509031#msg509031
Thanks for that link. I'll study the topic. I vaguely remember reading only parts of it in the past. :roll:
This is not related to the subject of the discussion but, since you use Bricscad, there is another strange behavior in the old versions concerning ssget in empty DWG:
Code: [Select]
(defun C:TestEmptyDWG ( / Ss_Set)
  (print (getvar "ACADVER"))
  (if (setq Ss_Set (ssget "_X"))
    (progn
      (print (cdr (assoc 0 (entget (ssname Ss_Set 0)))))
      (princ (strcat " sslength = " (itoa (sslength Ss_Set))))
    )
    (print "no ssget entities in DWG")
  )
  (princ)
)
Code: [Select]
: TESTEMPTYDWG
"20.0 BricsCAD"
"no ssget entities in DWG"

: TESTEMPTYDWG
"19.1 BricsCAD"
"VIEWPORT"  sslength = 1
This is my version of Ss-After:
Code: [Select]
(defun ALE_Ss-After (EntNam / SelSet)
  (cond
    ( (not EntNam) (ssget "_X" '((0 . "~VIEWPORT"))) ); "~VIEWPORT" x Bricscad
    ( (setq EntNam (entnext EntNam))
      (setq SelSet (ssadd EntNam))
      (while (setq EntNam (entnext EntNam))
        (if (entget EntNam) (ssadd EntNam SelSet))
      )
      SelSet
    )
  )
)

roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
Re: FYI: enlast is buggy!
« Reply #12 on: January 11, 2018, 05:39:35 AM »
@Marc'Antonio Alessi:
Are you testing this with the same dwg? Because I cannot reproduce this in BC V14 or V15. Maybe in one case you are testing with a dwg that (still) contains a 'main' paper space viewport. Which is an invisible entity that cannot be erased through normal user actions. To delete it you have to use vla-delete, entdel will not work.

EDIT: 'vla-deleting' a main viewport results in an _Audit issue. So such a VP should not be deleted.
« Last Edit: January 11, 2018, 05:58:58 AM by roy_043 »

roy_043

  • Water Moccasin
  • Posts: 1733
  • BricsCAD 18
Re: FYI: enlast is buggy!
« Reply #13 on: January 11, 2018, 05:57:34 AM »
@Marc'Antonio Alessi:
Actually I am trying to create a reliable and fast 'Ss-After' function myself. It is while doing so that I was confronted with the aforementioned issues with entlast and entnext.

Your function uses entnext which you have confirmed is buggy...

Here is my current version (maybe slow in large drawings?):
Code - Auto/Visual Lisp: [Select]
  1. ; Return value: Non-empty pickset or nil.
  2. ; Erased objects are not added to the set.
  3. (defun KGA_Conv_ObjectList_To_Pickset (lst / ret)
  4.   (setq ret (ssadd))
  5.   (foreach obj lst (if (not (vlax-erased-p obj)) (ssadd (vlax-vla-object->ename obj) ret)))
  6.   (if (/= 0 (sslength ret)) ret)
  7. )
  8.  
  9. ; (sssetfirst nil (SsAfter (car (entsel))))
  10. (defun SsAfter (enm / fnd tab)
  11.   (setq tab (strcase (vle-entget 410 enm)))
  12.   (while ; Required: entnext is buggy.
  13.     (and
  14.       (not fnd)
  15.       (setq enm (entnext enm))
  16.     )
  17.     (if
  18.       (and
  19.         (not (vlax-erased-p enm))              ; Required: entnext is buggy.
  20.         (= tab (strcase (vle-entget 410 enm))) ; Required: entnext is buggy.
  21.       )
  22.       (setq fnd enm)
  23.     )
  24.   )
  25.   (if fnd
  26.     (KGA_Conv_ObjectList_To_Pickset
  27.       (member
  28.         (vlax-ename->vla-object fnd)
  29.         (vle-collection->list
  30.           (vla-get-block
  31.           )
  32.         )
  33.       )
  34.     )
  35.   )
  36. )

EDIT: Improved version of SsAfter.
« Last Edit: January 14, 2018, 03:46:21 PM by roy_043 »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1019
  • Marco
Re: FYI: enlast is buggy!
« Reply #14 on: January 11, 2018, 08:28:18 AM »
@Marc'Antonio Alessi:
Are you testing this with the same dwg? Because I cannot reproduce this in BC V14 or V15. Maybe in one case you are testing with a dwg that (still) contains a 'main' paper space viewport. Which is an invisible entity that cannot be erased through normal user actions. To delete it you have to use vla-delete, entdel will not work.

EDIT: 'vla-deleting' a main viewport results in an _Audit issue. So such a VP should not be deleted.
You're right, unfortunately I can not replicate the problem, I started from an empty metric DWG...
I analyzed my support requests to BricsCAD and I saw that it's been 9 years since the problem was solved by BricsCAD
(SR19947). Time passes very quickly...
Code: [Select]
(defun C:TestEmptyDWGm ( / Ss_Set)
  (print (getvar "ACADVER"))
  (if (setq Ss_Set (ssget "_X"))
    (progn
      (print (cdr (assoc 0 (entget (ssname Ss_Set 0)))))
      (princ (strcat " sslength = " (itoa (sslength Ss_Set))))
    )
    (print "no ssget entities in DWG")
  )
  (princ)
)
(defun C:TestEmptyDWG1 ( / Ss_Set)
  (setvar "CTAB" "Layout1")
  (setvar "CTAB" "Model")
  (if (setq Ss_Set (ssget "_X"))
    (progn
      (print (cdr (assoc 0 (entget (ssname Ss_Set 0)))))
      (princ (strcat " sslength = " (itoa (sslength Ss_Set))))
    )
    (print "no ssget entities in DWG")
  )
  (princ)
)
(defun C:TestEmptyDWG2 ( / Ss_Set)
  (setvar "CTAB" "Layout2")
  (setvar "CTAB" "Model")
  (if (setq Ss_Set (ssget "_X"))
    (progn
      (print (cdr (assoc 0 (entget (ssname Ss_Set 0)))))
      (princ (strcat " sslength = " (itoa (sslength Ss_Set))))
    )
    (print "no ssget entities in DWG")
  )
  (princ)
)
Code: [Select]
;--------------------------
: (C:TESTEMPTYDWGm)
"19.1 BricsCAD"
"no ssget entities in DWG"

: (C:TESTEMPTYDWG1)
"VIEWPORT"  sslength = 1

: (C:TESTEMPTYDWG2)
"VIEWPORT"  sslength = 2
;--------------------------


;--------------------------
: (C:TESTEMPTYDWGm)
"21.0 BricsCAD"
"no ssget entities in DWG"

: (C:TESTEMPTYDWG1)
"VIEWPORT"  sslength = 1

: (C:TESTEMPTYDWG2)
"VIEWPORT"  sslength = 2
;--------------------------


;--------------------------
Comando: (C:TESTEMPTYDWGm)
"19.0s (LMS Tech)"
"no ssget entities in DWG"

Comando: (C:TESTEMPTYDWG1)
"VIEWPORT"  sslength = 1

Comando: (C:TESTEMPTYDWG2)
"VIEWPORT"  sslength = 2
;--------------------------