Setting UCS to Ellipse's major/minor axes

Setting UCS to Ellipse's major/minor axes

leeminardi
Mentor Mentor
457 Views
5 Replies
Message 1 of 6

Setting UCS to Ellipse's major/minor axes

leeminardi
Mentor
Mentor

I am working on a LISP program to create tangent lines to two ellipses.  The ellipses may be at any orientation in space but must lie on the same plane.  Although the ray command, unlike the line command, can be used in conjunction with the tangent OSNAP modifier to create a line from a point tangent to an ellipse, it does not work for creating a line tangent to two ellipses.

 

The math for computing coordinates and slopes at points on an ellipse is simplified if the coordinate system used is oriented such that the x axis passes through the center of the ellipse and points in the direction of the major axis.

 

I was hoping to use the trans function to convert WCS coordinates to ellipse object coordinates.  I have not had success with this approach.  Using UCS OB to set the current ucs to the ellipse yields a coordinate system that does not align the x axis with the major axis.  

 

Alternatively, I have had success by building a homogeneous transformation matrix for the ellipse and then inverting it to translate ellipse world coordinates to "proper" ellipse coordinates.  Although this approach  works I think it too complex and I was hoping there was a way to use trans or some other VLISP function to convert WCS to the desired coordinate system of the ellipse.

 

The following work-in-progress code provides two commands,  ucs_ob and  ucs_matrix that highlight the differences in the two approaches.    ucs_matrix yields the correct results whereas ucs_ob does not.

 

(defun c:ucs_ob	(/)
  (setq pA (getpoint "\nSpecify point for ellipse"))
  (setq ent (entsel "\nSelect ellipse."))
  (setq	ppA	    (cadr ent)		; pick point ellpse A
	enA	    (car ent)
	edA	    (entget enA)
	cenEllipseA (cdr (assoc 10 edA))
	smajorA	    (cdr (assoc 11 edA))
	ratio	    (cdr (assoc 40 edA))
	sminorA	    (mapcar '*
			    (list ratio ratio ratio)
			    (cross '(0 0 1) smajorA)
		    )
	a	    (distance '(0 0 0) smajorA)
	b	    (distance '(0 0 0) sminorA)

  )
	; set coordinate system to ellipse
  (command "_ucs" "ob" ena)
  (setq pAOCS (trans pA 0 1))
  (princ "\n\npA = ")
  (princ pA)
  (princ "\n\npA OCS = ")
  (princ pAOCS)
  (princ)
)


(defun c:ucs_matrix (/)
  (setq pA (getpoint "\nSpecify point for ellipse"))
  (princ "\nP = ")
  (princ pA)
  (setq ent (entsel "\nSelect ellipse."))
  (setq	ppA	    (cadr ent)		; pick point ellpse A
	enA	    (car ent)
	edA	    (entget enA)
	cenEllipseA (cdr (assoc 10 edA))
	smajorA	    (cdr (assoc 11 edA))
	ratio	    (cdr (assoc 40 edA))
	sminorA	    (mapcar '*
			    (list ratio ratio ratio)
			    (cross '(0 0 1) smajorA)
		    )
	a	    (distance '(0 0 0) smajorA)
	b	    (distance '(0 0 0) sminorA)

  )
  
(setq row1 (append (unitV smajorA) '(0.0))
      row2 (append (unitV sminorA) '(0.0))
      row3 '(0 0 1 0)
      row4 (append cenEllipseA '(1.0))
      mA	   (list row1 row2 row3 row4) ; matrix for ellipse A
)
; translate point from world to ellipse A coordinate system  
(setq miA (invm mA))  
(setq pAOCS (transform pA miA))
(princ "\n\npA = ")(princ pA)  
(princ "\n\npA OCS = ")(princ pAOCS)
(princ)
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun transform (a b / transpt)	;Coordinate transformation via matrix multiplication
					; a = point (3 coordinates)
					; b = homogeneous transformation matrix (3 x 4)
(setq aH (append a '(1.0)))		; aH = homogeneous point in local coordinates (1 x 4)
(setq	transpt				
	 (list				
	   (+				; transpt = list of x, y, z coordinates
	     (* (nth 0 aH) (nth 0 (nth 0 b)))
	     (* (nth 1 aH) (nth 0 (nth 1 b)))
	     (* (nth 2 aH) (nth 0 (nth 2 b)))
	     (* (nth 3 aH) (nth 0 (nth 3 b)))
	   )
	   (+
	     (* (nth 0 aH) (nth 1 (nth 0 b)))
	     (* (nth 1 aH) (nth 1 (nth 1 b)))
	     (* (nth 2 aH) (nth 1 (nth 2 b)))
	     (* (nth 3 aH) (nth 1 (nth 3 b)))
	   )
	   (+
	     (* (nth 0 aH) (nth 2 (nth 0 b)))
	     (* (nth 1 aH) (nth 2 (nth 1 b)))
	     (* (nth 2 aH) (nth 2 (nth 2 b)))
	     (* (nth 3 aH) (nth 2 (nth 3 b)))
	   )
	 )
  )
(setq transpt (list (nth 0 transpt) (nth 1 transpt) (nth 2 transpt) ))  
) ;end transform

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;           ;;;;;;;;;;;;;;;;;;;;;;

;; Matrix Inverse  -  gile & Lee Mac
;; Uses Gauss-Jordan Elimination to return the inverse of a non-singular nxn matrix.
;; Args: m - nxn matrix

(defun invm ( m / c f p r )
    
    (defun f ( p m )
        (mapcar '(lambda ( x ) (mapcar '(lambda ( a b ) (- a (* (car x) b))) (cdr x) p)) m)
    )
    (setq  m (mapcar 'append m (imat (length m))))
    (while m
        (setq c (mapcar '(lambda ( x ) (abs (car x))) m))
        (repeat (vl-position (apply 'max c) c)
            (setq m (append (cdr m) (list (car m))))
        )
        (if (equal 0.0 (caar m) 1e-14)
            (setq m nil
                  r nil
            )
            (setq p (mapcar '(lambda ( x ) (/ (float x) (caar m))) (cdar m))
                  m (f p (cdr m))
                  r (cons p (f p r))
            )
        )
    )
    (reverse r)
)
;; Identity Matrix  -  Lee Mac
;; Args: n - matrix dimension

(defun imat ( n / i j l m )
    (repeat (setq i n)
        (repeat (setq j n)
            (setq l (cons (if (= i j) 1.0 0.0) l)
                  j (1- j)
            )
        )
        (setq m (cons l m)
              l nil
              i (1- i)
        )
    )
    m
)

;;; Compute the cross product of 2 vectors a and b
(defun cross (a b / crs)
  (setq	crs (list
	      (- (* (nth 1 a) (nth 2 b))
		 (* (nth 1 b) (nth 2 a))
	      )
	      (- (* (nth 0 b) (nth 2 a))
		 (* (nth 0 a) (nth 2 b))
	      )
	      (- (* (nth 0 a) (nth 1 b))
		 (* (nth 0 b) (nth 1 a))
	      )
	    )				;end list
  )					;end setq c
)					;end cross

 

lee.minardi
0 Likes
Accepted solutions (2)
458 Views
5 Replies
Replies (5)
Message 2 of 6

leeminardi
Mentor
Mentor
Accepted solution

After thinking about this a bit more I found a simpler solution that was too obvious.  Since I have the major and minor axes just create a UCS via 3 points as follows:

(defun c:ucs_3pts	(/)
  (setq pA (getpoint "\nSpecify point for ellipse"))
  (setq ent (entsel "\nSelect ellipse."))
  (setq	ppA	    (cadr ent)		; pick point ellpse A
	enA	    (car ent)
	edA	    (entget enA)
	cenEllipseA (cdr (assoc 10 edA))
	smajorA	    (cdr (assoc 11 edA))
	ratio	    (cdr (assoc 40 edA))
	sminorA	    (mapcar '*
			    (list ratio ratio ratio)
			    (cross '(0 0 1) smajorA)
		    )
	a	    (distance '(0 0 0) smajorA)
	b	    (distance '(0 0 0) sminorA)

  )
	; set coordinate system to ellipse
  (command "_ucs" "3" cenellipsea (mapcar '+ cenellipsea smajora)
	   (mapcar '+ cenellipsea sminora) )
  (setq pAOCS (trans pA 0 1))
  (princ "\n\npA = ")
  (princ pA)
  (princ "\n\npA OCS = ")
  (princ pAOCS)
  (princ)
)
lee.minardi
0 Likes
Message 3 of 6

Kent1Cooper
Consultant
Consultant
Accepted solution

The "start point" of an Ellipse is one of the quadrant points of the major axis, and parameters work from 0 through 2pi as with a Circle, so:

 

(setq ell (car (entsel)))

(command "_.ucs"

  (trans (cdr (assoc 10 (entget ell))) 0 1)

  (trans (vlax-curve-getStartPoint ell) 0 1)

  (trans (vlax-curve-getPointAtParam ell (/ pi 2)) 0 1)

)

Kent Cooper, AIA
0 Likes
Message 4 of 6

leeminardi
Mentor
Mentor

@Kent1Cooper That works too.  Thanks.

lee.minardi
0 Likes
Message 5 of 6

Kent1Cooper
Consultant
Consultant

@leeminardi wrote:

That works too.  Thanks.


You're welcome, but a thought occurs to me:  Do you ever do this with partial Ellipses / elliptical arcs?  Mine won't work with those, except under specific circumstances [starts exactly at a major-axis quadrant point, and goes at least a quarter of the way around].  So an approach like yours that looks like it calculates where axis endpoints would be, even if they're not there, would be better if you don't always work with full Ellipses.

Kent Cooper, AIA
0 Likes
Message 6 of 6

leeminardi
Mentor
Mentor

@Kent1Cooper Are you aware of a VLISP program that will determine the line tangent to two ellipses?  I've done a search and have not found such a program or even the math for the calculation.  I was thinking of using a numerical solution to determine which of the 4 possible tangent lines should be created. 

lee.minardi
0 Likes