speed3b Posted March 10, 2016 Posted March 10, 2016 Hello all! My first post here (I think). I'm trying to write a lisp that will change the elevations of selected AECC_COGO_POINT's to *PROPERTY NOT SET*. The trouble I'm having is vlax-put-property and vla-put-elevation always expects a real number and I don't know what special vlax or vla command will just remove the elevation from the point. Ultimately, I plan to then change this to automatically find any cogo points in the drawing that have an elevation of 0 or less and delete the elevation (set to *PROPERTY NOT SET*) from it. Having a 0 elevation can cause issues with our field crews when they have stakeout points. And typically the office tech isn't paying attention to what they are doing. So I plan to implement that the office tech run this lisp before exporting any points. Figured this would be pretty simple for them to do. So far i have the following: (defun c:cogonoz (/ i ss) (setq ss (ssget '((0 . "AECC_COGO_POINT"))) i 0) (repeat (sslength ss) (setq sspt (vlax-ename->vla-object (ssname ss i))) (vlax-put-property sspt "Elevation" *) (setq i (1+ i)) ) ) I have tried using vla-put-elevation in place of the vlax-put-properties ... "Elevation". The lisp is only accepting a real number where the * is at currently. I've tried nil, null, *PROPERTY NOT SET*, a ., just plain "" or " ", and all of the previous inside of "". At this point, I figure both of the commands I'm trying to use will only accept a real number and there is possibly a different vla or vlax command that i need to use. Unfortunately, I'm still very new to this and am not familiar with all the syntax. I've searched around but can't find anything in clearing out an elevation from a cogo point within a lisp. Any help would be appreciated! Thank you! -Brett Quote
BlackBox Posted March 10, 2016 Posted March 10, 2016 Welcome to CADTutor. The simplest way to determine what you need, is to see what Property values an Object has, that's already set the way you want. As example, if you were to check the Elevation Property of a COGO Point that already reflects *PROPERTY NOT SET*, you'll get a returned value of -1.0e+020. Once you know that, simply apply that real number to a COGO Point: (vla-put-elevation [color="red"]<YourCogoPointObject>[/color] -1.0e+020) Cheers Quote
speed3b Posted March 10, 2016 Author Posted March 10, 2016 Hi BlackBox. Thank you for the quick reply. I should have mentioned that I did try doing that with no success, but had I took the scientific notation and dropped it in as regular decimal form. I'll try doing it using the scientific notation to see if that is some sort of trick. Perhaps I didn't convert it property too. I have to run to a meeting right now and will test and let you know the results as soon as I can. Thank you again! -Brett Quote
speed3b Posted March 10, 2016 Author Posted March 10, 2016 Hello again BlackBox. What you suggested worked great; I should not have tried to convert it to decimal form. Thank you for the help! Now I'm struggling to get ssget to select cogo points with elevations less than or equal to 0. I've tried the following: (setq ss (ssget '((0 . "AECC_COGO_POINT")(-4 . "<=")(38 . 0.0))) i 0) The result I get is this selects all cogo points regardless of elevation. (setq ss (ssget '((0 . "AECC_COGO_POINT")(-4 . "*,*,<=")(10 0.0 0.0 0.0))) i 0) The result I get is this won't select anything. Any suggestions? I know I could just have it grab all the points, then run it through an "if" statement to check if elevations is -Brett Quote
broncos15 Posted March 11, 2016 Posted March 11, 2016 Hello again BlackBox. What you suggested worked great; I should not have tried to convert it to decimal form. Thank you for the help! Now I'm struggling to get ssget to select cogo points with elevations less than or equal to 0. I've tried the following: (setq ss (ssget '((0 . "AECC_COGO_POINT")(-4 . "<=")(38 . 0.0))) i 0) The result I get is this selects all cogo points regardless of elevation. (setq ss (ssget '((0 . "AECC_COGO_POINT")(-4 . "*,*,<=")(10 0.0 0.0 0.0))) i 0) The result I get is this won't select anything. Any suggestions? I know I could just have it grab all the points, then run it through an "if" statement to check if elevations is -Brett I printed the dxf information and I can't find a dxf code for the elevations. Instead you could grab all the cogo points, then filter out (create either another selection set using ssadd or delete from the selection set using ssdel). You would do this using (this is untested): (setq cnt 0 ss1 (ssadd)) (repeat (sslength ss) (if (<= (vla-get-elevation (vlax-ename->vla-object (ssname ss cnt))) 0) (ssadd (ssname ss cnt) ss1) ) (setq cnt (+ cnt 1)) ) Quote
speed3b Posted March 11, 2016 Author Posted March 11, 2016 I printed the dxf information and I can't find a dxf code for the elevations. Well that certainly ruined my plan so it wouldn't have to do it for every point in the drawing every time the lisp runs. Certainly could be bad if I have 1000's of points in a drawing. Thank you for the info though. I figured since the elevation info shows up when you list the object and that the same info was stored in the 10 and 38 dxf codes and I would be able to utilize it. I ended up accomplishing it using the following: (defun c:cogonoz (/ i ss) (setq ss (ssget '((0 . "AECC_COGO_POINT"))) i 0) (repeat (sslength ss) (setq sspt (vlax-ename->vla-object (ssname ss i))) (if (<= (vla-get-elevation sspt) 0) (vla-put-elevation sspt -1.0e20) ) (setq i (1+ i)) ) ) So it will check every point and if the elevation is less than or equal to 0, it sets the elevation to -1.0e20, if not, it moves on. Would there be another way to accomplish this same sort of thing but using a completely different method? Not sure if every cogo point is stored to a list and it checks each point in the drawing via that list? Using the above took almost 60 seconds to apply it to 4560 points. Thank you for the help! -Brett Quote
BlackBox Posted March 11, 2016 Posted March 11, 2016 Guys - Very little of what makes up Civil 3D Objects has been exposed to Visual LISP (ActiveX COM), or .NET API for that matter, let alone AutoLISP & DXF... In fact, *most* things you can do with Civil 3D Objects is going to require Visual LISP at a minimum. That said, I cannot help but feel that there's a bigger goal here; why are you wanting to strip the elevations from these COGO Points in the first place? The only things that come to mind are point group filtering, or surface building, which can already be done through the respective Properties. More information is needed. To your code issue - Here's a quick alternative that is +/- 23% faster, and provides for UNDO functionality: (vl-load-com) (defun c:FOO (/ *error* acDoc ss) (defun *error* (msg) (if ss (vla-delete ss)) (if acDoc (vla-endundomark acDoc)) (cond ((not msg)) ; Normal exit ((member msg '("Function cancelled" "quit / exit abort"))) ; <esc> or (quit) ((princ (strcat "\n** Error: " msg " ** "))) ; Fatal error, display it ) (princ) ) (if (ssget "_:L" '((0 . "AECC_COGO_POINT"))) (progn (vla-startundomark (setq acDoc (vla-get-activedocument (vlax-get-acad-object))) ) (vlax-for x (setq ss (vla-get-activeselectionset acDoc)) (if (<= (vla-get-elevation x) 0.) (vla-put-elevation x -1.0e20) ) ) ) ) (*error* nil) ) Cheers Quote
broncos15 Posted March 11, 2016 Posted March 11, 2016 Black box is correct, programming Civil 3D is not documented well at all. The only way I can think to expedite the program is to use all visual lisp for selection. vla-select or vlax-safearray-put-element could both work. I haven't done much programming using these functions though. Quote
speed3b Posted March 11, 2016 Author Posted March 11, 2016 Guys - That said, I cannot help but feel that there's a bigger goal here; why are you wanting to strip the elevations from these COGO Points in the first place? Cheers The main issue is that when some of the office techs create points for the field crews they don't pay attention to the elevations of the points they are creating. They are simply giving them X & Y, but the default elevation for the point ends up at zero. Or if a cogo point gets moved via its pick box to another object at zero elevation, it snaps the elevation back to zero. Recently, for a reason I have yet to figure out, the tech actually keyed in a negative elevation. So how does this cause an issue? Well then the points get imported via a csv file to the data collector. When the field crew goes to do a stakeout with a robotic total station and the robot is told the elevation is at zero the scope plummets and points down at the ground. Additionally, if the point is used for a GPS site calibration or a geodetic coordinate system, then geodesics comes into play and the elevation values can play tricks on the equipment when measuring distance and applying scale factors. If I set the elevation to *property not set*, then I can let Civil3D assign a null elevation in the csv file for the elevation value during export. That null value is identified by the data collector during import and is replaced by the keyed in average project elevation when geodetic calculations are performed. Now typically we aren't dealing with 4000+ points at a time. I am simply using that many to test the reliability and practical use of the lisp. I do my best to try to educate and teach them about this stuff, but it seems to go in one ear and out the other, or they forget out about it a week later. Some people just don't understand QA/QC checks on their own work, they just want a button to click. Black box is correct, programming Civil 3D is not documented well at all. The only way I can think to expedite the program is to use all visual lisp for selection. vla-select or vlax-safearray-put-element could both work. I haven't done much programming using these functions though. I'm far from familiar with most of this stuff. I spend a lot of time on google looking at examples to figure out how to write everything I'm doing. I will attempt to google vla-select and vlax-safearray-put-element to see if there is a better solution to this. I tried the code BlackBox posted but it seemed to take close to the same amount of time as what mine did. I really do appreciate both your time for looking at this and helping me. -Brett Quote
broncos15 Posted March 14, 2016 Posted March 14, 2016 So I was thinking about this some more and I think you should you probably use method 5 of Lee Mac's selection set processing. With so many points having to be converted from an entity to a vla-object, it probably makes the most amount of sense. Lee's tutorial can be found here: http://www.lee-mac.com/selsetprocessing.html. Let me know if you have any more questions. Quote
BlackBox Posted March 14, 2016 Posted March 14, 2016 So I was thinking about this some more and I think you should you probably use method 5 of Lee Mac's selection set processing. With so many points having to be converted from an entity to a vla-object, it probably makes the most amount of sense. Lee's tutorial can be found here: http://www.lee-mac.com/selsetprocessing.html. Let me know if you have any more questions. How is that different from the code I posted last week in post #7? Quote
speed3b Posted March 14, 2016 Author Posted March 14, 2016 (edited) So I was thinking about this some more and I think you should you probably use method 5 of Lee Mac's selection set processing. With so many points having to be converted from an entity to a vla-object, it probably makes the most amount of sense. Lee's tutorial can be found here: http://www.lee-mac.com/selsetprocessing.html. Let me know if you have any more questions. That is very interesting. I ran the test5 and selected the 4560 cogo points and it prints them out instantly. Dropped my 3 lines of code in place of his print and repeated: (if (<= (vla-get-elevation o) 0) (vla-put-elevation o -1.0e20) ) It took about the same 50-55 seconds to get through and change the 4560 point elevations. So I stabbed around a bit and at first thought it was the if statement having to still check every single point in the selection set no matter what. To test I replaced my vla-put-elevation line with his print line and ran the lisp again. To my surprise it went through almost instantly and listed every point. I then manually changed almost all of the 4560 points to an elevation greater than zero, put my vla-put-elevation line back in and ran it. The 150ish points that were a zero elevation changed within a couple seconds. Here's where the oblong shaped gears in my head started turning. I changed all the elevations to *PROPERTY NOT SET* and ran it again. Tada... it took the 50-55 seconds. Since the value of *PROPERTY NOT SET* is -1.0e20 (a negative number) it was performing the vla-put-elevation on every point that was already set to *PROPERTY NOT SET*. To confirm I just added a check for that and modified as follows: (if (<= (vla-get-elevation sspt) 0) (if (/= (vla-get-elevation sspt) -1.0e20) (vla-put-elevation sspt -1.0e20) ) ) Now it runs great and it only takes more time if the elevation actually has to change. If there are no points that need to change it pretty much goes through instantly. It takes the same amount of time to select all the points and change the elevation in the properties palette, which makes sense. I can't ask for better performance than what Civil3D actually gives you. I dropped the code back into my original lisp and it works the same as Lee-Mac's test5 code (no noticeable difference). So now I end up with: (defun c:cogonoz (/ i ss) (setq ss (ssget '((0 . "AECC_COGO_POINT"))) i 0) (repeat (sslength ss) (setq sspt (vlax-ename->vla-object (ssname ss i))) (if (<= (vla-get-elevation sspt) 0.0) (progn (if (/= (vla-get-elevation sspt) -1.0e20) (progn (vla-put-elevation sspt -1.0e20) )) )) (setq i (1+ i)) ) ) Thank you for the help! I think this will suffice for what I want it to do. Edited: Cleaned up some mistakes... Edited March 15, 2016 by speed3b Quote
speed3b Posted March 15, 2016 Author Posted March 15, 2016 How is that different from the code I posted last week in post #7? I didn't notice until you mentioned it, but yes that code is the same as what you came up with. Still new to the programing side of AutoCAD and its different than any other very simple programs and routines I have ever done. Seems like there are way more methods to doing than other programing. Is there one particular reason that the method you used would be superior to what I have so far? Quote
broncos15 Posted March 16, 2016 Posted March 16, 2016 Speed3b, nice work on the code, and the check to see if the points were already set at *PROPERTY NOT SET*. I made a few minor changes to your code to hopefully ease the use of it and make it a little more straight forward. (defun c:cogonoz (/ i ss *error*) (defun *error* (msg) (if (not (member msg '("Function cancelled" "quit / exit abort")) ) (princ (strcat "\nError: " msg)) ) (princ) ) (if (setq ss (ssget "_A" '((0 . "AECC_COGO_POINT")))) ;;;This will select all the cogo points that aren't frozen, so the user doesn't have to ;;;Use an if statement so the code doesn't run if there aren't any cogo points (progn (setq i 0) (repeat (sslength ss) (setq sspt (vlax-ename->vla-object (ssname ss i))) (if (and (<= (vla-get-elevation sspt) 0.0) (/= (vla-get-elevation sspt) -1.0e20) ) (vla-put-elevation sspt -1.0e20) ) (setq i (1+ i)) ) ) ) ) Quote
BlackBox Posted March 16, 2016 Posted March 16, 2016 I didn't notice until you mentioned it, but yes that code is the same as what you came up with. Still new to the programing side of AutoCAD and its different than any other very simple programs and routines I have ever done. Seems like there are way more methods to doing than other programing. Is there one particular reason that the method you used would be superior to what I have so far? No worries; we all start somewhere. The LISP API is often referred to as being either AutoLISP, or Visual LISP, when they're parts of the same thing, but more accurately refer to methodology used to perform an action. As example, take iteration of a selection set. The former is often fastest using REPEAT+SSNAME to obtain the Entity Name (aka ObjectId), but painfully slow when also having to convert the Entity Name-->vla-Object, whereas Visual LISP's (ActiveX COM) vlax-For can directly iterate the Document's ActiveSelectionSet Collection Object (as vla-Objects), so no efficiency is lost converting from one to the other. Problem lies with knowing when to use which, as each has inherent benefits, particularly when you come to realize that not every Property, Method, or Event is exposed to either (AutoLISP or Visual LISP)... It's all about the right tool for the job, and I say that doing most development in .NET API these days... I regularly hop into VLIDE to quickly 'script' something in Visual LISP for my production projects to this day. The Visual LISP approach is the better approach for this task, as firstly, the Property you're after with COGO Points is not exposed to AutoLISP's required Entity Data, and secondly, allows for UNDO functionality without nested COMMAND function calls. Win-win. [Edit] - The only way to do what you're after, even faster, is to step up into the .NET API, and even then, the ObjectARX API (C++ for AutoCAD) will be faster still... See this short DevBlog article series for reference: The Right Tools for the Job Cheers Quote
speed3b Posted March 19, 2016 Author Posted March 19, 2016 (if (and (<= (vla-get-elevation sspt) 0.0) (/= (vla-get-elevation sspt) -1.0e20) ) (vla-put-elevation sspt -1.0e20) ) ) Very nice, I was wondering how to add multiple criteria (the and) to the if statement. That definitely cleans it up more and reads better. I'm not familiar at all with error handling, but have seen some mentions of it from other members (including BlackBox in his previous posted code). What occurs if an error handling is not accounted for (especially for a routine of this type and size)? Definitely isn't something I have worried about, I just want the code to run. Problem lies with knowing when to use which, as each has inherent benefits, particularly when you come to realize that not every Property, Method, or Event is exposed to either (AutoLISP or Visual LISP)... It's all about the right tool for the job, and I say that doing most development in .NET API these days... I regularly hop into VLIDE to quickly 'script' something in Visual LISP for my production projects to this day. The Visual LISP approach is the better approach for this task, as firstly, the Property you're after with COGO Points is not exposed to AutoLISP's required Entity Data, and secondly, allows for UNDO functionality without nested COMMAND function calls. Win-win. [Edit] - The only way to do what you're after, even faster, is to step up into the .NET API, and even then, the ObjectARX API (C++ for AutoCAD) will be faster still... See this short DevBlog article series for reference: Certainly, I agree. A mechanic is only as good as the tools he has and more importantly, his knowledge of using them. Some tools might work for more tasks, but are not ideal for certain jobs; while another may only serve to complete a specific task very efficiently. Right now my tool box is fairly empty and I feel like I'm just beating on pipes with a hammer. I took a Civil3D .NET API lab/class at AU a couple years back. I'll try digging my notes out and seeing what kind of damage I can do with that. I know the .NET API requires Microsoft Visual Studio (or is there other alternatives?). What do you use to program ObjectARX? Are there major differences in the programming methods of the two (I feel like this is a stupid question)? It is very interesting to see the efficiency differences of all the methods available. I didn't figure a process such as this could be sped up. Just doing a select similar of the 4000+ cogo points and manually changing the elevations to *PROPERTY NOT SET* via the properties palette takes the same amount of time as the routine we came up with does. Quote
broncos15 Posted March 21, 2016 Posted March 21, 2016 I'm not familiar at all with error handling, but have seen some mentions of it from other members (including BlackBox in his previous posted code). What occurs if an error handling is not accounted for (especially for a routine of this type and size)? Definitely isn't something I have worried about, I just want the code to run. Error handling is very important to use. It allows the user to hit escape while running the routine and have variables be reset, as well as ensure that variables are reset if something goes wrong. See Lee Mac's tutorial here: http://lee-mac.com/errorhandling.html as well as the one on afralisp: http://www.afralisp.net/autolisp/tutorials/error-trapping.php Quote
BlackBox Posted March 21, 2016 Posted March 21, 2016 Very nice, I was wondering how to add multiple criteria (the and) to the if statement. That definitely cleans it up more and reads better. Just to speed it up a bit; there's no need to query the elevation twice: (if (and (<= [color="red"](setq elev [/color](vla-get-elevation sspt)[color="red"])[/color] 0.0) (/= [color="red"]elev [/color]-1.0e20) ) (vla-put-elevation sspt -1.0e20) ) Certainly, I agree. A mechanic is only as good as the tools he has and more importantly, his knowledge of using them. Some tools might work for more tasks, but are not ideal for certain jobs; while another may only serve to complete a specific task very efficiently. Right now my tool box is fairly empty and I feel like I'm just beating on pipes with a hammer. I took a Civil3D .NET API lab/class at AU a couple years back. I'll try digging my notes out and seeing what kind of damage I can do with that. I know the .NET API requires Microsoft Visual Studio (or is there other alternatives?). What do you use to program ObjectARX? Are there major differences in the programming methods of the two (I feel like this is a stupid question)? It is very interesting to see the efficiency differences of all the methods available. I didn't figure a process such as this could be sped up. Just doing a select similar of the 4000+ cogo points and manually changing the elevations to *PROPERTY NOT SET* via the properties palette takes the same amount of time as the routine we came up with does. Both .NET and ObjectARX can be developed using Visual Studio, and there are other alternative IDE's out there. The reason you're only going to see marginal differences in efficiency with LISP variants, is the fact that each Get/Put call to an Object's Property is a standalone Transaction on the Object, whereas the .NET/ARX APIs allow for a single Transaction to be used, to open multiple Objects. There are other inherent aspects to .NET API that make it significantly more efficient than LISP, but not needed here. Also, given that the point of this exercise is 'reset' COGO Points with 0.0 or less elevation, to don't forget that you can iterate the parent Collection Object; you need not prompt user for a selection set (which takes time to acquire), and that would allow you to also batch process multiple drawings, should that be needed. Cheers Quote
johnevansdesign Posted November 2, 2020 Posted November 2, 2020 Thanks everyone for this discussion. I really needed some help modifying point elevations, and was told it couldn't be done in LISP. 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.