Request for AutoLISP

Request for AutoLISP

SnickerinTurtles
Enthusiast Enthusiast
3,351 Views
41 Replies
Message 1 of 42

Request for AutoLISP

SnickerinTurtles
Enthusiast
Enthusiast

Hi all, I am new to posting so please forgive me if I make any mistakes. 

 

I am looking to create an Lisp that will change the color of a specific layer name. For example in a landscape drawing I have xrefenced in some civil files that contain layers "Project#-HC|C-BLDG-OTLN" or "Project#-HC|C-UTIL-WATR". Now I have to go through and change these layers to their specific color in when working in a landscape drawing for landscape plotting purposes. Is there a way to make a lisp so that anytime I run the command it will change layer color  of "Project#-HC|C-BLDG-OTLN" to color 152 and "Project#-HC|C-UTIL-WATR" to color 190. 

 

Hopefully I am making sense if not please let me know and I will try to be more clear.

Thank you.

0 Likes
Accepted solutions (1)
3,352 Views
41 Replies
Replies (41)
Message 21 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Ran a few tests and here to confirm that  if I have two or four or however many xref  in the file. It looked at all the xrefs and made anything that matched the string "|C-BLDG" or whatever string matched after the "*" to the appropriate changes.

0 Likes
Message 22 of 42

dlanorh
Advisor
Advisor

The top of the tree is the acad-application (vlax-get-acad-object)

Below that you have the Preferences, Menus and Documents (drawings) collections.

You could have several drawings open in AutoCAD, but only one of them is the Active Document (the one you are looking at)

c_doc is the variable name I use for the current (active) document.

c_lyrs is the collection (list of objects) that represents all the defined layers in the document. Each of these objects has a collection of properties (eg. name, color, truecolor, linetype...)

 

likewise there is a collection of all the defined blocks in the drawing. Any xrefs in the drawing can be found in this collection. Blocks have a boolean (True False) "isxref" property, So it is easy to distinguish them from other blocks such as user defined blocks and layouts.

 

The user wouldn't have to type anything. It would be simpler to pop up a dialog containing a list of xreferences in the drawing and ask the user to select from the list with the mouse. The returned selection would be processed to strip out the file name.

 

The function below returns a list of xrefs files in the drawing. As it is a function you run it from the command line in braces.

 

(defun rh:xrefs ( / lst)
  (vlax-for blk (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))
    (if (= (vlax-get-property blk 'isxref) :vlax-true) (setq lst (cons (vlax-get blk 'name) lst)))
  );end_for
  lst
);end_defun

 

type (rh:xrefs) on the command line. Don't worry if the list is printed twice, the second is just caused by the command echo

 

I also didn't ask if these xrefs were attached or overlayed?

I am not one of the robots you're looking for

0 Likes
Message 23 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Thanks for the thorough explanation. It really does help and I know I got a lot to learn.  This is going to be fun. It will be like the old C++ days. And also the xrefs are overlayed not attached. 

0 Likes
Message 24 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Not really sure what changed over a couple of days but I ran this code again and I am getting this error now. 
"error: AutoCAD variable setting rejected: XREFOVERRIDE 1"  not sure as to why.

0 Likes
Message 25 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Hi dlanorh,

 

So here is what I was able to come up with based on what I could find.  So here is the whole code so far I know where the issues lie or at least I think I do.  I tired to make comments throughout to be helpful/show what I understand.

 

 

(defun c:xrlyrc ( / c_doc c_lyrs c_lst f_lst x_obj, x_lay) ; will need add variables for user input in this case I added x_obj and x_lay

  (v-load-com); I need this for some reason? not sure for user input part of this maybe? or to get some functions to work? 

  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        c_lyrs (vla-get-layers c_doc)
  );end_setq Thanks dlanorh for this code here

; Here i need some code to select the xref and store the xref name file so that it can replace the "PROJECT#-HC*"
; what I have below does not work, but I thought it might. It is what I could piece meal together based of what I could find or understand. This code is from sea.haven so thank you for your code here. I thought it would work here.
; The promt does not come up asking for the user to Select Xref Layer. not sure as to why.
  	
  (setq x_obj (vlax-ename->vla-object (car (nentsel "\nSelect Xref Layer")))); asks user to select xref layer and stores xref layer name to x_obj? 
  (setq x_lay (vla-get-layer obj)) ; sets layer name to variable x_lay

; I know this works and checks out I just need to add all the layers to the apporitate space.Thanks to dlanorh for this code. The "PROJECT#-HC*" needs to be replaced with the apporitate variable. In my case variable x_lay?
  (vlax-for lyr c_lyrs
    (if (wcmatch (strcase (vlax-get lyr 'name)) "~x_lay*");Checks to see the if the begining of the layer name matches and if true then it goes to the cond statement. In my case variable x_lay? Probably not the right syntax.
      (cond ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-OTLN,*|CS-BLDG-EAVE") (vlax-put lyr 'color 152)); Listed layers change color to 152
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-ANNO,*|CS-BLDG-CONC") (vlax-put lyr 'color 190)); Listed layers change color to 190
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG,*|CS-BLDG-DOOR,*|CS-BLDG-WIND") (vlax-put lyr 'color 156)); Listed layers change color to 156
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-DWNS,*|CS-BLDG-NUM~") (vlax-put-property lyr 'plottable :vlax-false)); Listed layers to non-plottable
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-COLU,*|CS-BLDG-STEP") (vlax-put-property lyr 'freeze :vlax-true)); Listed layers are frozen.
      );end_cond
    );end_if
  );end_for
  (princ)
);end_defun

 

0 Likes
Message 26 of 42

Kent1Cooper
Consultant
Consultant

A couple of things I notice:

 

Yes, (vl-load-com) may be needed to get the (vl...) functions in [once per editing session, but it's often built into routines that will need it if they contain the first call to any of them].

 

I think this:

  (setq x_lay (vla-get-layer obj))

should be this instead:

  (setq x_lay (vla-get-layer x_obj))

 

HOWEVER, the problem with (nentsel) is that it digs down to the lowest level  of nesting of whatever you pick on.  So if there's a Block nested in another Block in your Xref, and the part of it you pick on was originally drawn on Layer 0, what you will get from that will be Layer 0, not the Layer on which either level of Block was inserted, nor that on which the drawing was Xref'd.  And Layer 0 is a strictly on-its-own  Layer name, never associated with an Xref in XrefName|0 fashion.

 

I have a routine that accounts for that -- LayerQuellPick.lsp, available >here<.  Look at the setting of the layq variable.  If you pick on something that at its lowest level is on Layer 0, it steps up through nesting levels until it hits some other Layer, i.e. the one on which the object "appears."

 

But I expect you can just use (entsel) for the overall Xref, and pull the portion of its name from what you get there, rather than digging down to nested things.

Kent Cooper, AIA
0 Likes
Message 27 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Thanks for the help Kent1Cooper.

I went a head a looked the code you linked and based off your comments these are the changes to the code.  

(defun c:xrlyrc ( / c_doc c_lyrs c_lst f_lst x_obj x_lay); variables needed
  
  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        c_lyrs (vla-get-layers c_doc)
  );end_setq
	
  (setq x_obj (vlax-ename->vla-object (car (entsel "\nSelect Xref Layer")))) ;end_setq
  (setq x_lay (vla-get-layer x_obj)) ;end_setq

  (vlax-for lyr c_lyrs
    (if (wcmatch (strcase (vlax-get lyr 'name)) "~x_lay*")
      (cond ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-OTLN,*|CS-BLDG-EAVE") (vlax-put lyr 'color 152)); Listed layers change color to 152
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-ANNO,*|CS-BLDG-CONC") (vlax-put lyr 'color 190)); Listed layers change color to 190
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG,*|CS-BLDG-DOOR,*|CS-BLDG-WIND") (vlax-put lyr 'color 156)); Listed layers change color to 156
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-DWNS,*|CS-BLDG-NUM~") (vlax-put-property lyr 'plottable :vlax-false)); Listed layers to non-plottable
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-COLU,*|CS-BLDG-STEP") (vlax-put-property lyr 'freeze :vlax-true)); Listed layers are frozen.
      );end_cond
    );end_if
  );end_for
  (princ)
);end_defun

 

Here are my results from the previous code. The prompt asking the user to select the xref pops up and I can select an xref. (This is progress) The rest of the code runs but it makes the changes to all xrefs in the drawing and not just the one selected. So from what I understand that means the if statement checking "x_lay" layer matches does not work. This could be because of my syntax. Meaning this line below is typed in incorrectly.

   (if (wcmatch (strcase (vlax-get lyr 'name)) "~x_lay*")
      

More specifically the last bit "~x_lay*" is incorrect. 

 

I am in the right ball park?

0 Likes
Message 28 of 42

dlanorh
Advisor
Advisor

@SnickerinTurtles wrote:

Here are my results from the previous code. The prompt asking the user to select the xref pops up and I can select an xref. (This is progress) The rest of the code runs but it makes the changes to all xrefs in the drawing and not just the one selected. So from what I understand that means the if statement checking "x_lay" layer matches does not work. This could be because of my syntax. Meaning this line below is typed in incorrectly.

 

   (if (wcmatch (strcase (vlax-get lyr 'name)) "~x_lay*")
      

 

More specifically the last bit "~x_lay*" is incorrect. 

 

I am in the right ball park?


The wcmatch compare is case sensitive, so "X_LAY" is not the same as "x_lay". The test is making the layer name all upper case (strcase..), but you are testing against a lower case string. The tilda "~" as the first character of the match string is a wild card that means match anything except the pattern. 

I am not one of the robots you're looking for

0 Likes
Message 29 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Okay so I have tried a bunch of different variations from what I could find. This time it will not go into the cond statement and as stated it is probably what I am doing wrong with this line. 

Here is what I have tried. I got ride of the (strcase) because it seemed that I did not need it. I figure this cause the Xref file name is always "######-HC-XXXX" but as you where saying (strcase) makes it all uppercase so I removed it. 

I have done some research and I am still not understanding the different ways you can call a string variable.  And I tried these different ways which none worked.

 

(if (wcmatch (vlax-get lyr 'name) "'X_LAY*")
(if (wcmatch (vlax-get lyr 'name) "X_LAY*")

 

(if (wcmatch (vlax-get lyr 'name) 'X_LAY)
(if (wcmatch (vlax-get lyr 'name) X_LAY)

 I believe this last one is the correct way to do it. Anyways then I thought to check what is in my variable X_LAY is a string that stores the file name of the xref? If so I should be able to print that variable X_LAY and it should show me what is stored in X_LAY. So to test I added this line in the code.

 

(defun c:xrlyrc ( / c_doc c_lyrs c_lst f_lst x_obj X_LAY); variables needed
  
  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        c_lyrs (vla-get-layers c_doc)
  );end_setq
	
  (setq x_obj (vlax-ename->vla-object (car (entsel "\nSelect Xref Layer")))) ;end_setq
  (setq X_LAY (vla-get-layer x_obj)) ;end_setq
  (print X_LAY); this line added to see what was stored in X_LAY
  (vlax-for lyr c_lyrs
    (if (wcmatch (vlax-get lyr 'name) X_LAY)
      (cond ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-OTLN,*|CS-BLDG-EAVE") (vlax-put lyr 'color 152)); Listed layers change color to 152
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-ANNO,*|CS-BLDG-CONC") (vlax-put lyr 'color 190)); Listed layers change color to 190
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG,*|CS-BLDG-DOOR,*|CS-BLDG-WIND") (vlax-put lyr 'color 156)); Listed layers change color to 156
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-DWNS,*|CS-BLDG-NUM~") (vlax-put-property lyr 'plottable :vlax-false)); Listed layers to non-plottable
            ( (wcmatch (strcase (vlax-get lyr 'name)) "*|CS-BLDG-COLU,*|CS-BLDG-STEP") (vlax-put-property lyr 'freeze :vlax-true)); Listed layers are frozen.
      );end_cond
    );end_if
  );end_for
  (princ)
);end_defun

 

Once doing this I realized that X_LAY had the active layer doc that the xref was on. So if my xref was on layer1 it would spit out "layer1" or if it was on layer34 it printed out layer34.  So that tells me that this line is also incorrect.

setq x_obj (vlax-ename->vla-object (car (entsel "\nSelect Xref Layer")))) ;end_setq
  (setq X_LAY (vla-get-layer x_obj)) ;end_setq

 

So I need to figure this out before I figure out my syntax for calling a variable syntax. Right?

Thanks again for all the help. 

0 Likes
Message 30 of 42

dlanorh
Advisor
Advisor

@SnickerinTurtles wrote:

Okay so I have tried a bunch of different variations from what I could find. This time it will not go into the cond statement and as stated it is probably what I am doing wrong with this line. 

Here is what I have tried. I got ride of the (strcase) because it seemed that I did not need it. I figure this cause the Xref file name is always "######-HC-XXXX" but as you where saying (strcase) makes it all uppercase so I removed it. 

I have done some research and I am still not understanding the different ways you can call a string variable.  And I tried these different ways which none worked.

 

 

 

(if (wcmatch (vlax-get lyr 'name) "'X_LAY*")
(if (wcmatch (vlax-get lyr 'name) "X_LAY*")

 

 

 

 

 

(if (wcmatch (vlax-get lyr 'name) 'X_LAY)
(if (wcmatch (vlax-get lyr 'name) X_LAY)

 

 

 I believe this last one is the correct way to do it. Anyways then I thought to check what is in my variable X_LAY is a string that stores the file name of the xref? If so I should be able to print that variable X_LAY and it should show me what is stored in X_LAY. So to test I added this line in the code.

 

x_lay (X_LAY) is a variable. Autolisp is not case sensitive so either of these two variables will be recognised as the same. They contain a text string. You cannot predict what the text string contains in the way of upper and lower case characters, so when doing a case sensitive comparison they should both be converted to the same case. Upper case is usually used because converting to lower case requires an additional parameter to be passed.

 

 

 

(if (wcmatch (strcase (vlax-get lyr 'name)) (strcase (strcat "*" X_LAY "*"))

 

 

 

should be closer to a solution. I have included the wildcard character at the beginning and end of the string.

 

 

I am not one of the robots you're looking for

0 Likes
Message 31 of 42

Kent1Cooper
Consultant
Consultant
Accepted solution

I still don't get why you're  A)  picking a nested object to extract the Xref's name from the Layer of that object, when you can just get it from the Xref itself, and  B)  getting a list of all  Layers and stepping through them all, comparing them to the Layer names you're after, when you can just apply options to the ones you want.  Can't it be as simple as this?

 

 

 

(defun C:WHATEVER (/ xrs xrn)
  (if
    (and
      (setq xrs (entsel "\nSelect XREF to process is Layers: "))
      (setq xrn (cdr (assoc 2 (entget (car xrs))))); name from entity data
      (assoc 1 (tblsearch "block" xrn)); it's an Xref
    ); and
    (command "_.layer" ; then
      "_color" 152
        (strcat xrn "|CS-BLDG-OTLN," xrn "|CS-BLDG-EAVE")
      "_color" 190
        (strcat xrn "|CS-BLDG-ANNO," xrn "|CS-BLDG-CONC")
      "_color" 156
        (strcat xrn "|CS-BLDG," xrn "|CS-BLDG-DOOR," xrn "|CS-BLDG-WIND")
      "_plot" "_no"
        (strcat xrn "|CS-BLDG-DWNS," xrn "|CS-BLDG-NUM~")
      "_freeze"
        (strcat xrn "|CS-BLDG-COLU," xrn "|CS-BLDG-STEP")
      "" ; close Layer command
    ); command
  ); if
  (princ)
); defun
      

 

 

 

Kent Cooper, AIA
0 Likes
Message 32 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Thanks dlanorh. I am buying a few books on lisp language so I can start from the basics and work my way up. I am going to keep at this still. I have learned a lot in a short amount of time. I see how it is different yet similar to C++ and I am going need to study and learn more. Maybe if the local college offers a class I could take them assuming they offer them at night. 🙂 I would like to be able to do this myself or at least get to a point before asking others about it. What are some books if any to suggest? I'll also reply later with how far I get on this got read and try things out. 😛

0 Likes
Message 33 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Hi Kent1Cooper,

 

Thanks you for another solution. The reason I am still trying to go the other way is to mainly get the learning experience out of it. As I mentioned I learned C++ about 4 years ago and haven't used it since I learned it and I knew about lisp commands and that they could be created to do simple tasks to complex ones. Anyways I figured I could try to learn LISP and there are these specific tasks I thought could be useful, but I didn't really know where to start. I found this request lisp form and thought it might be a way to get these commands created and I could learn from the vast knowledge everyone here has. I am buying some books on LISP and if there are any you recommend please let me know, because I would like to come up with code and then post on these forms for improvement or help. I mean I wouldn't know if dlanorh was or is the easiest, most efficient way to run the command if you did not come in and say why do this when you can just check for the xref and if it matches then tell it what needs to happen to each layer rather than check them each time and go through this loop several times. Because it has to check each layer to see if they match. 

 

I think dlanorh ways shows me some more code and how the syntax of that code works while I try to understand vlax, entsel, if, and all the other functions. It may not be the easiest or best way to create this function, but it has taught me a lot and there are tons more to learn, but I gotta go back and build the foundation first. 🙂 If you have any books or anything you recommend let me know. Again, I am glad that you are still part of this conversation and didn't just quit on this topic. Thank you again. 

0 Likes
Message 34 of 42

dlanorh
Advisor
Advisor

Perhaps the attached PDF's can help. The best reference was the old complied acadauto.chm file (compiled help) but these have been replaced with the online help.

 

Almost forgot about the e-books. Search on Amazon or google "e-books Reinaldo Togores". They are a series of 4 e-books and an excellent reference/tutorial

 

The Language and its Development Environment (AutoCAD expert's Visual LISP Book 1)

 

Controlling AutoCAD from Visual LISP (AutoCAD expert's Visual LISP Book 2)

 

Programming 3D. Solids, Meshes & Surfaces. (AutoCAD expert's Visual LISP Book 3)

 

Advanced Programming Techniques (AutoCAD expert's Visual LISP Book 4)

 

When I bought them they were about £4.00 - £5.00 each (you'll have to convert to your currency)

 

I am not one of the robots you're looking for

0 Likes
Message 35 of 42

Kent1Cooper
Consultant
Consultant

@SnickerinTurtles wrote:

.... Because it has to check each layer to see if they match. .... 


Good for you for making the effort to learn more.  [I don't have books to suggest, but a Search in this Forum for books, tutorials, learning, and related terms will give you more than you can ever look into.]

 

The sentence quoted above still concerns me.  It is certainly not  necessary to check each Layer!  The Layer command will accept the Layer names of whatever Layers you want to do something to, and all other Layers can be ignored.  Pulling a list of all  Layer names, and stepping through it, means that you are checking whether Layer "0" is a relevant nested Layer in the subject Xref, and whether "DEFPOINTS" is, and whether "Peter" and "Paul" and "Mary" are, including whether all Layers that are not even nested in Xref's  are.  That's a heck of a lot of checking Layers that you're not going to do anything to.  But given the root drawing name of the Xref, you can put that together with the "pipe"-character connector and only  the specific under-Layer names you want, within each option you want applied, and that is all.  [That's what my suggestion does -- I hope it actually works, but I didn't set up the situation to try it.]  No dealing with irrelevant Layers at all; no pulling of a list of Layers at all.  And it won't care if some of them don't exist.  And it's not even case-sensitive as (wcmatch)-based checks are.

Kent Cooper, AIA
0 Likes
Message 36 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Sorry my mistake I meant to say dlanorh method has to check not your method. I see the confusion I created.

0 Likes
Message 37 of 42

SnickerinTurtles
Enthusiast
Enthusiast

Thanks for the extensive list of study and learning material. I will put this all to good use! Thank you again really appreciate you taking the time to help and teaching me. 

0 Likes
Message 38 of 42

Sea-Haven
Mentor
Mentor

Thanks Kent I use OBJ as my default in the majority of my coding so the x_ was missed.

0 Likes
Message 39 of 42

grobnik
Collaborator
Collaborator

 Hi to everybody, pls someone could give me a right way for using VLAX and color palette dialog box ? Usually I made macro in VBA, not in LSP.

 

Thank you.

0 Likes
Message 40 of 42

hak_vz
Advisor
Advisor

 

 

(setq clr (acad_colordlg 7))

 

This starts index color dialog and after selection places color number to variable clr. In this case we ask to open dialog with index color 7 selected

 

(setq clr (acad_truecolordlg 7))

 

Return color codes to be included in entity definition. Something like:

 

((62 . 132) (420 . 2997458))
((62 . 142) (420 . 38875) (430 . "PANTONE+ CMYK Uncoated$PANTONE Process Cyan U"))

 

 

@grobnik  Next time just start a new post

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes