Brok Posted April 19, 2023 Posted April 19, 2023 Hi, I want to check for the width and height of a Rectangle. I got this code (defun getRect () (if (setq rec (ssget "_X" (list '(0 . "LWPOLYLINE") '(8 . "LAYOUT") '(90 . 4) (cons 410 (getvar "ctab")) ))) (progn (setq e (ssname rec 0)) (setq coords (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget e)))) (setq height (distance (car coords) (nth 3 coords))) (setq width (distance (car coords) (nth 1 coords))) (if (= height 594.0) T (princ height) ) ) ) (princ) ) If I check for the Width it works and it returns T But If I try to get the height it returns false and prints 594.0 Why does this not return True as well? Quote
Steven P Posted April 19, 2023 Posted April 19, 2023 (edited) Copied and pasted stuff, try this: (defun c:rectcoords ( / MyRect Coords MyCoords ) (princ "\nSelect Rectangle") (if (setq MyRect (ssget "_+.:E:S" (list '(0 . "*POLYLINE") '(90 . 4) '(70 . 1)) )) ; Select single closed 4 line polyline (progn (setq Coords (vlax-get (vlax-ename->vla-object (ssname MyRect 0)) 'Coordinates) ) ; Get all coordinates (setq acount 0) (setq MyCoords (list)) (while (< acount (length Coords)) ; split coords list into pairs (setq MyCoords (append MyCoords (list (list (nth acount Coords) (nth (+ acount 1) Coords))))) (setq acount (+ 2 acount)) ) ; end while (setq height (distance (car MyCoords) (nth 3 MyCoords))) (setq width (distance (car MyCoords) (nth 1 MyCoords))) (if (= height 594.0) T (princ height) ) ; end if ) ; end progn (progn (princ "No Rectangle (4 vertex closed polyline) Selected") ) ; end progn ) ; end if (princ) ) ; end defun Edited April 19, 2023 by Steven P 1 Quote
Brok Posted April 19, 2023 Author Posted April 19, 2023 32 minutes ago, Steven P said: Copied and pasted stuff, try this: (defun c:rectcoords ( / MyRect Coords MyCoords ) (princ "\nSelect Rectangle") (if (setq MyRect (ssget "_+.:E:S" (list '(0 . "*POLYLINE") '(90 . 4) '(70 . 1)) )) ; Select single closed 4 line polyline (progn (setq Coords (vlax-get (vlax-ename->vla-object (ssname MyRect 0)) 'Coordinates) ) ; Get all coordinates (setq acount 0) (setq MyCoords (list)) (while (< acount (length Coords)) ; split coords list into pairs (setq MyCoords (append MyCoords (list (list (nth acount Coords) (nth (+ acount 1) Coords))))) (setq acount (+ 2 acount)) ) ; end while (setq height (distance (car MyCoords) (nth 3 MyCoords))) (setq width (distance (car MyCoords) (nth 1 MyCoords))) (if (= height 594.0) T (princ height) ) ; end if ) ; end progn (progn (princ "No Rectangle (4 vertex closed polyline) Selected") ) ; end progn ) ; end if (princ) ) ; end defun Thank you for your help. I have not tested your code yet but I see you chnged a lot. Does this mean the way I was getting getting the coordinates was wrong? I just don't understand why it would return false and print the same value (594.0) I was checking for in the if statement Quote
Lee Mac Posted April 19, 2023 Posted April 19, 2023 3 hours ago, Brok said: But If I try to get the height it returns false and prints 594.0 Why does this not return True as well? When comparing reals (aka doubles) in AutoLISP, you should use the equal function with a small tolerance (e.g. 1e-8 = 0.00000001) in order to account for infinitesimal inaccuracies that are inevitably introduced at the limits of the precision of this format - two doubles are rarely ever exactly equal on a bitwise level. As such, I would suggest changing: (= height 594.0) To: (equal height 594.0 1e-8) 1 1 Quote
Brok Posted April 20, 2023 Author Posted April 20, 2023 17 hours ago, Lee Mac said: When comparing reals (aka doubles) in AutoLISP, you should use the equal function with a small tolerance (e.g. 1e-8 = 0.00000001) in order to account for infinitesimal inaccuracies that are inevitably introduced at the limits of the precision of this format - two doubles are rarely ever exactly equal on a bitwise level. As such, I would suggest changing: (= height 594.0) To: (equal height 594.0 1e-8) Thank you Lee Mac. This worked perfectly Quote
ronjonp Posted April 20, 2023 Posted April 20, 2023 @Brok Don't forget to locali(sz)e your variables: (/ coords e height rec width) Quote
Steven P Posted April 21, 2023 Posted April 21, 2023 On 4/19/2023 at 11:55 AM, Brok said: Thank you for your help. I have not tested your code yet but I see you chnged a lot. Does this mean the way I was getting getting the coordinates was wrong? I just don't understand why it would return false and print the same value (594.0) I was checking for in the if statement It was quicker for me to copy and paste stuff I know works than to work out what doesn't work... however as above, there are people out there who can spot these things instantly! Quote
Steven P Posted April 21, 2023 Posted April 21, 2023 On 4/19/2023 at 2:08 PM, Lee Mac said: When comparing reals (aka doubles) in AutoLISP, you should use the equal function with a small tolerance (e.g. 1e-8 = 0.00000001) in order to account for infinitesimal inaccuracies that are inevitably introduced at the limits of the precision of this format - two doubles are rarely ever exactly equal on a bitwise level. As such, I would suggest changing: (= height 594.0) To: (equal height 594.0 1e-8) Lee, not sure if you'll get time to answer, but is there a global variable or setting that can be set to take account if these inaccuracies? Not something I have ever looked for yet though. Quote
Lee Mac Posted April 21, 2023 Posted April 21, 2023 (edited) 45 minutes ago, Steven P said: Lee, not sure if you'll get time to answer, but is there a global variable or setting that can be set to take account if these inaccuracies? Not something I have ever looked for yet though. No - such inaccuracies arise as an inherent consequence of the limited precision of the double-precision floating point format (for which the significand can represent decimal values to around 15-17 significant figures of precision). Consider how some numbers cannot be perfectly represented in base10 (decimal) - e.g. multiples of 1/3 represented in decimal would require a infinite number of decimal places to be represented exactly; whereas, these same numbers can be represented exactly in other bases - e.g. 1/3 in base3 (ternary) is exactly 0.1. The same applies to binary values, where other rational numbers cannot be represented exactly, but must instead be approximated to the precision afforded by the amount of memory allocated to the format used to store the value (in this case 64-bits used by the double-precision floating point format). As such, rounding will inevitably occur at the limit of precision following arithmetic operations, which then introduces infinitesimal differences and can result in a calculated value not being exactly equal to its literal counterpart - you can observe these differences directly using the rtos function to display all available decimal places: _$ (rtos x 2 16) "0.8000000000000000" _$ (* x x) 0.64 _$ (rtos (* x x) 2 16) "0.6400000000000002" _$ (= 0.64 (* x x)) nil _$ (equal 0.64 (* x x) 1e-8) T Edited April 21, 2023 by Lee Mac 1 Quote
Steven P Posted April 21, 2023 Posted April 21, 2023 Thanks Lee, As always a good explanation why calculations can be inaccurate (The way I look at this, using 1/3 as an example 1/3 = 0.333333333333333 to 15 decimal places 3x 0.333333333333333 = 0.999999999999999 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.