Author Topic: Point transformation from Block OCS to WCS  (Read 16780 times)

0 Members and 1 Guest are viewing this topic.

Peter Jamtgaard

  • Guest
Point transformation from Block OCS to WCS
« on: December 30, 2008, 12:19:09 PM »
Hello Group,

Long time, I have been trying to find an algorithm to convert a point inside a block [with a normal other than or including (0.0 0.0 1.0)] to the WCS and visa versa for an application I am developing.

I have a kinda klunky method using a cross products.

I was hoping for a fast matrix method?

I figure if anyone had it you guys would?

Peter


ronjonp

  • Needs a day job
  • Posts: 7526

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Point transformation from Block OCS to WCS
« Reply #2 on: December 30, 2008, 02:16:40 PM »
Hi,

If you can get the transformation matrix using nentsel or nentselp, you can use RCS2WCS and WCS2RCS functions.
You'd rather use the Gauss-Jordan method (same accuracy but runs faster) to inverse the matrix in WCS2RCS (replacing inv-mat by inverse)
Speaking English as a French Frog

Peter Jamtgaard

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #3 on: December 30, 2008, 03:44:25 PM »
Unfortunately I cannot use the nentsel or nentselp expressions.

I need to do this transformation without user entry, (many times).

I have been playing with the translatecoordinates method and am having some success. Not done yet.

Have any of you played with this method?

I would like to come up with a general expression for point transformation from acWorld to acOCS and acOCS to acWorld.

Peter

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Point transformation from Block OCS to WCS
« Reply #4 on: December 30, 2008, 04:33:37 PM »
Here's a way which "built" the transformation matrix, for nested objects it needs the "nested tree list" of all parents.

Excuse for poor translation of comments

using:
(TransNested point (list child [parent [grand-parent ...]]) from to)

EDIT : I forgot some sub routines

EDIT 2 : According to Joe's remark, I tried to make the routines work even if the Origin is not 0,0,0.

Code: [Select]
;; TransNested (gile)
;; Translates a point coordinates from WCS or UCS to RCS -coordinates system of a
;; reference (xref or block) whatever its nested level-
;;
;; Arguments
;; pt : the point to translate
;; rlst : the parents entities list from the deepest nested to the one inserted in
;;        current space -same as (last (nentsel)) or (last (nentselp))
;; from to : as with trans function: 0 for WCS, 1 for current UCS, 2 for RCS

(defun TransNested (pt rlst from to)
  (setq mat '((1 0 0) (0 1 0) (0 0 1)))
  (and (= 1 from) (setq pt (trans pt 1 0)))
  (and (= 2 to) (setq rlst (reverse rlst)))
  (and (or (= 2 from) (= 2 to))
       (while rlst
(setq geom (if (= 2 to)
      (RevRefGeom (car rlst))
      (RefGeom (car rlst))
    )
       rlst (cdr rlst)
       pt   (mapcar '+ (mxv (car geom) pt) (cadr geom))
)
       )
  )
  (if (= 1 to)
    (trans pt 0 1)
    pt
  )
)

;; RefGeom (gile)
;; Returns a list which first item is a 3x3 transformation matrix (rotation,
;; scales, normal) and second item the object insertion point in its parent
;; (xref, bloc or space)
;;
;; Argument : an ename

(defun RefGeom (ename / elst ang norm mat)
  (setq elst (entget ename)
ang  (cdr (assoc 50 elst))
norm (cdr (assoc 210 elst))
  )
  (list
    (setq mat
   (mxm
     (mapcar (function (lambda (v) (trans v 0 norm T)))
     '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))
     )
     (mxm
       (list (list (cos ang) (- (sin ang)) 0.0)
     (list (sin ang) (cos ang) 0.0)
     '(0.0 0.0 1.0)
       )
       (list (list (cdr (assoc 41 elst)) 0.0 0.0)
     (list 0.0 (cdr (assoc 42 elst)) 0.0)
     (list 0.0 0.0 (cdr (assoc 43 elst)))
       )
     )
   )
    )
    (mapcar
      '-
      (trans (cdr (assoc 10 elst)) norm 0)
      (mxv mat
   (cdr (assoc 10 (tblsearch "BLOCK" (cdr (assoc 2 elst)))))
      )
    )
  )
)

;; RevRefGeom (gile)
;; RefGeom inverse function

(defun RevRefGeom (ename / entData ang norm mat)
  (setq entData (entget ename)
ang (- (cdr (assoc 50 entData)))
norm (cdr (assoc 210 entData))
  )
  (list
    (setq mat
   (mxm
     (list (list (/ 1 (cdr (assoc 41 entData))) 0.0 0.0)
   (list 0.0 (/ 1 (cdr (assoc 42 entData))) 0.0)
   (list 0.0 0.0 (/ 1 (cdr (assoc 43 entData))))
     )
     (mxm
       (list (list (cos ang) (- (sin ang)) 0.0)
     (list (sin ang) (cos ang) 0.0)
     '(0.0 0.0 1.0)
       )
       (mapcar (function (lambda (v) (trans v norm 0 T)))
       '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))
       )
     )
   )
    )
    (mapcar '-
    (cdr (assoc 10 (tblsearch "BLOCK" (cdr (assoc 2 entData)))))
    (mxv mat (trans (cdr (assoc 10 entData)) norm 0))
    )
  )
)

;;; VXV Returns the dot product of 2 vectors
(defun vxv (v1 v2)
  (apply '+ (mapcar '* v1 v2))
)

;; TRP Transpose a matrix -Doug Wilson-
(defun trp (m)
  (apply 'mapcar (cons 'list m))
)

;; MXV Apply a transformation matrix to a vector -Vladimir Nesterovsky-
(defun mxv (m v)
  (mapcar '(lambda (r) (vxv r v)) m)
)

;; MXM Multiply two matrices -Vladimir Nesterovsky-
(defun mxm (m q)
  (mapcar '(lambda (r) (mxv (trp q) r)) m)
)

PS: I'd rather use RCS (for Reference Coordinates System) instead of OCS which is a particular coordinates system defined by AutoCAD for some 2D entities which refers only to the normal entity (see this thread)
« Last Edit: February 22, 2009, 11:04:38 AM by gile »
Speaking English as a French Frog

Peter Jamtgaard

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #5 on: December 30, 2008, 04:44:09 PM »
Group,

OK Here is what I came up with today.

They appear to work.

Anyone want to try to crash test them?

The block is not scaled but it handles a block with a normals other than (0.0 0.0 1.0)

The lstPoint argument is the point in the world in the TranslateWorldToObject function and a point in the block for the TranslateObjectToWorld function.

The objBlock argument in both function is the block object.

Peter

I have reposted the code in a later post

« Last Edit: January 08, 2009, 08:40:13 AM by Peter Jamtgaard »

Joe Burke

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #6 on: January 01, 2009, 05:48:54 AM »
Peter,

As I understand your code, it's not complete since is doesn't handle a scaled block. So the following may be nit-picking at this time. I think it does not return the correct point going from WCS to block coordinates when the origin of the block definition is not (0.0 0.0 0.0). Granted, that's a rare case, but still an issue.

Peter Jamtgaard

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #7 on: January 01, 2009, 08:11:55 PM »


I found the transformation in the code above was missing a couple minus signs.
After fixing that it accurately transforms the points.

I add the necessary code to transform points from non-uniform blocks and repost the corrected code.

Peter


Joe Burke

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #8 on: January 02, 2009, 09:38:02 AM »


I found the transformation in the code above was missing a couple minus signs.
After fixing that it accurately transforms the points.

I add the necessary code to transform points from non-uniform blocks and repost the corrected code.

Peter



Peter,

The code above looks the same as before. Maybe I'm missing something, but I don't see revised code.

Peter Jamtgaard

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #9 on: January 04, 2009, 04:52:34 PM »
I don't have the ability to edit my posts, so I will repost below.

Play with this and see if it works for you.

The coordinates of the point in the block are relative to the base point.
It is better if the base point of the block is '(0.0 0.0 0.0)

I would be interested in any algorithm that can extract the base point of a block using LISP.

As far as I know it is stored in the system variables in the drawing file of the block, but I do not know where it is in the block definition.

Do any of you know where it (the basepoint inside the block) is or how to get it?

Peter

Code: [Select]

; Function for transforming a point from world coordinate system to a block object coordinate system.
; It handles normals other than (0.0 0.0 1.0)
; lstPoint is the point to transform and objBlock is the block object
; The block is uniformly scaled at 1.0.
; Written By: Peter Jamtgaard copr 2008

(defun TranslateWorldToObject (objBlock         ; Block object
                               lstPointInWorld  ; Point in World Coordinate system
                               /       
                               lstInsertion     ; Insertion Point of Block
                               lstPoint         ; List Point of return translate coordinates
                               lstPointInBlock  ; Coordinates of point (RELATIVE TO BASE POINT)
                                                ; inside the block
                               sngTheta         ; Rotation angle of Block
                               varReturn        ; Variant return of translate coordinates
                              )
 (if (not objDocument)(setq objDocument (vla-get-activedocument
                                         (vlax-get-acad-object))))
 (setq lstInsertion    (vlax-get objBlock "insertionpoint")
       lstPoint        (mapcar '- lstPointInWorld lstInsertion )
       sngTheta        (vla-get-rotation objBlock)   
       varReturn       (vla-translateCoordinates (vla-get-utility
                                                 objDocument)               
                                                 (vlax-3d-point lstPoint)
                                                 acWorld
                                                 acOCS
                                                 :vlax-false
                                                 (vla-get-normal objBlock))
       lstPoint        (vlax-safearray->list (variant-value varReturn))
       lstPointInBlock (list (* (/ 1.0 (vla-get-XEffectiveScaleFactor objBlock))
                                (+ (*    (cos sngTheta) (car  lstPoint))
                                   (*    (sin sngTheta) (cadr lstPoint))))
                               (* (/ 1.0 (vla-get-YEffectiveScaleFactor objBlock))
                                (+ (* -1 (sin sngTheta) (car  lstPoint))
                                   (*    (cos sngTheta) (cadr lstPoint))))
                               (* (/ 1.0 (vla-get-ZEffectiveScaleFactor objBlock))
                                  (caddr lstPoint))
                         )
 )
)


; Function for transforming a point from block object coordinate system to a world coordinate system.
; It handles normals other than (0.0 0.0 1.0)
; lstPoint is the point to transform and objBlock is the block object
; The block is uniformly scaled at 1.0.
; Written By: Peter Jamtgaard copr 2008

(defun TranslateObjectToWorld (objBlock         ; Block object
                               lstPointInBlock  ; Coordinates of point (RELATIVE TO BASE POINT)
                                                ; inside the block
                               /       
                               lstInsertion     ; Insertion Point of Block
                               lstPoint         ; List Point of return translate coordinates
                               lstPointInWorld  ; Coordinates of point inside the WorldCS
                               sngTheta         ; Rotation angle of Block
                               varReturn        ; Variant return of translate coordinates
                              )
 (if (not objDocument)(setq objDocument (vla-get-activedocument
                                         (vlax-get-acad-object))))
 (setq lstInsertion    (vlax-get objBlock "insertionpoint")
       sngTheta        (vla-get-rotation objBlock)
       lstPointInBlock (list (* (vla-get-XEffectiveScaleFactor objBlock)
                                 (+ (*    (cos sngTheta) (car  lstPointInBlock))
                                    (* -1 (sin sngTheta) (cadr lstPointInBlock))))
                              (* (vla-get-YEffectiveScaleFactor objBlock)
                                 (+ (*    (sin sngTheta) (car  lstPointInBlock))
                                    (*    (cos sngTheta) (cadr lstPointInBlock))))
                              (* (vla-get-ZEffectiveScaleFactor objBlock)
                                 (caddr lstPointInBlock)))
       varReturn       (vla-translateCoordinates (vla-get-utility
                                                 objDocument)               
                                                 (vlax-3d-point lstPointInBlock)
                                                 acOCS
                                                 acWorld
                                                 :vlax-false
                                                 (vla-get-normal objBlock))
       lstPointInWorld (mapcar '+ lstInsertion
                                  (vlax-safearray->list (variant-value varReturn)))
 )
)


Spike Wilbury

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #10 on: January 04, 2009, 05:06:39 PM »
Some of my old dust lisp code....

Code: [Select]
(defun draw_point  (pt col / d)
  (setq d (* (getvar "viewsize") 0.015))
  (grdraw
    (trans (polar pt (* 0.25 pi) d) 0 1)
    (trans (polar pt (* 1.25 pi) d) 0 1)
    col
    (- col))
  (grdraw
    (trans (polar pt (* 0.75 pi) d) 0 1)
    (trans (polar pt (* 1.75 pi) d) 0 1)
    col
    (- col)))

;; get insertion point
(defun C:NESTIP (/ ndata edata matrix pin)
  (if (and (setq ndata (nentsel)) (> (length ndata) 2))
    (progn
      (setq edata  (assoc 10 (entget (car ndata)))
    matrix (caddr ndata)
    pin    (last matrix))
      (draw_point pin 7)))
  (princ))

Is the above, what you mean?....

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Point transformation from Block OCS to WCS
« Reply #11 on: January 04, 2009, 05:22:51 PM »
I thought that the Base Point of the block was always '(0 0 0)
The problem some user cause is when they do not pick the base point when creating the block and
the intended base point is off because the default base point is '(0 0 0) when the user should have
chosen an appropriate base point relative to the objects. 
When the Block object is created in the database with a relative base point the objects coordinates
are recalculated based on the Base Point being '(0 0 0)

Correct me if I am wrong.
Or are you talking about the INSERT & not the BLOCK.

PS
Oh the same problem can happen when you WBLOCK & don't pick an appropriate base point.
« Last Edit: January 04, 2009, 05:33:13 PM by CAB »
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Point transformation from Block OCS to WCS
« Reply #12 on: January 04, 2009, 05:29:11 PM »
Peter you don't see the "Modify Message" in the upper right of the post?
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

gskelly

  • Newt
  • Posts: 185
Re: Point transformation from Block OCS to WCS
« Reply #13 on: January 04, 2009, 07:15:05 PM »
Hi there... regarding the base point of a block, I frequently set a base point in a drawing in the area of interest for me. Particularly when I am interested in overlaying geometry from multiple land surveys or site plans. Maybe I'm an odd ball or maybe it has no relevance to the usage envisioned for the routine. Just thought I'd share my usage pattern :)

Greg
Bricscad v12

Joe Burke

  • Guest
Re: Point transformation from Block OCS to WCS
« Reply #14 on: January 05, 2009, 08:33:55 AM »
Peter, Charles, Luis and gile,

I don't have time right now to study recent code, but I will.

The point I was trying to make is this. The Origin property of a block definition is read/write. IOW, you cannot assume codewise the Origin is (0.0 0.0 0.0). So functions which attempt to transform a point from OCS to WCS or vice-versa need to allow for this possibility. Otherwise they will not return the correct point when the block origin is not (0.0 0.0 0.0).

An obvious question... why might the block origin not be (0.0 0.0 0.0) given it typically is. Code might change it which moves the insertion point without changing the position of block inserts. I have code which does this to fix blocks from outside sources which have no logical insertion point. The result is the origin point of a block definition may be (30.0 0.0 0.0).

I hope that's clear. The set of functions I wrote called ObjMatrix v2.lsp, which includes a TransPt function similar to gile's, allows for the possibility the origin point is not (0.0 0.0 0.0).

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Point transformation from Block OCS to WCS
« Reply #15 on: February 21, 2009, 10:07:17 AM »
Hi Joe,

Sorry I didn't see your reply before.
I tried to include the Origin in the RefGeom an RevRefGeom routines.
It seems to work...
Speaking English as a French Frog