Jump to content

Utilizing AutoCAD's FIND feature in lisp routines?


Comatosis

Recommended Posts

  • Replies 74
  • Created
  • Last Reply

Top Posters In This Topic

  • Comatosis

    27

  • Lee Mac

    19

  • BlackBox

    13

  • irneb

    10

Top Posters In This Topic

Now, because I have a drawing open, when I run my script AutoCAD is asking me if I want to open my already-open sheet read-only. Regardless of my answer, the script stops executing.

 

Is there a way around this?

 

To avoid all drawings you have open in your session, maybe:

 

(defun _getdrawinglist ( / lst )
   (vlax-for doc (vla-get-documents (vlax-get-acad-object))
       (setq lst (cons (vla-get-fullname doc) lst))
   )
   (
       (lambda ( path )
           (vl-remove-if
               (function
                   (lambda ( dwg ) (member (strcat path dwg) lst))
               )
               (vl-directory-files path "*.dwg" 1)
           )
       )
       (getvar 'DWGPREFIX)
   )
)

Of course, this only applies to those drawings that you have open in your current AutoCAD session, i.e. those drawings present in the Documents Collection.

 

To check for any drawings that may be open you would need to check if they were read-only or not, here is a crude way to check that:

 

(defun _getdrawinglist nil
   (
       (lambda ( path )
           (vl-remove-if-not
               (function
                   (lambda ( dwg / fdescr )
                       (if (setq fdescr (open (strcat path dwg) "a"))
                           (not (close fdescr))
                       )
                   )
               )
               (vl-directory-files path "*.dwg" 1)
           )
       )
       (getvar 'DWGPREFIX)
   )
)

Link to comment
Share on other sites

Do I have to call a "custom" command differently than "internal" autoCAD commands? I want to run my main function (a separate file altogether) on the open sheet first and then run the script on all others, but AutoCAD is telling me this:

 

Unknown command "command_name"
no function definition: "command_name"  

 

...depending on how I call it.

 

(command "command_name")
(command_name)

 

...don't do the job despite the routine in question being loaded on my sheet. I got it to work a couple of times but I have no idea what I did differently.

 

EDIT: I added "c:" before "command_name" and this seems to have done the trick. Sorry for being a lisp noob.

Edited by Comatosis
Problem fixed (I think)
Link to comment
Share on other sites

Yep, unfortunately lisp can't call a lisp created command as a normal command. You can only call a lisp function from lisp. That's why I tend to make the working functions with arguments and then the command just calls those after asking for user input. That way it's possible to run it both ways. Not to mention you can more easily make 2 versions of your command - one for dialogue and one for command line, even one choosing which from the CMDDIA / CDMACTIVE so it works like usual in scripts and interactively.

Link to comment
Share on other sites

You can call LISP functions using:

 

(YourLISPFunction)

 

Or, if they are defined as commands:

 

(c:YourLISPCommand)

 

This is how you must call Express Tools LISP functions.

Link to comment
Share on other sites

What I was on about was something like this:

(defun MyTest (str len / )
 (princ (strcat "The string you enetered was: "
                str
                "\nThe length you picked was: " (rtos len)))
)

(defun c:MyTest (/ str len)
 (if (and (setq str (getstring t "\nEnter a string: "))
          (setq len (getdist "Pick a distance: ")))
   (MyTest str len)
 )
 (princ)
)

There's no (standard) way to pass the values to the prompts if you call c:MyTest from lisp. But you can easily pass them as arguments to the MyTest function, actually that's exactly what happens inside the c:MyTest command.

Link to comment
Share on other sites

Sorry for the seemingly random thought process here; I'm just trying to tie some loose ends back in my main function.

 

Is there an easy way to explain how entnext works? I've used it already to gain access to attribute information inside blocks, but I guess I'm unclear as to the actual mechanics of it. I am now wanting to look for the same block attributes as above, except that these blocks are located within other blocks this time around.

 

I assume this involves some sort of nested iteration where I'm looking for "SEQEND" to move on to the next sub-entity in each block, but I haven't had much luck.

 

sslist in the example below consists of a bunch of "INSERT" objects, some of which contain the block sub-entities I want.

 


(setq index 0)
(setq test 0)
(setq test2 0)
(repeat (sslength sslist)
   (setq ent (ssname sslist index))
   (setq ent2 (entnext ent))  

   (while ent2
     (setq ent3 (entnext ent2))
       (while ent3
          (setq ent3 (entnext ent3))
          (setq test2 (1+ test2))
       )
      (setq ent2 (entnext ent2))
      (setq test (1+ test))
   )      

   ) ;end repeat
(princ test)
(princ)
(princ test2)
(princ) 

 

Here's the summary of my results after running the above on my stuff:

(sslength sslist) = 14

test = 322

test2 = 5608

 

I'm not sure what to make of the above numbers. Is "test" a count of all the sub-entities in each entity in sslist? Is "test2" a count of all the sub-entities inside each subentity?

 

Thanks

Edited by Comatosis
Link to comment
Share on other sites

Perhaps this will help to clarify; as I understand it:

 

[color=seagreen];; Set counters as integers[/color]
(setq index 0)
(setq test 0)
(setq test2 0)

[color=seagreen];; Begin repeat loop and run for each
;; item in the selection set[/color]
(repeat (sslength sslist)

   [color=seagreen];; Extract the eName from the 'index'
   ;; item of the selection set[/color]
   [color=seagreen];; *first level item*[/color]
   (setq ent (ssname sslist index))

   [color=seagreen];; Extract the next 'nested' eName[/color]
   [color=seagreen];; *second level item*[/color]
   (setq ent2 (entnext ent))
   
   [color=seagreen];; Begin while loop
   ;; While ent2 is non-nil[/color]
   (while ent2

      [color=seagreen];; Extract the next 'nested' eName[/color]
      [color=seagreen];; *third level item*[/color]
      (setq ent3 (entnext ent2))

       [color=seagreen];; Begin while loop
       ;; While ent3 is non-nil[/color]
       (while ent3

          [color=seagreen];; Extract the next 'nested' eName[/color]
          [color=seagreen];; Next *third level item*[/color]
          (setq ent3 (entnext ent3))

          [color=seagreen];; Increment the test2 counter[/color]
          (setq test2 (1+ test2))
        )

       [color=seagreen];; Extract the next 'nested' eName[/color]
       [color=seagreen];; Next *second level item*[/color]
       (setq ent2 (entnext ent2))

       [color=seagreen];; Increment test counter[/color]
       (setq test (1+ test))
    )
) ;end repeat  

[color=seagreen];; Display counters at the command line[/color]
(princ test)  
(princ)  
(princ test2)  
(princ)

 

** Note - If anyone can correct me where I may be wrong, I'd greatly appreciate it. :wink:

Link to comment
Share on other sites

I'm not sure that I understand...

 

If the nested entity (within a block) is a block or anything else, how is it (the nested entity) not 2nd level, etc?

 

Perhaps you could clarify?

 

Edit: Perhaps someone more adept at using entnext should step in before I muddle the waters here. :oops: LoL

Link to comment
Share on other sites

I just don't know how entnext is cycling through the entities/sub-entities.

 

At the start of my function, I compile a list of all blocks with a particular name, and extract one attribute out of them to produce a string list that I later use. (I have this working)

 

Next, I want to compile a list of all other blocks on the sheet, and check if the same block from above is nested inside them, in which case I'd extract that attribute as well and tack it on to the same string list from before. (this is the code I posted above)

 

On "tier 2," though, I have no idea what entnext is spitting out, as a lot of the sub-entities appear to just be repeats of previous ones. I figured my code above would've said something like, "for each entity, check to see if it has subentities and go through them. Then, check the subentities to see if they themselves contain sub-subentities, and go through these." This doesn't appear to be happening, though.

Link to comment
Share on other sites

That is what is happening (as I understand it); perhaps it would be easier to understand if you were to add some breakpoints immediately after the line where entnext has been issued, combined with adding the preceding variable to the Watch list.

 

Example:

...
(setq [b][color=blue]<VarToWatch>[/color][/b] (entnext <ent>))
[color=red][b]([/b][/color]while [b][color=blue]<VarToWatch>
[/color][/b]  ...

 

... Where has been added to the watch list, and ( represents the breakpoint in VLIDE.

Link to comment
Share on other sites

I'm running a pseudo-breakpoint along various points, of the form...

 

(princ variable_name)
(princ "\n")
(princ)
(getstring)

 

Setting actual breakpoints in VLIDE is hit-and-miss for me, sometimes they're recognized and other times they aren't. I still have to read up on how exactly to go about it.

 

Anyway, after checking for a specific block in the routine above, I ended up getting a count of 84 for # of occurences on the sheet. But, going through each entity made me realize that these were just the same 3 blocks being counted over and over, meaning I was doing the same thing 28 times instead of cycling through all the blocks as I assumed it would.

 

I appreciate all the help so far, but now I feel bad about keeping you up ;). I'll see if I can run some more tests and try to see what's going on.

Link to comment
Share on other sites

I think you might be going a bit too far. EntNext does nothing more than simply get the ename of the next entity in the DWG's database. If you don't give it a source entity, then it returns the ename of the very first entity. If you give it any valid ename it returns the ename following it as saved in the DWG's "current" block (note the model space and paper spaces are also blocks). So if you're in modelspace (e.g. TileMode=1) then (entnext) gives the ename of the 1st entity in model space. What I'm not sure of is if it gets the ename from the current PS if TileMode=0 - but I think not, just can't remember.

 

The use of entnext to get attributes is due to attributes actually being separate from the Insert object (though they follow it and have a SeqEnd to show they've stopped).

 

Using entnext inside a block's definition works exactly the same, except for your starting point: which you have to obtain from the -2 code of the block table record. So to get the 3rd nested entity of the block named "MyBlock" you need to do something like this:

(if (set blkDef (tblsearch "BLOCK" "MyBlock"))
 (progn
   (setq ename (cdr (assoc -2 blkDef))) ;Get the 1st nested ename inside the block definition
   (repeat 2 (setq ename (entnext ename))) ;Repeat entnext twice to get the 3rd
 )
)

Though watch out, that might error if the block contains less than 3 entities.

Link to comment
Share on other sites

I think I have it all figured it out now, though I'm sure it's terrible programming on my part, as evidenced by the multiple nested if statements in my code. 8)

 

I'm not too worried at this point, though. I accomplished what I set out to do, and for now I can't see myself trying to tweak this anymore. Thanks everyone for the help.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...