qifeifei 发表于 2025-6-27 13:40:41

双线延申并偏移剪切

本帖最后由 qifeifei 于 2025-6-27 13:43 编辑

平时做平面图衣柜
需要用到这个代码;使用AI写的代码 调试了很多了 效果也不太理想
有时候可能达到自己想要的效果 有时候又抽风 求优化

(defun c:T5 (/ ss ent obj p1 p2 dir unit len p2new leftEnt rightEnt left right
                newp1 newp2 mid allLines i crossEnt crossP1 crossP2 x1 x2
                y1 y2 ip1 ip2)

(vl-load-com)
(prompt "\n 开始运行命令...")

;; 选择竖向直线
(if (setq ss (ssget '((0 . "LINE,LWPOLYLINE"))))
    (progn
      (setq ent (ssname ss 0)
            obj (vlax-ename->vla-object ent)
            p1 (vlax-get obj 'StartPoint)
            p2 (vlax-get obj 'EndPoint)
            dir (mapcar '- p2 p1)
            len (distance p1 p2))

      ;; 判断竖线
      (if (< (abs (car dir)) 0.01)
      (progn
          (setq unit (mapcar '(lambda (x) (/ x len)) dir))
          (setq p2new (mapcar '+ p2 (mapcar '(lambda (x) (* x 18.0)) unit)))
          (vlax-put obj 'EndPoint p2new)
          (prompt (strcat "\n 已延申到新终点: "
                        (rtos (car p2new) 2 2) ", "
                        (rtos (cadr p2new) 2 2)))

          ;; 左右偏移
          (vla-offset obj 18.0)
          (setq rightEnt (entlast))
          (vla-offset obj -18.0)
          (setq leftEnt (entlast))

          ;; 获取偏移线坐标
          (setq right (vlax-ename->vla-object rightEnt))
          (setq left(vlax-ename->vla-object leftEnt))
          (setq newp1 (vlax-get obj 'StartPoint))
          (setq newp2 (vlax-get obj 'EndPoint))
          (setq mid (mapcar '(lambda (a b) (/ (+ a b) 2.0)) newp1 newp2))

          ;; 获取左右偏移的X范围
          (setq x1 (car (vlax-get left 'StartPoint)))
          (setq x2 (car (vlax-get right 'StartPoint)))
          (if (> x1 x2) (setq tmp x1 x1 x2 x2 tmp)) ; 交换x1 x2顺序

          ;; 查找在左右偏移线之间的横线
          (setq allLines (ssget "_X" '((0 . "LINE,LWPOLYLINE"))))
          (setq i -1)
          (while (and allLines (setq crossEnt (ssname allLines (setq i (1+ i)))))
            (setq crossObj (vlax-ename->vla-object crossEnt))
            (setq crossP1 (vlax-get crossObj 'StartPoint))
            (setq crossP2 (vlax-get crossObj 'EndPoint))

            ;; 横向判断:y 坐标相同,x 跨越 x1 ~ x2
            (if (and (equal (cadr crossP1) (cadr crossP2) 0.01)
                     (< (min (car crossP1) (car crossP2)) x1)
                     (> (max (car crossP1) (car crossP2)) x2))
            (progn
                ;; 计算交点:在左右偏移线 x1 和 x2 的交点处 break
                (setq y (cadr crossP1))
                (setq ip1 (list x1 y 0.0))
                (setq ip2 (list x2 y 0.0))

                ;; 执行 break
                (command "_.break" crossEnt ip1 ip2)
                (prompt "\n 成功剪切一条横线")
                (setq i (sslength allLines)) ; 跳出循环,只剪一条
            )
            )
          )

      )
      (prompt "\n 请只选择一条竖向的 LINE 或 LWPOLYLINE.")
      )
    )
    (prompt "\n 没有选择任何对象")
)
(princ)
)
成功展示:

qifeifei 发表于 2025-8-25 12:54:40

太感动了 我终于研制成了

你有种再说一遍 发表于 2025-6-27 18:03:20

哈哈,怎么感觉现在还比以前糟糕,以前都是求代码,
起码大家的代码都没有问题.

现在是拿着代码让别人改,别人还得从头看一次你的代码,
你代码的函数又不是别人的函数库,还得从头学一次.

真的把这个工作想得太简单了...
不是懂代码的用这个工具会让全部人都感受到痛苦.

qifeifei 发表于 2025-6-27 20:18:25

你有种再说一遍 发表于 2025-6-27 18:03
哈哈,怎么感觉现在还比以前糟糕,以前都是求代码,
起码大家的代码都没有问题.


好吧
我是有研究了部分;但是效果调试的不理想,才发出来
比较多的代码 我调试好的;我都自己用了 没发了

那等我空了 在研究下

xyp1964 发表于 2025-6-29 20:46:49

qifeifei 发表于 2025-6-27 20:18
好吧
我是有研究了部分;但是效果调试的不理想,才发出来
比较多的代码 我调试好的;我都自己用了 没 ...

;; 这种效果?


wlpkok 发表于 2025-6-29 22:15:01

xyp1964 发表于 2025-6-29 20:46
;; 这种效果?

大佬,求代码

qifeifei 发表于 2025-8-24 13:27:51

; --- 全局错误处理函数 ---
(defun *error* (msg)
(if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*QUIT*,*EXIT*,")))
    (princ (strcat "\n 程序出错或中断: " msg))
)
; 恢复系统变量
(if *old_cmdecho* (setvar "CMDECHO" *old_cmdecho*))
(if *old_osmode* (setvar "OSMODE" *old_osmode*))
(princ)
)

; --- 辅助函数:计算两条线段的交点 ---
; ent1, ent2: 实体名
; 返回: 交点坐标 (x y z) 或 nil
(defun get_line_intersection (ent1 ent2 / data1 data2 pt10 pt11 pt20 pt21 inters_pt)
(setq data1 (entget ent1))
(setq data2 (entget ent2))
(setq pt10 (cdr (assoc 10 data1)))
(setq pt11 (cdr (assoc 11 data1)))
(setq pt20 (cdr (assoc 10 data2)))
(setq pt21 (cdr (assoc 11 data2)))
; 计算线段交点 (nil 表示线段)
(setq inters_pt (inters pt10 pt11 pt20 pt21 nil))
inters_pt ; 返回交点或 nil
)

; --- 主函数 ---
(defun c:T5 (/ *old_cmdecho* *old_osmode* ss ent_original ent_data_original start_point_original end_point_original new_end_point mid_point_extended ent_left ent_right offset_dist selection_buffer ss_candidate_lines ent_hline pt_left pt_right i ent_check data_check pt1_check pt2_check mid_seg_ent_id found_mid_seg)
; --- 保存系统变量 ---
(setq *old_cmdecho* (getvar "CMDECHO"))
(setq *old_osmode* (getvar "OSMODE"))
(setvar "CMDECHO" 0) ; 关闭命令行回显
(setvar "OSMODE" 0); 关闭对象捕捉,确保点精确

; --- 参数设置 ---
(setq offset_dist 18.0)       ; 偏移距离和延伸距离
(setq selection_buffer 50.0) ; 用于选择水平线的缓冲区大小

; --- 1. 选择原始直线 ---
(princ "\n请选择一条直线: ")
(setq ss (ssget ":S" '((0 . "LINE")))) ; ":S" 限制只能选择一个实体

; --- 2. 检查是否选择了对象 ---
(if ss
    (progn
      ; --- 3. 获取原始实体信息 ---
      (setq ent_original (ssname ss 0))
      (setq ent_data_original (entget ent_original))
      (setq start_point_original (cdr (assoc 10 ent_data_original)))
      (setq end_point_original (cdr (assoc 11 ent_data_original)))

      ; --- 4. 延伸操作 (向北Y+) ---
      ; 确定哪个端点是"北端点" (Y值较大)
      (if (> (cadr start_point_original) (cadr end_point_original))
      (progn
          ; start_point_original 是北端点
          (setq new_end_point (list (car start_point_original) (+ (cadr start_point_original) offset_dist) (caddr start_point_original)))
          (setq ent_data_original (subst (cons 10 new_end_point) (assoc 10 ent_data_original) ent_data_original))
          ; mid_point_extended 应该是原始线段的中点
          (setq mid_point_extended (list
                                     (/ (+ (car end_point_original) (car new_end_point)) 2.0)
                                     (/ (+ (cadr end_point_original) (cadr new_end_point)) 2.0)
                                     (/ (+ (caddr end_point_original) (caddr new_end_point)) 2.0)
                                 )
          )
      )
      (progn
          ; end_point_original 是北端点
          (setq new_end_point (list (car end_point_original) (+ (cadr end_point_original) offset_dist) (caddr end_point_original)))
          (setq ent_data_original (subst (cons 11 new_end_point) (assoc 11 ent_data_original) ent_data_original))
          ; mid_point_extended 应该是原始线段的中点
          (setq mid_point_extended (list
                                     (/ (+ (car start_point_original) (car new_end_point)) 2.0)
                                     (/ (+ (cadr start_point_original) (cadr new_end_point)) 2.0)
                                     (/ (+ (caddr start_point_original) (caddr new_end_point)) 2.0)
                                 )
          )
      )
      )
      (entmod ent_data_original) ; 应用修改
      (princ "\n 选定直线已向北延伸18个单位。")

      ; --- 5. 向左偏移 ---
      (setq offset_point_left (list (- (car mid_point_extended) offset_dist) (cadr mid_point_extended) (caddr mid_point_extended)))
      (command "_.UNDO" "BE") ; 开始 UNDO 组
      (command "_.OFFSET" offset_dist ent_original offset_point_left "")
      (if (and (= (getvar 'CMDNAMES) "") (entlast)) ; 检查 OFFSET 是否成功
      (progn
          (setq ent_left (entlast))
          (princ "\n 向左偏移18个单位完成。")
      )
      (princ "\n 向左偏移可能失败。")
      )

      ; --- 6. 向右偏移 ---
      (setq offset_point_right (list (+ (car mid_point_extended) offset_dist) (cadr mid_point_extended) (caddr mid_point_extended)))
      (command "_.OFFSET" offset_dist ent_original offset_point_right "")
      (if (and (= (getvar 'CMDNAMES) "") (entlast)) ; 检查 OFFSET 是否成功
      (progn
          (setq ent_right (entlast))
          (princ "\n 向右偏移18个单位完成。")
      )
      (princ "\n 向右偏移可能失败。")
      )

      ; --- 7. 打断并删除水平线中间段 ---
      (princ "\n 开始查找并删除水平线中间段...")

      ; --- 8. 计算选择窗口 ---
      (setq min_x (- (car offset_point_left) selection_buffer))
      (setq max_x (+ (car offset_point_right) selection_buffer))
      (setq min_y (- (cadr mid_point_extended) selection_buffer))
      (setq max_y (+ (cadr mid_point_extended) selection_buffer))
      (setq corner1_window (list min_x max_y 0.0))   ; 左上
      (setq corner2_window (list max_x min_y 0.0)) ; 右下

      ; --- 9. 使用交叉窗口选择候选线 ---
      (setq ss_candidate_lines (ssget "C" corner1_window corner2_window '((0 . "LINE"))))
      
      (if ss_candidate_lines
      (progn
          (princ (strcat "\n 找到 " (itoa (sslength ss_candidate_lines)) " 条候选线段。"))
          (setq i 0)
          (repeat (sslength ss_candidate_lines)
            (setq ent_hline (ssname ss_candidate_lines i))

            ; --- 10. 排除原始线、左偏移线、右偏移线本身 ---
            (if (and (/= ent_hline ent_original) (/= ent_hline ent_left) (/= ent_hline ent_right))
            (progn
                ; --- 11. 计算交点 ---
                (setq pt_left (get_line_intersection ent_hline ent_left))
                (setq pt_right (get_line_intersection ent_hline ent_right))

                ; --- 12. 如果与两条竖线都有交点 ---
                (if (and pt_left pt_right)
                  (progn
                  (princ (strcat "\n 处理水平线..."))

                  ; --- 13. 执行两次打断 ---
                  ; 使用 _non 过滤器确保点精确传递
                  (command "_.BREAK" ent_hline (list '_non pt_left) (list '_non pt_left))
                  (if (/= (getvar 'CMDNAMES) "")
                      (princ "\n 第一次 BREAK 可能失败。")
                  )

                  (command "_.BREAK" ent_hline (list '_non pt_right) (list '_non pt_right))
                  (if (/= (getvar 'CMDNAMES) "")
                      (princ "\n 第二次 BREAK 可能失败。")
                  )

                  ; --- 14. 查找并删除中间段 ---
                  ; 再次选择窗口内的线,查找端点为 P1 和 P2 的线段
                  (setq ss_post_break (ssget "C" corner1_window corner2_window '((0 . "LINE"))))
                  (setq found_mid_seg nil) ; 标记是否找到
                  (if ss_post_break
                      (progn
                        (setq j 0)
                        (repeat (sslength ss_post_break)
                        (setq ent_check (ssname ss_post_break j))
                        (setq data_check (entget ent_check))
                        (setq pt1_check (cdr (assoc 10 data_check)))
                        (setq pt2_check (cdr (assoc 11 data_check)))
                        ; 检查端点是否为 P1 和 P2 (顺序无关,带容差)
                        (if (or
                              (and (< (distance pt1_check pt_left) 1e-4) (< (distance pt2_check pt_right) 1e-4))
                              (and (< (distance pt1_check pt_right) 1e-4) (< (distance pt2_check pt_left) 1e-4))
                              )
                            (progn
                              (setq found_mid_seg T)
                              (entdel ent_check) ; 删除找到的中间段
                              (princ "\n 已删除中间段。")
                              (setq j (sslength ss_post_break)) ; 找到即退出
                            )
                        )
                        (setq j (1+ j))
                        ) ; repeat j
                      ) ; progn if ss_post_break
                  ) ; if ss_post_break
                  (if (not found_mid_seg)
                      (princ "\n 未能找到中间段进行删除。")
                  )

                  ) ; if (and pt_left pt_right)
                ) ; if (/= ent_...)
            ) ; progn
            ) ; if ss_candidate_lines
            (setq i (1+ i))
          ) ; repeat i
          (princ "\n 候选线处理完成。")
      )
      (princ "\n 未找到候选线段。")
      ) ; if ss_candidate_lines

      (command "_.UNDO" "E") ; 结束 UNDO 组
      (command "_.REGEN") ; 最终重生成图形
      (princ "\n 所有操作已完成。")
    )
    ; --- 如果没有选择对象 ---
    (princ "\n 错误: 请先选择一条直线。")
)

; --- 恢复系统变量 ---
(setvar "CMDECHO" *old_cmdecho*)
(setvar "OSMODE" *old_osmode*)
(princ)
)

(princ "\nT5命令已加载。命令: T5")
(princ)至少方向对了 回头在研究剪切
页: [1]
查看完整版本: 双线延申并偏移剪切