找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 4339|回复: 8

[LISP程序]:将选定的两条曲线连成一条(vlisp+vba源码)

[复制链接]
发表于 2005-8-11 23:57:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
只为表示对晓东家园的支持。
先给出Vlisp的,再给出VBA的。

  1. ;;; 环境初始化
  2. (vl-load-com) ;_ 确保加载了 activex 支持

  3. ;;; c:ccc
  4. ;;; 将相邻的两条曲线合并成一条曲线,
  5. ;;; 同时如果一条曲线的两端点相邻则将此曲线封闭。
  6. ;;; 用户可手工选择两条曲线(spline,*polyline),或一条曲线,先选后选均可。
  7. (defun c:ccc (/                   comclosedist        fpprecision  selsets
  8.               selset           filtertype        filterdata   curve1
  9.               fplist1           curve2        fplist2             fparray
  10.               statan           endtan        newcurve     newcurvearray
  11.              )
  12.   (setq        *thisdrawing* (vla-get-activedocument (vlax-get-acad-object))
  13.         *modelspace*  (vla-get-ModelSpace *thisdrawing*)
  14.   )
  15.   (setq        comclosedist
  16.          10 ;_ 小于这个距离才合并或封闭
  17.         fpprecision
  18.          1.01 ;_ 获取 fitpoint 时使用的精度
  19.         filtertype
  20.          0 ;_ 0 在DXF格式中是 图元类型的组码
  21.         filterdata
  22.          "spline,*polyline" ;_ 图元类型的值
  23.         newcurve nil
  24.   )
  25.   ;; 曲线选择,一条或两条
  26.   (setq selsets (vla-get-selectionsets *thisdrawing*))
  27.   (if (= (vla-get-count selsets) 0)
  28.     (vla-add selsets (vlax-make-variant "ss1"))
  29.   )
  30.   (setq selset (vla-item selsets 0))
  31.   (vla-clear selset)
  32.   (vla-select
  33.     selset
  34.     acSelectionSetPrevious
  35.     filtertype
  36.     filterdata
  37.   )
  38.   (if (= 0 (vla-get-count selset))
  39.     (progn
  40.       (prompt
  41.         "\n请选择两条相邻的 spline,*polyline <退出>:"
  42.       )
  43.                                         ; (vla-SelectOnScreen selset filtertype filterdata)
  44.       (vla-SelectOnScreen selset)
  45.     )
  46.   )
  47.   ;; 进行曲线合并
  48.   (if (= 2 (vla-get-count selset))
  49.     (progn
  50.       ;; 获取第1条曲线的拟合点列表 fitpoints 。
  51.       (setq curve1 (vla-item selset 0))
  52.       (if (= "acdbspline" (strcase (vla-get-ObjectName curve1) t))
  53.         (setq fplist1 (spline_fplist curve1 fpprecision)) ;_ 对 spline ,直接或间接取它的 fitpoint 。
  54.         (setq fplist1 (pline_vertexlist curve1)) ;_ 对 *polyline ,取其 vertex 为 fitpoint 。
  55.       )
  56.       ;; 获取第2条曲线的拟合点列表 fitpoints 。
  57.       (setq curve2 (vla-item selset 1))
  58.       (if (= "acdbspline" (strcase (vla-get-ObjectName curve2) t))
  59.         (setq fplist2 (spline_fplist curve2 fpprecision)) ;_ 对 spline ,直接或间接取它的 fitpoint 。
  60.         (setq fplist2 (pline_vertexlist curve2)) ;_ 对 *polyline ,取其 vertex 为 fitpoint 。
  61.       )
  62.       ;; 删除旧曲线
  63.       (vla-delete curve1)
  64.       (vla-delete curve2)
  65.       ;; 合并两个fplist生成新曲线
  66.       (setq fplist1 (spline_combine2fpl fplist1 fplist2))
  67.       (setq fparray (vlax-make-safearray
  68.                       vlax-vbdouble
  69.                       (cons 0 (1- (length fplist1)))
  70.                     )
  71.       )
  72.       (vlax-safearray-fill fparray fplist1)
  73.       (setq
  74.         statan (setq
  75.                  endtan        (vlax-make-safearray vlax-vbDouble '(0 . 2))
  76.                )
  77.       )
  78.       (setq newcurve (vla-addspline *modelspace* fparray statan endtan))
  79.       ;; 将新曲线的 fitpoint 都 purge 掉,以减少图形数据量。
  80. ;;;      (vla-PurgeFitData newcurve)
  81.       ;; 将曲线加入 selset ,以供进一步处理
  82.       (vla-clear selset)
  83.       (setq newcurvearray (vlax-make-safearray vlax-vbObject '(0 . 0)))
  84.       (vlax-safearray-fill newcurvearray (list newcurve))
  85.       (vla-additems selset newcurvearray)
  86.     )
  87.   )
  88.   ;; 将曲线封闭
  89.   (if (= 1 (vla-get-count selset))
  90.     (progn
  91.       (setq newcurve (vla-item selset 0))
  92.       (if (> comclosedist
  93.              (distance (vlax-curve-getstartpoint newcurve)
  94.                        (vlax-curve-getEndPoint newcurve)
  95.              )
  96.           )
  97.         (progn
  98.           ;; 用 ssadd 创建的 selection set , 才适用于命令行。
  99.           ;; selset 的类型是 VLA-Object acadSelectionSet , 不适用于命令行。
  100.           ;; 两种选择集不能互相转换:(vlax-vla-object->ename selset) 返回 nil 。
  101.           (setq lspselset (ssadd (vlax-vla-object->ename newcurve)))
  102.           ;; 调用acad命令行
  103.           (command "splinedit" lspselset "c" "" "")
  104.         )
  105.       )
  106.     )
  107.   )
  108.   ;; 结束
  109.   (princ)
  110. )

  111. ;;; 返回 *polyline 的顶点(vertex)列表
  112. ;;; 参数说明,
  113. ;;; plobj -- polyline object , 类型为 vla-object .
  114. ;;; -----
  115. (defun pline_vertexlist
  116.        (plobj / plname vtxlist fp fplist plinetype vtxcount i)
  117.   (setq        plname (vlax-vla-object->ename plobj)
  118.         fplist nil
  119.         i      0
  120.   )
  121.   (setq vtxlist (vlax-safearray->list (vla-get-coordinates plobj)))
  122.   (setq plinetype (strcase (vla-get-objectname plobj) t))
  123.   (cond
  124.     ((= "acdblwpolyline" plinetype) ;_ 这时 vtxlist 是 x,y 坐标
  125.      (progn
  126.        (setq vtxcount (/ (length vtxlist) 2))
  127.        (repeat vtxcount
  128.          (setq
  129.            fp (trans (list (nth i vtxlist) (nth (+ i 2) vtxlist) 0)
  130.                      plname
  131.                      0
  132.               )
  133.          ) ;_ 同时将点的坐标从 ocs 转换为 wcs
  134.          (setq fplist (cons fp fplist))
  135.          (setq i (+ i 2))
  136.        )
  137.      )
  138.     )
  139.     ((= "acdbpolyline" plinetype) ;_ 这时 vtxlist 是 x,y,z 坐标
  140.      (progn
  141.        (setq vtxcount (/ (length vtxlist) 3))
  142.        (repeat vtxcount
  143.          (setq fp (trans (list (nth i vtxlist)
  144.                                (nth (+ i 2) vtxlist)
  145.                                (nth (+ i 3) vtxlist)
  146.                          )
  147.                          plname
  148.                          0
  149.                   )
  150.          ) ;_ 同时将点的坐标从 ocs 转换为 wcs
  151.          (setq fplist (cons fp fplist))
  152.          (setq i (+ i 3))
  153.        )
  154.      )
  155.     )
  156.   )
  157.   fplist ;_ 返回值
  158. ) ;_ pline_vertexlist 结束

  159. ;;; 返回 spline 的拟合点(fitpoint)列表
  160. ;;; 参数说明,
  161. ;;; splobj -- spline object , 类型为 vla-object .
  162. ;;; precision -- 获取 fitpoint 时的精确度。相邻两 fitpoint 将曲线分段。
  163. ;;;              分段两端点的曲线长度与直接距离相比,比值不大于 precision 。
  164. ;;; 算法说明,
  165. ;;; 随着曲线长度增加,计算量也线性增加。
  166. ;;; -----
  167. (defun spline_fplist (splobj             precision            /
  168.                       list_fps                ; list of fitpoints
  169.                       len_fps                ; length of the curve coverd by the fipoint list
  170.                       wcslist_rmsegs        ; end wcs list of remaining segments
  171.                       lenlist_rmsegs        ; length list of remaining segments
  172.                       fpwcs_segsta        ; fitpoint WCS of the current segment start
  173.                       fpwcs_segend        ; fitpoint WCS of the current segment end
  174.                       per_seg                ; percent of the curve coverd by the current segment, ex, 0.5, 0.25, ...
  175.                       len_seg                ; length of current segment
  176.                       dist_seg                ; distance between the current segment's two ends
  177.                       acprecision        ; actual precision
  178.                       wcs_sta                ; wcs of the curve's start point
  179.                       wcs_end                ; wcs of the curve's end point
  180.                      )
  181.   ;; 防止精度不合理
  182.   ;; 太高精度会死机或引起超过值域等错误。
  183.   (if (< precision 1.005)
  184.     (setq precision 1.005)
  185.   )
  186.   ;; 初始化
  187.   (setq list_fps (cons (vlax-curve-getstartPoint splobj) nil)) ;_ 将起点坐标加到 fitpoint 列表中
  188.   (setq len_fps 0.0) ;_ list_fps 的覆盖长度为 0.0
  189.   (setq wcslist_rmsegs (cons (vlax-curve-getendPoint splobj) nil)) ;_ 将终点坐标加到 剩余段终点列表
  190.   (setq        lenlist_rmsegs
  191.          (cons (vlax-curve-getDistAtParam
  192.                  splobj
  193.                  (vlax-curve-getEndParam splobj)
  194.                )
  195.                nil
  196.          )
  197.   ) ;_ 将曲线全长加到 剩余段终点列表
  198.   ;; 获取 list_fps
  199.   (while (/= wcslist_rmsegs nil) ;_ 当list_fps未覆盖整条曲线时继续
  200.     ;;
  201.     (setq len_seg (car lenlist_rmsegs))
  202.     (setq fpwcs_segsta (car list_fps))
  203.     (setq fpwcs_segend (car wcslist_rmsegs))
  204.     (setq dist_seg (distance fpwcs_segsta fpwcs_segend))
  205.     (setq acprecision
  206.            (/ len_seg dist_seg))
  207.     (if        (> precision acprecision)
  208.       ;; 精度达到要求时
  209.       (progn
  210.         (setq list_fps (cons fpwcs_segend list_fps)) ;_ fitpoint 列表增加一个点
  211.         (setq len_fps (+ len_fps len_seg)) ;_ fitpoint 覆盖的长度增加
  212.         (setq lenlist_rmsegs (cdr lenlist_rmsegs)) ;_ 剩余段列表减少一段
  213.         (setq wcslist_rmsegs (cdr wcslist_rmsegs))
  214.       )
  215.       ;; 精度不足时
  216.       (progn
  217.         (setq len_seg (/ len_seg 2)) ;_ 将当前的段一分为 2
  218.         (setq lenlist_rmsegs
  219.                (cons len_seg (cons len_seg (cdr lenlist_rmsegs)))
  220.         ) ;_ 剩余段列表第一段变为两段
  221.         (setq wcslist_rmsegs
  222.                (cons
  223.                  (vlax-curve-getPointAtDist splobj (+ len_fps len_seg))
  224.                  wcslist_rmsegs
  225.                )
  226.         ) ;_ 剩余段终点增加一个

  227.       )
  228.     )
  229.   )
  230.   list_fps ;_ 返回值
  231. ) ;_ spline_fplist 结束

  232. ;;; 返回两个 spline 拟合点列表的合并列表
  233. ;;; Combine two FitPoint Lists .
  234. (defun spline_combine2fpl (fpl1 fpl2 / rev1 rev2 mdist ndist fpcount i)
  235.   ;; 判断最邻近的端点,并决定是否要将拟合点列表返序
  236.   ;; 第1次
  237.   (setq        rev1  nil ;_ fpl1 不需反序
  238.         rev2  nil ;_ fpl2 不需反序
  239.         mdist (distance (last fpl1) (car fpl2)) ;_ 最邻近的端点的距离
  240.   )
  241.   ;; 第2次
  242.   (setq ndist (distance (last fpl1) (last fpl2)))
  243.   (if (> mdist ndist)
  244.     (setq rev1        nil
  245.           rev2        1
  246.           mdist        ndist
  247.     )
  248.   )
  249.   ;; 第3次
  250.   (setq ndist (distance (car fpl1) (car fpl2)))
  251.   (if (> mdist ndist)
  252.     (setq rev1        1
  253.           rev2        nil
  254.           mdist        ndist
  255.     )
  256.   )
  257.   ;; 第4次
  258.   (setq ndist (distance (car fpl1) (last fpl2)))
  259.   (if (> mdist ndist)
  260.     (setq rev1        1
  261.           rev2        1
  262.           mdist        ndist
  263.     )
  264.   )
  265.   ;; 完成两个拟合点列表合并
  266.   (if rev1
  267.     (setq fpl1 (reverse fpl1))
  268.   )
  269.   (if rev2
  270.     (setq fpl2 (reverse fpl2))
  271.   )
  272.   (setq        fpl1        (append fpl1 fpl2)
  273.         fpl2        nil
  274.         fpcount        (length fpl1)
  275.         i        0
  276.   )
  277.   (repeat fpcount
  278.     (setq fpl2 (append fpl2 (nth i fpl1)))
  279.     (setq i (+ 1 i))
  280.   )
  281.   fpl2
  282. )


  283. 以下是 VBA 的
  284. ' ---------------------------------------
  285. ' 合并两条曲线, 合并结果为一条 spline .
  286. ' 合并后, 如果曲线两端点距离足够小, 则将此曲线封闭.
  287. ' ---------------------------------------
  288. Sub curvecbcl()
  289.     Dim curve As AcadObject
  290.     Dim sset As AcadSelectionSet
  291.     Dim ftype(0) As Integer
  292.     Dim fdata(0) As Variant
  293.     Dim isnewcurve As Boolean
  294.     ' 选择两条曲线
  295.     If ThisDrawing.SelectionSets.Count < 1 Then
  296.         Set sset = ThisDrawing.SelectionSets.Add("ss01")
  297.     Else
  298.         Set sset = ThisDrawing.SelectionSets.Item("ss01")
  299.     End If
  300.     sset.Clear
  301.     ftype(0) = 0
  302.     fdata(0) = "spline,*polyline"
  303.     sset.Select acSelectionSetPrevious, ftype, fdata   '完成曲线选择(预选方式)
  304.     ' selset.SelectOnScreen ftype, fdata  '完成曲线选择(后选方式)
  305.     Select Case sset.Count
  306.     Case 2
  307.         Set curve = curvecombine(sset, 10)    ' 10是合并限距
  308.         isnewcurve = True
  309.     Case 1
  310.         Set curve = sset.Item(0)
  311.         isnewcurve = False
  312.     Case Else
  313.         MsgBox "操作错误: 请选择两条曲线以供连接,或选择一条曲线以供封闭."
  314.     End Select
  315.     If Not curve Is Nothing Then
  316.         curveclose curve, 10, isnewcurve        ' 10是闭合限距
  317.     End If
  318. End Sub


  319. ' -----------------------
  320. ' 如果两条曲线端点足够近, 则合并其 fitpoint 生成一条 spline .
  321. ' 合并成功后,自动删除原来的两条曲线
  322. Private Function curvecombine(ByRef ss As AcadSelectionSet, ByVal distlimit As Double)
  323.     Dim fps1 As Variant ' FitPoints of curve 1
  324.     Dim fps1count As Long
  325.     Dim fps2 As Variant ' FitPoints of curve 2
  326.     Dim fps2count As Long
  327.     ' ----调用 addspline 所需的参数----------------------
  328.     Dim fpsall() As Double   ' FitPoints of all the 2 curves,
  329.     Dim statan(0 To 2) As Double  ' starttangen of the new curve
  330.     Dim endtan(0 To 2) As Double 'endtangen of the new curve
  331.     ' ----以上3个参数类型只能是数组,若改为variant,则绘制不成功-------
  332.     Dim tangent As Variant   ' 用于辅助处理 statan 和 endtan
  333.     Dim distx(0 To 1, 0 To 1) As Double   '端点距离
  334.     Dim distmin As Variant
  335.     distmin = Array(distlimit, 0, 0) '(端点最小距离,曲线1方向标志,曲线2方向标志)
  336.     Dim newcurve(0 To 0) As AcadSpline
  337.     '合并曲线应满足的条件
  338.     If Not (ss.Count = 2) Then
  339.         MsgBox "错误原因:选择的不是两条曲线."
  340.         Exit Function '只能选择2条曲线
  341.     End If
  342.     If ss.Item(0).Closed Or ss.Item(0).Closed Then
  343.         MsgBox "错误原因:选择的曲线中至少有一条是已经闭合的."
  344.         Exit Function '已闭合的不作合并
  345.     End If
  346.     If UBound(ss.Item(0).IntersectWith(ss.Item(1), acExtendNone)) >= 0 Then
  347.         MsgBox "错误原因:选择的两条曲线有交点."
  348.         Exit Function '有交点时不作合并
  349.     End If
  350.     '取得 FitPoints
  351.     If UCase(ss.Item(0).ObjectName) Like "*POLYLINE" Then
  352.         fps1 = wcscoords_xpl(ss.Item(0))    'polyline 的 vertex 视作 fitpoint
  353.     Else
  354.         fps1 = ss.Item(0).FitPoints
  355.     End If
  356.     fps1count = (UBound(fps1) + 1) / 3
  357.     If UCase(ss.Item(1).ObjectName) Like "*POLYLINE" Then
  358.         fps2 = wcscoords_xpl(ss.Item(1))    ' polyline 的 vertex 视作 fitpoint
  359.     Else
  360.         fps2 = ss.Item(1).FitPoints
  361.     End If
  362.     fps2count = (UBound(fps2) + 1) / 3
  363.     ' 相近的端点应足够近(不大于distlimit)
  364.     Dim pt1sta As Variant
  365.     Dim pt1end As Variant
  366.     Dim pt2sta As Variant
  367.     Dim pt2end As Variant
  368.     pt1sta = Array(fps1(0), fps1(1), fps1(2))
  369.     pt1end = Array(fps1(UBound(fps1) - 2), fps1(UBound(fps1) - 1), fps1(UBound(fps1) - 0))
  370.     pt2sta = Array(fps2(0), fps2(1), fps2(2))
  371.     pt2end = Array(fps2(UBound(fps2) - 2), fps2(UBound(fps2) - 1), fps2(UBound(fps2) - 0))
  372.     distx(0, 0) = distance(pt1sta, pt2sta)
  373.     distx(0, 1) = distance(pt1sta, pt2end)
  374.     distx(1, 0) = distance(pt1end, pt2sta)
  375.     distx(1, 1) = distance(pt1end, pt2end)
  376.     Dim i As Long, j As Long
  377.     For i = 0 To 1
  378.         For j = 0 To 1
  379.             If distx(i, j) <= distmin(0) Then
  380.                 distmin(0) = distx(i, j)
  381.                 distmin(1) = (-1) ^ (i + 1) ' = -1 时, 表示要将 fitpoint数组 fps1 反序加入总表
  382.                 distmin(2) = (-1) ^ j       ' = -1 时, 表示要将 fitpoint数组 fps2 反序加入总表
  383.             End If
  384.         Next
  385.     Next    ' 至此已知道最靠近的端点是哪两个
  386.     If distmin(1) = 0 Then
  387.         MsgBox "错误信息: 曲线端点距离太远了, 不作合并."
  388.         Exit Function
  389.     End If
  390.     ' 构造 fitpoint 总表(数组)
  391.    
  392.     ReDim fpsall((fps1count + fps2count) * 3 - 1)
  393.    
  394.     Dim firstpt As Long, lastpt As Long
  395.     If distmin(1) = -1 Then
  396.         firstpt = fps1count - 1
  397.         lastpt = 0
  398.     Else
  399.         firstpt = 0
  400.         lastpt = fps1count - 1
  401.     End If
  402.     j = 0
  403.     For i = firstpt To lastpt Step distmin(1)
  404.          fpsall(j + 0) = fps1(i * 3 + 0)
  405.          fpsall(j + 1) = fps1(i * 3 + 1)
  406.          fpsall(j + 2) = fps1(i * 3 + 2)
  407.          j = j + 3
  408.     Next        '至此 fitpoint 总表已构造了一半
  409.     If distmin(2) = -1 Then
  410.         firstpt = fps2count - 1
  411.         lastpt = 0
  412.     Else
  413.         firstpt = 0
  414.         lastpt = fps2count - 1
  415.     End If
  416.     For i = firstpt To lastpt Step distmin(2)
  417.          fpsall(j + 0) = fps2(i * 3 + 0)
  418.          fpsall(j + 1) = fps2(i * 3 + 1)
  419.          fpsall(j + 2) = fps2(i * 3 + 2)
  420.          j = j + 3
  421.     Next        '至此 fitpoint 总表已构造完成
  422.     ' 确定 fitpoint 总表两端点的 tangent 值
  423.     ' 先确定起点的, 即 statan .
  424.     If UCase(ss.Item(0).ObjectName) Like "*SPLINE" Then
  425.         ' 对 spline 保持原来的 tangent 值, 只调整方向.
  426.         If distmin(1) = -1 Then
  427.             tangent = ss.Item(0).EndTangent
  428.             statan(0) = -tangent(0): statan(1) = -tangent(1): statan(2) = -tangent(2)
  429.         Else
  430.             tangent = ss.Item(0).StartTangent
  431.             statan(0) = tangent(0): statan(1) = tangent(1): statan(2) = tangent(2)
  432.         End If  ' 对未连接的端点
  433.     Else
  434.         ' 对 polyline 使用两点射线为 tangen.
  435.         statan(0) = fpsall(3) - fpsall(0): statan(1) = fpsall(4) - fpsall(1): statan(2) = fpsall(5) - fpsall(2)
  436.         tangent = Abs(statan(0))
  437.         For i = 1 To 2
  438.             If Abs(statan(i)) > tangent Then
  439.                 tangent = Abs(statan(i))
  440.             End If
  441.         Next
  442.         For i = 0 To 2
  443.             statan(i) = statan(i) / tangent
  444.         Next
  445.     End If
  446.     ' 再确定终点的, 即 endtan
  447.     If UCase(ss.Item(1).ObjectName) Like "*SPLINE" Then
  448.         ' 对 spline 保持原来的 tangent 值, 只调整方向.
  449.         If distmin(2) = -1 Then
  450.             tangent = ss.Item(1).StartTangent
  451.             endtan(0) = -tangent(0): endtan(1) = -tangent(1): endtan(2) = -tangent(2)
  452.         Else
  453.             tangent = ss.Item(1).EndTangent
  454.             endtan(0) = tangent(0): endtan(1) = tangent(1): endtan(2) = tangent(2)
  455.         End If  ' 对未连接的端点
  456.     Else
  457.         ' 对 polyline 使用两点射线为 tangen , 并确定方向.
  458.         endtan(0) = fpsall((fps1count + fps2count - 1) * 3 + 0) - fpsall((fps1count + fps2count - 2) * 3 + 0)
  459.         endtan(1) = fpsall((fps1count + fps2count - 1) * 3 + 1) - fpsall((fps1count + fps2count - 2) * 3 + 1)
  460.         endtan(2) = fpsall((fps1count + fps2count - 1) * 3 + 2) - fpsall((fps1count + fps2count - 2) * 3 + 2)
  461.         tangent = Abs(endtan(0))
  462.         For i = 1 To 2
  463.             If Abs(endtan(i)) > tangent Then
  464.                 tangent = Abs(endtan(i))
  465.             End If
  466.         Next
  467.         For i = 0 To 2
  468.             endtan(i) = endtan(i) / tangent
  469.         Next
  470.     End If
  471.    
  472.     ' 删除原有曲线
  473.     ss.Erase
  474.     ss.Clear
  475.     ' 生成新曲线(spline)
  476.     Set newcurve(0) = ThisDrawing.ModelSpace.AddSpline(fpsall, statan, endtan)
  477.     ' ThisDrawing.Regen (True)
  478.     ' 返回曲线对象
  479.     Set curvecombine = newcurve(0)
  480. End Function

  481. ' ---------------------------------
  482. ' 一条曲线两端足够近, 则将此曲线闭合.
  483. Private Sub curveclose(ByRef curve As AcadObject, ByVal distlimit As Double, isnewcurve As Boolean)
  484.     ' curve 为需封闭的曲线
  485.     ' distlimit 为封闭限制距离(端点距离不可大于此值)
  486.     ' isnewcurve 表示曲线是新生成的(选择方法不同).
  487.     Dim cmdtxt As String
  488.     Dim fps As Variant, fpscount As Long
  489.     Dim ptsta As Variant, ptend As Variant
  490.     If curve.Closed Then
  491.         ThisDrawing.Utility.Prompt "提示: 曲线原已闭合"
  492.         Exit Sub '已闭合的直接退出
  493.     End If
  494.      '取得 FitPoints
  495.     If UCase(curve.ObjectName) Like "*POLYLINE" Then
  496.         fps = wcscoords_xpl(curve)    'polyline 的 vertex 视作 fitpoint
  497.     Else
  498.         fps = curve.FitPoints
  499.     End If
  500.     fpscount = (UBound(fps) + 1) / 3
  501.     ptsta = Array(fps(0), fps(1), fps(2))
  502.     ptend = Array(fps((fpscount - 1) * 3 + 0), fps((fpscount - 1) * 3 + 1), fps((fpscount - 1) * 3 + 2))
  503.     If distance(ptsta, ptend) <= distlimit Then
  504.         ' 通过命令行调用 lisp 指令, 从而利用 autocad 的 splinedit 指令,(一时找不到更好的方法).
  505.         If isnewcurve Then
  506.             cmdtxt = "(command " & """splinedit""" & " " & "(ssget ""l"")" & " " & """C""" & " """" )" & " "
  507.         Else
  508.             cmdtxt = "(command " & """splinedit""" & " " & "(ssget ""p"")" & " " & """C""" & " """" )" & " "
  509.         End If
  510.         ThisDrawing.SendCommand cmdtxt
  511.         ThisDrawing.Regen (True)
  512.     End If
  513. End Sub
  514. ' 将一条 Xpolyline 的全部顶点坐标由OCS转换为WCS
  515. Function wcscoords_xpl(ByRef xpl As AcadObject)
  516.     Dim ub_ocs As Integer   'OCS项点列表的上界
  517.     Dim ptcount As Integer  '顶点的个数
  518.     Dim wcspt As Variant
  519.     Dim ocspt(0 To 2) As Double, _
  520.         ocspt_tmp As Variant
  521.     Dim wcspts() As Double
  522.     ub_ocs = UBound(xpl.Coordinates)
  523.     Select Case UCase(xpl.ObjectName)
  524.         Case "ACDBPOLYLINE"
  525.             ptcount = (ub_ocs + 1) / 2
  526.         Case "ACDBLWPOLYLINE"
  527.             ptcount = (ub_ocs + 1) / 2
  528.         Case Else
  529.             Exit Function
  530.     End Select
  531.     ReDim wcspts(0 To ptcount * 3 - 1) As Double
  532.     Dim i As Integer
  533.     For i = 0 To ptcount - 1
  534.         ocspt_tmp = xpl.Coordinate(i)
  535.         ocspt(0) = ocspt_tmp(0)
  536.         ocspt(1) = ocspt_tmp(1)
  537.         ocspt(2) = xpl.Elevation
  538.         wcspt = ThisDrawing.Utility.TranslateCoordinates(ocspt, acOCS, acWorld, False, xpl.Normal)
  539.         wcspts(i * 3 + 0) = wcspt(0)
  540.         wcspts(i * 3 + 1) = wcspt(1)
  541.         wcspts(i * 3 + 2) = wcspt(2)
  542.     Next
  543.     wcscoords_xpl = wcspts
  544. End Function

  545. ' 计算两点之间距离
  546. Function distance(ByVal sp As Variant, ByVal ep As Variant) As Double
  547.     Dim x As Double
  548.     Dim y As Double
  549.     Dim z As Double
  550.     x = sp(0) - ep(0)
  551.     y = sp(1) - ep(1)
  552.     z = sp(2) - ep(2)
  553.     distance = Sqr((Sqr((x ^ 2) + (y ^ 2)) ^ 2) + (z ^ 2))
  554. End Function
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
发表于 2005-8-12 09:48:13 | 显示全部楼层
好位置
Vlisp,如何加载,我用AP加载后执行ccc,出现如下错误:
错误 : ActiveX 服务器返回错误: 未知名称: Coordinates
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2005-8-12 14:07:52 | 显示全部楼层
經測試LISP 部分 selsets  變量由於在使用的過程中. 如果用戶用完undo回去. 再用這個程序時selsets變量內部的內容沒有清空, 使用就出錯了.
程序修改建議如用vla難解決可改用lisp的ssget涵數代替. 這樣可大大的減少出錯.



;;; ?境初始化
(vl-load-com) ;_ 确保加?了 activex 支持

;;; c:ccc
;;; 將相今的兩條曲線合并成一條曲線,
;;; 同時如果一條曲線的兩端點相鄰則將此曲線封閉。
;;; 用戶可手工選擇兩曲線(spline,*polyline),或一條曲線,先選后選均可。
(defun c:ccc (/                   comclosedist        fpprecision  selsets
              selset           filtertype        filterdata   curve1
              fplist1           curve2        fplist2             fparray
              statan           endtan        newcurve     newcurvearray
             )
  (setq        *thisdrawing* (vla-get-activedocument (vlax-get-acad-object))
        *modelspace*  (vla-get-ModelSpace *thisdrawing*)
  )
  (setq        comclosedist 10 ;_ 小于這個距离才合并或封閉
        fpprecision 1.01 ;_ ?取 fitpoint ?使用的精度
        filtertype 0 ;_ 0 在DXF格式中是 圖元類型的組碼
        filterdata "spline,*polyline" ;_ 圖元類型的值
        newcurve nil
  )
  ;; 曲線選擇,一條或兩條
  (setq selsets (ssget '((0 . "SPLINE,*POLYLINE"))))
  ;|(setq selsets (vla-get-selectionsets *thisdrawing*))
  (if (= (vla-get-count selsets) 0)
    (vla-add selsets (vlax-make-variant "ss1"))
  )
  (vla-update selset)
  (setq selset (vla-item selsets 0))
  (vla-clear selset)
;;;  (vla-select  selset  acSelectionSetPrevious filtertype  filterdata)
  (if (= 0 (vla-get-count selset))
    (progn
      (prompt"\n請選擇兩條相鄰的 spline,*polyline <退出>:")
      ; (vla-SelectOnScreen selset filtertype filterdata)
      (vla-SelectOnScreen selset)
    )
  )|;
  ;; 進行曲線合并
  (if (= 2 (SSLENGTH selsets));(= 2 (vla-get-count selset))
    (progn
      ;; 選取第1條曲線的合點列表 fitpoints 。
      ;;;(setq curve1 (vla-item selset 0))
      (setq curve1 (VLAX-ENAME->VLA-OBJECT (SSNAME selsets 0 ))); (vla-item selset 0))
      (if (= "acdbspline" (strcase (vla-get-ObjectName curve1) t))
        (setq fplist1 (spline_fplist curve1 fpprecision)) ;_ 對 spline ,直接或?接取它的 fitpoint 。
        (setq fplist1 (pline_vertexlist curve1)) ;_ 對 *polyline ,取其 vertex 為 fitpoint 。
      )
      ;; 選取第2條曲線的合點列表 fitpoints 。
      ;;;(setq curve2 (vla-item selset 1))
      (setq curve2 (VLAX-ENAME->VLA-OBJECT (SSNAME selsets 1)))
      (if (= "acdbspline" (strcase (vla-get-ObjectName curve2) t))
        (setq fplist2 (spline_fplist curve2 fpprecision)) ;_ ? spline ,直接或?接取它的 fitpoint 。
        (setq fplist2 (pline_vertexlist curve2)) ;_ ? *polyline ,取其 vertex ? fitpoint 。
      )
      ;;刪除曲線
      (vla-delete curve1)
      (vla-delete curve2)
      ;; 合并點表fplist生成新曲線
      (setq fplist1 (spline_combine2fpl fplist1 fplist2))
      (setq fparray (vlax-make-safearray
                      vlax-vbdouble
                      (cons 0 (1- (length fplist1)))
                    )
      )
      (vlax-safearray-fill fparray fplist1)
      (setq
        statan (setq
                 endtan        (vlax-make-safearray vlax-vbDouble '(0 . 2))
               )
      )
      (setq newcurve (vla-addspline *modelspace* fparray statan endtan))
      ;; ?新曲?的 fitpoint 都 purge 掉,以?少?形?据量。
;;;      (vla-PurgeFitData newcurve)
      ;; ?曲?加入 selset ,以供?一步?理
      (vla-clear selset)
      (setq newcurvearray (vlax-make-safearray vlax-vbObject '(0 . 0)))
      (vlax-safearray-fill newcurvearray (list newcurve))
      (vla-additems selset newcurvearray)
    )
  )
  ;; ?曲?封?
  (if (= 1 (vla-get-count selset))
    (progn
      (setq newcurve (vla-item selset 0))
      (if (> comclosedist
             (distance (vlax-curve-getstartpoint newcurve)
                       (vlax-curve-getEndPoint newcurve)
             )
          )
        (progn
          ;; 用 ssadd ?建的 selection set , 才适用于命令行。
          ;; selset 的?型是 VLA-Object acadSelectionSet , 不适用于命令行。
          ;; ?种??集不能互相??:(vlax-vla-object->ename selset) 返回 nil 。
          (setq lspselset (ssadd (vlax-vla-object->ename newcurve)))
          ;; ?用acad命令行
          (command "splinedit" lspselset "c" "" "")
        )
      )
    )
  )
  ;; ?束
  (princ)
)

;;; 返回 *polyline 的??(vertex)列表
;;; ???明,
;;; plobj -- polyline object , ?型? vla-object .
;;; -----
(defun pline_vertexlist
       (plobj / plname vtxlist fp fplist plinetype vtxcount i)
  (setq        plname (vlax-vla-object->ename plobj)
        fplist nil
        i      0
  )
  (setq vtxlist (vlax-safearray->list (vla-get-coordinates plobj)))
  (setq plinetype (strcase (vla-get-objectname plobj) t))
  (cond
    ((= "acdblwpolyline" plinetype) ;_ ?? vtxlist 是 x,y 坐?
     (progn
       (setq vtxcount (/ (length vtxlist) 2))
       (repeat vtxcount
         (setq
           fp (trans (list (nth i vtxlist) (nth (+ i 2) vtxlist) 0)
                     plname
                     0
              )
         ) ;_ 同???的坐?? ocs ??? wcs
         (setq fplist (cons fp fplist))
         (setq i (+ i 2))
       )
     )
    )
    ((= "acdbpolyline" plinetype) ;_ ?? vtxlist 是 x,y,z 坐?
     (progn
       (setq vtxcount (/ (length vtxlist) 3))
       (repeat vtxcount
         (setq fp (trans (list (nth i vtxlist)
                               (nth (+ i 2) vtxlist)
                               (nth (+ i 3) vtxlist)
                         )
                         plname
                         0
                  )
         ) ;_ 同???的坐?? ocs ??? wcs
         (setq fplist (cons fp fplist))
         (setq i (+ i 3))
       )
     )
    )
  )
  fplist ;_ 返回值
) ;_ pline_vertexlist ?束

;;; 返回 spline 的?合?(fitpoint)列表
;;; ???明,
;;; splobj -- spline object , ?型? vla-object .
;;; precision -- ?取 fitpoint ?的精确度。相?? fitpoint ?曲?分段。
;;;              分段?端?的曲??度与直接距离相比,比值不大于 precision 。
;;; 算法?明,
;;; ??曲??度增加,?算量也?性增加。
;;; -----
(defun spline_fplist (splobj             precision            /
                      list_fps                ; list of fitpoints
                      len_fps                ; length of the curve coverd by the fipoint list
                      wcslist_rmsegs        ; end wcs list of remaining segments
                      lenlist_rmsegs        ; length list of remaining segments
                      fpwcs_segsta        ; fitpoint WCS of the current segment start
                      fpwcs_segend        ; fitpoint WCS of the current segment end
                      per_seg                ; percent of the curve coverd by the current segment, ex, 0.5, 0.25, ...
                      len_seg                ; length of current segment
                      dist_seg                ; distance between the current segment's two ends
                      acprecision        ; actual precision
                      wcs_sta                ; wcs of the curve's start point
                      wcs_end                ; wcs of the curve's end point
                     )
  ;; 防止精度不合理
  ;; 太高精度?死机或引起超?值域等??。
  (if (< precision 1.005)
    (setq precision 1.005)
  )
  ;; 初始化
  (setq list_fps (cons (vlax-curve-getstartPoint splobj) nil)) ;_ ?起?坐?加到 fitpoint 列表中
  (setq len_fps 0.0) ;_ list_fps 的覆??度? 0.0
  (setq wcslist_rmsegs (cons (vlax-curve-getendPoint splobj) nil)) ;_ ???坐?加到 剩余段??列表
  (setq        lenlist_rmsegs
         (cons (vlax-curve-getDistAtParam
                 splobj
                 (vlax-curve-getEndParam splobj)
               )
               nil
         )
  ) ;_ ?曲?全?加到 剩余段??列表
  ;; ?取 list_fps
  (while (/= wcslist_rmsegs nil) ;_ ?list_fps未覆?整?曲????
    ;;
    (setq len_seg (car lenlist_rmsegs))
    (setq fpwcs_segsta (car list_fps))
    (setq fpwcs_segend (car wcslist_rmsegs))
    (setq dist_seg (distance fpwcs_segsta fpwcs_segend))
    (setq acprecision
           (/ len_seg dist_seg))
    (if        (> precision acprecision)
      ;; 精度?到要求?
      (progn
        (setq list_fps (cons fpwcs_segend list_fps)) ;_ fitpoint 列表增加一??
        (setq len_fps (+ len_fps len_seg)) ;_ fitpoint 覆?的?度增加
        (setq lenlist_rmsegs (cdr lenlist_rmsegs)) ;_ 剩余段列表?少一段
        (setq wcslist_rmsegs (cdr wcslist_rmsegs))
      )
      ;; 精度不足?
      (progn
        (setq len_seg (/ len_seg 2)) ;_ ??前的段一分? 2
        (setq lenlist_rmsegs
               (cons len_seg (cons len_seg (cdr lenlist_rmsegs)))
        ) ;_ 剩余段列表第一段???段
        (setq wcslist_rmsegs
               (cons
                 (vlax-curve-getPointAtDist splobj (+ len_fps len_seg))
                 wcslist_rmsegs
               )
        ) ;_ 剩余段??增加一?

      )
    )
  )
  list_fps ;_ 返回值
) ;_ spline_fplist ?束

;;; 返回?? spline ?合?列表的合并列表
;;; Combine two FitPoint Lists .
(defun spline_combine2fpl (fpl1 fpl2 / rev1 rev2 mdist ndist fpcount i)
  ;; 判?最?近的端?,并?定是否要??合?列表返序
  ;; 第1次
  (setq        rev1  nil ;_ fpl1 不需反序
        rev2  nil ;_ fpl2 不需反序
        mdist (distance (last fpl1) (car fpl2)) ;_ 最?近的端?的距离
  )
  ;; 第2次
  (setq ndist (distance (last fpl1) (last fpl2)))
  (if (> mdist ndist)
    (setq rev1        nil
          rev2        1
          mdist        ndist
    )
  )
  ;; 第3次
  (setq ndist (distance (car fpl1) (car fpl2)))
  (if (> mdist ndist)
    (setq rev1        1
          rev2        nil
          mdist        ndist
    )
  )
  ;; 第4次
  (setq ndist (distance (car fpl1) (last fpl2)))
  (if (> mdist ndist)
    (setq rev1        1
          rev2        1
          mdist        ndist
    )
  )
  ;; 完成???合?列表合并
  (if rev1
    (setq fpl1 (reverse fpl1))
  )
  (if rev2
    (setq fpl2 (reverse fpl2))
  )
  (setq        fpl1        (append fpl1 fpl2)
        fpl2        nil
        fpcount        (length fpl1)
        i        0
  )
  (repeat fpcount
    (setq fpl2 (append fpl2 (nth i fpl1)))
    (setq i (+ 1 i))
  )
  fpl2
)
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2005-12-22 20:49:50 | 显示全部楼层
正在学习中
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-1-3 00:21:34 | 显示全部楼层
正在找这个东东,非常谢谢
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-1-3 01:13:58 | 显示全部楼层
两条都是spline的时候测试可以,用pline测试出现错误
命令: ccc
选择对象: 找到 1 个

选择对象: 指定对角点: 找到 1 个,总计 2 个

选择对象:

错误: 参数类型错误: safearrayp #<variant 8197 ...>
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2007-7-6 09:10:41 | 显示全部楼层
研究研究,试试看
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 9个

财富等级: 恭喜发财

发表于 2014-8-15 00:06:06 | 显示全部楼层
这个比较有用,做个标记
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 118个

财富等级: 日进斗金

发表于 2017-5-12 12:31:33 | 显示全部楼层
正需要,谢谢楼主
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-4-26 23:13 , Processed in 0.385150 second(s), 47 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表