saim Posted January 29, 2018 Posted January 29, 2018 I'm looking for a lisp routine that gives me the area (value) of the interception of twoo areas. It is not required that the lisp draws the interception area, I just need the value (in fact, if it does draw, I will delete it later). It is for calculating the population of a given area. I have a map of the required area and a map of population density. As you may guess, they only match seldomly. So I need to get the intercepted areas and multiply by the densities, sum all the values and the result is what I'm looking for. I'm used to break copies of the polylines on the interception points and join the resulting polylines, which consumes a lot of time (I have plenty of areas to calculate). Since I have to show (on excell) what has been considered for the calculation, the lisp don't have to calculate the population for me, just the areas. If it helps, both polylines are always closed (although the "closed" property of the object may be "false" - it only ends at the same point it began) and made of line segments (there is no arc or whatsoever). Both polylines are on the same elevation. Do you know any lisp that does it? If not, how should I start to develop one of my own? If my english confuses you, please let me know. Quote
Lee Mac Posted January 29, 2018 Posted January 29, 2018 Alternatively, convert a copy of the polylines to regions (REGION command), perform an intersection (INTERSECT command), and query the area of the resulting region (Properties Palette / AREA command). This process could of course be automated using LISP. 1 Quote
saim Posted January 30, 2018 Author Posted January 30, 2018 (edited) "boundary" worked fine untill I have 2 resulting areas (think of 2 number-eight-shaped areas overlapping). Then, I'd have to sum the areas and I couldn't find a way to detect if that was required. Then I ran to the "regions" attempt and it worked great, so far. I'll spend some time trying to make a lisp for it (and figuring out a nice output, probably I'll really just have a print of the value). I'll cry for help if I find any trouble. In the meantime, thanks a lot! Edited January 30, 2018 by saim misspelling Quote
Lee Mac Posted January 30, 2018 Posted January 30, 2018 You're welcome - good luck with the program! Quote
saim Posted January 30, 2018 Author Posted January 30, 2018 How do I set the last created object to a variable? (so I can transform it into regions and delete it) (setq cp1 (car (entsel L))) and (setq cp1 (car (entsel "L"))) aren't working... Quote
saim Posted January 30, 2018 Author Posted January 30, 2018 I love this forum! You are so fast that I didn't get the chance to edit my last post with another question... The question was: Also... How do I get info from a region? Tried, for testing (entget car (entsel "\nSelect a region")) and got a "bad argument type" error... (of course, I did select a region) Quote
Grrr Posted January 30, 2018 Posted January 30, 2018 You are missing a set of syntaxes: (entget[b] [color="red"]([/color][/b]car (entsel "\nSelect a region")[b][color="red"])[/color][/b]) Quote
saim Posted January 31, 2018 Author Posted January 31, 2018 (edited) Thanks! But the area of a region is not one of its properties... Ok, I do have the "area" command and it works on regions. But it isn't working when I enter the region as a variable... Am I doing it wrong? (defun c:arint() ;area na interseção entre duas polylinhas (setq pl1 (car (entsel "\nSelecione o primeiro limite: "))); coloca o primeiro limite na variável pl1 (setq pl2 (car (entsel "\nSelecione o segundo limite: "))); coloca o segundo limite na variável pl2 (command "copy" pl1 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp1 (entlast)); joga a copia numa var (command "region" cp1 ""); transforma em uma region (setq r1 (entlast)); coloca a region numa var (command "copy" pl2 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp2 (entlast)); joga a copia numa var (command "region" cp2 ""); transforma em uma region (setq r2 (entlast)); coloca a region numa var (command "intersect" r1 r2 ""); cria uma intersecao das regions (setq ainter (entlast)); coloca a nova region numa var (command "area" "o" ainter) ) Also... The "area" command gives me both area and perimeter. How can I get just the area, to make ir clearer to the user? Edited January 31, 2018 by saim Quote
ronjonp Posted January 31, 2018 Posted January 31, 2018 (edited) Don't use the area command, try something like this ( you'll need to put a check that the object selected is actually a region ) (vl-load-com) ;; Loads ActiveX support (setq ainter (entsel "\nSelect region: ")) ;; Returns (<Entity name> point) (setq ainter (car ainter)) ;; Returns <Entity name> (setq ainter (vlax-ename->vla-object ainter)) ;; Returns #<VLA-OBJECT IAcadRegion> (vla-get-area ainter) ;; Returns the area Edited January 31, 2018 by ronjonp Quote
saim Posted January 31, 2018 Author Posted January 31, 2018 (edited) Only now I noticed the 2nd page of the thread... Looking at the posting times, you posted before I editted my previous entry. Now, you have there the whole code I was using before I saw your idea. As you can see, I don't want the user to actually click on the intersected region, I want the area displayed and then, delete the region (the deleting part is still not in the code). That doesn't mean I can't use your code, only that I have to change it a bit. So I tried to replace the "entsel" part by using "(entlast)". Here how the full code ended up and the error I got: (defun c:arint() ;area na interseção entre duas polylinhas (vl-load-com) (setq pl1 (car (entsel "\nSelecione o primeiro limite: "))); coloca o primeiro limite na variável pl1 (setq pl2 (car (entsel "\nSelecione o segundo limite: "))); coloca o segundo limite na variável pl2 (command "copy" pl1 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp1 (entlast)); joga a copia numa var (command "region" cp1 ""); transforma em uma region (setq r1 (entlast)); coloca a region numa var (command "copy" pl2 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp2 (entlast)); joga a copia numa var (command "region" cp2 ""); transforma em uma region (setq r2 (entlast)); coloca a region numa var (command "intersect" r1 r2 ""); cria uma intersecao das regions (setq ainter (entlast)); coloca a nova region numa var - THIS SHOULD REPLACE THE CLICKING PART (I guess it does) (setq ainter (car ainter)) (setq ainter (vlax-ename->vla-object ainter)) (vla-get-area ainter) ) bad argument type: consp I'm really just copying-pasting the activex part, for I have no idea how to deal with it... Edited January 31, 2018 by saim Quote
ronjonp Posted January 31, 2018 Posted January 31, 2018 I would suggest looking up the functions you're using and figuring out what they do. (entlast) returns an ename and car is used on lists ... therefore (setq ainter (car ainter)) will not work. Quote
saim Posted February 1, 2018 Author Posted February 1, 2018 Oops. Since "entsel" returns a list, I figured "entlast" (which sounds resemblant) would do the same. My bad. Now I have the area getting returned as I wanted. The final thing I need is to delete the resulting intersection, so the user won't have to do it manually. But (command "erase" ainter "") doesn't work. I suppose that during those vla-functions, the type of object or the variable changed and somehow I can no longer delete it using that syntax. Tried to check the hypotesis that it was just the variable (and the object remained deletable) and got up with this: (defun c:arint() ;area na interseção entre duas polylinhas (vl-load-com) (setq pl1 (car (entsel "\nSelecione o primeiro limite: "))); coloca o primeiro limite na variável pl1 (setq pl2 (car (entsel "\nSelecione o segundo limite: "))); coloca o segundo limite na variável pl2 (command "copy" pl1 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp1 (entlast)); joga a copia numa var (command "region" cp1 ""); transforma em uma region (setq r1 (entlast)); coloca a region numa var (command "copy" pl2 "" (list 0 0 0) (list 100 0 0)); copia a pl (setq cp2 (entlast)); joga a copia numa var (command "region" cp2 ""); transforma em uma region (setq r2 (entlast)); coloca a region numa var (command "intersect" r1 r2 ""); cria uma intersecao das regions (setq ainter (entlast)); coloca a nova region numa var - THIS SHOULD REPLACE THE CLICKING PART (I guess it does) (setq nami (vlax-ename->vla-object ainter)) (setq aarea (vla-get-area nami)) (command "erase" ainter "") (princ aarea) ) Yup! It was just the variable, now the surface is gone. But without the "princ" command, the area value doesn't show up and WITH the command, there is only one decimal and the number is getting shown twice (the area I tried was 96789.1 and the prompted value was 96789.196789.1). I know that if I check again how the "princ" command works I can get rid of the double-value problem, but I don't know how to get 4 decimals like your fix was getting me. Quote
ronjonp Posted February 1, 2018 Posted February 1, 2018 (edited) Try this to print your result with 4 decimal places: (print (rtos 96789.196789 2 4)) THIS thread may be of interest to you for handling region creation and subtracting/intersecting/unions of them. To expand that post here's some commented code that should do what you want as well. (defun c:iinter (/ r o n s) ;; RJP 02.01.2018 (vl-load-com) (if (and ;; Filter only lwpolylines (setq s (ssget ":L" '((0 . "lwpolyline")))) ;; Convert to a list of vla-objects (setq s (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))))) ;; Remove polylines that are not closed (will not make a region) (setq s (vl-remove-if '(lambda (x) (= 0 (vlax-get x 'closed))) s)) ;; Check that the result has at least 2 items (> (length s) 1) ;; Check that the first two items intersect (vla-intersectwith (car s) (cadr s) acextendnone) ) (progn ;; Get the active space (setq n (vlax-get (vla-get-activedocument (vlax-get-acad-object)) (if (= (getvar 'cvport) 1) 'paperspace 'modelspace ) ) ) ;; Create a region from the first item in the list (setq r (car (vlax-invoke n 'addregion (list (car s))))) ;; Create a region from the second item in the list (setq o (car (vlax-invoke n 'addregion (list (cadr s))))) ;; Intersect the two (vla-boolean r acintersection o) ;; Print results (print (rtos (vla-get-area r) 2 4)) ;; Delete intersected object (vla-delete r) ) ) ;;SSSHHHH (princ) ) Edited February 1, 2018 by ronjonp Quote
saim Posted February 16, 2018 Author Posted February 16, 2018 I've FINALLY returned to this issue. Some problems have taken me away from it, but I got back just to realize it was REALLy solved. You code is great! It makes a lot of stuff I hadn't even thought about - like filtering polylines from other objects and opened polylines from the list (though I will not use that last one, for most of my polylines do end at the same point as it has started, but are open - and that's why I thought your code wasn't working, before I got back). It has some commands I don't know, but the comments make it easier for me to look them up - I sure will! And that final comment - "SSSHHHH" - Hahah! It shown me what was the double-value problem. Solved! Thanks a lot, your great help was essential! 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.