; From a Tony Tanzillo suggestion, see ; John Uhden's @cv_inside function thread. ; minimal, dirty, etc... ; (defun ALE_IsInside (ImpPnt EntNam / NewEnt EntAre) (command "_.AREA" "_O" EntNam) (setq EntAre (getvar "AREA")) (command "_.OFFSET" (/ EntAre 10000) EntNam ImpPnt "" "_.AREA" "_O" (setq NewEnt (entlast)) ) (entdel NewEnt) (> EntAre (getvar "AREA")) ) command: pline 0.0 100,0 100,50 0,50 c command: (ALE_IsInside '(-0.00000000001 -0.00000000001) (entlast)) nil command: (ALE_IsInside '(0.00000000001 0.00000000001) (entlast)) T -- ________________________________________________ Marc'Antonio Alessi (TV) Italy (strcat "NOT a " (substr (ver) 8 4) " guru.") O.S. = XP Pro 2002 - Sp.1 - Ita AutoCAD = 2002 Ita - Sp.1 _VERNUM = "K.0.44" ACADVER = "15.06s (LMS Tech)" (ver) = "Visual LISP 2000 (it)" ________________________________________________
Marco, Thanks for the illustration. I like your improvement on Tony's good suggestion. With your method, you will probably not run into problems that may arise when the through point is inside the object but causes an error because the polyline can not be offset through the point. I think I understand your "dirty" comment and concur. A polyline can have an area without being closed so that may need checking. There may also still be some polylines that will not offset well despite the smallness of the offset distance. That is two or more polylines may be created some with a larger area than the original if the polyline has re-entrant geometry. Thanks for posting this solution. Regards, Doug
Marco, I was probably incorrect about the area of the polyline ever being larger when offset through a point inside a figure but in some cases the offset polyline becomes 2 or more separate figures. This is true whether the point is outside or inside and so the separate polylines created must be collected and the sum of the new areas should be smaller than the original area. Sorry for that error. Have a nice weekend. Regards, Doug
; new approach minimal, dirty, etc... ; comments are welcome ; (defun ALE_Bound_IsInside (ImpPnt EntNam / LstEnt NewEnt SnpBas RgnMod FuzFct) (setq FuzFct '(0.00001 0.00001) LstEnt (entlast) SnpBas (getvar "SNAPBASE") RgnMod (getvar "REGENMODE") ) (setvar "SNAPBASE" ImpPnt) (setvar "REGENMODE" 1) (command "_.ZOOM" "_NONE" (mapcar '- ImpPnt FuzFct) "_NONE" (mapcar '+ ImpPnt FuzFct) "_.BOUNDARY" "_A" "_B" "_N" EntNam "" "" "_NONE" ImpPnt "" "_.ZOOM" "_P" ) (setvar "SNAPBASE" SnpBas) (setvar "REGENMODE" RgnMod) (cond ( (eq LstEnt (setq NewEnt (entlast))) nil ) ( (entdel NewEnt) T ) ) ) command: pline 0.0 100,0 100,50 0,50 c command: (ALE_Bound_IsInside '(0.0000001 0.0000001) (entlast)) T command: (ALE_Bound_IsInside '(-0.0000001 -0.0000001) (entlast)) nil Note: I can not get more precision of about 0.0000001.
Hi Marco, I'm curious. Which one of these functions do you prefer, boundary or offset? I ran some tests. Watch out. ;-) I think I understand why you zoom with the boundary function, but not with the offset function. Boundary seems to need the zoom to attain precision, while offset doesn't. For that reason alone, I would tend to prefer offset. Maybe I'm flaky, but I tend to be suspicious of functions which need zoom to work right. Not to mention the screen hiccup. Regarding precision using your 100 x 50 unit example. Including Doug's function from the other thread and both functions posted here. All seem to choke somewhere around seven decimal places given your examples. That seems a wash and not a concern. BTW, I was not ignoring your post in the other thread about how to do this with plines comprised of line segments only. What wasn't clear in that thread, because of the way it started, was it was aimed at plines with bulges. So as Tony and (I think) Doug said, line segment solutions were not pertinent to the topic at hand. I expect a few more spins on this topic before it comes to conclusion. Regards Joe
Hi Joe, offset? I prefear the offset approach. To avoid what Doug pointed out: figures... we can use a minimum offset distance (on my tests is 0.0000001 - 7 dp), but maybe in rare cases we can have "Doug behaviour" Again: a new function with VisualLisp can escape the use of the AREA command, improvements are welcome. (defun ALE_IsInside (ImpPnt EntNam / NewEnt EntAre) (command "_.AREA" "_O" EntNam) (setq EntAre (getvar "AREA")) (command "_.OFFSET" 0.0000001 EntNam "_NONE" ImpPnt "" "_.AREA" "_O" (setq NewEnt (entlast)) ) (cond ( (eq EntNam NewEnt) (alert "I can't compute this point inside this object!") ) ( (entdel NewEnt) (> EntAre (getvar "AREA")) ) ) ) now the max "precision" is 8 dp (???): command: pline 0.0 100,0 100,50 0,50 c command: (ALE_IsInside '(0.00000001 0.00000001) (entlast)) T command: (ALE_IsInside '(0.000000001 0.000000001) (entlast)) nil Cheers. Marco
I had made a routine that passed the points of a polyline back to the ssget to select objects crossing the polyline, sometimes it would select the original polyline as well but other times it would not. I ended up cheating and offseting the polyline outwards by a very small amount. Then every thing worked fine. I think it had something to do with the zoom factor and screen pixel size that when it passed the point back to ssget ssget was using the current zoom factor and pixel size to determine which entities lay within the polyline. Something similar to not being able to select an entity that cannot be visually seen in the autocad view port. Does ths mean that Autocad uses its current display list to select and perhaps even snap to objects that is using it as some kind of primary filter/modeling array.. This would seem to be a quicker more logical approuch than trying the calculate relalationships of objects back in their original WCS in relation to the current Viewport... Am I on the right track here or is this pure fiction? Any comments....?
Marco, Maybe I'm reading it wrong. Seems to me the first cond is assuming the test against pline (EntNam) is the last drawn object before running the function. Otherwise EntNam would never equal NewEnt. Yes, no, maybe? Joe Burke
Joe, EntNam = the entity name where we are testing if the point ImpPnt is inside NewNam = the entity name of entity created by offset command if, for some reasons, the offest is not possible we have not a new entity (defun ALE_IsInside (ImpPnt EntNam / NewEnt EntAre) (command "_.AREA" "_O" EntNam) (setq EntAre (getvar "AREA")) (command "_.OFFSET" 0.0000001 EntNam "_NONE" ImpPnt "" "_.AREA" "_O" (setq NewEnt (entlast)) ) (cond ( (eq EntNam NewEnt) (princ "Point is on object or is not possible to compute this point inside this object!" ) nil ) ( (entdel NewEnt) (> EntAre (getvar "AREA")) ) ) ) I think it would be better to have a new cond: 1 It is not possible to compute this point inside this object > alert 2 Point is on object (not inside) > nil 3 Point is outside > nil 4 Point is inside > T Marco -- ________________________________________________ Marc'Antonio Alessi (TV) Italy (strcat "NOT a " (substr (ver) 8 4) " guru.") O.S. = XP Pro 2002 - Sp.1 - Ita AutoCAD = 2002 Ita - Sp.1 _VERNUM = "K.0.44" ACADVER = "15.06s (LMS Tech)" (ver) = "Visual LISP 2000 (it)" ________________________________________________
Marco, I may be all wet but... to test whether a new entity was created, I believe you have to establish the last entity first. (defun ALE_IsInside (ImpPnt EntNam / NewEnt EntAre) (setq Mark (entlast)) < code > (cond ((eq Mark NewEnt) Testing (eq EntNam NewEnt) is only valid if EntNam was the last drawn object. Joe Burke
You're absolutely right! I made a big mistake because my testing EntNam was the last entity and I had not foreseen that this could be always not true. My apologies for my lapse. -- I tryed with vl-catch-all-apply to test if the point is on object or it is an offset rejection, but OFFSET do not get any error in case of: "Point is on object" or "It is not possible to offset this object" Note: this is my translation of Offset command messages because I do not know the real english prompts. (defun ALE_IsInside (ImpPnt EntNam / LstEnt NewEnt EntAre AltStr) (command "_.AREA" "_O" EntNam) (setq EntAre (getvar "AREA") LstEnt (entlast) AltStr (vl-catch-all-apply '(lambda () (command "_.OFFSET" 0.0000001 EntNam "_NONE" ImpPnt "" ) ) ) NewEnt (entlast) ) (cond ( (eq LstEnt NewEnt) (and (vl-catch-all-error-p AltStr) (princ (vl-catch-all-error-message AltStr)) ) nil ) ( T (command "_.AREA" "_O" NewEnt) (entdel NewEnt) (> EntAre (getvar "AREA")) ) ) ) Sorry again. Marco
Marco, No need to apologize. Just an oversight. To test if the point is on the pline. This is from Doug's function in the other thread. (setq Closest (vlax-curve-getclosestpointto (vlax-ename->vla-object EntNam) ImpPnt)) (if (not (equal Closest ImpPnt 1e-10)) < OK to proceed... > Joe Burke
Thanks, here is my last attempt: ; ImpPnt: must be a 3D point ; (defun ALE_IsInside (ImpPnt EntNam / VlaObj LstEnt NewEnt EntAre) (vl-load-com) (setq VlaObj (vlax-ename->vla-object EntNam)) (cond ( (not (vlax-property-available-p VlaObj 'Area)) (not (princ "It isn't possible to compute this object!")) ) ( (equal (vlax-curve-getclosestpointto VlaObj ImpPnt) ImpPnt 1e-10) (not (princ "Point is on object!")) ) ( (and (setq LstEnt (entlast)) (not (command "_.OFFSET" 0.0000001 EntNam "_NONE" ImpPnt "")) (eq LstEnt (setq NewEnt (entlast))) ) (not (princ "It isn't possible to compute this point inside this object!") ) ) ( T (setq EntAre (vlax-get-property (vlax-ename->vla-object NewEnt) 'Area)) (entdel NewEnt) (> (vlax-get-property VlaObj 'Area) EntAre) ) ) ) --
This technique was mentioned in the previous thread. It should work fine but is limited to straight line polyline segments. If you are speaking about drawing a point and then selecting it, then the technique would also depend on pdmode and pdsize. The select command and ssget also depend on the objects selected being within the display. In addition, commands that require zooms could be distracting to users. It wouldn't bother me if the program was for me only and it saved me a couple hours of programming. ;-)