I'm having trouble accessing the information stored in the lists STPT1
and ENDPT1
which are x(0)
, y(1)
, and z(2)
coordinates.
For instance, after getting a point: (45.4529 21.6384 0.0)
when I inspect with Visual LISP (-(NTH 1 STPT1) 0.5)
I get a REAL 21.1384
, but the following:
(SETQ STPTP2 '((NTH 0 STPT1) (- (NTH 1 STPT1) 0.5) 0))
creates the list:
((NTH 0 STPT1) (- (NTH 1 STPT1) 0.5) 0)
instead of:
(45.4529 21.1384 0.0)
My goal is to simultaneously create two parallel lines that are 0.5 units apart from each other.
How can I access the information in different positions of the lists STPT1
and ENDPT1
and then assign them in lists STPT2
and ENDPT2
?
(VL-LOAD-COM)
(DEFUN C:CURBYOURENTHUSIASM ( / STPT1 ENDPT1 STPT2 ENDPT2)
(SETQ STPT1 (GETPOINT "\nSpecify start point: "))
(SETQ ENDPT1 (GETPOINT STPT1 "\nSpecify end point: "))
(SETQ STPT2 '((NTH 0 STPT1) (-(NTH 1 STPT1) 0.5) 0))
(SETQ ENDPT2 '((NTH 0 ENDPT1) (-(NTH 1 ENDPT1) 0.5) 0))
(SETQ TOP (ENTMAKE (LIST (CONS 0 "LINE")(CONS 10 STPT1)(CONS 11 ENDPT1)(CONS 8 "CONCRETE"))))
(SETQ BOTTOM (ENTMAKE (LIST (CONS 0 "LINE")(CONS 10 STPT2)(CONS 11 ENDPT2)(CONS 8 "CONCRETE"))))
(PRINC)
)
There are a number of issues with your current code:
You have one too many closing parentheses on line 5 of your code:
(SETQ STPT2 '((NTH 0 STPT1) (-(NTH 1 STPT1) 0.5) 0)))
The final closing parenthesis at the end of the above expression is closing the defun
expression, resulting in the remaining expressions being evaluated on load, rather than when the function is evaluated.
You are incorrectly quoting the following expressions as literal expressions:
(SETQ STPT2 '((NTH 0 STPT1) (-(NTH 1 STPT1) 0.5) 0))
(SETQ ENDPT2 '((NTH 0 ENDPT1) (-(NTH 1 ENDPT1) 0.5) 0))
Expressions which follow the single quote will not be evaluated by the AutoLISP interpreter, but will instead be taken at 'face-value'.
This means that the nth
and -
functions will not be evaluated, but will instead be interpreted simply as symbols within a nested list structure. For more information on literal expressions, you may wish to refer to my tutorial describing the Apostrophe & Quote Function.
To construct a list of variable (i.e. non-literal) data, you should use the list
function, e.g.:
(setq stpt2 (list (nth 0 stpt1) (- (nth 1 stpt1) 0.5) 0))
You are unnecessarily loading the Visual LISP ActiveX extensions (using (vl-load-com)
), but are not using any functions from this library in your code. This is a relatively minor issue, but worth mentioning nonetheless.
Correcting the above issues and formatting your code with appropriate indentation, we have the following:
(defun c:curbyourenthusiasm ( / stpt1 endpt1 stpt2 endpt2 )
(setq stpt1 (getpoint "\nSpecify start point: "))
(setq endpt1 (getpoint stpt1 "\nSpecify end point: "))
(setq stpt2 (list (nth 0 stpt1) (- (nth 1 stpt1) 0.5) 0))
(setq endpt2 (list (nth 0 endpt1) (- (nth 1 endpt1) 0.5) 0))
(setq top (entmake (list (cons 0 "line") (cons 10 stpt1) (cons 11 endpt1) (cons 8 "concrete"))))
(setq bottom (entmake (list (cons 0 "line") (cons 10 stpt2) (cons 11 endpt2) (cons 8 "concrete"))))
(princ)
)
This code will now run successfully, but there are a number of possible improvements:
You should test for valid user input before proceeding to operate on data obtained from the user: if the user dismisses the prompts without supplying a point, any arithmetic operations on the list values will error, as such values will be nil
.
You can avoid such errors by simply using an if
statement:
(defun c:curbyourenthusiasm ( / ep1 sp1 )
(if
(and
(setq sp1 (getpoint "\nSpecify start point: "))
(setq ep1 (getpoint "\nSpecify end point: " sp1))
)
(progn
;; Continue with program operations
)
)
(princ)
)
Currently your code will always offset the second line in the negative y-direction which will result in a variation in the line spacing as the angle of the line changes - when the line angle is vertical, the two lines will overlap.
To avoid this, you can use the polar
function to calculate a point offset a predetermined distance from the specified start & end points, in a direction perpendicular to the line angle, which you can calculate using the angle
function:
(defun c:curbyourenthusiasm ( / ang ep1 ep2 sp1 sp2 )
(if
(and
(setq sp1 (getpoint "\nSpecify start point: "))
(setq ep1 (getpoint "\nSpecify end point: " sp1))
)
(progn
(setq ang (- (angle sp1 ep1) (/ pi 2))
sp2 (polar sp1 ang 0.5)
ep2 (polar ep1 ang 0.5)
)
;; Continue with program operations
)
)
(princ)
)
The getpoint
function will return points whose coordinates are expressed relative to the current UCS (User Coordinate System) active at the time that the program is evaluated.
However, the points associated with DXF groups 10 & 11 for a LINE
entity in the drawing database are expected to be expressed relative to the WCS (World Coordinate System).
We can transform points between the two coordinate systems using the AutoLISP trans
function:
(defun c:curbyourenthusiasm ( / ang ep1 ep2 sp1 sp2 )
(if
(and
(setq sp1 (getpoint "\nSpecify start point: "))
(setq ep1 (getpoint "\nSpecify end point: " sp1))
)
(progn
(setq ang (- (angle sp1 ep1) (/ pi 2))
sp2 (trans (polar sp1 ang 0.5) 1 0)
ep2 (trans (polar ep1 ang 0.5) 1 0)
sp1 (trans sp1 1 0)
ep1 (trans ep1 1 0)
)
;; Continue with program operations
)
)
(princ)
)
Where you have constant data (e.g. explicit numerical data or strings), you can quote such data as literal data in the code, avoiding the need for the interpreter to evaluate the list
and cons
functions to construct the data structures:
For example:
(cons 0 "line")
Can become:
'(0 . "line")
Since 0
and "line"
are both constant data and may therefore be marked as literals.
Implementing all of the above, we have the following:
(defun c:curbyourenthusiasm ( / ang ep1 ep2 sp1 sp2 )
(if
(and
(setq sp1 (getpoint "\nSpecify start point: "))
(setq ep1 (getpoint "\nSpecify end point: " sp1))
)
(progn
(setq ang (- (angle sp1 ep1) (/ pi 2))
sp2 (trans (polar sp1 ang 0.5) 1 0)
ep2 (trans (polar ep1 ang 0.5) 1 0)
sp1 (trans sp1 1 0)
ep1 (trans ep1 1 0)
)
(entmake (list '(0 . "LINE") '(8 . "concrete") (cons 10 sp1) (cons 11 ep1)))
(entmake (list '(0 . "LINE") '(8 . "concrete") (cons 10 sp2) (cons 11 ep2)))
)
)
(princ)
)