All,
I'm currently trying to write a LISP function that does the following:
-prompts user to select a Feature Line
-prompts user to select a starting and ending point along that Feature Line
-prompts the user to enter a keyword determining which calculation formula to use (from a list of four, based on the TR-55 Hydrology manual)
-calculates the flow time based on the above
-returns the segment length, segment slope, and flow time at the Command Line
I've written up some code (see below) and get an error: too few arguments. Can someone take a look and see what I'm doing wrong? I'm not a good programmer so apologies in advance...
*ninja edit: the original problem (too few arguments) was because I foolishly didn't specify for the user to actually select a point. Added (getpoint) to the vlax-curve-getclosestpointto lines.
Now however I'm getting an error "no function definition: get2ddistancebetweenpoints. I know this is function exists, but I must be calling it wrong. Any help?
(defun c:conctime ( / sel obj compoint1 compoint2 seglen z1 z2 slope ftype segtime rdlen rdslope rdtime)
(vl-load-com)
(princ "\nSelect Feature Line: ")
(setq sel (ssget "+.:s" '((0 . "AECC_FEATURE_LINE"))))
(if sel
(progn
(setq obj (vlax-ename->vla-object (ssname sel 0)))
(princ "\nSelect Start Point: ")
(setq compoint1 (vlax-curve-getClosestPointTo obj))
(princ "\nSelect End Point: ")
(setq compoint2 (vlax-curve-getClosestPointTo obj))
(setq seglen (vlax-curve-get2dDistanceBetweenPoints compoint1 compoint2))
(setq z1 (caddr compoint1))
(setq z2 (caddr compoint2))
(setq slope (abs (/ (- z1 z2) seglen)))
(initget 1 "Sheet Unpaved Paved Channel")
(setq ftype (getkword " [Sheet/Unpaved/Paved/Channel]: "))
(cond ((= ftype "Sheet")
(setq segtime (* 60 (/ (* 0.007 (expt (* 0.3 seglen) 0.8)) (* 1.8276 (expt slope 0.4)))))
)
((= ftype "Unpaved")
(setq segtime (/ seglen (* 60 (* 16.1345 (expt slope 0.5)))))
)
((= ftype "Paved")
(setq segtime (/ seglen (* 60 (* 20.3282 (expt slope 0.5)))))
)
((=ftype "Channel")
(setq segtime (/ seglen 360))
)
)
(setq rdlen (rtos seglen 2 2))
(setq rdslope (rtos slope 2 2))
(setq rdtime (rtos segtime 2 2))
(princ rdlen)
(terpri)
(princ rdslope)
(terpri)
(princ rdtime)
(princ)
)
)
)
Solved! Go to Solution.
Solved by hippe013. Go to Solution.
The Distance function returns a two dimensional distance when the arguments are two dimensional. It returns the three dimensional distance when both of the arguments supplied are are three dimensional.
@hippe013 , you've been a wealth of knowledge. Thanks so much for your help!
I've gotten the first iteration of the LISP to work as intended, returning values that match my hand checks. So now I've moved on to the next iteration. Here I would like to be able to calculate multiple flow segments along one Feature Line. I'm basically trying to create a loop where the user clicks a start/end point and selects a flow type (as before), and those values are added to a list. This would continue until the user hits Enter, at which point the routine would spit out the sets of values like so:
SHEET
100.00 feet
1.27 percent slope
20.44 minutes
UNPAVED
155.04 feet
0.70 percent slope
8.47 minutes
etc etc. The end goal is to print those values to either an AutoCAD table, .txt file, or Excel file - but that's a topic for later.
Right now I'm getting an error: "bad argument type: numberp: nil." Any thoughts on what's causing it? See code below...
(defun c:conctime ( / sel obj compoint1 compoint2 seglen z1 z2 segslope ftype segtime rdlen rdslope rdtime seglist count1 curseg count2)
(vl-load-com)
(setq count1 0) ;counter for tracking number of segments
(setq count2 0) ;counter for printing segment info
;get Feature Line from drawing
(princ "\nSelect Feature Line: ")
(setq sel (ssget "+.:s" '((0 . "AECC_FEATURE_LINE")))) ;prevents selection of multiple FLs
(if sel ;error trapping, only moves forward if selection set exists
(progn
(setq obj (vlax-ename->vla-object (ssname sel 0))) ;defines "obj" variable based on existing selection set
(while
(princ "\nSelect Start Point: ")
(setq compoint1 (vlax-curve-getClosestPointTo obj (getpoint))) ;grabs point on object nearest to point selected, this ensures the point is actually on FL
(princ "\nSelect End Point: ")
(setq compoint2 (vlax-curve-getClosestPointTo obj (getpoint)))
(setq seglen (abs (- (vlax-curve-getDistAtPoint obj compoint1) (vlax-curve-getDistAtPoint obj compoint2)))) ;defines length between selected points
(setq z1 (caddr compoint1)) ;extract z coordinate from point
(setq z2 (caddr compoint2))
(setq segslope (abs (/ (- z1 z2) seglen))) ;math to get slope
(initget 1 "Sheet Unpaved Paved Channel") ;brings up selection menu
(setq ftype (getkword " [Sheet/Unpaved/Paved/Channel]: ")) ;sets keyword based on user selection
(cond ((= ftype "Sheet")
(setq segtime (* 60 (/ (* 0.007 (expt (* 0.3 seglen) 0.8)) (* 1.8276 (expt slope 0.4))))) ;math based on TR-55/2018 CONB DECDM
)
((= ftype "Unpaved")
(setq segtime (/ seglen (* 60 (* 16.1345 (expt slope 0.5)))))
)
((= ftype "Paved")
(setq segtime (/ seglen (* 60 (* 20.3282 (expt slope 0.5)))))
)
((=ftype "Channel")
(setq segtime (/ seglen 360))
)
(setq rdlen (rtos seglen 2 2)) ;defines new variables rounded to two decimal places
(setq rdslope (rtos (* segslope 100) 2 2))
(setq rdtime (rtos segtime 2 2))
(setq curseg (list ftype rdlen rdslope rdtime)) ;creates a list of current segment type, length, slope, time
(setq seglist (append seglist curseg)) ;adds current segment data to overall list
) ;cond
(setq count1 (+ count1 1)) ;tolls the counter tracking number of segments
) ;while
(while (< count2 (- count1 3))
(princ (nth no seglist)) ;returns first ftype to command line
(terpri) ;linebreak before next print
(princ (nth (+ no 1) seglist))
(princ " feet")
(terpri)
(princ (nth (+ no 2) seglist))
(princ " percent slope")
(terpri)
(princ (nth (+ no 3) seglist))
(princ " minutes")
(setq count2 (+ count2 4))
) ;while
) ;progn
) ;if
(princ) ;last print ends routine
) ;defun
Thanks...
First: Add a space between = and ftype in your cond statement "((=ftype "Channel")
Second: Where does the 'slope' variable as used in the cond statement get its value prior to being used?
That could be why you get "; error: bad argument type: numberp: nil"
Use vlide to run your code. You can animate your code using this IDE. Where an error occurs it will leave that area highlighted making it easier to debug.
regards,
hippe013
One more thing.
Avoid dividing by an integer, unless that is what you need, but that's rarely the case.
Test the following on a command line:
(/ 360 11) = 32
(/ 360 11.0) = 32.7273
Thanks for the tip about the VLIDE - you were correct about the result of the previous error. Now I'm confused about a new error haha. When I run the command I get the message "bad argument type: 2d/3d point:nil." Using the debugger on VLIDE, it pointed me to this line:
(setq compoint1 (vlax-curve-getClosestPointTo obj (getpoint)))
As the source of the error. I find this odd since that line hasn't been a problem in previous iterations. Any thoughts on why this is throwing an error?
What would happen if the user failed to get a point? You are handing the result of (getpoint) right over to vlax-curve-getclosestpointto without checking whether getpoint was successful or not.
Can't find what you're looking for? Ask the community or share your knowledge.