Jump to content

How can I determine (via lisp) The Greatest Distance a closed polyline can be offset inboard.


Recommended Posts

Posted

As the title says, I would like to determine the maximum distance a Closed Polyline can be offset inboard.

 

I thought I could do this by using the Centroid point. As you can see from the attached image The centroid point is not the true geometric center.

 

It also occurred to me that while this may work on simple polygons, it would not work on shapes that "subdivide" as they are offset.

 

The best way I can think of currently would be to find the largest circle that can be inscribed within the polyline, which would be very difficult to determine automatically in complex shapes. Is there a simpler method? Or does anyone have a method of finding the largest inscribed diameter?

 

 

CentroidVsGeometricCenter.JPG

SampleGeometry.JPG

Posted

The centroid point is, by definition, is the true geometric center but I don't think the solution to your task has anything to do with the centroid.

 

I think the approach to take with a VLISP program is to use an iterative approach with the offset command.  After selecting the closed polyline a point needs to be specified that is inside the polyline. This might not be the centroid (the centroid for the letter "C" is not inside its profile). The program should make a guess for an offset and if successful another larger value for the offset could be tried until the result is not successful. Offset outputs the message "Cannot offset that object." if it cannot make an offset. AT this point the program could systematically try smaller values until a valid offset is created.  I do not know how to check for the output error message in VLISP.  If you can determine that I think I could write the program. 

Posted (edited)

I may be guessing but if ignore fillets if you take a the poly shape and do a 1/2 angle of the corners where they intersect is the maximum then perp check. No real idea where to start.

 

image.thumb.png.9c3eb29cd63f5179432d6d60e20e37d4.png

image.png

Edited by BIGAL
Posted
On 8/25/2019 at 1:33 AM, thebiglebowski said:

As the title says, I would like to determine the maximum distance a Closed Polyline can be offset inboard.

 

I thought I could do this by using the Centroid point. As you can see from the attached image The centroid point is not the true geometric center.

 

It also occurred to me that while this may work on simple polygons, it would not work on shapes that "subdivide" as they are offset.

 

The best way I can think of currently would be to find the largest circle that can be inscribed within the polyline, which would be very difficult to determine automatically in complex shapes. Is there a simpler method? Or does anyone have a method of finding the largest inscribed diameter?

 

Hi

 

Some solutions for finding the maximum inscribed circle.

Posted

Here's a VLISP program that will calculate the maximum offset within a tolerance.  The program is a work in progress but I thought I would post the progress I have made.  The program creates an offset with a starting value and then creates another offset with a value of delta larger.  This continues until an offset cannot be created at which point the new offset value become the last successful offset plu one half delta and the process continues.

There are several variables which I have "hard wired" which could be calculated automatically as a function of the polyline.  They include the step size  delta, a tolerance value tol, and the maximum number of iterations n to be done before the program quits.

 

The offset polylines that the program creates remain after the calculation.  The program needs to be modified to delete these polylines and should be more clever about the step size value.  I don't have time right now for these enhancements but thought I share the progress I've made.

 

To test out the program with the values I assumed  for delta and tol create a closed polyline that is on the order of 10 x 10 units.  Making the changes I've noted above should enable the program to work on any size geometry.

 

(defun c:MaxOffset ()
; calculates the maximum offset value for the interior of
; a closed polyline
; version 1  8/28/2019  L. Minardi
; offset lines used for the calculation need to be manually
; deleted.  
  (setq ent (entsel "\nPick POLYLINE"))
  (setq p (getpoint "\nSpecify point inside polygon."))
  (setq delta 1.0)
  (setq dold 10000)
  (setq tol 0.05) ; tolerance
  (setq nmax 20) ; maximum iterations before quiting
  (setq d 1.1)
  (setq n 0)
  (while (or (> (abs (- d dold)) tol) (> n 20))
    (setq n (+ n 1))
    (command "offset" d ent p "")
    (setq entoff (entlast))
    (if	(equal entold entoff)
      (progn  ; offset NOT created
	(setq delta (/ delta 2))
	(setq d (+ dold delta))
      )					; end no good
      (progn  ; offset IS created
	(setq entold entoff)
	(setq dold d)
	(setq d (+ d delta))
      )					; end good  
    ) 
  )					; end while
  (princ "\nd max = ")
  (princ dold)
  (princ)

)

  

Posted

I had the same brute-force thought approach like @lrm, although IMO that wouldn't be the best algorithm.

Heres my attempt -

(defun MaxInnerOffset ( e repfuzz / OppositePtOnCurve poly->Midsegs tol o r tmp )
  
  (defun OppositePtOnCurve ( curve p / dis )
    (vlax-curve-getPointAtDist curve
      (rem
        (+
          (vlax-curve-getDistAtPoint curve p)
          (* 0.5 (setq dis (vlax-curve-getDistAtParam curve (vlax-curve-getEndParam curve))))
        )
        dis
      )
    )
  ); defun OppositePtOnCurve
  
  (setq poly->Midsegs
    (lambda ( e / i p pL )
      (if (and (eq 'ENAME (type e)) (wcmatch (cdr (assoc 0 (entget e))) "*POLYLINE"))
        (repeat (setq i (fix (+ (vlax-curve-getEndParam e) (if (vlax-curve-IsClosed e) 0 1))))
          (if (setq p (vlax-curve-getPointAtParam e (+ 0.5 (setq i (1- i))))) (setq pL (cons p pL)))
        )
      )
      pL
    )
  ); setq poly->MidsegsNtans
  
  (and 
    (setq tol 0.001)
    e
    ; (setq e (car (entsel)))
    (setq o (vlax-ename->vla-object e))
    (setq r 
      (* -0.5 
        (apply 'max
          (mapcar '(lambda (x) (distance x (OppositePtOnCurve e x) ))
            (poly->Midsegs e)
          )
        )
      )
    ); setq r
    
    (setq tol (* r (- tol)))
    (progn 
      (repeat repfuzz
        (while (vl-catch-all-error-p (setq tmp (vl-catch-all-apply 'vlax-invoke (list o 'Offset (setq r (+ r tol)))))))
        (and (listp tmp) (mapcar 'vla-Delete tmp))
        (setq tol (* 0.01 tol))
      ); repeat 
    )
  ); and 
  r
); defun MaxInnerOffset 

Test sub(s) -

(MaxInnerOffset (car (entsel)) 100)
(
  (lambda ( / e o r )
    (and 
      (setq e (car (entsel)))
      (setq o (vlax-ename->vla-object e))
      (progn 
        (vlax-invoke o 'Offset (setq r (MaxInnerOffset e 100)))
        (print r)
      )
    )
  ); lambda 
)

 

Posted

Maybe an iteration like an index answer using 1/2's say bounding box then 1/2 dist next step 1/4 if no then out else in +1/8 in/out +1/16 in out etc till answer is say 1e-05. Comparing entlast's

 

The simplest way to describe the iteration is 10000 entries it takes 13 goes to find the desired answer of a sorted list. Just need time.

Posted

Here's a revision to the program I posted earlier.  The user is asked to enter an initial guess for the maximum offset.  The value enter is used with the offset command to create an internal offset polyline, if possible, and then another one offset by the same amount.  If the second offset yield a value that is too large then the offset value is halved until it is not too large. The process is continued until the tolerance (0.001) is reached.  If the initial guess is either too large or too small an error message is displayed advising the user to use a different guess.

 

MaxOffset.v2.lsp

 

I ran the program several times on the following geometry with these results:

image.png.160e2e1b468d85967b052b1176a389e4.png

 

 

Initial Guess       Time (ms)  Number of iterations      Maximum Offset

0.5                          141                          35                              11.4082

1.0                           94                           25                              11.4082

5.0                           63                           18                              11.4087

10                            62                           18                              11.4087

 

@Grrr, it may not be the most efficient algorithm but it seems fast enough! 

 

Note, I had difficulty deleting the offset polylines used to make the calculation.  It appears that (lastent) will only go back so far.  I'm sure there is a better way.

 

(Note, the option to place the program in a code window was not available when I made this post)


(defun c:MaxOffset ()
; calculates the maximum offset value for the interior of
; a closed polyline
; version 2  8/29/2019  L. Minardi
; offset lines used for the calculation need to be manually
; deleted.  
  (setq ent (entsel "\nPick POLYLINE"))
  (setq p (getpoint "\nSpecify point inside polygon."))
  (setq dinit (getreal "\nSpecify intial guess for offset: "))
  (setq d dinit)
  (setq starttime (getvar "MILLISECS"))
  (setq tol 0.001)            ; tolerance
  (setq delta d)

  (setq dold (+ d (* 100 tol)))
  (setq nmax 100)            ; maximum iterations before quiting
  (setq n 0)
  (while (and (> (abs (- d dold)) tol) (< n nmax))
    (setq n (+ n 1))
    (command "offset" d ent p "")
    (setq entoff (entlast))
    (if    (equal entold entoff)
      (progn                ; offset NOT created
    (setq delta (/ delta 2))
    (setq d (+ dold delta))
    (if (= n 1)
      (setq n (+ nmax 1))
    )
      )                    ; end no good
      (progn                ; offset IS created
    (setq entold entoff)
    (setq dold d)
    (setq d (+ d delta))
      )                    ; end good  
    )

  )                    ; end while
  (setq endtime (getvar "MILLISECS"))
  (setq dtime (- endtime starttime))
  
  (if (= n nmax)
    (progn
      (princ "\nSolution not found.")
      (princ "\nThe value of the offset it too small.")
      (princ "\nTry a larger value than ")
      (princ dinit)
    )
    (progn
      (if (= n (+ nmax 1))
    (progn
      (princ "\nSolution not found.")
      (princ "\nThe value of the offset it too large.")
      (princ "\nTry a smaller value than ")
      (princ dinit)
    )
(progn
  (setvar "cmdecho" 0)
  (setq i 0)
  (while (< i n)
    (command "erase" (entlast) "")
    (setq i (+ i 1))
  )
(setvar "cmdecho" 1)
  (princ "\nmax offset = ")
  (princ dold)
  (princ "\nTime of execution: ")
  (princ dtime)
  (princ "\nNumber of iterations: ")
  (princ n)

  )
      )
    )
  )


  (princ)

)

 

 

Posted (edited)

Type [ c o d e ] [ / c o d e ] without spaces this will make a code block. I rarely use the code option.

 

You should be able to erase (entlast) or entold or entoff did not delve to deep. You may need a separate variable that you erase. If you want to leave them till last you can erase a selection set use ssadd to build, adding the entity names. (setq ssp (ssadd (entlast) ssp))

Edited by BIGAL
Posted

Thank you for the tips @BIGAL. The OP has yet to  respond to any of the posts so I will wait for some feedback before putting any more time into the program.

 

Lee

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...