Jump to content

Wrong transformation of cylinder for arbitrary UCS


MJLM

Recommended Posts

I found this thread on the swamp and wanted to use this nice code of Lee's to insert a cylinder into space. However, I wanted to be able to feed the points in the form of some UCS, not WCS. It does not work well. Apart from the vla commands wanting a WCS point, ot seems the transformation matrix kinda works for WCS transformations only (?). Here is my version of the code.

 

(defun emcyl (p_st p_nd c_rad / p_st p_nd c_rad  c_hgt c_mat c_obj c_vec)

	; p_st & p_nd points are expressed in an arbitrary UCS and being fed to this routine as such
	
	(setq
		c_hgt (distance p_st p_nd)
		c_vec (mapcar '- p_nd p_st)
		c_obj (vla-addcylinder (vla-get-modelspace *acdoc*) (vlax-3D-point (trans p_st 1 0)) c_rad c_hgt)
		c_mat (mapcar '(lambda ( v ) (trans v 1 c_vec t)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))
	)
	
	(vla-transformby c_obj
		(vlax-tmatrix
			(append
				(mapcar 'append c_mat
					(mapcar 'list
						(mapcar '+ (trans (list 0.0 0.0 (/ c_hgt 2.0)) c_vec 1 t)
							(mapcar '- p_st (mxv c_mat p_st))
						)
					)
				)
			   '((0.0 0.0 0.0 1.0))
			)
		)
	)
)

Note that I changed the 'trans v 0 vector...' to 'trans v 1 vector...' to transform from and to the local UCS. Not what I though it should do.

 

Any suggestions appreciated.

Link to comment
Share on other sites

Lee's code works well for WCS points, so all you should do is instead of feeding WCS points directly you should change all WCS points to (trans UCSPT 1 0)...

It should go something like this :

 

(defun emcyl ( p_st p_nd c_rad / c_hgt c_mat c_obj c_vec )

        ; p_st & p_nd points are expressed in an arbitrary UCS and being fed to this routine as such
        
        (setq
                c_hgt (distance p_st p_nd)
                c_vec (mapcar '- (trans p_nd 1 0) (trans p_st 1 0))
                c_obj (vla-addcylinder (vla-get-modelspace *acdoc*) (vlax-3D-point (trans p_st 1 0)) c_rad c_hgt)
                c_mat (mapcar '(lambda ( v ) (trans v 0 c_vec t)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))
        )
        
        (vla-transformby c_obj
                (vlax-tmatrix
                        (append
                                (mapcar 'append c_mat
                                        (mapcar 'list
                                                (mapcar '+ (trans (list 0.0 0.0 (/ c_hgt 2.0)) c_vec 0 t)
                                                        (mapcar '- (trans p_st 1 0) (mxv c_mat (trans p_st 1 0)))
                                                )
                                        )
                                )
                               '((0.0 0.0 0.0 1.0))
                        )
                )
        )
)

 

Edited by marko_ribar
Link to comment
Share on other sites

Thank you. However I already tried that and although I thought it would easily work, it simply does not. Does it really work for you when on an active UCS?

Link to comment
Share on other sites

BTW. You have localized arguments... Remove them from localization, they are nilled automatically when function is executed...

p_st p_nd c_rad are arguments and not variables...

Link to comment
Share on other sites

4 hours ago, MJLM said:

I found this thread on the swamp and wanted to use this nice code of Lee's to insert a cylinder into space. However, I wanted to be able to feed the points in the form of some UCS, not WCS. It does not work well. Apart from the vla commands wanting a WCS point, ot seems the transformation matrix kinda works for WCS transformations only (?). Here is my version of the code.

 

Note that I changed the 'trans v 0 vector...' to 'trans v 1 vector...' to transform from and to the local UCS. Not what I though it should do.

 

Did you read the commented version a few posts later? The change of basis matrix constructed in my code is used to transform the cyclinder from the WCS plane to the plane whose normal is defined by the given line vector; the cylinder created by the addcylinder ActiveX method is defined relative to the WCS, not the active UCS. Furthermore, the vector that you are currently supplying is defined relative to the active UCS, and not the WCS as anticipated by the trans function.

Link to comment
Share on other sites

Thank you for the replies. At the end I managed to do it like that.

Btw, to Marko Ribar comment, p_st & p_nd are arguments that live within the scope only. They are passed from variables that are outside of this scope and are further needed.

(defun emcyl (p_st p_nd c_rad / p_st p_nd c_rad  c_hgt c_mat c_obj c_vec)

	; p_st & p_nd are point lists expressed in an arbitrary UCS

	(setq
		c_hgt (distance p_st p_nd)
		c_vec (mapcar '- p_nd p_st)
		c_obj (vla-addcylinder (vla-get-modelspace *acdoc*) (vlax-3D-point p_st) c_rad c_hgt)
		c_mat (mapcar '(lambda ( v ) (trans v 0 c_vec t)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))
	)
	
	(vla-transformby c_obj
		(vlax-tmatrix
			(append
				(mapcar 'append c_mat
					(mapcar 'list
						(mapcar '+ (trans (list 0.0 0.0 (/ c_hgt 2.0)) c_vec 0 t)
							(mapcar '- p_st (mxv c_mat p_st))
						)
					)
				)
			   '((0.0 0.0 0.0 1.0))
			)
		)
	)
	
	(transform1 c_obj)
)


(defun transform1 (obj2tran / x y z obj2tran m)

	(setq x (getvar 'ucsxdir))
	(setq y (getvar 'ucsydir))
	(setq z (trans '(0 0 1) 1 0 t))

	(setq m
		(list
			(list (car x) (car y) (car z) (car (trans '(0 0 0) 1 0)))
			(list (cadr x) (cadr y) (cadr z) (cadr (trans '(0 0 0) 1 0)))
			(list (caddr x) (caddr y) (caddr z) (caddr (trans '(0 0 0) 1 0)))
			'(0.0 0.0 0.0 1.0)
		)
	)
	(vla-transformby obj2tran (vlax-tmatrix m))
)

It doesn't seem ideal since it runs two consecutive transformations but at least it serves well. I initially thought that just one transformation of the entity  based on a UCS instead of a WCS would be possible, or is it after all? Rhetorical question mostly.

 

Link to comment
Share on other sites

57 minutes ago, MJLM said:

p_st & p_nd are arguments that live within the scope only. They are passed from variables that are outside of this scope and are further needed.

 

Declaring symbols as arguments to a function results in their scope being local to the function, as such, the symbols should not appear as local variables to the right of the forward slash within the defun expression; observe:

_$ (setq x "a")
"a"
_$ (defun f ( x ) (print x) (princ))
F
_$ (f 1.2)
1.2 
_$ x
"a"

As for the transformation, I'm not sure why you are overcomplicating it, the following will perform successfully under all UCS & View settings:

;; Add Cylinder  -  Lee Mac
;; Generates a cylinder using two centre points and a radius
;; spc - [vla] Block container object
;; pt1 - [lst] WCS point corresponding to centre of cylinder base
;; pt2 - [lst] WCS point corresponding to centre of cylinder top face
;; rad - [num] Cylinder radius

(defun LM:addcylinder ( spc pt1 pt2 rad / hgt mat obj vec )
    (setq vec (mapcar '- pt2 pt1)
          hgt (distance  pt2 pt1)
          obj (vla-addcylinder spc (vlax-3D-point pt1) rad hgt)
          mat (mapcar '(lambda ( v ) (trans v 0 vec t)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))
    )
    (vla-transformby obj
        (vlax-tmatrix
            (append
                (mapcar 'append mat
                    (mapcar 'list
                        (mapcar '+ (trans (list 0.0 0.0 (/ hgt 2.0)) vec 0 t)
                            (mapcar '- pt1 (mxv mat pt1))
                        )
                    )
                )
               '((0.0 0.0 0.0 1.0))
            )
        )
    )
    obj
)

;; Matrix x Vector  -  Vladimir Nesterovsky
;; Args: m - nxn matrix, v - vector in R^n

(defun mxv ( m v )
    (mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
)

For example:

(defun c:test ( / p q r )
    (if (and (setq p (getpoint "\nSpecify base of cylinder: "))
             (setq q (getpoint "\nSpecify top of cylinder: " p))
             (setq r (getdist  "\nSpecify cylinder radius: " p))
        )
        (LM:addcylinder
            (vlax-get-property
                (vla-get-activedocument (vlax-get-acad-object))
                (if (= 1 (getvar 'cvport)) 'paperspace 'modelspace)
            )
            (trans p 1 0) (trans q 1 0) r)
    )
    (princ)
)

 

Link to comment
Share on other sites

You are right. I may got confused by my initial tries and got mislead that it didn't work. Sorry about that.

 

About the local arguments, it s just a habit and I feel more secure nullifying like that. By doing it as you say, the 'x' variable remains global and when the routine is called from a nested situation of some levels above it may interfere with the rest of the code, say like calling a higher variable which mistakenly has the same name. By nullifying I will at least get an exception. This can be seen in your code above. The points p & q are the variables passed to the local scope as pt1 and pt2. These names however are somewhat common and could easily get messed up with pt variables already loaded in runtime. If my concern is wrong please let me know.

Link to comment
Share on other sites

14 minutes ago, MJLM said:

About the local arguments, it s just a habit and I feel more secure nullifying like that. By doing it as you say, the 'x' variable remains global and when the routine is called from a nested situation of some levels above it may interfere with the rest of the code, say like calling a higher variable which mistakenly has the same name. By nullifying I will at least get an exception. This can be seen in your code above. The points p & q are the variables passed to the local scope as pt1 and pt2. These names however are somewhat common and could easily get messed up with pt variables already loaded in runtime. If my concern is wrong please let me know.

 

Your understanding of the scope of arguments is incorrect. Symbols defined as arguments are local to the function to which they apply - in my function, the symbols pt1 & pt2 only have meaning within the LM:addcylinder function.

 

You can demonstrate this for yourself:

(defun foo ( / pt1 pt2 )

    (setq pt1 '(0 0 0)
          pt2 '(1 2 3)
    )

    (princ "\npt1 & pt2 within the scope of 'foo' BEFORE evaluation of 'bar':")
    (print pt1)
    (prin1 pt2)

    (bar '(3 4 5) '(4 5 6))

    (princ "\npt1 & pt2 within the scope of 'foo' AFTER evaluation of 'bar':")
    (print pt1)
    (prin1 pt2)

    (princ)
)

(defun bar ( pt1 pt2 )
    (princ "\npt1 & pt2 within the scope of 'bar':")
    (print pt1)
    (prin1 pt2)
)
_$ (foo)

pt1 & pt2 within the scope of 'foo' BEFORE evaluation of 'bar':
(0 0 0) (1 2 3)
pt1 & pt2 within the scope of 'bar':
(3 4 5) (4 5 6)
pt1 & pt2 within the scope of 'foo' AFTER evaluation of 'bar':
(0 0 0) (1 2 3)

This can also be demonstrated with symbol arguments for functions such as foreach, e.g.:

_$ (setq x "a")
"a"
_$ (progn (foreach x '(0 1 2 3) (print x)) (princ))

0 
1 
2 
3
_$ x
"a"

Observe from the above output that when the symbol x is supplied as an argument to the foreach function, a new value for this symbol is pushed onto the stack within the scope of the foreach expression, and then popped to yield its original value outside of this expression.

Edited by Lee Mac
Link to comment
Share on other sites

Thank you for the explanation. I had problems once with some variables getting wrong values and although it is quite some time and I don' remember the details, I understood that there was a conflict with common naming and function calls and hence I got this mistaken understanding. Anyway, now I know where to look more carefully.

Link to comment
Share on other sites

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