Autolisp 实体数据检索

Sys*_*ive 0 lisp arrays list autocad autolisp

我正在尝试 autocad,我想在矩形和直线之间建立一条“高速公路”。我需要矩形中的 2 个点。有任何想法吗?

(setq en(car(entsel"\Get rectangle : ")))
 (entget en)
Run Code Online (Sandbox Code Playgroud)

我的整个代码

    (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)
)       
Run Code Online (Sandbox Code Playgroud)

Lee*_*Mac 6

在 AutoCAD 中,矩形(使用 AutoCADRECTANG命令创建)使用封闭的 2D 轻量折线 ( ) 实体表示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
)
Run Code Online (Sandbox Code Playgroud)

这里,每个顶点的 2D OCS 坐标使用 DXF 数据中的 DXF 组 10 条目存储。

有多种方法可以获取 DXF 数据中多次出现的 DXF 组所保存的值列表(从而获取折线的顶点列表)。

由于AutoLISP 函数返回关联列表中键的第一次出现,因此assoc我将这些函数称为massoc函数(即多个assoc)。


1.foreach

(defun massoc1 ( key lst / rtn )
    (foreach x lst
        (if (= key (car x))
            (setq rtn (cons (cdr x) rtn))
        )
    )
    (reverse rtn)
)
Run Code Online (Sandbox Code Playgroud)

第一个示例简单地迭代提供的关联列表中的每个项目,如果该项目的地址寄存器( )的内容等于所需的,则与键关联的值(或递减的内容) r寄存器 - ) 添加到函数返回的列表中。carkeycdr

该列表在返回之前会被反转,因为列表是反向构建的,每个项目都被推到列表的前面 - 这比使用append/的组合list按顺序构建列表要有效得多。


2.追加/mapcar

(defun massoc2 ( key lst )
    (apply 'append
        (mapcar
            (function
                (lambda ( x ) (if (= key (car x)) (list (cdr x))))
            )
            lst
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

然而,迭代列表的另一种方法是,因为mapcar返回每个列表项的所提供函数的评估结果,所以那些不满足条件的项如果if语句将导致nil出现在“mapcar.mapcar”返回的列表中。

nil通过利用 AutoLISP 中的对偶性nil和空列表(),应用该append函数附加 所返回的列表中存在的所有子列表和 nil 值,可以删除这些值mapcar


3. vl-如果不删除则删除

(defun massoc3 ( key lst )
    (mapcar 'cdr
        (vl-remove-if-not
            (function (lambda ( x ) (= key (car x))))
            lst
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

正如上面所说:如果提供给函数的谓词函数vl-remove-if-not返回nilvl-remove-if也可以与否定谓词函数一起使用),则项目将被删除 - 因此第一个元素不等于所需键的项目将被删除。

然后,该mapcar函数用于返回与 返回的每个关联列表项关联的值vl-remove-if-not


4. while/关联/成员

(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)
)
Run Code Online (Sandbox Code Playgroud)

此方法比之前的方法要高效得多,因为assoc&member函数用于直接跳转到提供的列表中的目标项目,而不是迭代 & 测试每个项目。

assoc返回关联列表中某个键的第一次出现,并member返回列表的尾部,其中第一项等于所提供的参数。

通过这种方式,assoc函数检索目标项,member函数返回从该项开始的列表的其余部分,并且通过使用 重复重新定义该列表以包含该目标项之后的所有项cdr


5. 递归/关联/成员

(defun massoc5 ( key lst / itm )
    (if (setq itm (assoc key lst))
        (cons (cdr itm) (massoc5 key (cdr (member itm lst))))
    )
)
Run Code Online (Sandbox Code Playgroud)

然而,上述情况的一种变体,在这种情况下,不是为找到的每个项目重新定义列表,而是将列表的其余部分作为参数传递给函数的递归计算。


6. acet-list-m-assoc(快速工具)

(defun massoc6 ( key lst )
    (mapcar 'cdr (acet-list-m-assoc key lst))
)
Run Code Online (Sandbox Code Playgroud)

此版本的函数利用了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))
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

最后一个示例本质上是上面演示的示例的递归版本foreach。该函数只是查看提供的列表中的第一项,如果第一个元素与参数匹配key,则将其cons与列表的其余部分一起添加到递归调用返回的列表中,否则将传递列表的其余部分递归调用,但没有将项目添加到返回值中。


例子

现在我们已经讨论了定义此类函数的各种方式,那么应该如何使用此类函数呢?

上述每个函数都接受两个参数:一个“键”和一个关联列表。这在语法上与标准 AutoLISP 函数相同assoc

这样的函数可用于获取 DXF 关联列表中与 DXF 组 10 关联的所有值,使用以下语法:

(massoc 10 <dxf-data>)
Run Code Online (Sandbox Code Playgroud)

例如(在 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))
Run Code Online (Sandbox Code Playgroud)

这可以通过以下方式在示例程序中使用:

(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)
)
Run Code Online (Sandbox Code Playgroud)

性能考虑因素

就性能而言,同一函数的上述变体并不相同 - 那些迭代所提供列表中的每个项目的效率低于使用内置函数(例如 和 )直接“跳”到目标项目的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
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,这些assoc/member功能被证明是最快的,Express Tools 功能紧随其后。