1

I am wanting to automatically convert all sides of a rectangle drawn by the user into concave arcs (about 10 degrees all around). I found this wonderful routine written by Marko Ribar (sorry if that's not correct credit) that does exactly what I'm looking for, except that the user has to manually define direction and degree of the arcs using the mouse. Push mouse positive Y direction = convex. Pull mouse negative Y direction = concave (which is what I want). Does anyone know how to add code to automatically pull in the negative Y direction about 10 degrees once rectangle is selected? Is there an easier way to accomplish this task by just making 10 degree arcs instead of lines when drawing a rectangle?

;Code to convert rectangle lines into arcs:

(defun c:lwstraight2arced ( / nthmassocsubst lw enx vs gr enxb p b i pt1 pt2 pt3 pt4 myrec )

;My added code to draw a rectangle by the user picking two opposite corners-----------------
(setq pt1 (getpoint "\nEnter first corner: "))
(setq pt3 (getcorner pt1 "\nEnter cross corner: "))
(setq pt2 (list (car pt1) (cadr pt3)))
(setq pt4 (list (car pt3) (cadr pt1)))
(setq myrec (command "rectangle" pt1 pt3 ""))
;end of my added code------------------------


  (defun nthmassocsubst ( n key value lst / k slst p j plst m tst pslst )
    (setq k (length (setq slst (member (assoc key lst) lst))))
    (setq p (- (length lst) k))
    (setq j -1)
    (repeat p
      (setq plst (cons (nth (setq j (1+ j)) lst) plst))
    )
    (setq plst (reverse plst))
    (setq j -1)
    (setq m -1)
    (repeat k
      (setq j (1+ j))
      (if (equal (assoc key (member (nth j slst) slst)) (nth j slst) 1e-6)
        (setq m (1+ m))
      )
      (if (and (not tst) (= n m))
        (setq pslst (cons (cons key value) pslst) tst t)
        (setq pslst (cons (nth j slst) pslst))
      )
    )
    (setq pslst (reverse pslst))
    (append plst pslst)
  )

;
; ----removed original code that has user select a line or rectangle manually-----
;          (setq lw (car (entsel "\nPick LWPOLYLINE straight polygon...")))
;-----end of original code-----



;-------My new code to have a previously drawn rectangle above automatically selected-----------------------------------
            (setq lw (entlast))
;-----End of my new code------


  (setq enx (entget lw))
  (setq vs (getvar 'viewsize))
  (while (= 5 (car (setq gr (grread t))))
    (setq enxb (acet-list-m-assoc 42 enx))
    (setq p (cadr gr))
    (setq b (/ (cadr p) vs))
    (setq i -1)
    (foreach dxf42 enxb
      (setq enx (nthmassocsubst (setq i (1+ i)) 42 b enx))
    )
    (entupd (cdr (assoc -1 (entmod enx))))
  )
  (princ)
)

Here is what I hope to achieve once a rectangle is drawn by the user. A slightly concaved rectangle without user input.

enter image description here

I have added to the routine the following steps:

-Get area of rectangle by multiplying length by width. -Draw circles and rectangles with a specific size at each corner based on square footage of rectangle in inches.

Here is the working code with the additions above:

(defun c:concavearc ( / b p q s z myrecarea convertrecarea pt1 pt2 pt3 pt4 circleset24 circleset36 circleset48)
; Create concave arcs from a rectangle
    (setq s 20.0) ;; Arc sagitta
    
    (if (and (setq p (getpoint "\nSpecify first corner: "))
             (setq q ((if (zerop (getvar 'worlducs)) getpoint getcorner) p "\nSpecify opposite corner: "))
             (mapcar 'set '(p q) (mapcar '(lambda ( x ) (mapcar x p q)) '(min max)))
             (setq z (trans '(0 0 1) 1 0 t)
                   b (mapcar '(lambda ( a b c ) (/ s (- a b) -0.5)) q p '(0 0))
             )
        )
        (entmake
            (list
               '(000 . "LWPOLYLINE")
               '(100 . "AcDbEntity")
               '(100 . "AcDbPolyline")
               '(090 . 4)
               '(070 . 1)
                (cons 010 (trans p 1 z))
                (cons 042 (car b))
                (cons 010 (trans (list (car q) (cadr p)) 1 z))
                (cons 042 (cadr b))
                (cons 010 (trans q 1 z))
                (cons 042 (car b))
                (cons 010 (trans (list (car p) (cadr q)) 1 z))
                (cons 042 (cadr b))
                (cons 210 z)
            )
        )
    )


;Add width of 2" and dashed line to arc polyline -----------------------------------------
  
(setvar "cmdecho" 0); disable command echo 
(setq Plnwdth (ssget "L"));get last entity
(command "pedit" Plnwdth "W" 2 "");set last entity width to 2

 (if (null (tblsearch "ltype" "dashed"))  
  (command ".linetype" "load" "dashed" "acad.lin" "")
 )

(command "change" Plnwdth "" "p" "LType" "Dashed" "" "ltScale" "30" "");lynetype
(setvar "cmdecho" 1); restore command echo
;end add width of 2 to arc polyline-----------------------------------------



;End concave arcs-----------------------------------------


;Setting corners of rectangle to variables --------------------------------------------------------------


; Get the four points of rectangle drawn by user above
(setq pt1 p)
(setq pt3 q)
(setq pt2 (list (car pt1) (cadr pt3)))
(setq pt4 (list (car pt3) (cadr pt1)))
(setq mylength (distance pt1 pt2)); length
(setq mywidth (distance pt1 pt4)); width
(setq myrecarea (* mylength mywidth)); Get area of rectangle (length x width)


(setvar "unitmode" 1);units to be displayed as entered
(setq convertrecarea (rtos myrecarea 4 2)); converts "convertrecarea" string into architectural format:

; Change units from decimal to Architectural
  (if *decimal*
    (progn
      (command "_.-units" "2" "" "" "" "" "")
      (setq *decimal* nil)
    )
    (progn
      (command "_.-units" "4" "" "" "" "" "")
      (setq *decimal* t)
    )
  )







; create conditional "if/and" functions based on rectangle area in square inches.
; if area of rectangle below 14400 SQ.Inches, give message to redraw rectangle
      (if
        (<= myrecarea 14400)
        (prompt "Area to small. Redraw area again")
      ); End IF
; if area of rectangle is between 14401 SQ.Inches and 57600 SQ.Inches, place a 24" circle at each corner of rectangle points
  
    (if
        (and
          (>= myrecarea 14401)
          (<= myrecarea 57600)
        ); End AND
              (progn
        (command "-color" "t" "99,100,102" ""); Change color
                (command "circle" pt1 "d" 24 0 ""); Create circle
        (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 ""); Copy circle to all four points of rectangle
        (setq circleset24 (ssget "_C" pt1 pt3 '((0 . "CIRCLE")))); Create selection set of circles using fencing around rectangle
        (command "_hatch" "p" "AR-Conc" "2" "0" "s" circleset24 ""); Hatch selected circles
        
;Create rectangle from centerpoint. Copy to each corner
    (command "-color" "t" "255,255,255" "")
    (setq len 2)
    (setq wid 2)
    (setq z1 (trans '(0 0 1) 1 0 t))
    (if (setq cnt1 pt1)
        (entmake
            (list
               '(000 . "LWPOLYLINE")
               '(100 . "AcDbEntity")
               '(100 . "AcDbPolyline")
               '(090 . 4)
               '(070 . 1)
                (cons 010 (trans (mapcar '+ cnt1 '(-2 -2)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 2 -2)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 2  2)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '(-2  2)) 1 z1))
                (cons 210 z1)

            )
        )
    )
        (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 "")
        
          ); End Progn
    ); End IF
  
; if area of rectangle is between 57601 SQ.Inches and 129600 SQ.Inches, place a 36" circle at each corner of rectangle points
    (if
        (and
          (>= myrecarea 57601)
          (<= myrecarea 129600)
        ); End AND
          (progn
        (command "-color" "t" "99,100,102" "")
            (command "circle" pt1 "d" 36 0 "")
            (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 "")
        (setq circleset36 (ssget "_C" pt1 pt3 '((0 . "CIRCLE"))))
        (command "_hatch" "p" "AR-Conc" "2" "0" "s" circleset36 "")

;Create rectangle from centerpoint. Copy to each corner
    (command "-color" "t" "255,255,255" "")
    (setq len 3)
    (setq wid 3)
    (setq z1 (trans '(0 0 1) 1 0 t))
    (if (setq cnt1 pt1)
        (entmake
            (list
               '(000 . "LWPOLYLINE")
               '(100 . "AcDbEntity")
               '(100 . "AcDbPolyline")
               '(090 . 4)
               '(070 . 1)
                (cons 010 (trans (mapcar '+ cnt1 '(-3 -3)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 3 -3)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 3  3)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '(-3  3)) 1 z1))
                (cons 210 z1)

            )
        )
    )
        (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 "")

        
          ); End Progn
    ); End IF
  
; if area of rectangle is between 129601 SQ.Inches and 230400 SQ.Inches, place a 48" circle at each corner of rectangle points

    (if
        (and
         (>= myrecarea 129601)
         (<= myrecarea 230400)
        ); End AND
          (progn
       (command "-color" "t" "99,100,102" "")
           (command "circle" pt1 "d" 48 0 "")
       (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 "")
       (setq circleset48 (ssget "_C" pt1 pt3 '((0 . "CIRCLE"))))
       (command "_hatch" "p" "AR-Conc" "2" "0" "s" circleset48 "")
       

;Create rectangle from centerpoint. Copy to each corner
    (command "-color" "t" "255,255,255" "")
    (setq len 4)
    (setq wid 4)
    (setq z1 (trans '(0 0 1) 1 0 t))
    (if (setq cnt1 pt1)
        (entmake
            (list
               '(000 . "LWPOLYLINE")
               '(100 . "AcDbEntity")
               '(100 . "AcDbPolyline")
               '(090 . 4)
               '(070 . 1)
                (cons 010 (trans (mapcar '+ cnt1 '(-4 -4)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 4 -4)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '( 4  4)) 1 z1))
                (cons 010 (trans (mapcar '+ cnt1 '(-4  4)) 1 z1))
                (cons 210 z1)

            )
        )
    )
        (command "_copy" "last" "" "M" pt1 pt2 pt3 pt4 "")

          ); End Progn
    ); End IF


; if area of rectangle is above 230401 SQ.Inches tell user to redraw area

    (if
        (>= myrecarea 230401)
        (prompt "Area to big. Redraw area again")
    ); End IF
    (princ convertrecarea)

);End "concavearc"

The new addition is working but I would like to be able to do the following:

Put the Arc segment of code inside an "IF" Statement so if rectangle drawn by user is too big or too small, prompt user "Out of range" and end routine. Right now, it draws the arcs regardless if out of range.

I tried to put in an IF statement below but didn't work. Here is a snippet of that:

        (defun c:concavearc ( / b p q s z myrecarea convertrecarea pt1 pt2 pt3 pt4)
          
        ; ------------------ Create concave arcs from a rectangle----------
            (setq s 20.0) ;; Arc sagitta
            
        (if (and (setq p (getpoint "\nSpecify first corner: "))
                     (setq q ((if (zerop (getvar 'worlducs)) getpoint getcorner) p "\nSpecify opposite corner: "))
        
            ; Get the four points of rectangle drawn by user above
            (setq pt1 p)
            (setq pt3 q)
            (setq pt2 (list (car pt1) (cadr pt3)))
            (setq pt4 (list (car pt3) (cadr pt1)))
            (setq mylength (distance pt1 pt2)); length
            (setq mywidth (distance pt1 pt4)); width
            (setq myrecarea (* mylength mywidth)); Get area of rectangle (length x width)
             
        
        ; If area drawn is above 129601square inches or below 14400 square inches display message the "not in range". Else, draw concave arcs.   
            (if
                (and
                 (>= myrecarea 129601)
                 (<= myrecarea 14400)
                ); End and
             (prompt "Not in range. Redraw area again")   
        
             (progn
                     Concave Arc code here....
    
              );End Progn
           );End "if/and" conditional statement
   );End "get points"

Just as an internal issue. How do you put in numbers for Square feet rather than inches?

Example:

(<= myrecarea 14400)

into

(<= myrecarea 100 Sq. Ft.)
Robert
  • 63
  • 6
  • Can you define where you're measuring the 10 degrees relative to? – Lee Mac Jun 21 '21 at 22:52
  • Hi Lee. Thank you for your response. I added an image above to what I'm looking for. Once a rectangle is drawn by the user, its converted into concave arcs. I gave an arbitrary number of 10 degrees but It can be anything that achieves the effect seen in the image. The routine works great if using the mouse. Just not sure where in the code to put a fixed number to achieve the same result. Perhaps this routine is a more difficult way to get this result (since no input is required after drawing a rectangle). Just looking to convert the lines into inward facing arcs really... – Robert Jun 23 '21 at 00:29

2 Answers2

1

For this task, I would suggest a function along the lines of the following:

(defun c:caverec ( / b p q s z )

    (setq s 1.0) ;; Arc sagitta
    
    (if (and (setq p (getpoint "\nSpecify first corner: "))
             (setq q ((if (zerop (getvar 'worlducs)) getpoint getcorner) p "\nSpecify opposite corner: "))
             (mapcar 'set '(p q) (mapcar '(lambda ( x ) (mapcar x p q)) '(min max)))
             (setq z (trans '(0 0 1) 1 0 t)
                   b (mapcar '(lambda ( a b c ) (/ s (- a b) -0.5)) q p '(0 0))
             )
        )
        (entmake
            (list
               '(000 . "LWPOLYLINE")
               '(100 . "AcDbEntity")
               '(100 . "AcDbPolyline")
               '(090 . 4)
               '(070 . 1)
                (cons 010 (trans p 1 z))
                (cons 042 (car b))
                (cons 010 (trans (list (car q) (cadr p)) 1 z))
                (cons 042 (cadr b))
                (cons 010 (trans q 1 z))
                (cons 042 (car b))
                (cons 010 (trans (list (car p) (cadr q)) 1 z))
                (cons 042 (cadr b))
                (cons 210 z)
            )
        )
    )
    (princ)
)

Here, the degree of curvature of the four sides of the rectangle is controlled by the single parameter s defined at the top of the code - this parameter corresponds to the length of the arc sagitta, spanning the distance between the arc midpoint and the midpoint of the chord between each pair of vertices.

The code prompts the user to specify two points corresponding to opposite corners of the rectangle, and will proceed to construct a closed 4-vertex 2D polyline (LWPOLYLINE) for which the bulge of each segment is calculated by dividing the sagitta by half the chord length (which equates to the tangent of a quarter of the angle spanned by the arc, which is the definition of the bulge of a polyline segment - I describe this relationship in more detail here).

The code acquires the two points relative to the active UCS and calculates the remaining two vertices with respect to the active UCS, before transforming all coordinates to be relative to the Object Coordinate System (OCS). This means that the rectangle will be aligned to the x-axis of the active UCS and will operate as expected under all UCS & View settings within AutoCAD.

The function uses the getpoint function to prompt for the opposite corner when the UCS is not equal to the WCS in order to avoid confusion arising from the use of getcorner, which does not honour UCS rotation.

The resulting polyline will be constructed on the current layer, inheriting all object properties (colour, lineweight, linetype etc.) active at the time that the program is evaluated.

Lee Mac
  • 15,615
  • 6
  • 32
  • 80
  • 1
    Thank you Lee. The routine works beautifully. You are a true Guru! I have been fine tuning the value of "S" in your routine to fit the size I'm looking for and it will come in handy when I start making my conditional statements based on the sq. ft. area of the rectangle the user creates. This is just what I needed. Thanks! – Robert Jun 26 '21 at 21:18
  • Hi Lee. I have added my conditional statements below your routine and its working. I'm now trying to encompass your routine into my conditional statements so if the user draws a rectangle that is out of range, they are asked to redraw it and the routine ends. Cant get that part to work unfortunately. If you see what I'm doing wrong by chance, please let me know. Thanks for your help! – Robert Jul 04 '21 at 19:50
0
(defun c:caverec ( / *error* acos newton postprocess cmd tst a b c d e f g l n p q r s w x z a1 a2 b1 b2 c1 c2 ii cmin cmax lw dx dy ll )

    (defun *error* ( m )
        (if command-s
            (command-s "_.undo" "_e")
            (vl-cmdf "_.undo" "_e")
        )
        (if cmd
            (setvar 'cmdecho cmd)
        )
        (if m
            (prompt m)
        )
        (princ)
    )

    (defun acos ( x )
        (cond
            (   (equal x 1.0 1e-8) 0.0   )
            (   (equal x -1.0 1e-8) pi   )
            (   (and (> x 0) (equal x 0.0 1e-8)) (/ pi 2.0)   )
            (   (and (< x 0) (equal x -0.0 1e-8)) (* 3.0 (/ pi 2.0))   )
            (   (atan (sqrt (- 1.0 (* x x))) x)   )
        )
    )

    (defun newton ( chord arclen / k x ) ;; use the Newton method to compute the arc half angle acminording to its length and chord
        (setq k (/ chord arclen)
              x pi
        )
        (repeat 10
            (setq x (- x (/ (- (sin x) (* k x)) (- (cos x) k))))
        )
    )

    (defun n ( m c / r ) ;; n - area between arc and its chord ; m - sagitta of arc ; c - chord of arc
        (if (> (setq r (/ (+ (expt m 2) (/ (expt c 2) 4.0)) (* 2.0 m))) m)
            (-
                (*
                    (* (expt r 2) pi)
                    (/ (acos (/ (- r m) r)) pi)
                )
                (*
                    (- r m)
                    (/ c 2.0)
                )
            )
            (progn (prompt "\nr not bigger than m...") (exit))
        ) ;; if
    ) ;; Area between arc and its chord

    (defun r ( c l / a ) ;; r - radius of arc ; c - chord of arc ; l - length of arc

        ;; (setq r (/ (+ (expt i 2) (expt (/ c 2) 4.0)) (* 2.0 i))) ;;; ( * )
        ;; (setq i (- r (sqrt (- (expt r 2) (/ (expt c 2) 4.0)))))

        ;; i^2+c^2/4=2*r^2(1-(cos(a/2))) ;; cosine theorem
        ;; i^2=2*r^2(1-(cos(a/2)))-c^2/4 ;;; ( 0 ) ;;;
        ;; ( * ) => r=(i^2+c^2/4)/(2*i)
        ;; r=(2*r^2(1-(cos(a/2)))-c^2/4+c^2/4)/(2*i)
        ;; r=r^2*(1-(cos(a/2)))/i
        ;; i=r*(1-(cos(a/2)))
        ;; i/r=1-cos(a/2)
        ;; cos(a/2)=1-i/r
        ;; a/2=acos(1-i/r)
        ;; a=2*acos(1-i/r)
        ;; <) = r^2*pi*(a/(2*pi))
        ;; <) = r^2*pi*2*acos(1-i/r)/(2*pi)
        ;; <) = r^2*acos(1-i/r)
        ;; |) = <) - <|
        ;; |) n = r^2*acos(1-i/r)-(r-i)*c/2 ;;; ( I ) ;;;
        ;; n=r^2*acos(1-i/r)-r*c/2+i*c/2
        ;; n=r^2*a/2-r*c/2+i*c/2 ;;; ( II ) ;;;
        ;; r^2*a/2-r*c/2+i*c/2-n=0
        ;; r=(c/2[+/-]sqrt(c^2/4-2*a*(i*c/2-n)))/a
        ;; ) = r*a=c/2+sqrt(c^2/4-a*i*c+2*a*n) ;; must be "+" [  )  is acways bigger than  |  ,pcus here is hacf of  |  ,so here this is especiaccy the case  ] ;;; ( III ) ;;;
        ;; |> = i*c/2 ;;; ( IV ) ;;;
        
        ;; c'=sqrt(i^2+c^2/4) ;;; ( V ) ;;;
        ;; i'^2+c'^2/4=2*r^2(1-(cos(a/4))) ;; cosine theorem
        ;; ( V ) => i'^2+(i^2+c^2/4)/4=2*r^2(1-(cos(a/4)))
        ;; i'^2=2*r^2(1-(cos(a/4)))-(i^2+c^2/4)/4 ;;; ( VI ) ;;;
        ;; ( * ) => r=(i'^2+c'^2/4)/(2*i')
        ;; ( V ) => r=(i'^2+(i^2+c^2/4)/4)/(2*i')
        ;; ( VI ) => r=(2*r^2(1-(cos(a/4)))-(i^2+c^2/4)/4+(i^2+c^2/4)/4)/(2*i')
        ;; r=r^2(1-(cos(a/4))/i'
        ;; i'=r*(1-(cos(a/4))) ;;; ( VII ) ;;;
        ;; i'/r=1-cos(a/4)
        ;; cos(a/4)=1-i'/r
        ;; a/4=acos(1-i'/r)
        ;; a=4*acos(1-i'/r)
        ;; <) = r^2*pi*(a/(2*pi))
        ;; <) = r^2*pi*4*acos(1-i'/r)/(2*pi)
        ;; <) = 2*r^2*acos(1-i'/r)
        ;; ( I ) => /) = \) [ |) = <) - <| ] => n1=n2 = 2*r^2*acos(1-i'/r)-(r-i')*c'/2
        ;; ( V ) => n1=n2 = 2*r^2*acos(1-i'/r)-(r-i')*sqrt(i^2+c^2/4)/2 ;;; ( VIII ) ;;;
        ;; |) = n = |> + /) + \) <=> ( IV ) & ( VIII ) => n = i*c/2 + 4*r^2*acos(1-i'/r)-(r-i')*sqrt(i^2+c^2/4)/2
        ;; ( VII ) => n=i*c/2+4*r^2*acos(1-r*(1-(cos(a/4)))/r)-(r-r*(1-(cos(a/4))))*sqrt(i^2+c^2/4)/2
        ;; n=i*c/2+r^2*a/4-r*(cos(a/4))*sqrt(i^2+c^2/4)/2 ;;; ( IX ) ;;;
        ;; ( II ) & ( IX ) => n = r^2*a/2-r*c/2+i*c/2=i*c/2+r^2*a/4-r*(cos(a/4))*sqrt(i^2+c^2/4)/2
        ;; r^2*(a/4-a/2)+r*(c/2-(cos(a/4)*sqrt(i^2+c^2/4)/2))=0 |/r
        ;; -r*a/4+c/2-cos(a/4)*sqrt(i^2+c^2/4)/2=0 |*-4
        ;; r*a-2*c+2*cos(a/4)*sqrt(i^2+c^2/4)=0
        ;; r*a=2*(c-cos(a/4)*sqrt(i^2+c^2/4)) ;;; ( X ) ;;;
        ;; r=2*(c-cos(a/4)*sqrt(i^2+c^2/4))/a
        ;; ( 0 ) => r=2*(c-cos(a/4)*sqrt(2*r^2(1-(cos(a/2)))-c^2/4+c^2/4))/a
        ;; r=2*(c-cos(a/4)*sqrt(2)*r*sqrt(1-(cos(a/2))))/a |*(a/r)
        ;; a=2*(c-cos(a/4)*sqrt(2)*sqrt(1-(cos(a/2))))
        ;; a=2*c-2*sqrt(2)*cos(a/4)*sqrt(1-(cos(a/2)))
        ;; a=2*c-2*sqrt(2)*cos(a/4)*sqrt(1-((cos(a/4))^2-(sin(a/4))^2))
        ;; a=2*c-2*sqrt(2)*cos(a/4)*sqrt(2*(cos(a/4))^2)
        ;; a=2*c-4*(cos(a/4))^2
        ;; a+4*(cos(a/4))^2=2*c ; t=a/4
        ;; 4*t+4*(cos(t))^2=2*c |/4
        ;; t+(cos(t))^2=c/2
        ;; t=acos(sqrt(c/2-t))

        (setq a (newton c l))
        (setq r (abs (/ c 2.0 (sin a))))
    ) ;; Arc radius

    (defun x ( e l1 l2 ii / n1 n2 )
        (setq ii (- ii 0.01))
        (setq n1 (n ii c1))
        (setq n2 (n ii c2))
        (setq r1 (/ (+ (expt ii 2) (expt (/ c1 2) 4.0)) (* 2.0 ii)))
        (setq a1 (* 2.0 (acos (/ (- r1 ii) r1))))
        (setq r2 (/ (+ (expt ii 2) (expt (/ c2 2) 4.0)) (* 2.0 ii)))
        (setq a2 (* 2.0 (acos (/ (- r2 ii) r2))))
        (if (< e (+ n1 n2))
            (x e (l c1 a1 ii) (l c2 a2 ii) ii)
            ii
        )
    )

    (defun l ( c a i ) ;; l - length of arc ; c - chord of arc ; a - angle of arc ; i - sagitta of arc
        (* 2.0
            (-
                c
                (*
                    (cos (/ a 4.0))
                    (sqrt (+ (expt i 2) (/ (expt c 2) 4.0)))
                )
            )
        )
    )

    (defun postprocess ( lw / lwx a1 a2 b1 b2 r1 r2 ii g loop dxf42 )
        (setq lwx (entget lw))
        (setq b1 (cdr (assoc 42 lwx)))
        (setq b2 (cdr (assoc 42 (cdr (member (cons 42 b1) lwx)))))
        (setq a1 (* 4.0 (atan b1)) a2 (* 4.0 (atan b2)))
        (setq r1 (abs (/ c1 2.0 (sin (/ a1 2.0)))))
        (setq r2 (abs (/ c2 2.0 (sin (/ a2 2.0)))))
        (setq ii (- r1 (sqrt (- (expt r1 2) (/ (expt c1 2) 4.0)))))
        (setq loop 1)
        (prompt "\nleft mouse click for finish ; < - concaving ; > - convexing shape ; speed - type : 1,2,3,4,5,6,7,8,9...")
        (while (/= (car (setq g (grread))) 3)
            (if (and (= (car g) 2) (< 48 (cadr g) 58))
                (progn (prompt "\nselected speed : ") (princ (setq loop (- (cadr g) 48))))
                (repeat loop
                    (cond
                        (   (equal g (list 2 60))
                            (setq ii (+ ii (* loop 0.01)))
                        )
                        (   (equal g (list 2 62))
                            (setq ii (- ii (* loop 0.01)))
                        )
                    )
                    (setq b1 (/ ii c1 -0.5) b2 (/ ii c2 -0.5))
                    (setq dxf42 (vl-remove-if '(lambda ( x ) (/= (car x) 42)) lwx))
                    (entupd (cdr (assoc -1 (entmod (mapcar '(lambda ( x ) (cond ( (and (= (car x) 42) (= (rem (vl-position x dxf42) 2) 0)) (cons 42 b1) ) ( (and (= (car x) 42) (/= (rem (vl-position x dxf42) 2) 0)) (cons 42 b2) ) ( t x ))) lwx)))))
                )
            )
        )
    )

    (setq cmd (getvar 'cmdecho))
    (setvar 'cmdecho 0)
    (if (equal 0 (getvar 'undoctl)) 
        (vl-cmdf "_.undo" "_all")
    )
    (if
        (or
            (not (equal 1 (logand 1 (getvar 'undoctl))))
            (equal 2 (logand 2 (getvar 'undoctl)))
        ) ;; or
        (vl-cmdf "_.undo" "_control" "_all")
    )
    (if (equal 4 (logand 4 (getvar 'undoctl)))
        (vl-cmdf "_.undo" "_auto" "_off")
    )
    (while (equal 8 (logand 8 (getvar 'undoctl)))
        (vl-cmdf "_.undo" "_end")
    )
    (vl-cmdf "_.undo" "_begin")
    (if
        (and
            (setq p (getpoint "\nPick or specify first corner : "))
            (progn
                (prompt "\nPick or specify opposite corner : ")
                (while (= (car (setq g (grread t))) 5)
                    (setq q (cadr g))
                    (redraw)
                    (setq dx (- (car q) (car p)))
                    (setq dy (- (cadr q) (cadr p)))
                    (mapcar
                       '(lambda ( pair )
                            (grdraw (car pair) (cadr pair) 2 0)
                        )
                        (mapcar
                           '(lambda ( a b )
                                (mapcar
                                   '(lambda ( c d )
                                        (mapcar '+ c d)
                                    )
                                    a b
                                )
                            )
                            (repeat 4
                                (setq ll (cons (list p q) ll))
                            )
                            (list
                                (list (list 0 0) (list 0 (- dy)))
                                (list (list dx 0) (list 0 0))
                                (list (list dx dy) (list (- dx) 0))
                                (list (list 0 dy) (list (- dx) (- dy)))
                            )
                        )
                    )
                )
                q
            )
            (mapcar 'set '(p q) (mapcar '(lambda ( x ) (mapcar x p q)) '(min max)))
            (setq c1 (- (car q) (car p)) c2 (- (cadr q) (cadr p)))
            (setq cmin (min c1 c2) cmax (max c1 c2))
            (setq z (trans '(0.0 0.0 1.0) 1 0 t))
            (or
                (progn
                    (while
                        (and
                            (not f)
                            (setq a
                                (cond
                                    (   (initget 6)   )
                                    (   (setq a (getreal "\nArcs bulge angle in decimal degrees <90.0> : "))   )
                                    (   (prompt "\nArcs sagitta instead of angle : \nleft mouse click for \"Yes\" (sagitta input) / enter for \"No\" (proceed with 90.0 degree) : ")   )
                                    (   t
                                        (while
                                            (and
                                                (not (equal (setq g (grread)) (list 2 13)))
                                                (/= (car g) 3)
                                            )
                                        )
                                        (if (= (car g) 3)
                                            (setq f nil a nil)
                                            (progn (setq f t) 90.0)
                                        )
                                    )
                                )
                            )
                            (setq tst
                                (> a 90.0) ;; Adjacent arcs do not cross each other
                            )
                            (setq f (not tst))
                            (setq a (cvunit a "degree" "radian"))
                            (setq tst
                                (not
                                    (<=
                                        (- (/ (sin (/ a 4.0)) (cos (/ a 4.0))))
                                        (/ (/ cmin 2.0) cmax -0.5)
                                        0.0
                                    )
                                ) ;; Opposite arcs do not cross each other
                            )
                            (setq f (not tst))
                        ) ;; and
                    ) ;; Arcs bulge angle
                    a
                )
                (progn
                    (while
                        (and
                            (not f)
                            (setq s
                                (cond
                                    (   (initget 6)    )
                                    (   (setq s (getdist "\nArcs sagitta <1.0> : "))   )
                                    (   (prompt "\nArcs by area instead of angle or sagitta : \nleft mouse click for \"Yes\" (area input) / enter for \"No\" (proceed with 1.0 sagitta distance) : ")   )
                                    (   t
                                        (while
                                            (and
                                                (not (equal (setq g (grread)) (list 2 13)))
                                                (/= (car g) 3)
                                            )
                                        )
                                        (if (= (car g) 3)
                                            (setq f nil s nil)
                                            (progn (setq f t) 1.0)
                                        )
                                    )
                                )
                            )
                            (setq tst
                                (> s (/ cmin 2.0)) ;; Opposite arcs do not cross each other
                            )
                            (not (setq f (not tst)))
                        ) ;; and
                        (if tst
                            (prompt "\ntoo large sagitta... retry...")
                        )
                    ) ;; Arcs sagitta
                    s
                )
                (progn
                    (while
                        (and
                            (not f)
                            (or
                                (setq tst
                                    (not
                                        (<=
                                            (setq c
                                                (-
                                                    (setq d (* c1 c2))
                                                    (* 2 (n (- (abs (/ c1 2.0 (sin (/ pi 4.0)))) (sqrt (- (expt (abs (/ c1 2.0 (sin (/ pi 4.0)))) 2) (/ (expt c1 2) 4.0)))) c1))
                                                    (* 2 (n (- (abs (/ c2 2.0 (sin (/ pi 4.0)))) (sqrt (- (expt (abs (/ c2 2.0 (sin (/ pi 4.0)))) 2) (/ (expt c2 2) 4.0)))) c2))
                                                )
                                            )
                                            (setq w
                                                (cond
                                                    (   (initget 7)   )
                                                    (   (setq w (getreal (strcat "\nSpecify desired area from : " (rtos c 2 20) " to " (rtos d 2 20) " : ")))
                                                        w
                                                    )
                                                )
                                            )
                                            d
                                        )
                                    ) ;; Choosen area in valid range
                                )
                                (not (setq f (not tst)))
                            ) ;; or
                        )
                        (prompt "\nInvalid area input...")
                        (setq f nil)
                    ) ;; Area input
                    w
                ) ;; progn
            ) ;; or
            (setq b
                (cond
                    (   a
                        (list (- (/ (sin (/ a 4.0)) (cos (/ a 4.0)))) (- (/ (sin (/ a 4.0)) (cos (/ a 4.0)))))
                    )
                    (   s
                        (mapcar '(lambda ( c ) (/ s c -0.5)) (list c1 c2))
                    )
                    (   w
                        (setq e (/ (- d w) 2.0))
                        (setq r1 (abs (/ c1 2.0 (sin (/ pi 4.0)))))
                        (setq ii (- r1 (sqrt (- (expt r1 2) (/ (expt c1 2) 4.0)))))
                        (setq a1 (* 2.0 (acos (/ (- r1 ii) r1))))
                        (setq r2 (abs (/ c2 2.0 (sin (/ pi 4.0)))))
                        (setq a2 (* 2.0 (acos (/ (- r2 ii) r2))))
                        (setq s (x e (l c1 a1 ii) (l c2 a2 ii) ii))
                        (mapcar '(lambda ( c ) (/ s c -0.5)) (list c1 c2))
                    )
                )
            )
        ) ;; and
        (setq lw
            (entmakex
                (list
                   '(000 . "LWPOLYLINE")
                   '(100 . "AcDbEntity")
                   '(100 . "AcDbPolyline")
                   '(090 . 4)
                   '(070 . 1)
                    (cons 038 (caddr (trans '(0.0 0.0 0.0) 1 z)))
                    (cons 010 (trans p 1 z))
                    (cons 042 (car b))
                    (cons 010 (trans (list (car q) (cadr p)) 1 z))
                    (cons 042 (cadr b))
                    (cons 010 (trans q 1 z))
                    (cons 042 (car b))
                    (cons 010 (trans (list (car p) (cadr q)) 1 z))
                    (cons 042 (cadr b))
                    (cons 210 z)
                )
            )
        )
    ) ;; if
    (prompt "\nleft mouse click to finish, enter to adjust with (grread)...")
    (while
        (and
            (not (equal (setq g (grread)) (list 2 13)))
            (/= (car g) 3)
        )
        (prompt "\nenter or left click...")
    )
    (if (/= (car g) 3)
        (postprocess lw)
    )
    (*error* "\ndone...")
)
  • Hi Marko. Thanks for the update. I've been working on 6 points instead of 4. Here is a link to my current issue if interest in giving any advice and making it work in all scenarios.. https://www.cadtutor.net/forum/topic/75188-autolisp-issue-with-connecting-all-6-points-of-a-rectangle-four-corner-and-two-mid-points-with-arc-lines/ – Robert May 31 '22 at 04:10