(getpropertyvalue block "Rotation") returns 90 or 270 degree when the block is rotated to any value in ZX or ZY plane

(getpropertyvalue block "Rotation") returns 90 or 270 degree when the block is rotated to any value in ZX or ZY plane

ShricharanaB
Advocate Advocate
2,187 Views
25 Replies
Message 1 of 26

(getpropertyvalue block "Rotation") returns 90 or 270 degree when the block is rotated to any value in ZX or ZY plane

ShricharanaB
Advocate
Advocate

Hi, 

 

I'm trying to get the rotation of a block. 

I would need both  angle  in XY plane and angle to XY values to attach some other blocks to this block in proper orientation (think attaching legs to conveyors). Though I could make do with only the angle in XY plane as I would know the angle to XY plane beforehand or I can calculate it from block attributes. 

(getpropertyvalue block "Rotation") or getting assoc of 50  of the block works only when the block is not rotated in the z direction. But if the block is rotated by any value in z direction then they return 90 or 270 depending on z rotation direction.

How can I get the actual rotation of the block in XY plane at least?  

Not rotated in z:

ShricharanaB_0-1672903191834.pngShricharanaB_1-1672903213677.png

ShricharanaB_2-1672903239111.png

 

Rotated in z:

ShricharanaB_4-1672903378856.pngShricharanaB_3-1672903358207.png

ShricharanaB_5-1672903404650.png

 

 

 

 

 

 

0 Likes
Accepted solutions (3)
2,188 Views
25 Replies
Replies (25)
Message 2 of 26

Moshe-A
Mentor
Mentor

@ShricharanaB  hi,

 

just Pulling out from the waist, have you tried changeing the UCS?

 

moshe

 

Message 3 of 26

ShricharanaB
Advocate
Advocate
Hi,
Thanks for the reply.
If I understand correctly, You are saying I can change the UCS and add whatever blocks I need to it and then reset the UCS? I've not used UCS before so I've little idea about it.
0 Likes
Message 4 of 26

Moshe-A
Mentor
Mentor

@ShricharanaB  hi,

 

Well i do not think you can retrieve rotation angle from XY plane in object database. Autocad database generally offers coordinates in WCS and from there you have to do 3d transformation of points (never need that 😀) but if you set the right UCS and insert your 2d block, you can measure angle with dim angular or calculate angle with current UCS points.

 

Moshe

 

Message 5 of 26

leeminardi
Mentor
Mentor
Accepted solution

Here's a way to get the angle of a block's angle projected to the XY plane using nentsel.  Do you alos want the angle of a block x axis with respect to the WCS XY plane?

(defun c:BlockXYangle ( / edata m n c angr ang angXYRad angXYDeg )
; determines if block is normal to the XY plane and if it is not
; outputs its angle with in the XY plane.
  (setq osm (getvar 'osmode))
  (command "ucs" "")
  (setvar 'osmode 0)
  (setq	d	(nentsel "\nPlease select a block")
	pp	(nth 1 d)
	m	(nth 2 d)		; matrix
	x_dir	(nth 0 m)
	y_dir	(nth 1 m)
	z_dir	(nth 2 m)		; block normal
	base_pt	(nth 3 m)
  )
					; get z rotation value
  (if (not (equal (nth 2 z_dir) 1.0 0.0001))
    (progn
      (setq ename (car (nth 3 d))
	    edata (entget ename)
	    angr  (cdr (assoc 50 edata))
	    ang	  (/ (* 180.0 angr) pi)
      )
      (princ "\nNormal vector = ")
      (princ z_dir)
      (princ "\nBlock Rotation Angle = ")
      (princ ang)
      (setq angXYRad (angle '(0 0 0)
			    (list (car x_dir) (cadr x_dir) 0.0)
		     )
      )
      (setq angXYDeg (/ (* angXYRad 180.) pi))
      (princ "\nAngle in XY plane = ")
      (princ angXYDeg)
    )					;    end    progn
    (princ "\nBlock is normal to XY plane")
  )					; end if
  (setvar 'osmode osm)
  (princ)
)

 

lee.minardi
Message 6 of 26

_gile
Consultant
Consultant
Accepted solution

Hi,

 

The Rotation (or DXF group code 50) of a block reference is the rotation in radians about the X axis of the block reference OCS (Object Coordinate System). You can see this topic at TheSwamp.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 26

ShricharanaB
Advocate
Advocate

Hi,

 

@leeminardi  Thank you. Using your function seems to work for me how I need it with little modification for arguments and return.  Is it possible to get the angle of x axis of block to the xy plane? 

@_gile I will go through it. Thank you. 

@Moshe-A . For rotation from XY plane I'm using attributes from the block. Elevation difference between two points and length basically. Though I think there might be much better ways. Thanks for the suggestion, I have yet to try it out. Need to learn CS operations in AutoLISP before I can get into that.

Now I have a different issue. I'm feeling the lack of my understanding or Co-ordinate system of AutoCAD. 

I'm getting the assoc 10 of the block for the insertion point. Again when the block is not rotated in z I'm getting the value I expect, but when it is rotated in z (same as in the previous case) the insertion point I'm getting is completely different. As a result inserting another block at the point will insert it some where else and not at the insertion point of the block. 

 

What am I doing wrong here? 

Link posted by @_gile cleared the above issue. Thanks!

One more thing, these will be 3d blocks  not 2d. 

0 Likes
Message 8 of 26

_gile
Consultant
Consultant

@ShricharanaB  a écrit :

One more thing, these will be 3d blocks  not 2d. 


It doesn't matter. a block always have an 'extrusion direction' (the normal of the plane the block lies on) which is used to define its OCS with the Arbitrary Axis Algorithm.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 9 of 26

leeminardi
Mentor
Mentor

@ShricharanaB As requested, I've added code to output the angle of the x axis of the block with the WCS xy plane.

The output does not distinguish if the block's x axis is pointing above or below the xy plane.   Is this ok?

(defun c:BlockAngles ( / edata m n c angr ang angXYRad angXYDeg angXBXRad angXBXDeg )
; determines if block is normal to the XY plane and if it is not
; outputs the angle of the block's projected x axis to the xy plane with the WCS x axis and
; the block's x axis with the WCS XY plane.
; L. Minardi 1/6/2023  
  (setq osm (getvar 'osmode))
  (command "ucs" "")
  (setvar 'osmode 0)
  (setq	d	(nentsel "\nPlease select a block")
	pp	(nth 1 d)
	m	(nth 2 d)		; matrix
	x_dir	(nth 0 m)
	y_dir	(nth 1 m)
	z_dir	(nth 2 m)		; block normal
	base_pt	(nth 3 m)
  )
					; get z rotation value
  (if (not (equal (nth 2 z_dir) 1.0 0.0001))
    (progn
      (setq ename (car (nth 3 d))
	    edata (entget ename)
	    angr  (cdr (assoc 50 edata))
	    ang	  (/ (* 180.0 angr) pi)
      )
      (princ "\nNormal vector = ")
      (princ z_dir)
      (princ "\nBlock Rotation Angle = ")
      (princ ang)
; calculate angle of block's project x axis with WCS x axis
      (setq angXYRad (angle '(0 0 0) (list (car x_dir) (cadr x_dir) 0.0)))
      (setq angXYDeg (/ (* angXYRad 180.) pi))
      (princ "\nAngle of block's x axis projected to XY plane with WCS X axis = ")
      (princ angXYDeg)
; calculate angle of block's x axis with WCS xy plane
      (setq angXBXRad (acos (sqrt (- 1. (abs (caddr x_dir))))))
      (setq angXBXDeg (/ (* angXBXRad 180.) pi))
      (princ "\nAngle of block's X axis to WCS XY plane = ")
      (princ angXBXDeg)
    )					; end progn
    (princ "\nBlock is normal to XY plane")
  )					; end if
  (setvar 'osmode osm)
  (princ)
)
;; ArcCosine  -  Lee Mac
;; Args: -1 <= x <= 1
(defun acos ( x )
    (if (<= -1.0 x 1.0)
        (atan (sqrt (- 1.0 (* x x))) x)
    )
)

  

lee.minardi
0 Likes
Message 10 of 26

john.uhden
Mentor
Mentor

@Moshe-A 

Perhaps you meant "shooting from the hip."

John F. Uhden

0 Likes
Message 11 of 26

ShricharanaB
Advocate
Advocate

Hi, @leeminardi,

 

Thank you so much for taking the time to help me with this.

Yes I would need the direction of incline as well. As the blocks will be both inclined and declined.  I tried to modify it like so,

 

(setq angXBXRad (acos (sqrt (- 1. (abs (caddr x_dir))))))
      (setq angXBXRad (* angXBXRad (/ (caddr x_dir) (abs (caddr x_dir)))))
      (setq angXBXDeg (/ (* angXBXRad 180.) pi))

 

 But clearly my understanding is not correct as I'm not getting the expected value. Could you please explain? or is there some reference I could go through to understand this better? 

0 Likes
Message 12 of 26

ShricharanaB
Advocate
Advocate

Hi,

 

Changing the above code to the below seems to work properly. Now I have a much better understanding of what I'm dealing with here. 

 

(setq angXBXRad (asin (abs (caddr x_dir))))
(setq angXBXRad (* angXBXRad (/ (caddr x_dir) (abs (caddr x_dir)))))
(setq angXBXDeg (/ (* angXBXRad 180.) pi))

 

gives me the angle in positive and negative according to incline or decline.  

0 Likes
Message 13 of 26

ShricharanaB
Advocate
Advocate

Hello again,

 

How could I modify this to work on an entire drawing?

I would get a SS from ssget filtering for only the required blocks, then use foreach or mapcar to get rotations for each block. 

Then I'm thinking I would need to use the tableobject to send a single element to get the data in below code, not sure where to get these from within the block and how to use that tableobject  of a block.

(setq	d	(nentsel "\nPlease select a block")
	pp	(nth 1 d)
	m	(nth 2 d)		; matrix
	x_dir	(nth 0 m)
	y_dir	(nth 1 m)
	z_dir	(nth 2 m)		; block normal
	base_pt	(nth 3 m)
  )

 

0 Likes
Message 14 of 26

ShricharanaB
Advocate
Advocate

Hi @leeminardi  @_gile ,

I've been trying to modify your code to make it work with selection of multiple blocks by sending it the ename, so far I've found @_gile 's function to get transformation matrix that is same as that returned by nentselp. But I see that nentselp and nentsel return transformation matrix differently. I have very little idea about the transformation matrices and trying to understand them to no avail yet. How can I get the angle I need from the nentselp transformation matrix? 

Here is an example: 

nentsel - ((-0.610059 -0.686533 0.395601) (0.747514 -0.664246 -5.55112e-17) (0.262777 0.295717 0.918422) (206.258 4322.33 -1072.24))
nentselp - ((-0.610059 0.747514 0.262777 206.258) (-0.686533 -0.664246 0.295717 4322.33) (0.395601 2.42236e-17 0.918422 -1072.24) (0.0 0.0 0.0 1.0))

 

Is there a way to calculate the same from extrusion direction (assoc 210)? 

0 Likes
Message 15 of 26

_gile
Consultant
Consultant

@ShricharanaB  a écrit :

Hi, 

 

I'm trying to get the rotation of a block. 

I would need both  angle  in XY plane and angle to XY values to attach some other blocks to this block in proper orientation (think attaching legs to conveyors).


If you want to insert other blocks with the same orientation, you do not need to know th the know the "angle  in XY plane and angle to XY values".

You can simply use the Normal (DXF 201) and Rotation (DXF 40) of the source block and set the same values to the newly inserted blocks.

 

(defun c:test (/ source normal name point rotation block)
  (if
    (and
      (setq source (car (entsel "\nSelect a block: ")))
      (= (cdr (assoc 0 (entget source))) "INSERT")
      (setq
	name (getstring "\nEnter the name of the block to insert: ")
      )
      (tblsearch "block" name)
      (setq point (getpoint "\nSpecify the insertion point: "))
    )
     (progn
       (command "_insert" name point 1 "" 0)
       (setq block (entlast))
       (setpropertyvalue
	 block
	 "Normal"
	 (getpropertyvalue source "Normal")
       )
       (setpropertyvalue  block "Position" (trans point 1 0))
       (setpropertyvalue
	 block
	 "Rotation"
	 (getpropertyvalue source "Rotation")
       )
     )
  )
  (princ)
)


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 16 of 26

_gile
Consultant
Consultant

@ShricharanaB  a écrit :

Hi @leeminardi  @_gile ,

I've been trying to modify your code to make it work with selection of multiple blocks by sending it the ename, so far I've found @_gile 's function to get transformation matrix that is same as that returned by nentselp. But I see that nentselp and nentsel return transformation matrix differently. I have very little idea about the transformation matrices and trying to understand them to no avail yet.


Using transformation matrices with AutoLISP is not that simple (there are no dedicated native LISP functions). But most of the time the 'trans' function can do the job, it also accepts as argument a vector (extrusion direction) or an 'ename' (extrusion direction of the entity).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 17 of 26

ShricharanaB
Advocate
Advocate

Hi @_gile ,

Even though the block is added in the correct orientation in this method, the attributes seem to have different  rotation and location from the block, below pic is an example. (original block above, added block below in the image)

ShricharanaB_0-1673341311722.png

 

More over, I need to add multiple blocks along the x axis of the block, the legs  will always be vertical (example below). The spacing of the legs will depend on the length of the block, so I need to calculate it at runtime. 

I'm using modified polar function which includes angle to XY plane as well to get these points offset from the insert point of the block (wiz-polar3d function from wizman from theswamp). Hence the need for x axis angle to XY plane. 

Currently my command works using the function leeminardi wrote for a single block, which uses nentsel. Because of nentsel I can't use it on multiple blocks. I'm stuck here. 

 

ShricharanaB_1-1673341604014.png

 

 

 

0 Likes
Message 18 of 26

_gile
Consultant
Consultant
Accepted solution

@ShricharanaB  a écrit :

Hi @_gile ,

Even though the block is added in the correct orientation in this method, the attributes seem to have different  rotation and location from the block


Simply synchronize the block (command ATTSYNC).

 


@ShricharanaB  a écrit :

More over, I need to add multiple blocks along the x axis of the block, the legs  will always be vertical (example below). The spacing of the legs will depend on the length of the block, so I need to calculate it at runtime. 

I'm using modified polar function which includes angle to XY plane as well to get these points offset from the insert point of the block (wiz-polar3d function from wizman from theswamp). Hence the need for x axis angle to XY plane. 


Try this:

 

(setq br (car (entsel "\nSelect block reference: ")))
(setq rotation (getpropertyvalue br "Rotation"))
(setq xaxis (trans (list (cos rotation) (sin rotation)) br 0 T))
(setq angleOnXY (angle '(0. 0.) (list (car xaxis) (cadr xaxis))))
(setq angleToXY
       (atan (caddr xaxis)
	     (sqrt (- 1. (* (caddr xaxis) (caddr xaxis))))
       )
)

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 19 of 26

leeminardi
Mentor
Mentor

@ShricharanaB It is always a good idea to get as complete a definition of a problem to be solved at the start as possible. The problem definition should include information about what is given (known) the features required and the final output. I jumped into your post making what may have been inappropriate assumptions.

 

Your original request was to "...get the rotation of a block" and then clarified to state "actual rotation of the block in XY plane".   You then requested (post #7) "...the angle of x axis of block to the xy plane". Which I found a bit curious because the angle of the x axis of a block to the xy plane does not provide the slope of the block's XY plane unless the block's Y axis is parallel to the XY plane. Since you stated you were working in 3D I assumed that the block could be fully skewed in space in which case you would want to know the angle of the block's z axis to the world Z direction.  This can easily be determined from the arccosine of the dot product of the block's z axis with the vector (0 0 1).  But then you talk about the block's "incline and decline" (post 11) without a definition of what that means.  At this point I formulated that you were assuming that a block may not be parallel to the XY plane but that its Y axis was and that incline means a positive slope of the block's x axis as relative to the world X axis.  Is this fair to assume?

 

You then go on to ask (post 13) "How could I modify this to work on an entire drawing?"  I interpreted that to mean how can you output the slope angle for a  selection of blocks. But you also ask for " I need to add multiple blocks along the x axis of the block, the legs  will always be vertical" Does this mean that the basepoint of the added blocks should be on the x axis of the selected block (or blocks) and oriented such that their z axis is parallel to World Z and their x direction parallel to the selected block's x axis projected to the World XY plane?

 

Is the following a fair summary of what you have and what you want to accomplish?  If not, please clarify.

 

Given,

  1. A drawing with multiple instances of different blocks positioned in full 3D space. 
  2. The 3D orientation of the blocks is such that the y axis of the block is parallel to the World XY plane. 
  3. A block (BlockA) that will be added by the program.

Output

  1. Insert an existing block (blockA) positioned at the location of the originally selected blocks but oriented such that BlockA's Z axis is parallel to the World z axis and its x axis is parallel to the projection of the selected block's x axis projected to the World XY plane.
  2. Multiple (user specified) copies of blockA should be added for each selected block with a spacing and number of instances specified by the user.   The copies should be positioned along the x axis of the selected block and oriented parallel to the orignal BlockA.  

 

 

lee.minardi
0 Likes
Message 20 of 26

john.uhden
Mentor
Mentor

@leeminardi 

Vectorman,

Your mouth must be dry and your brain matter depleted after all that verbiage.

Go have a beer or more to replenish your losses, but no gliding.

John F. Uhden

0 Likes