我很难访问存储在列表STPT1
和ENDPT1
中的信息,它们是x(0)
、y(1)
和z(2)
坐标。
例如,在得到点:(45.4529 21.6384 0.0)
之后,当我使用Visual (-(NTH 1 STPT1) 0.5)
进行检查时,我得到了一个真正的21.1384
,但如下所示:
(SETQ STPTP2 '((NTH 0 STPT1) (- (NTH 1 STPT1) 0.5) 0))
创建列表:
((NTH 0 STPT1) (- (NTH 1 STPT1) 0.5) 0)
而不是:
(45.4529 21.1384 0.0)
我的目标是同时创建两条平行线,每条平行线相距0.5个单位。
如何在列表STPT1
和ENDPT1
的不同位置访问信息,然后在列表STPT2
和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)
)
发布于 2018-12-26 16:07:18
当前问题
当前代码存在一些问题:
1.不平衡的父母关系
在代码的第5行中有一个太多的结束括号:
(SETQ STPT2 '((NTH 0 STPT1) (-(NTH 1 STPT1) 0.5) 0)))
上述表达式末尾的最后一个结束括号是关闭defun
表达式,结果是在加载时计算其余表达式,而不是在计算函数时。
2.引用的可变数据
将下列表达式引用为文字表达式是错误的:
(SETQ STPT2 '((NTH 0 STPT1) (-(NTH 1 STPT1) 0.5) 0))
(SETQ ENDPT2 '((NTH 0 ENDPT1) (-(NTH 1 ENDPT1) 0.5) 0))
单引号后面的表达式不会由AutoLISP解释器计算,而是按“面值”计算。
这意味着不会对nth
和-
函数进行计算,而是将其简单地解释为嵌套列表结构中的符号。有关文字表达式的更多信息,您可能希望参考我的教程描述撇号&引号函数。
要构造变量(即非文字)数据的列表,应该使用list
函数,例如:
(setq stpt2 (list (nth 0 stpt1) (- (nth 1 stpt1) 0.5) 0))
3.不必要的ActiveX
您不必要地加载Visual扩展(使用(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 (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)
)
这段代码现在将成功运行,但是有一些可能的改进:
可能的改进
1.用户输入验证
在对从用户获得的数据进行操作之前,您应该测试有效的用户输入:如果用户不提供点就删除提示,列表值上的任何算术操作都会出错,因为这些值将是nil
。
只需使用if
语句即可避免此类错误:
(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)
)
2.线角变化
目前,您的代码总是在负y方向上偏移第二行,这将导致行间距随直线角度的变化而变化--当直线角为垂直时,这两条线将重叠。
为了避免这种情况,您可以使用polar
函数计算一个点偏移到指定起点和终点的预定距离,其方向与直线角垂直,您可以使用angle
函数计算该方向:
(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)
)
3. UCS的会计
getpoint
函数将返回在程序评估时相对于当前UCS (用户坐标系统)活动的坐标表示的点。
然而,与DXF组10 & 11相关联的用于绘图数据库中的LINE
实体的点将被表示为相对于WCS (世界坐标系)。
我们可以使用AutoLISP trans
函数在两个坐标系之间转换点:
(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)
)
4.引用常量数据
如果您有常量数据(例如,显式数值数据或字符串),您可以在代码中引用这些数据作为文字数据,从而避免了解释器计算list
和cons
函数来构造数据结构的需要:
例如,:
(cons 0 "line")
可以成为:
'(0 . "line")
因为0
和"line"
都是常量数据,因此可能被标记为文本。
为此,我们有以下各点:
(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)
)
https://stackoverflow.com/questions/53933906
复制相似问题