@omarsvn hi,
Here is my best version, do not scare 😀 i will explain every thing you need to know and if you have more questions i am here.
first the format:
an autocad BACK command \ (c:back) function which wraps every thing inside, this way it's not interfere with other code in autolisp memory.
line #1: declare local functions
line #2: declare local variables
for now lets skip local functions and jump to line #44 where all starts
line #46 starts UNDO Group
line #83 end UNDO Group
this wraps all AutoCAD commands run in between for 1 UNDO command.
line #45 and line #84 complements each other, they disable AutoCAD commands echo to the command line window.
line #49 is to pick a pline
line #52 make sure a pline is selected
line #53 you specify the offset
line #54 you specify the rectangle width
the above code lines all wrapped in an (if) plus (and) function so if something goes wrong, the function will exist quietly.
line #57 gets the Centroid (the middle) point of the pline, for now lets skip the explanation how it done.
line #59 gets the points (geometric) of the pline, again lets skip it for now it is too sophisticated for you.
line #64 through #77 is the real job you are interested in
a loop (foreach) through the pline points each edge represented by p0 & p1 points
for each edge a perpendicular is dropped from centroid to the edge, this is to know the angle where to lay the rectangle (outside the pline and not inside)
enjoy
Moshe
(defun c:back (/ _geometric getCentroid sharp-angle near-edge ; local functions
pick ename elist of wth c0 points^ p0 p1 bx rm r0 r1 r2 r3)
; anonymous function, return pline geometric
(setq _geometric (lambda (l) (mapcar (function (lambda (item) (cdr item)))
(vl-remove-if-not (function (lambda (item) (= (car item) 10))) l))))
; return pline centroid 2d point
(defun getCentroid (ent / AcDbRegion centroid)
(command "._copy" "_si" ent "_none" "0,0,0" "_none" "0,0,0")
(command "._region" "_si" (entlast))
(setq AcDbRegion (vlax-ename->vla-object (entlast))) ; allocating memory
(setq centroid (vlax-safearray->list (vlax-variant-value (vla-get-centroid AcDbRegion))))
(vlax-release-object AcDbRegion) ; dispose memory
(command "._erase" "_si" (entlast)) ; delete region
centroid
); getCentroid
; return triangle sharp angle
(defun sharp-angle (a0 a1 / a2)
(if (> a1 a0)
(setq a2 (- a1 a0))
(setq a2 (- a0 a1))
)
(if (> a2 (* pi 1.5))
(- (* pi 2) a2)
a2
)
); sharp-angle
; return triangle near edge length
(defun near-edge (t0 t1 c0 / a0 a1 cx)
(setq a0 (angle t0 t1))
(setq a1 (angle t0 c0))
(setq cx (distance t0 c0))
(* (cos (sharp-angle a0 a1)) cx)
); near-edge
; here start c:back
(setvar "cmdecho" 0) ; disable command echo
(command "._undo" "_begin"); ; start command group
(if (and
(setq pick (entsel "\nPick a pline: ")) ; pick an object
(setq ename (car pick)) ; get entity name
(setq elist (entget ename)) ; get entiy database
(eq (cdr (assoc '0 elist)) "LWPOLYLINE") ; is it a pline?
(setq of (getdist "\nSpecify offset: ")) ; get offset
(setq wth (getdist "\nSpecify rectangle width: ")) ; get rectangle width
)
(progn
(setq c0 (getCentroid ename)) ; get pline centroid
(setq points^ (_geometric elist)) ; get pline geometric
(setq points^ (append points^ (list (car points^)))) ; append first point to list
(command "._layer" "_make" "fusion" "") ; create "fusion" layer if it is not exist
(setq p0 (car points^)) ; get 1st pline point
(foreach p1 (cdr points^) ; loop through pline points, chop 1st point
; calculater perpendicular point from centroid towards edge
(setq bx (near-edge p0 p1 c0))
(setq rm (polar p0 (angle p0 p1) bx))
(setq r0 (polar p0 (angle c0 rm) of)) ; 1st rectangle point
(setq r1 (polar p1 (angle c0 rm) of)) ; 2nd rectangle point
(setq r2 (polar p1 (angle c0 rm) (+ of wth))) ; 3th rectangle point
(setq r3 (polar p0 (angle c0 rm) (+ of wth))) ; 4th rectangle point
(command "._pline" "_none" r0 "_none" r1 "_none" r2 "_none" r3 "_close") ; draw rectangle
(setq p0 p1) ; back safe 1st point
); foreach
); progn
); if
(command "._undo" "_end") ; end command undo for 1 undo
(setvar "cmdecho" 1) ; enable command echo
(princ)
); c:back