Autolisp实体数据检索
Autolisp entity data retrieval
我正在试用 autocad,我想在矩形和直线之间构建一个 "highway"。我需要矩形中的 2 个点。有什么想法吗?
(setq en(car(entsel"\Get rectangle : ")))
(entget en)
我的全部代码
(defun temaLisp(/ )
;HIGHWAY BUILDER
;My project is a highwaybulder
;How does it work?
;Select a rectangle and draw from there to a distance the highway where it meets a stop(Line)
(princ "TemaLisp ")
;get rectangle (prompt "\nSelect the ends of a station")
(setq en(car(entsel"\Get rectangle : ")))
(entget en)
;get the stop (Line)
(setq line2 (car (entsel "\nSelect the second line: ")))
(setq p3 (cdr (assoc 10 (entget line2))))
(setq p4 (cdr (assoc 11 (entget line2))))
;of the highway &optional (size 50)
(setq mid1 (midpt pt3 pt4)) ; midpoint for dotted line
; Draw the lines
(command "line" mid1 mid2)
)
(setq rectangle (entget en))
第一点你可以通过:
(setq P1(assoc 10 rectangle ))
然后删除P1之前的所有内容
(setq rectangle (cdr (member P1 rectangle)))
并获得下一个分数
(setq P2(assoc 10 rectangle ))
你可以循环while
在 AutoCAD 中,矩形(使用 AutoCAD RECTANG
命令创建)使用封闭的二维轻型多段线 (LWPOLYLINE
) 实体表示。
一个 LWPOLYLINE
实体包含以下 DXF 数据:
(
(-1 . <Entity name: 7ffff706880>) ;; Pointer to self
(0 . "LWPOLYLINE") ;; Entity Type
(330 . <Entity name: 7ffff7039f0>) ;; Point to parent
(5 . "FFF") ;; Handle
(100 . "AcDbEntity") ;; Class
(67 . 0) ;; Tilemode
(410 . "Model") ;; Layout
(8 . "0") ;; Layer
(100 . "AcDbPolyline") ;; Subclass
(90 . 4) ;; Vertices
(70 . 1) ;; Bitwise flag (1=Closed)
(43 . 0.0) ;; Constant width
(38 . 0.0) ;; Elevation
(39 . 0.0) ;; Thickness
(10 18.9133 17.6315) ;; Vertex coordinate (OCS)
< ... additional vertex data ... >
(10 18.9133 12.7863) ;; Vertex coordinate (OCS)
(40 . 0.0) ;; Segment starting width
(41 . 0.0) ;; Segment ending width
(42 . 0.0) ;; Segment bulge
(91 . 0) ;; Vertex identifier
(210 0.0 0.0 1.0) ;; Extrusion (normal) vector
)
此处,每个顶点的 2D OCS 坐标使用 DXF 数据中的 DXF 组 10 条目进行存储。
有很多方法可以获取 DXF 数据中多次出现的 DXF 组所包含的值列表(从而获取多段线的顶点列表)。
由于 assoc
AutoLISP 函数 return 是关联列表中键的第一次出现,我将这些函数称为 massoc
函数(即 m多个assoc).
1。 foreach
(defun massoc1 ( key lst / rtn )
(foreach x lst
(if (= key (car x))
(setq rtn (cons (cdr x) rtn))
)
)
(reverse rtn)
)
第一个示例简单地遍历提供的关联列表中的每个项目,如果c地址a地址[= item 的 130=]rregister(car
) 等于所需的 key
,与键关联的值(或 c d增量 r寄存器的内容 - cdr
) 被函数添加到 returned 列表中。
此列表在 returned 之前被反转,因为列表是反向构建的,每个项目都被推到列表的前面 - 这比使用 [=30 的组合更有效=]/list
按顺序构建列表。
2。追加/地图车
(defun massoc2 ( key lst )
(apply 'append
(mapcar
(function
(lambda ( x ) (if (= key (car x)) (list (cdr x))))
)
lst
)
)
)
迭代列表的另一种方法,但是,由于 mapcar
returns 是对每个列表项提供的函数的评估结果,那些不符合条件的项如果 if
语句将导致 nil
出现在由 `mapcar.return 编辑的列表中。
这些 nil
值是通过利用 nil
和 AutoLISP 中的空列表 ()
的二元性删除的,通过应用 append
函数附加所有子列表 &由 mapcar
.
编辑的 return 列表中存在 nil 值
3。 vl-remove-if-not
(defun massoc3 ( key lst )
(mapcar 'cdr
(vl-remove-if-not
(function (lambda ( x ) (= key (car x))))
lst
)
)
)
正如锡罐上所说:如果提供给 vl-remove-if-not
函数的谓词函数 returns nil
(vl-remove-if
也可以与一个否定的谓词函数)——因此第一个元素不等于所需键的项目将被删除。
然后 mapcar
函数用于 return 与每个关联列表项关联的值 return 由 vl-remove-if-not
编辑。
4。 while / assoc / member
(defun massoc4 ( key lst / itm rtn )
(while (setq itm (assoc key lst))
(setq rtn (cons (cdr itm) rtn) lst (cdr (member itm lst)))
)
(reverse rtn)
)
此方法比之前的方法更有效,因为 assoc
和 member
函数用于直接跳转到提供的列表中的目标项,而不是迭代 &测试每一项。
assoc
return 是关联列表中第一次出现的键,member
return 是列表的尾部,第一项等于提供的参数。
这样,assoc
函数检索目标项,member
函数returns从此项开始的列表的其余部分,并重复重新定义列表通过使用 cdr
.
包含此目标项目之后的所有项目
5。递归/关联/成员
(defun massoc5 ( key lst / itm )
(if (setq itm (assoc key lst))
(cons (cdr itm) (massoc5 key (cdr (member itm lst))))
)
)
然而,在上述情况下的变体,在这种情况下,不是为找到的每个项目重新定义列表,而是将列表的其余部分作为参数传递给函数的递归评估。
6。 acet-list-m-assoc(快速工具)
(defun massoc6 ( key lst )
(mapcar 'cdr (acet-list-m-assoc key lst))
)
此版本的函数使用 acet-list-m-assoc
定义为 Express Tools 库的一部分的函数,作为完整版本 AutoCAD 的可选补充提供。
但这是作弊! :-)
7。基本递归
(defun massoc7 ( key lst )
(if lst
(if (= key (caar lst))
(cons (cdar lst) (massoc7 key (cdr lst)))
(massoc7 key (cdr lst))
)
)
)
最后一个示例本质上是上面演示的 foreach
示例的递归版本。该函数只查看提供的列表中的第一项,如果第一个元素与 key
参数匹配,则它 cons
到列表 return 由递归调用编辑与列表的其余部分一起,否则列表的其余部分将传递给递归调用,而不会将项目添加到 return.
例子
既然我们已经讨论了可以定义此类函数的各种方式,那么应该如何使用此类函数?
上述每个函数都接受两个参数:'key' 和关联列表。这在语法上与标准 AutoLISP assoc
函数相同。
此类函数可用于获取与 DXF 关联列表中的 DXF 组 10 关联的所有值,使用语法:
(massoc 10 <dxf-data>)
例如(在 Visual LISP IDE 控制台):
;; Obtain a LWPOLYLINE entity
_$ (setq ent (car (entsel)))
<Entity name: 7ffff706880>
;; Retrieve the DXF data
_$ (setq dxf (entget ent))
((-1 . <Entity name: 7ffff706880>) (0 . "LWPOLYLINE") ... (91 . 0) (210 0.0 0.0 1.0))
;; Obtain the values associated with all DXF group 10 entries
_$ (massoc 10 dxf)
((13.0161 12.4807) (25.727 12.4807) (25.727 18.6426) (13.0161 18.6426))
这可以通过以下方式在示例程序中使用:
(defun c:test ( / dxf ent )
(if
(and
(setq ent (car (entsel "\nSelect rectangle: ")))
(setq dxf (entget ent))
(= "LWPOLYLINE" (cdr (assoc 0 dxf)))
)
(print (massoc 10 dxf))
)
(princ)
)
(defun massoc ( key lst / rtn )
(foreach x lst
(if (= key (car x))
(setq rtn (cons (cdr x) rtn))
)
)
(reverse rtn)
)
性能注意事项
就性能而言,同一函数的上述变体并不相同 - 迭代所提供列表中每个项目的变体的效率低于使用 'skip' 直接针对目标项目的变体 in-built 函数,例如 assoc
和 member
.
作为快速比较,请考虑以下基准测试结果:
;;;Benchmarking ................Elapsed milliseconds / relative speed for 32768 iteration(s):
;;;
;;; (MASSOC5 2 L).....1482 / 1.25 <fastest> ;; recursive/assoc/member
;;; (MASSOC4 2 L).....1482 / 1.25 ;; while/assoc/member
;;; (MASSOC6 2 L).....1498 / 1.24 ;; acet-list-m-assoc
;;; (MASSOC3 2 L).....1638 / 1.13 ;; vl-remove-if-not
;;; (MASSOC7 2 L).....1747 / 1.06 ;; basic recursion
;;; (MASSOC1 2 L).....1748 / 1.06 ;; foreach
;;; (MASSOC2 2 L).....1856 / 1 <slowest> ;; append/mapcar
正如预期的那样,assoc/member
函数被证明是最快的,Express Tools 函数紧随其后。
我正在试用 autocad,我想在矩形和直线之间构建一个 "highway"。我需要矩形中的 2 个点。有什么想法吗?
(setq en(car(entsel"\Get rectangle : ")))
(entget en)
我的全部代码
(defun temaLisp(/ )
;HIGHWAY BUILDER
;My project is a highwaybulder
;How does it work?
;Select a rectangle and draw from there to a distance the highway where it meets a stop(Line)
(princ "TemaLisp ")
;get rectangle (prompt "\nSelect the ends of a station")
(setq en(car(entsel"\Get rectangle : ")))
(entget en)
;get the stop (Line)
(setq line2 (car (entsel "\nSelect the second line: ")))
(setq p3 (cdr (assoc 10 (entget line2))))
(setq p4 (cdr (assoc 11 (entget line2))))
;of the highway &optional (size 50)
(setq mid1 (midpt pt3 pt4)) ; midpoint for dotted line
; Draw the lines
(command "line" mid1 mid2)
)
(setq rectangle (entget en))
第一点你可以通过:
(setq P1(assoc 10 rectangle ))
然后删除P1之前的所有内容
(setq rectangle (cdr (member P1 rectangle)))
并获得下一个分数
(setq P2(assoc 10 rectangle ))
你可以循环while
在 AutoCAD 中,矩形(使用 AutoCAD RECTANG
命令创建)使用封闭的二维轻型多段线 (LWPOLYLINE
) 实体表示。
一个 LWPOLYLINE
实体包含以下 DXF 数据:
(
(-1 . <Entity name: 7ffff706880>) ;; Pointer to self
(0 . "LWPOLYLINE") ;; Entity Type
(330 . <Entity name: 7ffff7039f0>) ;; Point to parent
(5 . "FFF") ;; Handle
(100 . "AcDbEntity") ;; Class
(67 . 0) ;; Tilemode
(410 . "Model") ;; Layout
(8 . "0") ;; Layer
(100 . "AcDbPolyline") ;; Subclass
(90 . 4) ;; Vertices
(70 . 1) ;; Bitwise flag (1=Closed)
(43 . 0.0) ;; Constant width
(38 . 0.0) ;; Elevation
(39 . 0.0) ;; Thickness
(10 18.9133 17.6315) ;; Vertex coordinate (OCS)
< ... additional vertex data ... >
(10 18.9133 12.7863) ;; Vertex coordinate (OCS)
(40 . 0.0) ;; Segment starting width
(41 . 0.0) ;; Segment ending width
(42 . 0.0) ;; Segment bulge
(91 . 0) ;; Vertex identifier
(210 0.0 0.0 1.0) ;; Extrusion (normal) vector
)
此处,每个顶点的 2D OCS 坐标使用 DXF 数据中的 DXF 组 10 条目进行存储。
有很多方法可以获取 DXF 数据中多次出现的 DXF 组所包含的值列表(从而获取多段线的顶点列表)。
由于 assoc
AutoLISP 函数 return 是关联列表中键的第一次出现,我将这些函数称为 massoc
函数(即 m多个assoc).
1。 foreach
(defun massoc1 ( key lst / rtn )
(foreach x lst
(if (= key (car x))
(setq rtn (cons (cdr x) rtn))
)
)
(reverse rtn)
)
第一个示例简单地遍历提供的关联列表中的每个项目,如果c地址a地址[= item 的 130=]rregister(car
) 等于所需的 key
,与键关联的值(或 c d增量 r寄存器的内容 - cdr
) 被函数添加到 returned 列表中。
此列表在 returned 之前被反转,因为列表是反向构建的,每个项目都被推到列表的前面 - 这比使用 [=30 的组合更有效=]/list
按顺序构建列表。
2。追加/地图车
(defun massoc2 ( key lst )
(apply 'append
(mapcar
(function
(lambda ( x ) (if (= key (car x)) (list (cdr x))))
)
lst
)
)
)
迭代列表的另一种方法,但是,由于 mapcar
returns 是对每个列表项提供的函数的评估结果,那些不符合条件的项如果 if
语句将导致 nil
出现在由 `mapcar.return 编辑的列表中。
这些 nil
值是通过利用 nil
和 AutoLISP 中的空列表 ()
的二元性删除的,通过应用 append
函数附加所有子列表 &由 mapcar
.
3。 vl-remove-if-not
(defun massoc3 ( key lst )
(mapcar 'cdr
(vl-remove-if-not
(function (lambda ( x ) (= key (car x))))
lst
)
)
)
正如锡罐上所说:如果提供给 vl-remove-if-not
函数的谓词函数 returns nil
(vl-remove-if
也可以与一个否定的谓词函数)——因此第一个元素不等于所需键的项目将被删除。
然后 mapcar
函数用于 return 与每个关联列表项关联的值 return 由 vl-remove-if-not
编辑。
4。 while / assoc / member
(defun massoc4 ( key lst / itm rtn )
(while (setq itm (assoc key lst))
(setq rtn (cons (cdr itm) rtn) lst (cdr (member itm lst)))
)
(reverse rtn)
)
此方法比之前的方法更有效,因为 assoc
和 member
函数用于直接跳转到提供的列表中的目标项,而不是迭代 &测试每一项。
assoc
return 是关联列表中第一次出现的键,member
return 是列表的尾部,第一项等于提供的参数。
这样,assoc
函数检索目标项,member
函数returns从此项开始的列表的其余部分,并重复重新定义列表通过使用 cdr
.
5。递归/关联/成员
(defun massoc5 ( key lst / itm )
(if (setq itm (assoc key lst))
(cons (cdr itm) (massoc5 key (cdr (member itm lst))))
)
)
然而,在上述情况下的变体,在这种情况下,不是为找到的每个项目重新定义列表,而是将列表的其余部分作为参数传递给函数的递归评估。
6。 acet-list-m-assoc(快速工具)
(defun massoc6 ( key lst )
(mapcar 'cdr (acet-list-m-assoc key lst))
)
此版本的函数使用 acet-list-m-assoc
定义为 Express Tools 库的一部分的函数,作为完整版本 AutoCAD 的可选补充提供。
但这是作弊! :-)
7。基本递归
(defun massoc7 ( key lst )
(if lst
(if (= key (caar lst))
(cons (cdar lst) (massoc7 key (cdr lst)))
(massoc7 key (cdr lst))
)
)
)
最后一个示例本质上是上面演示的 foreach
示例的递归版本。该函数只查看提供的列表中的第一项,如果第一个元素与 key
参数匹配,则它 cons
到列表 return 由递归调用编辑与列表的其余部分一起,否则列表的其余部分将传递给递归调用,而不会将项目添加到 return.
例子
既然我们已经讨论了可以定义此类函数的各种方式,那么应该如何使用此类函数?
上述每个函数都接受两个参数:'key' 和关联列表。这在语法上与标准 AutoLISP assoc
函数相同。
此类函数可用于获取与 DXF 关联列表中的 DXF 组 10 关联的所有值,使用语法:
(massoc 10 <dxf-data>)
例如(在 Visual LISP IDE 控制台):
;; Obtain a LWPOLYLINE entity
_$ (setq ent (car (entsel)))
<Entity name: 7ffff706880>
;; Retrieve the DXF data
_$ (setq dxf (entget ent))
((-1 . <Entity name: 7ffff706880>) (0 . "LWPOLYLINE") ... (91 . 0) (210 0.0 0.0 1.0))
;; Obtain the values associated with all DXF group 10 entries
_$ (massoc 10 dxf)
((13.0161 12.4807) (25.727 12.4807) (25.727 18.6426) (13.0161 18.6426))
这可以通过以下方式在示例程序中使用:
(defun c:test ( / dxf ent )
(if
(and
(setq ent (car (entsel "\nSelect rectangle: ")))
(setq dxf (entget ent))
(= "LWPOLYLINE" (cdr (assoc 0 dxf)))
)
(print (massoc 10 dxf))
)
(princ)
)
(defun massoc ( key lst / rtn )
(foreach x lst
(if (= key (car x))
(setq rtn (cons (cdr x) rtn))
)
)
(reverse rtn)
)
性能注意事项
就性能而言,同一函数的上述变体并不相同 - 迭代所提供列表中每个项目的变体的效率低于使用 'skip' 直接针对目标项目的变体 in-built 函数,例如 assoc
和 member
.
作为快速比较,请考虑以下基准测试结果:
;;;Benchmarking ................Elapsed milliseconds / relative speed for 32768 iteration(s):
;;;
;;; (MASSOC5 2 L).....1482 / 1.25 <fastest> ;; recursive/assoc/member
;;; (MASSOC4 2 L).....1482 / 1.25 ;; while/assoc/member
;;; (MASSOC6 2 L).....1498 / 1.24 ;; acet-list-m-assoc
;;; (MASSOC3 2 L).....1638 / 1.13 ;; vl-remove-if-not
;;; (MASSOC7 2 L).....1747 / 1.06 ;; basic recursion
;;; (MASSOC1 2 L).....1748 / 1.06 ;; foreach
;;; (MASSOC2 2 L).....1856 / 1 <slowest> ;; append/mapcar
正如预期的那样,assoc/member
函数被证明是最快的,Express Tools 函数紧随其后。