Nentsel and Matrices

Discussion in 'AutoCAD' started by Micheal Landon, Mar 14, 2005.

  1. I've read all the postings on this newsgroup regarding this topic as well as the AutoCAD documentation. Several postings have touched on what I'm trying to do, but either they've not addressed it completely or I do not understand the answers.

    I am trying to translate a point. I am using nentsel (not nentselp) to select an object. I can successfully translate the definition points of this object when it is nested one level deep, such as a line within an xref. What I am unable to do is translate these points when it is nested further.

    I realize that the list returned by nentsel provides the point at which the user picked the object, the object's entity name, the 4x4 transformation matrix, and all the entity names in which it is nested. I also understand that I must translate the points for each level the object is nested. How do I get the transformation matrix for each level?

    Please type slowly for me... I am feeling really stupid when it comes to this topic.

    TIA
     
    Micheal Landon, Mar 14, 2005
    #1
  2. Micheal Landon

    Joe Burke Guest

    Good question.

    One thing to keep in mind. Nentsel returns a 4x3 transformation matrix which is
    useless with functions like vlax-tmatrix and the TransformBy method. My advice, use
    nentselp and work with 4x4 matrices, like what nentselp returns.

    Right, when you want to transform a point or an object nested more than one level
    deep, you have to apply each trans matrix involved. And it has to be done in the
    correct order, depending on whether you are going OCS to WCS or the other way.

    What's needed is the ability to calculate a 4x4 matrix, based on data extracted from
    a block reference ename. That's the crux of the issue.

    Also, an inverse matrix is needed if want to trans a point from WCS to OCS.

    I've posted functions which attempt to do that. James Allen and others have posted
    similar functions. I'll post my latest stuff tomorrow. It's revised from what I
    posted before. Better, but still not bulletproof. It includes a function designed to
    translate a point, per your question, going either OCS to WCS or the other way.

    BTW, is this the correct spelling of your first name: Micheal?

    Joe Burke
     
    Joe Burke, Mar 14, 2005
    #2
  3. it is your latest email, Joe?

    I want to sent to you something about this topic...

    LE.
     
    Luis Esquivel, Mar 14, 2005
    #3
  4. ok Joe.... I close my web site I have this mail address: lspboxAThotmail.com
    for now...

    LE
     
    Luis Esquivel, Mar 14, 2005
    #4
  5. Micheal Landon

    Joe Burke Guest

    Hi Luis,

    No. My email address here leads to an old inactive thing. I'll try an email to you,
    so you have my current address.

    Looking forward to your thoughts on this.

    Regards
    Joe
     
    Joe Burke, Mar 14, 2005
    #5
  6. Micheal Landon

    Joe Burke Guest

    Luis,

    You should have received email from me at that address.

    Joe
     
    Joe Burke, Mar 14, 2005
    #6
  7. Micheal Landon

    James Allen Guest

    In addition to what Joe said, 4x4 matrices are easier to use for nested
    transformations. Consider:

    1-level deep:
    if nentselp = (n2 pkpt Q1 (n1))
    Pw = Q1 x P1 where
    Pw is the point in WCS,
    Q1 is the transformation matrix associated with block insertion n1,
    P1 is the point in n1's OCS, and
    n1 is the top-level block.

    3-levels deep:
    if nentselp = (n4 pkpt Q (n3 n2 n1))
    Pw = Q1 x Q2 x Q3 x P3 = Q x P3 where
    Q# is the transformation matrix associated with block insertion n#,
    Q = Q1 x Q2 x Q3, and
    n1 is the top-level block.
    **This only works if Q1 - Q3 are square matrices of the same dimensions
    (e.g. 4x4).**

    [Micheal?, this part may be all you really need]
    Notice though, if *all* you need is to transform a -point- from the -most
    deeply nested- OCS to WCS, then you can just use the transformation matrix
    returned by nentselp because it already represents the compound matrix.
    Something like (use attached lsp):
    (setq Pw (MWE:Mx (list Q P3))); Pw = Q x P3
    [/Micheal...]

    The same (using nentselp's matrix) goes for transforming objects (some of
    what Joe mentioned), provided there are no Non-Uniformly Scaled Blocks
    involved. But if you need object transformation through NUS Blocks, or
    anything (even just point transforms) involving partial nesting or inverse
    tranformation, then as Joe indicated, you will need to build the component
    matrices. With those in hand you can do whatever you want. Like the
    following to invert:
    (setq P3 (MWE:Mx (list -Q3 -Q2 -Q1 Pw))); P3 = -Q3 x -Q2 x -Q1 x Pw where -
    (as in -Q#) indicates an inverse matrix.

    Also note that each component matrix is built differently and used in
    reverse order for inverse transformations.
     
    James Allen, Mar 14, 2005
    #7
  8. Thanks for your response. I look forward to reviewing the code you plan to post tomorrow. I've been programming for AutoCAD for about 14 years now and coordinate transformations have always been a problem for me.

    As far as the name goes, yes it's spelled correctly as far as my Mom is concerned. It's just that the rest of the world spells it another way. <g>
     
    Micheal Landon, Mar 14, 2005
    #8
  9. This can be done with a simple formula.... I do not understand why make it
    this to complicated... even for non-uniform, scaled, mirrored or rotated or
    any deep-nest...

    LE.

     
    Luis Esquivel, Mar 14, 2005
    #9
  10. Thanks for the additional information. This is alot for me to digest quickly. It seems obvious that I need to use nentselp instead of nentsel because of the matix dimensions. I have to wonder why nentsel returns a 4x3 when all the other functions use a 4x4.

    The reason I wanted to stay with nentsel instead of nentselp is two-fold. 1. I have the user selecting an object so I have the need for the nentsel object selection functionality. 2 I am not 100% certain that if I use the point returned by nentsel to select an object using nentselp that I will indeed select the object selected by nentsel. Has anyone here experienced a problem with this?
     
    Micheal Landon, Mar 14, 2005
    #10
  11. I'd like a simple formula. Would you mind sharing it?
     
    Micheal Landon, Mar 14, 2005
    #11
  12. I'd like a simple formula. Would you mind sharing it?


    What is going to be the end use for a function like this?

    For a none profitable organization?


    :)
     
    Luis Esquivel, Mar 14, 2005
    #12
  13. Micheal Landon

    James Allen Guest

    Hi Luis, even 3D? If so, I guess I'm not aware of that formula and would
    love to know about it.

    On the other hand, if one can guarantee that their use will always be
    limited to 2D, then I know the formulas become much simpler. If Micheal can
    make that guarantee, then his job can be made much easier. Even then, I'm
    still not sure about *a* simple formula to cover all these cases. Maybe 2.
    ;)

    Anyway, I work 3D enough that I tend to assume I need to allow for it. And
    since he didn't specify, and asked a very general question... well. Just
    covering all bases.

    Micheal, what specifically are you trying to accomplish? And sorry if I got
    carried away.
     
    James Allen, Mar 15, 2005
    #13
  14. I am a 2D guy..... 6'-0" tall.... :)

    No, seriously..... I have tested this formula with 2d data.... can you
    provide to me a drawing sample, please.... I would do some test, this night
    at home....


    LE.
     
    Luis Esquivel, Mar 15, 2005
    #14
  15. Two what?
     
    Luis Esquivel, Mar 15, 2005
    #15
  16. Micheal Landon

    Joe Burke Guest

    Hi Micheal,

    This might be useful.

    ;; Function based on Doug Wilson's Transpose function
    ;; to convert a 4x3 matrix from (nentsel)
    ;; to a 4x4 matrix from (nentselp)
    ;; (c)2002, John F. Uhden, Cadlantic (05-18-02)
    (defun 4x3->4x4 (matrix)
    (append (apply 'mapcar (cons 'list matrix))'((0.0 0.0 0.0 1.0)))
    )

    Joe Burke
     
    Joe Burke, Mar 15, 2005
    #16
  17. Micheal Landon

    Joe Burke Guest

    Hi Micheal.

    Here's the code I promised. I hope the header comments are sufficient to describe
    what they do and how they work.

    Given your original question, trans a deep nested point, the function to look at is
    the last one, TransPt. The other functions support TransPt, though they have
    applications beyond simply translating a point.

    Regards
    Joe Burke

    Code:
    ;-------------------------------------------------------------------
    ;; Apply a transformation matrix to a vector by Vladimir Nesterovsky
    (defun mxv (m v)
    (mapcar '(lambda (row) (apply '+ (mapcar '* row v))) m)
    ) ;end
    ;; Multiply two matrices by Vladimir Nesterovsky
    (defun mxm (m q / qt)
    (setq qt (apply 'mapcar (cons 'list q)))
    (mapcar '(lambda (mrow) (mxv qt mrow)) m)
    ) ;end
    
    ;-------------------------------------------------------------------
    ;; Joe Burke - posted 3/14/2005
    ;; Argument: a block reference ename or vla-object.
    ;; Returns a 4x4 transformation matrix similar to nentselp.
    ;; Checks for equal scale factors because the transformby
    ;; method cannot use a non-uniformly scaled matrix. Well, at least
    ;; within the fuzz factor 1e-8 specified below.
    ;; Deals with block ref normals (0 0 1) and (0 0 -1), not others.
    (defun ObjMatrix ( vobj / ang inspt nrml xsf ysf zxf
    sclmatrix rotmatrix movmatrix resmatrix nrmlmatrix )
    (if (= (type vobj) 'ENAME)
    (setq vobj (vlax-ename->vla-object vobj))
    )
    (and
    (= "AcDbBlockReference" (vlax-get vobj 'ObjectName))
    (setq ang (vlax-get vobj 'Rotation))
    (setq inspt (vlax-get vobj 'InsertionPoint))
    (setq nrml (vlax-get vobj 'Normal))
    (setq xsf (vlax-get vobj 'XScaleFactor))
    (setq ysf (vlax-get vobj 'YScaleFactor))
    (setq zsf (vlax-get vobj 'ZScaleFactor))
    (equal (abs xsf) (abs ysf) 1e-8)
    (equal (abs ysf) (abs zsf) 1e-8)
    (setq sclmatrix
    (list
    (list xsf 0 0 0)
    (list 0 ysf 0 0)
    (list 0 0 zsf 0)
    (list 0 0 0 1)
    )
    )
    (setq rotmatrix
    (list
    (list (cos ang) (- (sin ang)) 0 0)
    (list (sin ang) (cos ang) 0 0)
    (list 0 0 1 0)
    (list 0 0 0 1)
    )
    )
    (setq movmatrix
    (list
    (list 1 0 0 (car inspt))
    (list 0 1 0 (cadr inspt))
    (list 0 0 1 (caddr inspt))
    (list 0 0 0 1)
    )
    )
    (if (= -1 (caddr nrml))
    (setq nrmlmatrix
    (list
    '(-1 0 0 0)
    '(0 1 0 0)
    '(0 0 -1 0)
    '(0 0 0 1)
    )
    )
    (setq nrmlmatrix
    (list
    '(1 0 0 0)
    '(0 1 0 0)
    '(0 0 1 0)
    '(0 0 0 1)
    )
    )
    )
    (setq resmatrix (mxm movmatrix (mxm nrmlmatrix
    (mxm rotmatrix sclmatrix))))
    ) ;and
    resmatrix
    ) ;end
    
    ;-------------------------------------------------------------------
    ;; Returns the inverse transformation matrix of ObjMatrix.
    (defun InverseObjMatrix ( vobj / ang inspt nrml xsf ysf zxf
    sclmatrix rotmatrix movmatrix resmatrix nrmlmatrix )
    (if (= (type vobj) 'ENAME)
    (setq vobj (vlax-ename->vla-object vobj))
    )
    (and
    (= "AcDbBlockReference" (vlax-get vobj 'ObjectName))
    (setq ang (- (vlax-get vobj 'Rotation)))
    (setq inspt (mapcar '- (vlax-get vobj 'InsertionPoint)))
    (setq nrml (vlax-get vobj 'Normal))
    (setq xsf (/ 1.0 (vlax-get vobj 'XScaleFactor)))
    (setq ysf (/ 1.0 (vlax-get vobj 'YScaleFactor)))
    (setq zsf (/ 1.0 (vlax-get vobj 'ZScaleFactor)))
    (equal (abs xsf) (abs ysf) 1e-8)
    (equal (abs ysf) (abs zsf) 1e-8)
    (setq sclmatrix
    (list
    (list xsf 0 0 0)
    (list 0 ysf 0 0)
    (list 0 0 zsf 0)
    (list 0 0 0 1)
    )
    )
    (setq rotmatrix
    (list
    (list (cos ang) (- (sin ang)) 0 0)
    (list (sin ang) (cos ang) 0 0)
    (list 0 0 1 0)
    (list 0 0 0 1)
    )
    )
    (setq movmatrix
    (list
    (list 1 0 0 (car inspt))
    (list 0 1 0 (cadr inspt))
    (list 0 0 1 (caddr inspt))
    (list 0 0 0 1)
    )
    )
    (if (= -1 (caddr nrml))
    (setq nrmlmatrix
    (list
    '(-1 0 0 0)
    '(0 1 0 0)
    '(0 0 -1 0)
    '(0 0 0 1)
    )
    )
    (setq nrmlmatrix
    (list
    '(1 0 0 0)
    '(0 1 0 0)
    '(0 0 1 0)
    '(0 0 0 1)
    )
    )
    )
    (setq resmatrix (mxm sclmatrix (mxm rotmatrix
    (mxm nrmlmatrix movmatrix))))
    ) ;and
    resmatrix
    ) ;end
    
    ;-------------------------------------------------------------------
    ;; Supporting functions: ObjMatrix, InverseObjMatrix and mxm.
    ;; Function supports nested blocks.
    ;; Arguments:
    ;; pt - point to translate
    ;; blklst - typically a list of enames returned
    ;; by (last nentsel) or (last nentselp)
    ;; FROM and TO similar to trans: WCS = 0, UCS = 1 and OCS = 2
    ;; examples: (TransPt point blocklist 1 2) UCS > OCS
    ;;           (TransPt point blocklist 2 0) OCS > WCS
    (defun TransPt ( pt blklst from to / ptmatrix matrix matrixlst res )
    (and
    (or
    (= 3 (length pt))
    (setq pt (append pt '(0.0)))
    )
    (or
    (or (= from 0) (= from 2))
    (setq pt (trans pt 1 0))
    )
    (if (or (= to 0) (= to 1))
    (setq matrixlst (mapcar 'ObjMatrix  blklst)) ;to WCS or UCS
    (setq matrixlst (reverse (mapcar 'InverseObjMatrix blklst))) ;to OCS
    )
    ;test for any nil matrix caused by a non-uniformly scaled block
    (apply 'and matrixlst)
    (setq matrix (car matrixlst))
    (if (> (length matrixlst) 1)
    (repeat (1- (length matrixlst))
    (setq matrix (mxm (cadr matrixlst) matrix))
    (setq matrixlst (cdr matrixlst))
    )
    T
    )
    (setq ptmatrix
    (list
    (list 1 0 0 (car pt))
    (list 0 1 0 (cadr pt))
    (list 0 0 1 (caddr pt))
    (list 0 0 0 1)
    )
    )
    (setq matrix (mxm matrix ptmatrix))
    (setq res
    (list
    (last (car matrix))
    (last (cadr matrix))
    (last (caddr matrix))
    )
    )
    (or
    (or (= to 0) (= to 2))
    (setq res (trans res 0 1))
    )
    ) ;and
    res
    ) ;end
    ;-------------------------------------------------------------------
    
     
    Joe Burke, Mar 15, 2005
    #17
  18. Micheal Landon

    James Allen Guest

    Micheal, just FYI, you don't -have- to programmatically supply a point to
    nentselp. You can use it just like nentsel (i.e. let the user pick). Check
    help. In fact, I can't think of any reason to use nentsel over nentselp.
    Also keep in mind that not only are the dimensions different, but the values
    are transposed, which the code Joe posted addresses. I'm not sure why the
    difference. Perhaps nentsel is an old leftover maintained purely for
    backward compatibility.

    James


    quickly. It seems obvious that I need to use nentselp instead of nentsel
    because of the matix dimensions. I have to wonder why nentsel returns a 4x3
    when all the other functions use a 4x4.
    1. I have the user selecting an object so I have the need for the nentsel
    object selection functionality. 2 I am not 100% certain that if I use the
    point returned by nentsel to select an object using nentselp that I will
    indeed select the object selected by nentsel. Has anyone here experienced a
    problem with this?
     
    James Allen, Mar 15, 2005
    #18
  19. Micheal Landon

    James Allen Guest

    Two formulas. X and Y.

    James


     
    James Allen, Mar 15, 2005
    #19
  20. Micheal Landon

    James Allen Guest

    Hey, me too! (or pretty close anyway)

    I guess I also tend to think in terms of methods for object transformation,
    which by extension also allow point transformation. But I know he just
    mentioned point transformation, which maybe is also all you are referring
    to. Anyway, what kind of sample? 3D, deep nested, NUSB?

    James
     
    James Allen, Mar 15, 2005
    #20
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.