Jump to content

Create layers with LISP


Loque
 Share

Recommended Posts

An Introduction to...

 

Creating Layers Using Entmake

 

 

A Basic Example

 

Here is perhaps the simplest version of a function to create a layer using the entmake function, given a layer name:

 

(defun _layer ( name )
   (if (null (tblsearch "LAYER" name))
       (entmake
           (list
              '(000 . "LAYER")
              '(100 . "AcDbSymbolTableRecord")
              '(100 . "AcDbLayerTableRecord")
              '(070 . 0)
               (cons 002 name)
           )
       )
   )
)
 

The code simply says: "If the layer doesn't exist in the Layer Table (tblsearch check), use entmake to create it".

 

The above may be called in the following way to create a layer named 'Test':

 

(_layer "Test")
 

Hence, to create multiple layers we could call the above function from another function:

 

(defun c:test ( / )
   (foreach layer
      '(
           "Layer1"
           "Layer2"
           "Layer3"
       )
       (_layer layer)
   )
   (princ)
)
 

Which would create three layers: "Layer1", "Layer2" and "Layer3" with default properties (i.e. Colour = White, Linetype = Continuous, etc.).

 

Refining the Properties

 

Referring to the DXF Reference hyperlinked above, note the DXF Group Codes for the following basic properties:

 

  2  =  Layer Name
  6  =  Layer Linetype
 62  =  Layer Colour
290  =  Layer Plotting Flag
370  =  Layer Lineweight Enum
 

Hence, to expand the '_layer' function to include the option to specify a Layer Colour, we need to include DXF Group Code 62:

 

(defun _layer2 ( name colour )
   (if (null (tblsearch "LAYER" name))
       (entmake
           (list
              '(000 . "LAYER")
              '(100 . "AcDbSymbolTableRecord")
              '(100 . "AcDbLayerTableRecord")
              '(070 . 0)
               (cons 002 name)
               (cons 062 colour)
           )
       )
   )
)
 

The function '_layer2' now requires an extra parameter (the layer colour) when called:

 

(_layer2 "Test Colour" 3)
 

Would create a Green Layer (colour 3) called "Test Colour".

 

Again, there are many ways this revised function could be called from another program to create multiple layers, here are a few examples:

 

Using a foreach loop with an association list:

 

(defun c:test2 ( / )
   (foreach pair
      '(
           ("Layer4" 1)
           ("Layer5" 3)
           ("Layer6" 2)
       )
       (apply '_layer2 pair)
   )
   (princ)
)
 

Using a mapcar expression:

 

(defun c:test2 ( / )
   (mapcar '_layer2 '("Layer4" "Layer5" "Layer6") '(1 3 2))
   (princ)
)
 

(For more on mapcar, see here)

 

Adding More Properties

 

Let us now add some more properties to the function:

 

(defun _layer3 ( name colour linetype lineweight plot )
   (if (null (tblsearch "LAYER" name))
       (entmake
           (list
              '(000 . "LAYER")
              '(100 . "AcDbSymbolTableRecord")
              '(100 . "AcDbLayerTableRecord")
              '(070 . 0)
               (cons 002 name)
               (cons 006 linetype)
               (cons 062 colour)
               (cons 290 plot)
               (cons 370 lineweight)
           )
       )
   )
)
 

This function '_layer3' now includes the DXF Group codes for the layer name (DXF 2), colour (DXF 62), linetype (DXF 6), lineweight (DXF 370) and the plotting flag (DXF 290).

 

However, when calling the function we need to be careful to use the correct data types for these Group Codes.

 

For example, the lineweight (DXF 370) must be an integer value equal to the decimal lineweight multiplied by 100.

 

Hence a lineweight of 2.11mm would have a DXF Group 370 value of 211.

 

Similarly, the plotting flag (DXF 290) requires an integer value of either 0 (layer won't plot) or 1 (layer will plot).

 

And so we might call the function '_layer3' in the following way:

 

(_layer3 "Test Props" 4 "Continuous" 40 1)
 

This would create a plottable layer called "Test Props" with a Layer Colour of 4 (Cyan), Continuous Linetype, and a Lineweight of 0.40mm.

 

Note that when supplying the DXF Data list to the entmake function, the Linetype assigned to DXF Group 6 must exist in the Linetype Table (i.e. be loaded in the drawing) for the layer to be created.

 

With this in mind we can add some error trapping to the code to allow for linetypes which are not loaded, and set the layer to use a Continuous linetype for these cases:

 

(defun _layer4 ( name colour linetype lineweight plot )
   (if (null (tblsearch "LAYER" name))
       (entmake
           (list
              '(000 . "LAYER")
              '(100 . "AcDbSymbolTableRecord")
              '(100 . "AcDbLayerTableRecord")
              '(070 . 0)
               (cons 002 name)
               (cons 006
                   (if (tblsearch "LTYPE" linetype)
                       linetype
                       "Continuous"
                   )
               )
               (cons 062 colour)
               (cons 290 plot)
               (cons 370 lineweight)
           )
       )
   )
)
 

Again this function could be called from another program to create many layers at once, as the following example demonstrates:

 

(defun c:test4 ( / )
   (foreach item
      '(
           ("Layer7" 4 "HIDDEN"     40 1)
           ("Layer8" 3 "Continuous" 90 0)
           ("Layer9" 2 "PHANTOM"    20 1)
       )
       (apply '_layer4 item)
   )
   (princ)
)
 

Other properties can be refined by modifying other values of the DXF data list, such as the DXF Group 70 bitflag value to control whether the layer is Locked, Frozen, or Frozen in VP when created; however, I shall save these for another day.

 

An Extension: Modifying Existing Layers

 

This final extension demonstrates how to allow the function to modify the properties of existing layers should the layer already exist in the Layer Table when the function is called.

 

The following is a more advanced function I wrote some time ago, I shall post it here as a final example:

 

(defun LM:CreateLayer ( name color ltype lnwt plot )
   (
       (lambda ( _function )
           (_function
               (list
                  '(000 . "LAYER")
                  '(100 . "AcDbSymbolTableRecord")
                  '(100 . "AcDbLayerTableRecord")
                  '(070 . 0)
                   (cons 002 name)
                   (cons 006 (if (tblsearch "LTYPE" ltype) ltype "Continuous"))
                   (cons 062 color)
                   (cons 290 plot)
                   (cons 370 lnwt)
               )
           )
       )
       (if (tblsearch "LAYER" name)
           (lambda ( data ) (entmod (cons (cons -1 (tblobjname "LAYER" name)) data)))
           entmakex
       )
   )
)
 

Hence, to modify "Layer9" from the earlier example, I could call:

 

(LM:CreateLayer "Layer9" 5 "Continuous" 211 0)
 

Or, to create a new "Layer10", (or modify if it already exists):

 

(LM:CreateLayer "Layer10" 6 "HIDDEN" -3 1)
 

Note the use of "-3" as the Lineweight Enum to indicate a 'Default' Lineweight setting.

 

Thats about all I have time for, but I hope this helps.

 

If you have any questions about what I have posted, just ask.

 

Happy coding,

 

Lee

Edited by Lee Mac
Link to comment
Share on other sites

Of course...LeeMac did a great job...but coz I'm noob I 'm still struggling with an a issue...

So...I'm very fond of Bigal's idea of creating some kind of group layers that we could call them when we would working on such projects(coz several people is working on project at the same time so we are using same standards/defined layers).

For instance,we are vectorizing infrastructure of some area and I would use some kind of a lisp that woud have defined all layers that are connected to the infrastructure. So basically what I'm asking is; when I press "infra" it would create layers with defined colors,linetype, line weight,etc.

 

("001_Highways"[continous-color 25--0.30], "002_Major_roads"[continous--color 45--0.25], "003_Local_roads"[continous--color 65--0.20], "004_Railroads"[continous--color 65--0.15], "005_Pipelines"[continous--color 150--0.15] ..

[line type,color,line weight]

(this is an example there are many more layers...)

Something like this if it is possible...and is it possible to add extra layers to this routine...if I want to add layer like "007_Nature_line" where should I put it into routine coz in near future there will be more layers that i want to include to routine. That lisp would save lives and hours and hours of creating new layers for each project.

 

Thx in advance and with a bit delay, Merry Christmas for all kind and patience people that lingers on this forum and best of luck in upcoming New Year

Link to comment
Share on other sites

when I press "infra" it would create layers with defined colors,linetype, line weight,etc.

 

 

You are after the magic button. Did you know that if you made an empty drawing with all your new layers set up, then by inserting the drawing, all the layers came with it. Rather what you are expecting the Lisp to do for you.

 

 

...and is it possible to add extra layers to this routine..

 

If you used the empty drawing technique, then you have the knowledge to add extra layers as you want, instead of delving into the hinterland of a lisp routine.

Link to comment
Share on other sites

What a guy. :) Lee Mac the philanthropist of programming. And one heck of a tutor as well. :geek:

 

That is one of the best step by step descriptions I have ever seen. Well done Lee. 8)

 

Vist our website: :)

 

dear sir, lee

 

great example thx................

 

Cheers guys! Glad it was comprehensible :)

 

Just fixed a few typos lurking here and there, I wrote it a little too quick last night :oops:

Link to comment
Share on other sites

...(this is an example there are many more layers...)

Something like this if it is possible...and is it possible to add extra layers to this routine...if I want to add layer like "007_Nature_line" where should I put it into routine coz in near future there will be more layers that i want to include to routine. That lisp would save lives and hours and hours of creating new layers for each project. ...

Well you could see these in LM's tut quite easily. Say you have a set of layers you'd like to create on one button click you could use LM's routine in the same way he's explained. Tip: those foreach or mapcar functions.

 

Now that method means you need to add the extra layers into the lisp routine. E.g.

(defun c:infra ( / )
   (foreach item
      '(
		("001_Highways" 25 "Continuous" 30 1)
		("002_Major_roads" 45 "Continuous" 25 1)
		("003_Local_roads" 65 "Continuous" 20 1)
		("004_Railroads" 65 "Continuous" 15 1)
		("005_Pipelines" 150 "Continuous" 15 1)
       )
       (apply 'LM:CreateLayer item)
   )
   (princ)
)

Then if you want to add another layer to the same routine at a later stage you'd edit the LSP and add say the 007_Nature_Line layer at the end of that list (or even anywhere in between as it doesn't matter where).

 

Though this shows that it's a bit technical to add/remove layers from your macros. Thus the insert template DWG is a very easy way of getting round this problem. It allows you to setup the layers direct in one DWG file. And all thats needed to edit it later would be to edit that DWG file.

 

The disadvantage(s) of the DWG insert method is that you'd need to purge the block created through insert. But worse: you can't easily have a modification to existing layer properties as per LM's LM:CreateLayer defun.

 

You've got 2 distinct options to circumvent even these - still building onto LM's code:

  1. Add the layers in Excel into a CSV / TAB delimeted text file. Have your routine read the file into a list and then send to LM:CreateLayer
  2. Use ObjectDBX to read the layers from the template DWG into a list to send to LM:CreateLayer

The first one has many more options, though you'd not find that much more use out of changing to use XLS files or so. I'd actually go with the 2nd option - which means that you get the most notable advantage of the DWG method by directly editing your template DWG for future changes (yet still allowing for modifying existing layers back to the template's layers' properties).

 

It's all about how far you'd like your code to go. E.g. you could have a folder filled with template DWG's each for a different macro. In such case you could even have lisp generate the macros for you by reading the folder and then generating a menu item for each. The options are endless, but become more and more extreme as you want more and more functionality.

 

If you don't want to write some comprehensive lisp, then (as others have pointed out) the DWG method doesn't even need lisp at all. You can simply write a command macro directly in the CUI or you can have a SCR file which gets called through the SCRIPT command. This would be the simplest way of going about it (if you don't need to set existing layers back to their template settings).

Link to comment
Share on other sites

Thanks for the compliment! Though you've done most of the work! And your tut is very comprehensive already.

 

I'm just trying to explain the pros & cons of all the methods available. We'd need more info from the OP to be able to say which is the best for his case. Perhaps the insert method is sufficient and all these things are overkill, or perhaps he needs the further extreme by having a folder full of templates which he can add, remove and/or modify at future dates without needing to edit any code or macros.

Link to comment
Share on other sites

Would'nt creating drawing with just layers in it and editing that be just as easy as hard coding new values or creating a .csv file?

 

(Command "-INSERT" "C:\\Users\\YoMama\\Documents\\LayerFile" CANCEL)

 

Great Turtorial Lee!!!!

Link to comment
Share on other sites

It is such a shame when these threads degenerate into chat and persiflage.

 

Perhaps all posts after #35 should be stricken. I thought that was what Moderators were for.

 

 

P.S. As this was originally post #45, I see that Moderators have been to work

Edited by eldon
added P.S.
Link to comment
Share on other sites

It is such a shame when these threads degenerate into chat and persiflage.

 

Perhaps all posts after #35 should be stricken. I thought that was what Moderators were for.

 

I really don't see where the little added banter detracted from the thread.

Link to comment
Share on other sites

I really don't see where the little added banter detracted from the thread.

Chat and banter are good as long as it doesn't belittle the user's.

It allows people to get opinions about thing and ultimately learn.

 

I have found this thread very helpful as it has showed me how other people do simular thing and allows me do more in the future.

Thanks to all who have contrubuted

Edited by SunnyTurtle
Link to comment
Share on other sites

Thx ..lee mac, you are really something, you helped me a lot. ( I figured couple days ago your code/tutorial :) )

Irneb and pBe thank you as well, awesome guys.

 

So, this looks something like this.. I believe..( I'll adjust layer names,colors,etc... in near future as well as shortcuts)

 

(defun _infra ( name colour linetype lineweight plot )
   (if (null (tblsearch "LAYER" name))
       (entmake
           (list
              '(0 . "LAYER")
              '(100 . "AcDbSymbolTableRecord")
              '(100 . "AcDbLayerTableRecord")
              '(70 . 0)
               (cons 2 name)
               (cons 6
                   (if (tblsearch "LTYPE" linetype)
                       linetype
                       "Continuous"
                   )
               )
               (cons 62 colour)
               (cons 290 plot)
               (cons 370 lineweight)
           )
       )
   )
)
(defun c:infra ( / )
   (foreach item
      '(
           ("uber" 4 "HIDDEN"     40 1)
           ("nice" 3 "Continuous" 90 1)
           ("awesome" 2 "PHANTOM"    20 1)
       )
       (apply '_infra item)
   )
   (princ)
)

 

I have found this thread very helpful as it has showed me how other people do simular thing and allows me do more in the future.

Thanks to all who have contrubuted

SunnyTurtle, I couldn't agree more...

 

P.S. I did ask a question about topology even posted a thread "Lisp routine for topology" http://www.cadtutor.net/forum/showthread.php?65481-Lisp-routine-for-topology so...if anyone is familiar with this routine please take a look.

 

(I don't know if this is rude to post link to another thread so if I did break any forum laws I apologize in advance)

 

and Happy New Year !!!

Link to comment
Share on other sites

P.S. I did ask a question about topology even posted a thread "Lisp routine for topology" http://www.cadtutor.net/forum/showthread.php?65481-Lisp-routine-for-topology so...if anyone is familiar with this routine please take a look.

 

(I don't know if this is rude to post link to another thread so if I did break any forum laws I apologize in advance)

 

Tisk, tisk...

 

how_rude.jpg

 

:P

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
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.

 Share

×
×
  • Create New...