;; RoundOffset.lsp -- command: ROFF
;; Version 1.1: accepts closed LWPOLYLINEs with any width.
;; Offset distance is measured from the centerline; output width is zero.
;; Load with APPLOAD. Prompts are ASCII for older AutoLISP installations.
;; OFFSET's Erase preference is deliberately set to No to keep the source.
;; Geometry generation and removal of overlapping portions use native OFFSET.

(defun c:ROFF (/ *error* saved item sel ent data dist side before next outdata widthok)
  (setq saved
    (mapcar '(lambda (name) (cons name (getvar name)))
      '("OFFSETGAPTYPE" "OFFSETDIST" "OSMODE" "CMDECHO")))

  (defun *error* (msg)
    (foreach item saved (setvar (car item) (cdr item)))
    (if (and msg (not (wcmatch (strcase msg) "*CANCEL*,*QUIT*,*BREAK*")))
      (princ (strcat "\nROFF: " msg)))
    (princ))

  (setq sel (entsel "\nSelect original closed 2D polyline: "))
  (if sel
    (progn
      (setq ent (car sel) data (entget ent))
      (cond
        ((/= (cdr (assoc 0 data)) "LWPOLYLINE")
          (princ "\nUse a lightweight 2D polyline. Join separate lines with PEDIT first."))
        ((= 0 (logand 1 (cdr (assoc 70 data))))
          (princ "\nThe polyline must be closed. Use PEDIT > Close first."))
        (T
          (princ "\nDistance is measured from the original polyline centerline.")
          (initget 7)
          (setq dist (getdist "\nOffset distance (drawing units): "))
          (setq side (getpoint "\nClick the offset side (outside for an outer boundary): "))
          (if side
            (progn
              (setvar "OFFSETGAPTYPE" 1)
              (setvar "OSMODE" 0)
              (setvar "CMDECHO" 0)
              (setq before (entlast))
              (command-s "_.OFFSET" "_Erase" "_No" dist ent "_non" side "")
              (if (equal before (entlast))
                (princ "\nNo offset was created. Check the geometry, distance and selected side.")
                (progn
                  (setq next (entnext before) widthok T)
                  (while next
                    (setq outdata (entget next))
                    (if (= (cdr (assoc 0 outdata)) "LWPOLYLINE")
                      (if (entmod
                            (mapcar
                              '(lambda (pair)
                                 (if (member (car pair) '(40 41 43))
                                   (cons (car pair) 0.0)
                                   pair))
                              outdata))
                        (entupd next)
                        (setq widthok nil)))
                    (setq next (entnext next)))
                  (if widthok
                    (princ "\nRounded offset created with zero width; original retained.")
                    (princ "\nOffset created, but output width could not be reset. Check its layer lock."))))))))))

  (foreach item saved (setvar (car item) (cdr item)))
  (princ))

(princ "\nRoundOffset v1.1 loaded (wide polylines supported). Type ROFF.")
(princ)
