broncos15 Posted October 29, 2015 Posted October 29, 2015 I was wondering if there was a way to create a lisp routine that allows the user to select a feature line and then at any point where another feature line crosses it, it would either add a pi or an elevation point to both feature lines at the crossing point. The reason I am wondering is because it is so easy to accidently forget to add a pi or elevation point when creating a new feature line which screws up all of the grading. My thought on creating it would be to either have the lisp break any feature lines that are crossing and then rejoin them. Do you guys think this could work? Quote
BIGAL Posted October 30, 2015 Posted October 30, 2015 Looking at 3rd party Civ3d add ons ARD is one, the nice thing it does is if you have two roads crossing it knows this and matches the intersection point lift one road the other goes with it. Whilst this is not feature line its close, the software does have lots of inbuilt matching ability and may be able to do it. We dont use feature lines much. Can you post an image etc so its clearer about the situation Quote
broncos15 Posted October 30, 2015 Author Posted October 30, 2015 Looking at 3rd party Civ3d add ons ARD is one, the nice thing it does is if you have two roads crossing it knows this and matches the intersection point lift one road the other goes with it. Whilst this is not feature line its close, the software does have lots of inbuilt matching ability and may be able to do it. We dont use feature lines much. Can you post an image etc so its clearer about the situation This would be a common example. I am making a curb cut and I want to make sure that all the feature lines that are touching have PI's or elevation points at those points. That way, when I straight grade, it actually updates both feature lines. Quote
broncos15 Posted October 30, 2015 Author Posted October 30, 2015 That's weird, I upload the image and it looks correct but then when I am sending my reply, it doesn't show up correctly. Quote
Hippe013 Posted October 30, 2015 Posted October 30, 2015 I work quite a bit with feature lines and I know the struggle! I would like to take a shot at this. I am currently at work at the moment but I would be willing to come up with something over this weekend. regards, hippe013 Quote
broncos15 Posted October 30, 2015 Author Posted October 30, 2015 I work quite a bit with feature lines and I know the struggle! I would like to take a shot at this. I am currently at work at the moment but I would be willing to come up with something over this weekend. regards, hippe013 Hippe013, I look forward to it if you can come up with something. My thought of breaking the feature lines got more complicated when I realized that there could be a scenario where two feature lines could be associated with two different surfaces (although I know this scenario is an outlier and wouldn't happen very often in day to day grading). Quote
BlackBox Posted October 30, 2015 Posted October 30, 2015 Why not just add/create/copy the Feature Lines to the same Site? By definition, Feature Lines must be associated to a given Site. If you have two Feature Lines that intersect, one assigned to Site 1, and the other to Site 2, they exists as-is in terms of Elevation Points within Elevation Editor (i.e., Feature Line 2 does not 'intersect' Feature Line 1). However, if you simply move the second Feature Line from Site 2 to Site 1, and re-launch Elevation Editor, you'll see that there is an inferred 'intersection' now at the corresponding elevation. HTH Quote
broncos15 Posted October 30, 2015 Author Posted October 30, 2015 Why not just add/create/copy the Feature Lines to the same Site? By definition, Feature Lines must be associated to a given Site. If you have two Feature Lines that intersect, one assigned to Site 1, and the other to Site 2, they exists as-is in terms of Elevation Points within Elevation Editor (i.e., Feature Line 2 does not 'intersect' Feature Line 1). However, if you simply move the second Feature Line from Site 2 to Site 1, and re-launch Elevation Editor, you'll see that there is an inferred 'intersection' now at the corresponding elevation. HTH This inferred intersection doesn't actually exist though. I always add feature lines to the same site, but things like the "setfeaturegrade" command get really weird when there isn't an elevation point or PI at places where feature lines intersect. Quote
BlackBox Posted October 31, 2015 Posted October 31, 2015 This inferred intersection doesn't actually exist though. I always add feature lines to the same site, but things like the "setfeaturegrade" command get really weird when there isn't an elevation point or PI at places where feature lines intersect. Defining what does, and does not 'exist' is a bit beyond the scope of this thread, given the OP - things like SetFeatureGrade Command getting weird were not included in the OP either, as that introduces a different context to the problem you've presented prior. If you need a PI, then simply add a PI - Not sure how you expect a LISP routine to properly identify which Feature Line to automagically cull the elevation from, if the inference elevation is somehow insufficient... More information is needed. Quote
Hippe013 Posted October 31, 2015 Posted October 31, 2015 This is what I came up with. I call the command 'FLINT' for feature line intersection. Prompts user to select a featureline. It then finds what site it belongs to and all other featurelines that belong to the same site. It finds the intersections using the intersectwith method and then inserts ElevationPoints on both the selected featureline and the featureline that was intersected. The elevation as to which the ElevationPoint is set appears to be rather random, but the point was to automatically add ElevationPoints at the intersections. A prompt could be added to have the user enter the elevation for the inserted point. Give this a test and let me know what you think. regards, hippe013 (defun c:FLINT ( / fl site fls p-count sa catch n proc) (setq ss (ssget "_+.:E:S" '((0 . "AECC_FEATURE_LINE")))) (if ss (progn (setq fl (vlax-ename->vla-object (ssname ss 0))) (setq site (FL:FL->site fl)) (setq fls (vlax-get-property site 'Featurelines)) (setq p-count 0) (vlax-for f fls (if (not (equal f fl)) (progn (setq sa (vlax-variant-value (vlax-invoke-method fl 'IntersectWith f acExtendNone))) (setq catch (vl-catch-all-apply 'vlax-safearray->list (list sa))) (if (not (vl-catch-all-error-p catch)) (progn (setq catch (fl:list->pntlist catch)) (setq n 0) (repeat (length catch) (setq p (nth n catch)) (if (not (member p proc)) (progn ;Use 2 for Elevation Point - Use 1 for PI (vlax-invoke-method fl 'InsertFeaturePoint (vlax-3d-point p) 2) (vlax-invoke-method f 'InsertFeaturePoint (vlax-3d-point p) 2) (fl:drx p 2) (setq proc (append proc (list p))) (setq p-count (+ p-count 2)) ) ) (setq n (+ n 1)) ) ) (progn) ) ) ) ) (princ (strcat "\nInserted " (itoa p-count) " Elevation Points.")) ) (princ "\nNothing was Selected.") ) (princ) ) (defun FL:Site->FL-ID-List (site / fls cnt ret n li) (setq fls (vlax-get-property site 'Featurelines)) (setq cnt (vlax-get-property fls 'Count)) (if (= cnt 0) (setq ret nil) (progn (setq n 0) (repeat cnt (setq li (append li (list (vlax-get-property (vla-item fls n) 'ObjectID)))) (setq n (1+ n)) ) (setq ret li) ) ) ret ) (defun FL:List->pntlist (li / newli) (setq n 0) (repeat (/ (length li) 3) (setq newli (append newli (list (list (nth n li) (nth (+ n 1) li) (nth (+ n 2) li))))) (setq n (+ n 3)) ) newli) (defun FL:FL->Site (fl / cvlapp cvlad sites ret n site objid-list ) (setq cvlapp (vlax-get-property fl 'application)) (setq cvlad (vlax-get-property cvlapp 'ActiveDocument)) (setq sites (vlax-get-property cvlad 'Sites)) (setq ret nil) (setq n 0) (repeat (vlax-get-property sites 'Count) (setq site (vla-item sites n)) (setq objid-list (FL:Site->FL-ID-List site)) (if (member (vlax-get-property fl 'ObjectID) objid-list) (setq ret site) ) (setq n (1+ n)) ) ret ) (defun FL:drx (ctr clr / cor1 cor2 cor3 cor4 vs xs) (setq vs (getvar "viewsize")) (setq xs (/ vs 40)) (setq cor1 (polar ctr (* pi 0.25) xs)) (setq cor2 (polar ctr (* pi 0.75) xs)) (setq cor3 (polar ctr (* pi 1.25) xs)) (setq cor4 (polar ctr (* pi 1.75) xs)) (grdraw ctr cor1 clr 0) (grdraw ctr cor2 clr 0) (grdraw ctr cor3 clr 0) (grdraw ctr cor4 clr 0) ) 1 Quote
BlackBox Posted October 31, 2015 Posted October 31, 2015 For those interested, there's also a newly exposed Feature Line API: http://www.theswamp.org/index.php?topic=49908.0 Quote
broncos15 Posted October 31, 2015 Author Posted October 31, 2015 This is what I came up with. I call the command 'FLINT' for feature line intersection. Prompts user to select a featureline. It then finds what site it belongs to and all other featurelines that belong to the same site. It finds the intersections using the intersectwith method and then inserts ElevationPoints on both the selected featureline and the featureline that was intersected. The elevation as to which the ElevationPoint is set appears to be rather random, but the point was to automatically add ElevationPoints at the intersections. A prompt could be added to have the user enter the elevation for the inserted point. Give this a test and let me know what you think. regards, hippe013 (defun c:FLINT ( / fl site fls p-count sa catch n proc) (setq ss (ssget "_+.:E:S" '((0 . "AECC_FEATURE_LINE")))) (if ss (progn (setq fl (vlax-ename->vla-object (ssname ss 0))) (setq site (FL:FL->site fl)) (setq fls (vlax-get-property site 'Featurelines)) (setq p-count 0) (vlax-for f fls (if (not (equal f fl)) (progn (setq sa (vlax-variant-value (vlax-invoke-method fl 'IntersectWith f acExtendNone))) (setq catch (vl-catch-all-apply 'vlax-safearray->list (list sa))) (if (not (vl-catch-all-error-p catch)) (progn (setq catch (fl:list->pntlist catch)) (setq n 0) (repeat (length catch) (setq p (nth n catch)) (if (not (member p proc)) (progn ;Use 2 for Elevation Point - Use 1 for PI (vlax-invoke-method fl 'InsertFeaturePoint (vlax-3d-point p) 2) (vlax-invoke-method f 'InsertFeaturePoint (vlax-3d-point p) 2) (fl:drx p 2) (setq proc (append proc (list p))) (setq p-count (+ p-count 2)) ) ) (setq n (+ n 1)) ) ) (progn) ) ) ) ) (princ (strcat "\nInserted " (itoa p-count) " Elevation Points.")) ) (princ "\nNothing was Selected.") ) (princ) ) (defun FL:Site->FL-ID-List (site / fls cnt ret n li) (setq fls (vlax-get-property site 'Featurelines)) (setq cnt (vlax-get-property fls 'Count)) (if (= cnt 0) (setq ret nil) (progn (setq n 0) (repeat cnt (setq li (append li (list (vlax-get-property (vla-item fls n) 'ObjectID)))) (setq n (1+ n)) ) (setq ret li) ) ) ret ) (defun FL:List->pntlist (li / newli) (setq n 0) (repeat (/ (length li) 3) (setq newli (append newli (list (list (nth n li) (nth (+ n 1) li) (nth (+ n 2) li))))) (setq n (+ n 3)) ) newli) (defun FL:FL->Site (fl / cvlapp cvlad sites ret n site objid-list ) (setq cvlapp (vlax-get-property fl 'application)) (setq cvlad (vlax-get-property cvlapp 'ActiveDocument)) (setq sites (vlax-get-property cvlad 'Sites)) (setq ret nil) (setq n 0) (repeat (vlax-get-property sites 'Count) (setq site (vla-item sites n)) (setq objid-list (FL:Site->FL-ID-List site)) (if (member (vlax-get-property fl 'ObjectID) objid-list) (setq ret site) ) (setq n (1+ n)) ) ret ) (defun FL:drx (ctr clr / cor1 cor2 cor3 cor4 vs xs) (setq vs (getvar "viewsize")) (setq xs (/ vs 40)) (setq cor1 (polar ctr (* pi 0.25) xs)) (setq cor2 (polar ctr (* pi 0.75) xs)) (setq cor3 (polar ctr (* pi 1.25) xs)) (setq cor4 (polar ctr (* pi 1.75) xs)) (grdraw ctr cor1 clr 0) (grdraw ctr cor2 clr 0) (grdraw ctr cor3 clr 0) (grdraw ctr cor4 clr 0) ) Hippe013 this code is awesome! It is going to be a sweet one for me to study to learn some new coding techniques. My home computer doesn't have autocad on it unfortunately, so I'll have to wait until Monday to test it out unfortunately. Thank you for coming up with this code, it is much better way of doing it than my initial thought. Quote
Hippe013 Posted October 31, 2015 Posted October 31, 2015 Broncos15 - Cheers! I hope it works for you! BlackBox - Great link! I've been trying to move over to vb.net. I'm just finding the learning curve to be rather steep. I can see that using .net has much more access to properties and methods. Though at this point I'm very much a noob when it comes to vb.net. Lots to learn! regards, hippe013 Quote
broncos15 Posted October 31, 2015 Author Posted October 31, 2015 Broncos15 - Cheers! I hope it works for you! BlackBox - Great link! I've been trying to move over to vb.net. I'm just finding the learning curve to be rather steep. I can see that using .net has much more access to properties and methods. Though at this point I'm very much a noob when it comes to vb.net. Lots to learn! regards, hippe013 Hippe013, after glancing through the code more I think I have a solution that would work well for assigning elevations, especially for typical work flow. The user would create a new feature line and assign elevations from the surface of there choice (ie FG). Then they could run this flint code choosing a feature line that is already on the surface. My thinking is that a prompt would be most useful that allows the user to choose what surface to assign elevations to the newly created elevation points (most often they would choose the FG surface). They could then add the new feature line to the surface after this. I think by having a prompt that allows the user to choose what surface to assign elevations to the elevation points would solve the randomness issue. The randomness issue isn't a huge issue though if you think my method is to complex because it would be easy to regrade those few elevation points after running flint. Thanks again for creating this, I really appreciate it! Quote
Hippe013 Posted October 31, 2015 Posted October 31, 2015 Yes, The possibilities are endless as far as prompting for the elevations. You could have it automatically extract the elevations from a surface using the FindElevatioAtXY method of the tin surface object. Or you could have the user enter elevations individually or a default elevation for all of them. This currently just grabs whatever elevation is found through the IntersectWith method. This way if there are a lot of intersections then they are added quickly without user interaction. You could implement some command settings that read and write to the cfg file using getcfg and setcfg. This is an easy way for the command to remember settings that the user has set. I personally would leave this as is (I plan to use this at work) and just regrade as necessary. I am not a fan of the implied intersections as I would rather have an ElevationPoint there for grading through. Feel free to manipulate the code to fit your needs. I am happy to have provided you with a starting point. Quote
BlackBox Posted November 1, 2015 Posted November 1, 2015 BlackBox - Great link! I've been trying to move over to vb.net. I'm just finding the learning curve to be rather steep. I can see that using .net has much more access to properties and methods. Though at this point I'm very much a noob when it comes to vb.net. Lots to learn! Not that many moons ago, I didn't even know what a LISP Defun was; flash forward to my decision to skip VBA and jump from Visual LISP to .NET, and I made a similar choice - to start learning VB. It was my experience that this was actually a hindrance to my learning .NET, which contradicted my basis for starting with VB- that it was very similar syntactically to Visual LISP (ActiveX COM) - something that distracted me by looking for similarities in APIs rather than learning the more distinctive aspects that make .NET what it is. That led me to ultimately drop VB altogether, and start teaching myself C#... And 1800 page Andrew Troelsen book later, 100% of my .NET coding is in C# - custom .NET plugins, custom LispFunction Method plugins (to expand LISP API), VSTO/Windows apps, and WPF Browser apps, etc - and I couldn't be happier with making the leap. This has made me not only better at my daily CAD Production, but also a better CAD/Network admin. Cheers Quote
broncos15 Posted November 2, 2015 Author Posted November 2, 2015 (edited) Yes, The possibilities are endless as far as prompting for the elevations. You could have it automatically extract the elevations from a surface using the FindElevatioAtXY method of the tin surface object. Or you could have the user enter elevations individually or a default elevation for all of them. This currently just grabs whatever elevation is found through the IntersectWith method. This way if there are a lot of intersections then they are added quickly without user interaction. You could implement some command settings that read and write to the cfg file using getcfg and setcfg. This is an easy way for the command to remember settings that the user has set. I personally would leave this as is (I plan to use this at work) and just regrade as necessary. I am not a fan of the implied intersections as I would rather have an ElevationPoint there for grading through. Feel free to manipulate the code to fit your needs. I am happy to have provided you with a starting point.Hippe013, After testing the code out at my office, I have to say I don't think there is a need to add in any more prompts. It works really well and I know I am going to use it a lot while grading. The only thing that I noticed is that the code has issues when there is already an elevation point on the line. When there is already an elevation point at an intersection, it will add in another elevation point on top of the first one. This could cause issues if the user uses flint on the same feature line multiple times (like when more feature lines are added in at a later date). I tried fixing this by changing the insertion from an elevation point to a PI (because CAD doesn't allow you to add multiple PI's on top of each other for the same object), the issue then is that if there is just if there are multiple crossings, but a PI at just one of them, then the code won't run at all. Thanks again for making this code, it will really expedite grading for me and I know many other people that stumble across this post! My code below with PI's, but I am still having issues with it running when there is already a PI at one of the crossings: (defun c:FEATURELINECROSSING (/ fl site fls p-count sa catch n proc) (setq ss (ssget "_+.:E:S" '((0 . "AECC_FEATURE_LINE")))) (if ss (progn (setq fl (vlax-ename->vla-object (ssname ss 0))) (setq site (FL:FL->site fl)) (setq fls (vlax-get-property site 'Featurelines)) (setq p-count 0) (vlax-for f fls (if (not (equal f fl)) (progn (setq sa (vlax-variant-value (vlax-invoke-method fl 'IntersectWith f acExtendNone) ) ) (setq catch (vl-catch-all-apply 'vlax-safearray->list (list sa)) ) (if (not (vl-catch-all-error-p catch)) (progn (setq catch (fl:list->pntlist catch)) (setq n 0) (repeat (length catch) (setq p (nth n catch)) (if (not (member p proc)) (progn ;Use 2 for Elevation Point - Use 1 for PI (vlax-invoke-method fl 'InsertFeaturePoint (vlax-3d-point p) 1 ) (vlax-invoke-method f 'InsertFeaturePoint (vlax-3d-point p) 1 ) (fl:drx p 1) (setq proc (append proc (list p))) (setq p-count (+ p-count 1)) ) ) (setq n (+ n 1)) ) ) (progn) ) ) ) ) (princ (strcat "\nInserted " (itoa p-count) " PI's.") ) ) (princ "\nNothing was Selected.") ) (princ) ) (defun FL:Site->FL-ID-List (site / fls cnt ret n li) (setq fls (vlax-get-property site 'Featurelines)) (setq cnt (vlax-get-property fls 'Count)) (if (= cnt 0) (setq ret nil) (progn (setq n 0) (repeat cnt (setq li (append li (list (vlax-get-property (vla-item fls n) 'ObjectID)) ) ) (setq n (1+ n)) ) (setq ret li) ) ) ret ) (defun FL:List->pntlist (li / newli) (setq n 0) (repeat (/ (length li) 3) (setq newli (append newli (list (list (nth n li) (nth (+ n 1) li) (nth (+ n 2) li) ) ) ) ) (setq n (+ n 3)) ) newli ) (defun FL:FL->Site (fl / cvlapp cvlad sites ret n site objid-list) (setq cvlapp (vlax-get-property fl 'application)) (setq cvlad (vlax-get-property cvlapp 'ActiveDocument)) (setq sites (vlax-get-property cvlad 'Sites)) (setq ret nil) (setq n 0) (repeat (vlax-get-property sites 'Count) (setq site (vla-item sites n)) (setq objid-list (FL:Site->FL-ID-List site)) (if (member (vlax-get-property fl 'ObjectID) objid-list) (setq ret site) ) (setq n (1+ n)) ) ret ) (defun FL:drx (ctr clr / cor1 cor2 cor3 cor4 vs xs) (setq vs (getvar "viewsize")) (setq xs (/ vs 40)) (setq cor1 (polar ctr (* pi 0.25) xs)) (setq cor2 (polar ctr (* pi 0.75) xs)) (setq cor3 (polar ctr (* pi 1.25) xs)) (setq cor4 (polar ctr (* pi 1.75) xs)) (grdraw ctr cor1 clr 0) (grdraw ctr cor2 clr 0) (grdraw ctr cor3 clr 0) (grdraw ctr cor4 clr 0) ) Edited November 2, 2015 by broncos15 Quote
broncos15 Posted November 2, 2015 Author Posted November 2, 2015 After messing around with the code this morning, I am still having issues with having it insert an elevation point where one already exists. I know that I need another if statement at this portion of the code: (if (not (member p proc)) (progn (vlax-invoke-method fl 'InsertFeaturePoint (vlax-3d-point p) 2) (vlax-invoke-method f 'InsertFeaturePoint (vlax-3d-point p) 2) However, I have searched and can't find how to have the if statement test whether an elevation point exists. Does anyone know what the if statement would need to look like to test and see if an elevation point exists, and if it doesn't then to run the above code? Quote
Hippe013 Posted November 4, 2015 Posted November 4, 2015 Broncos15, I just saw your reply. I guess I never thought about what would happen if it was run more than once or if there was already an elevation point. I will take another look at my code and add in a test expression that if an elevation point or PI exists in the spot then skip inserting that point. It may take me a couple days to sit down and look at it. regards, hippe013 Quote
broncos15 Posted November 4, 2015 Author Posted November 4, 2015 Broncos15, I just saw your reply. I guess I never thought about what would happen if it was run more than once or if there was already an elevation point. I will take another look at my code and add in a test expression that if an elevation point or PI exists in the spot then skip inserting that point. It may take me a couple days to sit down and look at it. regards, hippe013 Hippe013, thank you so much for getting back to me! I would love to see what that test expression would look like because I have messed around with it for a long time and I can't seem to think of how to write it. Unfortunately, I have just started learning Visual Lisp so I am pretty unfamiliar with all of the vla functions, which is why I am trying to learn them and see examples. Thanks again for the help with this code, it is really useful and has been cool to look through and learn more about. Also, I was curious after looking through all of the code. Why is (vl-load-com) not needed anywhere in the code if it makes use of Visual Lisp functions? 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.