Jump to content

Recommended Posts

Posted
;;----------------------------=={ SmartPath }==-----------------------------;;
;;                                                                          ;;
;;  Creates a path connecting selected objects using various methods.       ;;
;;  Synthesized and enhanced by ajmalps, based on concepts from  	        ;;
;;  scripts by Kent Cooper, BlackBox, RJP, cab, and others.                 ;;
;;                                                                          ;;
;;  Command: SmartPath                                                      ;;
;;                                                                          ;;
;;--------------------------------------------------------------------------;;
;;  Date: August 6, 2025 (Fixed error handler on clean exit)                ;;
;;--------------------------------------------------------------------------;;

(vl-load-com)

(defun c:SmartPath
       (/ *error* _get_midpoints _sort_nearest _sort_along_path _get_wire_settings doc ov_osmode ov_cmdecho
	  sort_mode node_ss path_ent point_list sorted_list start_pt output_type layer)

  ;; --- CORRECTED Robust Error Handler ---
  (defun *error* (msg)
    (if ov_cmdecho (setvar 'CMDECHO ov_cmdecho))
    (if ov_osmode (setvar 'OSMODE ov_osmode))
    (if doc (vla-endundomark doc))
    ;; Check if msg is a valid string before trying to process it
    (if (and msg (not (wcmatch (strcase msg t) "*CANCEL*,*QUIT*,*BREAK*")))
      (princ (strcat "\nError: " msg))
    )
    (princ)
  )

  ;; --- Helper: Get Center of Any Object's Bounding Box ---
  (defun _get_midpoints (ss / i ent vla_obj pt1 pt2 pt_list)
    (setq i 0)
    (repeat (sslength ss)
      (setq ent (ssname ss i))
      (if (and (setq vla_obj (vlax-ename->vla-object ent))
	       (vlax-method-applicable-p vla_obj 'GetBoundingBox)
	  )
	(progn
	  (vla-GetBoundingBox vla_obj 'pt1 'pt2)
	  (setq pt_list (cons (mapcar '(lambda (a b) (/ (+ a b) 2.0)) (vlax-safearray->list pt1) (vlax-safearray->list pt2)) pt_list))
	)
      )
      (setq i (1+ i))
    )
    pt_list
  )

  ;; --- Helper: Sort by Nearest Neighbor ---
  (defun _sort_nearest (pt_list / current_pt sorted_list closest_pt)
    (setq current_pt (car pt_list) pt_list (cdr pt_list) sorted_list (list current_pt))
    (while pt_list
      (setq closest_pt (car pt_list))
      (foreach pt (cdr pt_list) (if (< (distance current_pt pt) (distance current_pt closest_pt)) (setq closest_pt pt)))
      (setq current_pt closest_pt sorted_list (cons current_pt sorted_list) pt_list (vl-remove current_pt pt_list))
    )
    (reverse sorted_list)
  )

  ;; --- Helper: Sort Along a Guide Path ---
  (defun _sort_along_path (path_ent pt_list / path_obj)
    (setq path_obj (vlax-ename->vla-object path_ent))
    (mapcar 'cdr (vl-sort (mapcar '(lambda (pt) (cons (vlax-curve-getDistAtPoint path_obj (vlax-curve-getClosestPointTo path_obj pt)) pt)) pt_list) '(lambda (a b) (< (car a) (car b)))))
  )

  ;; --- Helper for Custom Wire Settings ---
  (defun _get_wire_settings ( / temp_h temp_a)
    (if (not *wire_height*) (setq *wire_height* 5.0))
    (if (not *wire_angle_deg*) (setq *wire_angle_deg* 15.0))
    (setq temp_h (getdist (strcat "\nEnter chamfer height <" (rtos *wire_height*) ">: ")))
    (setq temp_a (getangle (strcat "\nEnter chamfer angle in degrees <" (rtos *wire_angle_deg*) ">: ")))
    (if temp_h (setq *wire_height* temp_h))
    (if temp_a (setq *wire_angle_deg* (/ (* temp_a 180.0) PI)))
    (list *wire_height* *wire_angle_deg*)
  )

  ;;============== Main Execution Starts Here ==============
  (setq doc (vla-get-activedocument (vlax-get-acad-object)))
  (vla-startundomark doc)

  (setq ov_cmdecho (getvar 'CMDECHO) ov_osmode (getvar 'OSMODE))
  (setvar 'CMDECHO 0)

  (initget "Nearest Path")
  (setq sort_mode (getkword "\nSelect sorting mode [Nearest/Path] <Nearest>: "))
  (if (not sort_mode) (setq sort_mode "Nearest"))

  (cond
    ((= sort_mode "Nearest")
     (princ "\nSelect objects to connect: ")
     (if (and (setq node_ss (ssget '((0 . "~VIEWPORT")))) (setq start_pt (getpoint "\nPick point to start path from: ")) (setq point_list (_get_midpoints node_ss)))
       (setq sorted_list (_sort_nearest (cons start_pt point_list)))
     )
    )
    ((= sort_mode "Path")
     (princ "\nSelect guide path (line, pline, spline, etc.): ")
     (if (and (setq path_ent (car (entsel))) (princ "\nSelect objects to connect: ") (setq node_ss (ssget '((0 . "~VIEWPORT")))) (setq point_list (_get_midpoints node_ss)))
       (setq sorted_list (_sort_along_path path_ent point_list))
     )
    )
  )

  (if sorted_list
    (progn
      (initget "Polyline Line Arc Spline Wire")
      (setq output_type (getkword "\nSelect output type [Polyline/Line/Arc/Spline/Wire] <Polyline>: "))
      (if (not output_type) (setq output_type "Polyline"))

      (setq layer (getstring (strcat "\nEnter layer for path <" (getvar "CLAYER") ">: ")))
      (if (= "" layer) (setq layer (getvar "CLAYER")))

      (setvar 'OSMODE 0)
      (princ (strcat "\nDrawing " output_type "..."))

      (cond
	((= output_type "Polyline")
	 (entmakex (append '((0 . "LWPOLYLINE") (100 . "AcDbEntity") (100 . "AcDbPolyline")) (list (cons 8 layer) (cons 90 (length sorted_list)) '(70 . 0)) (mapcar '(lambda (pt) (cons 10 pt)) sorted_list)))
	)
	((= output_type "Line")
	 (mapcar '(lambda (p1 p2) (entmakex (list '(0 . "LINE") (cons 8 layer) (cons 10 p1) (cons 11 p2)))) sorted_list (cdr sorted_list))
	)
	((= output_type "Arc")
	 (mapcar '(lambda (p1 p2 / ptm) (setq ptm (polar (polar p1 (angle p1 p2) (/ (distance p1 p2) 2.0)) (+ (angle p1 p2) (/ PI 2.0)) (* (distance p1 p2) 0.18))) (command "_.ARC" "_none" p1 "_none" ptm "_none" p2) (if (entlast) (command "_.CHPROP" (entlast) "" "_LA" layer ""))) sorted_list (cdr sorted_list))
	)
	((= output_type "Wire")
	 (progn
	   (setq settings (_get_wire_settings) w_height (car settings) w_ang_deg (cadr settings) w_ang_rad (/ (* w_ang_deg PI) 180.0))
	   (mapcar
	     '(lambda (p_start p_end / offset_start offset_end)
		(setq offset_start (polar p_start (+ (angle p_start p_end) w_ang_rad) w_height) offset_end (polar p_end (- (angle p_end p_start) w_ang_rad) w_height))
		(entmakex (list '(0 . "LWPOLYLINE") (cons 8 layer) '(100 . "AcDbEntity") '(100 . "AcDbPolyline") '(90 . 4) '(70 . 0) (cons 10 p_start) (cons 10 offset_start) (cons 10 offset_end) (cons 10 p_end)))
	      )
	     sorted_list
	     (cdr sorted_list)
	   )
	 )
	)
	((= output_type "Spline")
	 (entmakex (append '((0 . "SPLINE") (100 . "AcDbEntity") (100 . "AcDbSpline")) (list (cons 8 layer) '(70 . 8) '(71 . 3) (cons 72 (length sorted_list)) (cons 73 (length sorted_list)) '(74 . 0)) (mapcar '(lambda (pt) (cons 11 pt)) sorted_list)))
	)
      )
      (princ " Done.")
    )
    (princ "\nPath creation cancelled or no valid objects found.")
  )

  (*error* nil)
)

(princ "\n:: SmartPath.lsp loaded. Command: SmartPath ::")
(princ)

try this 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...