Jump to content
traumathecat

LISP routine format and commands

Recommended Posts

traumathecat

Hi all,

 

I've never written a LISP routine before and I am finding myself in need of a function that I can't seem to be able to do without LISP, so I have begun my first attempt. It's not going so well.

 

I need to be able to pick two points and have a square drawn that uses those two points as opposite corners.

 

I think if I can check the angle between the two points, then add or subtract 45-degrees from that, I will get the rotation for the square, and I can then use the RECTANGLE command to draw it by picking the first point, setting the rotation, and then pick the second point.

 

I think the code should look something like this:

(defun C:square (/p1 rot p2)

(set q p1 (getpoint "\n Pick first corner:"))

(set q p2 (getpoint "\n Pick opposite corner:"))

(set q rotang (-45 (
ANGLE
p1 p2)))

(command "RECTANGLE" p1 "R" " rotang "" p2)

(princ)

)

The first problem I run into is that I don't know how to check the angle between the two points. I know I can get it by using the DIST command and the value comes up as "Angle in XY-plane" but I don't know how to then use that value as my ANGLE value.

 

Second, I have no idea if I am even on the right track as far as writing the code.

Any help would be greatly appreciated.

I'm working in Civil 3D 2011.

Share this post


Link to post
Share on other sites
Lee Mac

Perhaps this will point you towards your goal :

 

(defun c:square ( / pt2 pt2 ang ) ; Define function and localise variables

 (if ; If the following
   (and ; Both the statements must return T
     (setq pt1 (getpoint "\nSpecify First Point: ")) ; Prompt for first point
     (setq pt2 (getpoint "\nSpecify Opposite Corner: " pt1)) ; Prompt for second point
   )
   (progn
     (setq ang (- (angle pt1 pt2) (/ pi 4.))) ; get angle (in rads) and subtract 45 degrees
     
     (command "_.rectangle" "_non" pt1 "_R" (* 180. (/ ang pi)) "_non" pt2) ; Invoke Rectangle command
   )
 )

 (princ) ; Exit Quietly
)

PS> Nice one for localising your variables, most people miss that :)

 

To expand, you will have to watch out for OSnap, and also perhaps consider switching CMDECHO to 0, then reset. But we'll take it one step at a time.

Edited by Lee Mac
Updated to avoid OSnap

Share this post


Link to post
Share on other sites
Lee Mac

As a bit of food for thought, this is how I would approach it:

 

(defun c:square ( / *error* pt2 pt2 ang side )

 (defun *error* ( msg )
   (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
       (princ (strcat "\n** Error: " msg " **")))
   (princ)
 )

 (if
   (and
     (setq pt1 (getpoint "\nSpecify First Point: ")) 
     (setq pt2 (getpoint "\nSpecify Opposite Corner: " pt1))
   )
   (progn
     (setq pt1  (trans pt1 1 0) pt2 (trans pt2 1 0)
           ang  (- (angle pt1 pt2) (/ pi 4.))
           side (sqrt (/ (expt (distance pt1 pt2) 2) 2.)))

     (LM:LWPoly (list pt1 (polar pt1 ang side)
                      pt2 (polar pt1 (+ ang (/ pi 2.)) side))
       1
     )
   )
 )

 (princ)
)

(defun LM:LWPoly ( lst cls )
 (entmakex
   (append
     (list
       (cons 0 "LWPOLYLINE")
       (cons 100 "AcDbEntity")
       (cons 100 "AcDbPolyline")
       (cons 90 (length lst))
       (cons 70 cls)
     )
     (mapcar '(lambda ( p ) (cons 10 p)) lst)
   )
 )
)

Perhaps it might be a bit above you at the moment, but maybe its something to work towards :)

Share this post


Link to post
Share on other sites
traumathecat
Perhaps this will point you towards your goal :

 

(defun c:square ( / pt2 pt2 ang ) ; Define function and localise variables

(if ; If the following
(and ; Both the statements must return T
(setq pt1 (getpoint "\nSpecify First Point: ")) ; Prompt for first point
(setq pt2 (getpoint "\nSpecify Opposite Corner: " pt1)) ; Prompt for second point
)
(progn
(setq ang (- (angle pt1 pt2) (/ pi 4.))) ; get angle (in rads) and subtract 45 degrees

(command "_.rectangle" pt1 "_R" (* 180. (/ ang pi)) pt2) ; Invoke Rectangle command
)
)

(princ) ; Exit Quietly
)

PS> Nice one for localising your variables, most people miss that :)

 

To expand, you will have to watch out for OSnap, and also perhaps consider switching CMDECHO to 0, then reset. But we'll take it one step at a time.

 

THANK YOU, THANK YOU, THANK YOU! :D I love it! So far it is working perfectly. You have saved me hours and hours of manually calculating and placing squares (I have around 4,000 of them).

 

PS> Thank you... I tried to find whatever information and tutorials I could online to at least attempt to write something on my own, so I was able to figure out a little bit of the format, but I still have a lot to learn!

Share this post


Link to post
Share on other sites
traumathecat
As a bit of food for thought, this is how I would approach it:

 

(defun c:square ( / *error* pt2 pt2 ang side )

(defun *error* ( msg )
(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
(princ (strcat "\n** Error: " msg " **")))
(princ)
)

(if
(and
(setq pt1 (getpoint "\nSpecify First Point: ")) 
(setq pt2 (getpoint "\nSpecify Opposite Corner: " pt1))
)
(progn
(setq pt1 (trans pt1 1 0) pt2 (trans pt2 1 0)
ang (- (angle pt1 pt2) (/ pi 4.))
side (sqrt (/ (expt (distance pt1 pt2) 2) 2.)))

(LM:LWPoly (list pt1 (polar pt1 ang side)
pt2 (polar pt1 (+ ang (/ pi 2.)) side))
1
)
)
)

(princ)
)

(defun LM:LWPoly ( lst cls )
(entmakex
(append
(list
(cons 0 "LWPOLYLINE")
(cons 100 "AcDbEntity")
(cons 100 "AcDbPolyline")
(cons 90 (length lst))
(cons 70 cls)
)
(mapcar '(lambda ( p ) (cons 10 p)) lst)
)
)
)

Perhaps it might be a bit above you at the moment, but maybe its something to work towards :)

 

haha... definitely above me, but I like a challenge. And, I hate not knowing how to do things. :) So, I definitely will take a look and try to understand how you've done this.

Share this post


Link to post
Share on other sites
Lee Mac

My pleasure - happy to help.

 

With regards to the first code, it is a 'preliminary' of sorts, as you will have trouble as far as OSnap interference goes - perhaps use "_non" before supplying the points to the command function to ignore OSnap. (I'll update the code).

 

The second is faster and you needn't worry about OSnap as it adds the object directly to the drawing database, bypassing all command calls.

 

As for help with LISP, I posted this thread a while back, hopefully you can glean something from it:

 

http://www.cadtutor.net/forum/showthread.php?49515-Useful-LISP-Links

 

Lee

Share this post


Link to post
Share on other sites
traumathecat
My pleasure - happy to help.

 

With regards to the first code, it is a 'preliminary' of sorts, as you will have trouble as far as OSnap interference goes - perhaps use "_non" before supplying the points to the command function to ignore OSnap. (I'll update the code).

 

The second is faster and you needn't worry about OSnap as it adds the object directly to the drawing database, bypassing all command calls.

 

As for help with LISP, I posted this thread a while back, hopefully you can glean something from it:

 

http://www.cadtutor.net/forum/showthread.php?49515-Useful-LISP-Links

 

Lee

 

I've been using the second code and it has been working great (I've done 50 sets of points). But, I just got to this set of points and I got the funky square in red. I ran the first one on the same points and got the blue square. I'm not sure what threw it off here. The rest are giving me the same square using either method.

 

squares.JPG

 

Thanks for the link, I look forward to checking it out and learning more. :)

Share this post


Link to post
Share on other sites
Lee Mac

I'm not sure what would throw it off... hmmm not sure on that one.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×