Edit lisp to check for layer (if not add)

Edit lisp to check for layer (if not add)

Jonathan3891
Advisor Advisor
8,482 Views
14 Replies
Message 1 of 15

Edit lisp to check for layer (if not add)

Jonathan3891
Advisor
Advisor

I need to edit this lisp to set a layer current before drawing the pipe break, and if they layer does not exist then create it.

 

(defun c:pb ()
 (setq pt1 (getpoint "\n Select First Point: "))
 (setq pt2 (getpoint "\n Select Second Point: ")
 dist (distance pt1 pt2)
 ang (angle pt1 pt2)
 pt3 (polar pt1 ang (/ dist 2.0))
 )
 (setvar "plinewid" 0.0)
 (command ".pline" pt2 "arc" "angle" "60" pt3 pt1 "angle" "-60" pt3 "")
 ) 

 

Thanks for the help.


Jonathan Norton
Blog | Linkedin
0 Likes
Accepted solutions (2)
8,483 Views
14 Replies
Replies (14)
Message 2 of 15

Kent1Cooper
Consultant
Consultant
Accepted solution

[Related to the task, if not this question, you may be interested in this.  See my Comment there for a little benefit that it has over your routine.]

 

If you Search for (if (not (tblsearch "layer" on this Board [which is one way to check whether a Layer exists], you'll find countless routines that do that kind of thing.  But it can be simpler -- I never bother to check whether a Layer exists, but I simply have the routine Make it in a Layer command.  It doesn't matter whether it exists or not, and the Make option will set it current in the process, which means things like color and linetype assignments can use the Enter default for which Layer to assign them to.  The one perhaps non-intuitive thing is that it's a good idea to Thaw the Layer first [which won't cause any error if it doesn't exist yet], because if it exists already but is Frozen, it can't be made current, and therefore its name can't be given to the Make option.

 

(command "_.layer" "_thaw" "YourLayerName" "_make" "YourLayerName" "_color' YourColor "" "")

 

Include linetype and/or other option(s) as desired.  You probably won't want a non-continuous linetype for this purpose, but another advantage of using a Layer command rather than other approaches such as (entmake) to create the Layer is that it is not necessary to have a non-continuous linetype loaded in the drawing already [and therefore not necessary to check whether it is] to assign it to a Layer -- unlike with the (entmake) or (vla-...) ways of doing it, the Layer command will find it.

Kent Cooper, AIA
Message 3 of 15

Jonathan3891
Advisor
Advisor

This is what I've come up with, and it seems to work great. Can you tell me if its coded efficent?

 

(defun c:pb (/ olayer)
 
 (setq olayer (vlax-variant-value (vla-getvariable (vla-get-activedocument
 (vlax-get-acad-object)) "clayer")))
 
 (setq pt1 (getpoint "\n Select First Point: "))
 (setq pt2 (getpoint "\n Select Second Point: ")
 dist (distance pt1 pt2)
 ang (angle pt1 pt2)
 pt3 (polar pt1 ang (/ dist 2.0))
 )

 (if (not (tblsearch "layer" "c_gen_Symbol")) 
 (command "-layer" "m" "c_gen_symbol" "c" "80" "" "L" "continous" "") 
 (setvar "clayer" "c_gen_symbol")

 )

 (setvar "plinewid" 0.0)
 (command ".pline" pt2 "arc" "angle" "60" pt3 pt1 "angle" "-60" pt3 "")

 (vla-setvariable (vla-get-activedocument (vlax-get-acad-object)) "clayer" olayer)
 
 (princ)
 
 )

 


Jonathan Norton
Blog | Linkedin
0 Likes
Message 4 of 15

Kent1Cooper
Consultant
Consultant

@Anonymous_dude wrote:

This is what I've come up with, and it seems to work great. Can you tell me if its coded efficent?

.... 


It could be reduced somewhat.

 

(defun c:pb (/ olayer pt1 pt2 dist ang pt3); added the rest of the local variables
  (setq ; combined more variable settings into the one (setq) function

    olayer (getvar 'clayer); most people use this simpler approach [at both ends], without all the (vlax-...) stuff
    pt1 (getpoint "\n Select First Point: ")
    pt2 (getpoint "\n Select Second Point: ")
    dist (distance pt1 pt2)
    ang (angle pt1 pt2)
    pt3 (polar pt1 ang (/ dist 2.0))
  ); end setq
  (command "-layer" "m" "c_gen_symbol" "c" "80" "" "")

    ; no need to check for it; the Make option will set it current for you; and no need to

    ; specify continuous linetype [even if you spell it right], because it's always the default,

    ; unless you think maybe the Layer may already exist with a different linetype, and

    ; you want to correct that
  (setvar 'plinewid 0.0)
  (command ".pline" pt2 "arc" "angle" "60" pt3 pt1 "angle" "-60" pt3 "")
  (setvar 'clayer olayer)
  (princ)
)

 

One thing I did that is completely optional [but saves an entire code character in each instance!] is to use the apostrophe before system variable names ['clayer, 'plinewid] in place of the double-quotes both before and after.  Both (setvar) and (getvar) functions will work with either approach.

 

EDIT:  Also, you don't need the hyphen before the Layer command name.  You would need it in a command macro or a Script, to suppress the dialog box, but not inside a (command) function, where the default is to not use the dialog box [if you want one, you need to force it to come up by preceding the (command) function with (initdia) to INITiate the DIAlog box].  If you're using any overlay program such as the specialty Architectural or Civil or other ones, it's possible that it will have a specially-defined Layer command, and will have undefined the native Layer command, so that (command "layer" ...) will not work.  So I always use the preceding decimal to force it to use the native AutoCAD command, and I use the preceding underscore so it will work in other-than-English-language versions AutoCAD, since these Boards are used by people all over the world:  (command "_.layer" ...).

 

Further EDIT:  To be really safe, as described in my first Reply, you might add Thawing that Layer first:

(command "_.layer" "t" "c_gen_symbol" "m" "c_gen_symbol" "c" "80" "" "")

but don't bother if there's no likelihood that it would ever be Frozen.

 

AND another thing:  You can combine more than one command into a single (command) function:

  (setvar 'plinewid 0.0)

  (command

    "_.layer" "t" "c_gen_symbol" "m" "c_gen_symbol" "c" "80" "" ""

    ".pline" pt2 "arc" "angle" "60" pt3 pt1 "angle" "-60" pt3 ""

  ); command

Consider also whether you should have the routine turn running Object Snap off, because you may get unexpected results if you don't.

Kent Cooper, AIA
0 Likes
Message 5 of 15

Jonathan3891
Advisor
Advisor

Thank you kent for all the help, we are almost there!

 

It will work correctly the first time its ran, but after that it doesnt put the symbol on the correct layer.

 

(defun c:pb (/ olayer pt1 pt2 dist ang pt3)
 
 (setq olayer (getvar "clayer"))
 (setq pt1 (getpoint "\n Select First Point: "))
 (setq pt2 (getpoint "\n Select Second Point: ")
  dist (distance pt1 pt2)
  ang (angle pt1 pt2)
  pt3 (polar pt1 ang (/ dist 2.0))
 );end setq

 (if (not (tblsearch "layer" "c_gen_Symbol")) 
 (command "_.layer" "t" "c_gen_symbol" "m" "c_gen_symbol" "c" "80" "" "")
 
 )

 (setvar "plinewid" 0.0)
 (command ".pline" pt2 "arc" "angle" "60" pt3 pt1 "angle" "-60" pt3 "")

 (setvar "clayer" olayer)
 
 (princ)
 
 )

 

And If I remove this snippet

(if (not (tblsearch "layer" "c_gen_Symbol")) 

it give me an error

Point or option keyword required.
; error: Function cancelled

 


Jonathan Norton
Blog | Linkedin
0 Likes
Message 6 of 15

Kent1Cooper
Consultant
Consultant
Accepted solution

@Anonymous_dude wrote:

Thank you kent for all the help, we are almost there!

 

It will work correctly the first time its ran, but after that it doesnt put the symbol on the correct layer.

.... 

And If I remove this snippet

(if (not (tblsearch "layer" "c_gen_Symbol")) 

it give me an error

Point or option keyword required.
; error: Function cancelled

 


The incorrect Layer would be because as you have it, if the Layer does exist already, it does nothing, including not setting it current.  That's what I like about the Make option without checking whether the Layer exists:  if it does, it sets it current; if it doesn't, it creates it and sets it current.  It ends up being the current Layer in any case.

As to the error, did you also remove the right parenthesis below the Layer command line, which concludes the (if) function that checks for the existence of the Layer?  If you left that one in, it would complete the (defun) function and end the command definition, then the routine would set PLINEWID and go into the Pline command, but there would be no pt2 variable set, which would be the source of the error message.

Kent Cooper, AIA
0 Likes
Message 7 of 15

Jonathan3891
Advisor
Advisor
Thanks Kent!

Jonathan Norton
Blog | Linkedin
0 Likes
Message 8 of 15

scot-65
Advisor
Advisor

In lieu of setting the environment to add an object,
let AutoCAD create the object in the current environment,
and when finished, direct it to the proper layer.

Also, you did not check for proper user input before executing.
That's a no no. What would happen if you *accidently* started

this command only to [Esc] out of it?

(if (and
     (setq pt1 (getpoint "\n Select First Point: "))
     (setq pt2 (getpoint "\n Select Second Point: "))

    );and
 (progn
  (setvar 'CMDECHO 0)

  (if (not (tblsearch "layer" "c_gen_Symbol"))
   (command "-layer" "New" "c_gen_symbol" "c" "80" "" "L" "continuous" "" "") );if
  (setvar "plinewid" 0.0)
  (command ".pline"

   pt2 "arc" "angle" "60" (polar pt1 (angle pt1 pt2) (/ (distance pt1 pt2) 2.0))

   pt1 "angle" "-60" (polar pt1 (angle pt1 pt2) (/ (distance pt1 pt2) 2.0)) "")
  (command ".chprop" "Last" "" "LAyer" "c_gen_Symbol" "" "")

  (setvar 'CMDECHO 1)
 );progn
);if

(setq pt1 nil pt2 nil)(princ)

 

 

Check line that is "-layer" for proper syntax (2 errors).

 

[untested]

 


Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 9 of 15

Kent1Cooper
Consultant
Consultant

@scot-65 wrote:

....

  (if (not (tblsearch "layer" "c_gen_Symbol"))
   (command "-layer" "New" "c_gen_symbol" "c" "80" "" "L" "continuous" "" "") );if
.... 


That will assign color 80 and the Continuous linetype to whatever the current Layer happens to be, which in this case will not be the New one that you intend to assign them to.  Using Enter after the color number [or word -- "red" etc.] and linetype name accepts the current Layer for the assignment, and works when you've used the Make option, since in that case the specified Layer becomes current.  But the New option does not make it current -- in fact, it can be used to create many New Layers all at once, in a comma-delimited string, and of course not all of those can become current.  If you use the New option, you must spell out the Layer name again for the color and linetype assignments if they are for that New Layer.  And I repeat, there's no need to assign Continuous as a linetype -- all new Layers have it by default, so you don't need to use the linetype option unless you want to assign a non-continuous linetype, or if you want to "fix" a possible "wrong" linetype in an already-existing Layer.

Kent Cooper, AIA
0 Likes
Message 10 of 15

Jonathan3891
Advisor
Advisor
I cant get your code to work Scot. I get an error "malformed string on input"

How do I check for proper user input before executing? Currently if I [Esc] I get an error "Error; Function Cancled"

Jonathan Norton
Blog | Linkedin
0 Likes
Message 11 of 15

scot-65
Advisor
Advisor
The line you are questioning I did not create.
I only noticed a misspelling and a closing double quote.

Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 12 of 15

scot-65
Advisor
Advisor
Could there be a double quote missing in the pline part?
The "if" takes care of checking for proper user input.
An internal error handler will keep the command prompt quiet.
Here's a quick and dirty example:
(defun *error" (msg) (princ))

Keep at it!!!

Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 13 of 15

Kent1Cooper
Consultant
Consultant

@scot-65 wrote:
Could there be a double quote missing in the pline part?
....

I don't think so, but there's an extraneous Enter [""] at the end of the CHPROP command.  The one following the Layer name ends the command.

Kent Cooper, AIA
0 Likes
Message 14 of 15

Anonymous
Not applicable

@Kent1Cooper I really appreciate your thorough answers, they have been very helpful. I've been able to edit the above code to make a really nice tool for my company. However, It needs to be a little more flexible. For various reasons, we do not always use the same layer name for our Basin's. So I need the command to Ask the user "What Basin would you like to analyze (by selecting a basin polyline), analyze the basins, make a text layer by adding "-Text" to the selected basin layer, then place the labels.


I appreciate any help. This is literally day 2 of lisp coding, so I don't have any coding vocabulary. I wish I could bring more to the table! 🙂

This is the code I have now.
-----------------------------------------


(defun c:LB  (/ acsp ss e ptList ID StrField txt p)
(vl-load-com)      
      (setq  acsp (vla-get-modelspace (vla-get-activedocument
                                        (vlax-get-acad-object))))
      (if (setq ss (ssget (progn
                                      (initget 1 "Y N")
                                      (setq ans (getkword "\nProcess All Polylines [Yes/No]: "))
                                      (if (eq "Y" ans) "_X" ":L"))
                                             '((0 . "*POLYLINE")
                        (8 . "C-Topo-Drainage-Basin")
                        (-4 . "&")
                        (70 . 1)(410 . "Model"))))
      (repeat (sslength ss)
            (setq e     (ssname ss 0)
                  sum   '(0 0)
                  verts (cdr (assoc 90 (entget e))))
            (setq ptList
                       (mapcar 'cdr
                               (vl-remove-if-not
                                     '(lambda (x) (= (car x) 10))
                                     (entget e))))
            (foreach x ptList (setq sum (mapcar '+ x sum)))
            (setq ID (itoa (vla-get-objectid (vlax-ename->vla-object e))))
            (setq StrField
                       (strcat
                             "%<\\AcObjProp Object(%<\\_ObjId "
                             ID
                             ">%).Area \\f \"%lu2%pr2%ps[, Ac]%ct8[0.xxx-xxxxxxxx]\">%"))
            (command "_.layer" "_thaw" "C-Topo-Drainage-Basin-Text" "_make" "C-Topo-Drainage-Basin-Text" "c" "5" "C-Topo-Drainage-Basin-Text" "" "")
	    (vla-put-AttachmentPoint
                  (setq txt (vla-addMText
                                  acsp
                                  (setq p (vlax-3d-point
                                                   (mapcar '/ sum
                                                         (list verts
                                                               verts))))
                                  0  StrField))
                  acAttachmentPointMiddleCenter)
            (vla-put-InsertionPoint txt p)
            (ssdel e ss)
            )(princ "\0 Objects found:"))
      (princ)
      )



 

 

0 Likes
Message 15 of 15

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

... I need the command to Ask the user "What Basin would you like to analyze (by selecting a basin polyline), analyze the basins, make a text layer by adding "-Text" to the selected basin layer.... 


 

Add something like this near the top:

(setq BasinLayer ;; or whatever you want to call it

  (cdr (assoc 8 (entget (car (entsel "\nSelect Basin on desired Layer: ")))))

 

); setq

 

[It can be made far more sophisticated, such as to check whether you picked something of the right kind, and ask again if you missed or picked an invalid object.]

 

Then use that BasinLayer variable in the (ssget) filter by replacing:

'((0 . "*POLYLINE")

with:

(list '(0 . "*POLYLINE")

and:

(-4 . "&")

(70 . 1)(410 . "Model"))))

with:

'(-4 . "&") '(70 . 1)

'(410 . "Model"))))

and:

(8 . "C-Topo-Drainage-Basin")

with:

(cons 8 BasinLayer)

and finally, use

(strcat BasinLayer "-Text")

 

in the new-Layer command.

Kent Cooper, AIA