David Bethel Posted September 9, 2010 Posted September 9, 2010 Given (3) unique 3D points that are not colinear, I need to calculate the group 210 extrusion value for a plane made of these 3 points: (setq p10 '(2 2 2) p11 '(4 2 2) p12 '(4 2 4)) Would return '(0 -1 0) or '(0 1 0) I know that I've seen the formula in the distant past but it is long gone from my mind. I could probably do it via a UCS command and (trans), but that is crude. TIA -David Quote
Lee Mac Posted September 9, 2010 Posted September 9, 2010 (edited) No check for collinearity, but I'll leave that to you: ;; Vector normal (Lee Mac) (defun normal ( p1 p2 p3 ) (one (vcv (mapcar '- p3 p2) (mapcar '- p3 p1))) ) ;; Vector x Scalar (Lee Mac) (defun vxs ( v s ) (mapcar '(lambda ( n ) (* n s)) v) ) ;; Vector norm (Lee Mac) (defun nrm ( v ) (sqrt (apply '+ (mapcar '(lambda ( n ) (* n n)) v))) ) ;; Unit Vector (Lee Mac) (defun one ( v ) ( (lambda ( n ) (if (equal 0.0 n 1e-14) nil (vxs v (/ 1.0 n)))) (nrm v)) ) ;; Vector Cross Product (Lee Mac) (defun vcv ( u v ) (list (- (* (cadr u) (caddr v)) (* (cadr v) (caddr u))) (- (* (car v) (caddr u)) (* (car u) (caddr v))) (- (* (car u) (cadr v)) (* (car v) (cadr u))) ) ) _$ (normal p10 p11 p12) (0.0 1.0 0.0) Edited September 9, 2010 by Lee Mac Quote
CALCAD Posted September 9, 2010 Posted September 9, 2010 Lee Mac beat me to it, as usual, but here is code from gile that maybe does what you need. ;; AnglePlanePlane ;; Returns the angle (radians) between two planes (using Al Kashi theorem) ;; the returned angle is always between 0 and pi radians ;; ;; Arguments: the single unit normal vectors of the planes (defun AnglePlanePlane (nor1 nor2) ((lambda (d) (acos (/ (- 2 (* d d)) 2)) ) (distance nor1 nor2) ) ) ;;; Acos ;;; Returns the Arc Cosine of number ;;; ;;; Argument: a number between -1 and 1 (defun acos (num) (cond ((equal num 1 1e-9) 0.0) ((equal num -1 1e-9) pi) ((< -1 num 1) (atan (sqrt (- 1 (expt num 2))) num) ) ) ) ;; CrossProduct ;; Returns the cross product (vector) of two vectors ;; ;; Arguments: two vectors (defun CrossProduct (v1 v2) (list (- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2))) (- (* (caddr v1) (car v2)) (* (car v1) (caddr v2))) (- (* (car v1) (cadr v2)) (* (cadr v1) (car v2))) ) ) ;; Normalize ;; Returns the single unit vector of a vector ;; ;; Argument : un vecteur (defun Normalize (v) ((lambda (l) (if (/= 0 l) (mapcar (function (lambda (x) (/ x l))) v) ) ) (distance '(0 0 0) v) ) ) ;; Norm_3Points ;; Returns the single unit normal vector of a plane definedby 3 points ;; ;; Arguments: three points (defun norm_3pts (p0 p1 p2) (Normalize (CrossProduct (mapcar '- p1 p0) (mapcar '- p2 p0))) ) Quote
fixo Posted September 9, 2010 Posted September 9, 2010 Given (3) unique 3D points that are not colinear, I need to calculate the group 210 extrusion value for a plane made of these 3 points: (setq p10 '(2 2 2) p11 '(4 2 2) p12 '(4 2 4)) Would return '(0 -1 0) or '(0 1 0) I know that I've seen the formula in the distant past but it is long gone from my mind. I could probably do it via a UCS command and (trans), but that is crude. TIA -David Try a function from there: http://www.caduser.ru/forum/index.php?PAGE_NAME=read&FID=2&TID=32826 ;; (return normal to plane defined by 3 points) ;********************************************************** ; Вектор нормали к плоскости. Плоскость задана 3-мя точкам, ;********************************************************** ; P1, P2, P3 - точки ; Возвращает вектор нормали. (P1 P2 P3 не на одной прямой) ;Примечание: в большинстве функций библиотеки полскость задается точкой и вектором нормали к ней ;Если в Вашем случае плоскость задана 3-мя точками используйте эту функцию для вычисления вектора нормали (defun 3d_WNormp (P1 P2 P3 / W1 W2) (setq W1 (mapcar '- P2 P1) W2 (mapcar '- P3 P2) ) (list (- (* (cadr W1)(caddr W2)) (* (caddr W1)(cadr W2))) (- (* (caddr W1)(car W2)) (* (car W1)(caddr W2))) (- (* (car W1)(cadr W2)) (* (cadr W1)(car W2))) ) ) ~'J'~ Quote
Lee Mac Posted September 9, 2010 Posted September 9, 2010 All use the Vector cross product, only mine and Giles normalise the resultant perpendicular vector. Quote
David Bethel Posted September 9, 2010 Author Posted September 9, 2010 Thanks! Gile's looks a bit familiar, but not exactly. Lee's will take some study! ;;;Are Points CoLinear ;;;ARG -> 3 Points and Fuzz ;;;RET -> T nil (defun is_pt_colinear (p1 p2 p3 fz) (or (equal (distance p1 p3) (+ (distance p1 p2) (distance p2 p3)) fz) (equal (distance p1 p2) (+ (distance p1 p3) (distance p3 p2)) fz) (equal (distance p2 p3) (+ (distance p1 p2) (distance p1 p3)) fz))) -David Quote
Lee Mac Posted September 9, 2010 Posted September 9, 2010 With a little concision: ;; Collinearity check (Lee Mac) (defun isCollinear ( p1 p2 p3 fz ) (equal (rem (angle p1 p2) pi) (rem (angle p2 p3) pi) fz) ) Quote
David Bethel Posted September 9, 2010 Author Posted September 9, 2010 With a little concision: ;; Collinearity check (Lee Mac) (defun isCollinear ( p1 p2 p3 fz ) (equal (rem (angle p1 p2) pi) (rem (angle p2 p3) pi) fz) ) I would think that only applies to 2d points. _David Quote
Lee Mac Posted September 9, 2010 Posted September 9, 2010 I would think that only applies to 2d points. _David Good point. Quote
CALCAD Posted September 9, 2010 Posted September 9, 2010 Is a collinear check really needed? Using gile's code, a collinear set of points returns nil. What else could go wrong? Quote
Lee Mac Posted September 9, 2010 Posted September 9, 2010 Is a collinear check really needed? Using gile's code, a collinear set of points returns nil. What else could go wrong? Of course, as the cross product of parallel vectors is the zero vector... except I didn't allow for a zero norm, hence have updated my code with a minor fix Quote
gile Posted September 10, 2010 Posted September 10, 2010 Hi, The Normalize routine returns nil for a 0, 0, 0 vector. Here's a routine to evaluates if all points in a list ar colinear (works with 3d points too) ;; Linearp (gile) ;; Evaluates if all points in the list are colinear ;; ;; Arguments: a points list (defun linearp (lst / v1 v2) (or (null (cddr lst)) (and (or (null (setq v1 (Normalize (mapcar '- (cadr lst) (car lst))))) (null (setq v2 (Normalize (mapcar '- (caddr lst) (car lst))))) (equal v1 v2 1e-9) (equal v1 (mapcar '- v2) 1e-9) ) (linearp (cdr lst)) ) ) ) ;; Normalize ;; Returns the single unit vector of a vector ;; ;; Argument : a vector (defun Normalize (v) ((lambda (l) (if (/= 0 l) (mapcar (function (lambda (x) (/ x l))) v) ) ) (distance '(0 0 0) v) ) ) Quote
David Bethel Posted September 10, 2010 Author Posted September 10, 2010 I don't think that 3 colinear points can create a plane. Any return would lead to a error of some kind. So a nil return would be correct. At least in my way of I thinking.... Just so long as it would not crash. -David Quote
gile Posted September 10, 2010 Posted September 10, 2010 I don't think that 3 colinear points can create a plane. Any return would lead to a error of some kind. So a nil return would be correct. At least in my way of I thinking.... Just so long as it would not crash. -David It's the way the routines posted by CALCAD work. (if (setq normal (Norm_3pts p1 p2 p3)) (princ (strcat "\nThe normal vector is: " (vl-princ-to-string normal))) (princ "\np1 p2 p3 are colinear, they do not define a plane") ) Quote
David Bethel Posted September 10, 2010 Author Posted September 10, 2010 Gile, Yes, I see how that works. We are converting sets of 3DAFCEs to extrudable entities: [b][color=BLACK]([/color][/b]and [b][color=FUCHSIA]([/color][/b]setq i -1 ss [b][color=NAVY]([/color][/b]ssget [color=#2f4f4f]"X"[/color] '[b][color=MAROON]([/color][/b][b][color=GREEN]([/color][/b]0 . [color=#2f4f4f]"3DFACE"[/color][b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]while [b][color=NAVY]([/color][/b]setq en [b][color=MAROON]([/color][/b]ssname ss [b][color=GREEN]([/color][/b]setq i [b][color=BLUE]([/color][/b]1+ i[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]setq ed [b][color=MAROON]([/color][/b]entget en[b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]foreach p '[b][color=MAROON]([/color][/b]10 11 12 13[b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]set [b][color=GREEN]([/color][/b]read [b][color=BLUE]([/color][/b]strcat [color=#2f4f4f]"P"[/color] [b][color=RED]([/color][/b]itoa p[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b]cdr [b][color=BLUE]([/color][/b]assoc p ed[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]setq ocs [b][color=MAROON]([/color][/b]cond [b][color=GREEN]([/color][/b][b][color=BLUE]([/color][/b]not [b][color=RED]([/color][/b]is_pt_colinear p10 p11 p12 1e-8[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]normal p10 p11 p12[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b][b][color=BLUE]([/color][/b]not [b][color=RED]([/color][/b]is_pt_colinear p10 p11 p13 1e-8[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]normal p10 p11 p13[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b][b][color=BLUE]([/color][/b]not [b][color=RED]([/color][/b]is_pt_colinear p11 p12 p13 1e-8[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]normal p11 p12 p13[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b] [b][color=GREEN]([/color][/b]T nil[b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b] [b][color=NAVY]([/color][/b]and ocs [b][color=MAROON]([/color][/b]entmake [b][color=GREEN]([/color][/b]list [b][color=BLUE]([/color][/b]cons 0 [color=#2f4f4f]"SOLID"[/color][b][color=BLUE])[/color][/b][b][color=BLUE]([/color][/b]cons 62 256[b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 6 [color=#2f4f4f]"BYLAYER"[/color][b][color=BLUE])[/color][/b][b][color=BLUE]([/color][/b]cons 39 0[b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]assoc 8 ed[b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 10 [b][color=RED]([/color][/b]trans p10 0 ocs[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 11 [b][color=RED]([/color][/b]trans p11 0 ocs[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 12 [b][color=RED]([/color][/b]trans p13 0 ocs[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 13 [b][color=RED]([/color][/b]trans p12 0 ocs[b][color=RED])[/color][/b][b][color=BLUE])[/color][/b] [b][color=BLUE]([/color][/b]cons 210 ocs[b][color=BLUE])[/color][/b][b][color=GREEN])[/color][/b][b][color=MAROON])[/color][/b] [b][color=MAROON]([/color][/b]entdel en[b][color=MAROON])[/color][/b][b][color=NAVY])[/color][/b][b][color=FUCHSIA])[/color][/b] [b][color=FUCHSIA]([/color][/b]prin1[b][color=FUCHSIA])[/color][/b][b][color=BLACK])[/color][/b] We know the the faces are coplaner due to way they were generated, but not know that they do not have a pair of coincidental points ( 3 sided face ). So I test for different combinations of points to find the plane. I could probably make it a bit more efficient using the null test. -David Quote
gile Posted September 10, 2010 Posted September 10, 2010 If your 'normal' routine returns nil in case of colinear points, you can write: (setq ocs (cond ((normal p10 p11 p12)) ((normal p10 p11 p13)) ((normal p11 p12 p13)) ) ) By my side, dealing with 3d faces, I'd rather convert them to have only triangular faces with p12 equal to p13. I wrote a little routine to convert 3dfaces this way: ;; Triang3dFace ;; Divides a quadrangular 3d face into two triangular 3d faces and returns its ename ;; or 'normalise' a triangular one (3rd and 4th vertices overlapped) and returns nil. ;; ;; Argument : a 3d face (ENAME) (defun Triang3dFace (f3d / p1 p2 p3 p4) (setq elst (entget f3d) p1 (cdr (assoc 10 elst)) p2 (cdr (assoc 11 elst)) p3 (cdr (assoc 12 elst)) p4 (cdr (assoc 13 elst)) ) (cond ((equal p3 p4 1e-9) nil) ((equal p1 p2 1e-9) (entmod (subst (cons 11 p3) (assoc 11 elst) (subst (cons 12 p4) (assoc 12 elst) elst) ) ) nil ) ((equal p1 p4 1e-9) (entmod (subst (cons 13 p3) (assoc 13 elst) elst)) nil ) (T (if (< (distance p2 p4) (distance p1 p3)) (progn (entmod (subst (cons 12 p4) (assoc 12 elst) elst) ) (entmakex (subst (cons 10 p2) (assoc 10 elst) (subst (cons 11 p3) (assoc 11 elst) (subst (cons 12 p4) (assoc 12 elst) elst) ) ) ) ) (progn (entmod (subst (cons 13 p3) (assoc 13 elst) elst)) (entmakex (subst (cons 11 p3) (assoc 11 elst) (subst (cons 12 p4) (assoc 12 elst) elst) ) ) ) ) ) ) ) ;; TRIFACE ;; Converts selected 3d faces in 'normalised' triangular faces (defun c:TriFace (/ n ss ent) (if (and (setq n -1 ss (ssget '((0 . "3DFACE"))) ) ) (while (setq ent (ssname ss (setq n (1+ n)))) (Triang3dFace ent) ) ) (princ) ) Quote
David Bethel Posted September 11, 2010 Author Posted September 11, 2010 Gile, That sounds a lot like what 3Dmax does. With 3dsout and 3dsin, you get something very similar. Thanks! -David 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.