thebiglebowski Posted August 24, 2019 Posted August 24, 2019 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? Quote
dlanorh Posted August 25, 2019 Posted August 25, 2019 Look at posts 41 and 47 in this topic https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/centroid-of-polyline/td-p/2198899/page/3 Quote
lrm Posted August 28, 2019 Posted August 28, 2019 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. Quote
BIGAL Posted August 28, 2019 Posted August 28, 2019 (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. Edited August 28, 2019 by BIGAL Quote
Stefan BMR Posted August 28, 2019 Posted August 28, 2019 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. Quote
lrm Posted August 28, 2019 Posted August 28, 2019 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) ) Quote
Grrr Posted August 28, 2019 Posted August 28, 2019 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 ) Quote
BIGAL Posted August 29, 2019 Posted August 29, 2019 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. Quote
lrm Posted August 30, 2019 Posted August 30, 2019 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: 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) ) Quote
BIGAL Posted August 30, 2019 Posted August 30, 2019 (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 August 30, 2019 by BIGAL Quote
lrm Posted August 30, 2019 Posted August 30, 2019 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 Quote
Recommended Posts
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.