Jump to content

(3) 3D Point To UCS Extrusion Direction


Recommended Posts

Posted

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

Posted (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 by Lee Mac
Posted

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)))
)

Posted
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'~

Posted

All use the Vector cross product, only mine and Giles normalise the resultant perpendicular vector.

Posted

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

Posted

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)
)

Posted
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

Posted

Is a collinear check really needed? Using gile's code, a collinear set of points returns nil. What else could go wrong?

Posted
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 :)

Posted

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)
 )
)

Posted

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

Posted
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")
)

Posted

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

Posted

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)
)

Posted

Gile,

 

That sounds a lot like what 3Dmax does. With 3dsout and 3dsin, you get something very similar. Thanks! -David

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...