Jump to content

3D rotate block from the base point and the other point of the blok ?


Recommended Posts

dr.hybride

hello

 

does anyone knows, if is it possible to 3d rotate a 3d bloc from its base point and the other point of the block ? for sure in LISP😀.

 

thank you

 

 

Link to post
Share on other sites
  • Replies 22
  • Created
  • Last Reply

Top Posters In This Topic

  • lrm

    9

  • dr.hybride

    7

  • rlx

    5

  • CADTutor

    1

Top Posters In This Topic

Popular Posts

If you are working in 3D you will need to specify two angles to define the location of the second point. For example, an angle in the XY plane and an angle about the z axis. The distance is not import

Posted Images

rlx

I dont use 3D for my work but can't you use ALIGN command for this? Should work for 2 & 3D transformations. First point would be block insertionpoint from and 2nd point is whatever point (on the block) you feed to align command , then press enter , et voila...done

 

Maybe post a picture and someone with more 3D knowledge can give you a more intelligent answer.

Link to post
Share on other sites

With the rotate3d command (not to be confused with 3drotate) you can specify 2 points to define an axis of rotation at any 3d orientation you wish.

Link to post
Share on other sites
dr.hybride
Posted (edited)
hello everyone 

I found that but I want to change the second point which will be defined with the angle, one meter from the first point.

 

(defun c:3rtx ( / *error* obj tmppoint)
;3D rotate texts mtexts and blocks aound an axis aligned
;on the x axis, passing by their individual insertion points.
;made by Jef! 2015-12-11.
  (defun *error* ( msg )
       (if (not (member msg '("Function cancelled" "quit / exit abort")))
           (princ (strcat "\nError: " msg))
       )
       (princ)
  )
  (princ "\nSelect objects to rotate")
  (if (ssget)
       (progn
           (vlax-for obj (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))
              (if (or (eq (vla-get-objectname obj) "AcDbMText")
                      (eq (vla-get-objectname obj) "AcDbText")
                      (eq (vla-get-objectname obj) "AcDbBlockReference")
                  )
                  (progn
                     (vla-Rotate3D obj (vlax-3d-point (setq tmppoint (vlax-get obj 'InsertionPoint))) (vlax-3d-point (mapcar '+ tmppoint '(1 0 0))) (/ pi 2))
                     (if (and (eq (vla-get-objectname obj) "AcDbBlockReference")
                              (= (vlax-get-property obj 'HasAttributes) :vlax-true)
                         )
                         (vl-cmdf "_.AttSync" "Name" (vla-get-name obj))
                     )
                  )
               )
            )
        )
     (princ "nothing selected")
    )
  (princ)
) 

 

 

 

exemple.PNG

Edited by CADTutor
Moved code to code block
Link to post
Share on other sites
Quote

I found that but I want to change the second point which will be defined with the angle, one meter from the first point.

If you are working in 3D you will need to specify two angles to define the location of the second point. For example, an angle in the XY plane and an angle about the z axis. The distance is not important as the two points are defining an axis of rotation and it doesn't matter how far apart they are.  It's not clear what you are trying to do.  Your first post indicated that you want to rotate a block in 3D space but your last post seems to imply that you really just want to rotate in a plane.

  • Funny 1
Link to post
Share on other sites
dr.hybride

Sorry i was not clear, i agree with you, i know that to rotate ( 3Drotate and not rotate 3d ) you need to select two points and define an angle, but the thing is i have a lot of block so i dont want to select for each block two points. the idea is that i wanted to use formula trigonometry ( cosinus angle something like this) to select automatically the second point.

see the picture

image.thumb.png.beb955afe8f57f0d5b12b15b339616f2.png

Link to post
Share on other sites

It is still not clear to me what is your goal.  Perhaps someone else would like to jump in and help.  

Could you clarify the following?

1.  Do you want a vlisp program that will allow you to select many blocks at one time and have them all rotate to some specified orientation or do you want to work on a single block?

2. Do you realize that the angle specified in the Properties panel is the angle of rotation in the WCS and does not reflect the current UCS nor the fact the the block may be rotated out of the WCS XY plane?

3. If you want to rotate an object so that it is oriented from a base point to a reference point you can use the Reference option with the rotate command.  For example,  the block MyBox is oriented at an angle of 30°.  Let's say we would like the long side of the box to point from the base point to the point at right.

image.thumb.png.39bc875f4985d4ffa4d43122b0ee1afa.png

Give the rotate command, select the block and then the base point.

Now input R (reference)  and specify the base point (1)  and a second point (2) for the reference direction and a point for the new direction (3).

 

image.png.fa991082c795d215d285212036693dab.png

The result is the following.

image.png.ef707d7ee1be3d3c1690f64c8b8ba25b.png

 

Is this what you want to do?

 

 

image.png

image.png

Link to post
Share on other sites
dr.hybride

thank you for your help lrm

 

yes i want to select many block at one time and rotate at 90°

 

 

image.thumb.png.308f23f82deb72159cffa024efd065f8.png

Link to post
Share on other sites

The following command rot90x,  will rotate a block by 90° about its x axis but will only do one at a time.  Perhaps someone else can enhance it for multiple blocks or has another approach.

(defun c:rot90x (/)
; rotates a block by 90° about its x axis.  
  (setq	blk    (cdr (nentsel))
	xdir   (nth 0 (nth 1 blk))
	basept (nth 3 (nth 1 blk))
	refpt  (mapcar '+ basept xdir)
  )
  (command "_rotate3d" basept "" "2" basept refpt 90.0)
  (princ)
)

 

Link to post
Share on other sites
rlx

untested but assuming Irm's code works I hope this also works :

[code]

 

(defun t1 ( / ss i blk xdir basept refpt)
  (if (setq ss (ssget '((0 . "INSERT"))))
    (repeat (setq i (sslength ss))
      (setq blk (ssname ss (setq i (1- i))))
      (setq xdir (nth 0 (nth 1 blk)) basept (nth 3 (nth 1 blk)) refpt (mapcar '+ basept xdir))
      (command "_rotate3d" basept "" "2" basept refpt 90.0)
    )
  )
  (princ (strcat "\nRotated " (if ss (itoa (sslength ss)) "0") " blocks"))
  (princ)
)

 

[/code]

 

Edited by rlx
has [code] tags changed?
Link to post
Share on other sites

@rlx, mine works for one block, yours does not for multiple blocks.

 

Error "; error: bad argument type: consp <Entity name: 238f0cb2930>" with: 

      (setq xdir (nth 0 (nth 1 blk)) basept (nth 3 (nth 1 blk)) refpt (mapcar '+ basept xdir))

 

I'm not sure what you are trying to do with xdir.  It's the direction vector of the x axis in WCS of the block.  The challenge is going on to the next object in a selection set.  It's not clear to me how, or if,  you can do that with nentsel.  blk via nentsel contains the block's transformation matrix.  blk via ssget in your program is just the entity name.

Link to post
Share on other sites
CADTutor
1 hour ago, rlx said:

has [code] tags changed?

 

Yes, I'm afraid so. The new forum software no longer supports BBcode. It's now considered a legacy feature. However, the editor code blocks work in the same way as before.

Link to post
Share on other sites
rlx

@lrm , ah , yes I see what you mean , hence the untested , didn't take into account entsel returns matrix , probably have to replace this with retrieve inspoint for each block with nentselp or get matrix from block itself. Will have to look at this later :sleeping: because has been very long day for me / very short night.

 

@david , ok , understood , will use editor code blocks from now on

 

😑 🛌 💤

Link to post
Share on other sites
dr.hybride

Hello evryone thank you all

 

but it does not work. i tested and see the result in the picture

 

image.thumb.png.c7b6a9fc48d1679d3f20a398231b7692.png

 

Link to post
Share on other sites
rlx

maybe like this (stolen & adapted from master Lee)

 

;;; https://www.cadtutor.net/forum/topic/50653-rotate3d-lisp-need-help/
(defun c:3drblk ( / ang axs idx lst obj sel )
   (setq ang (/ pi 2.0))
   (if (setq sel (ssget "_:L" '((0 . "INSERT"))))
       (progn
           (repeat (setq idx (sslength sel))
               (setq lst
                   (cons
                       (cons (setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))
                           (vlax-get obj 'insertionpoint)
                       )
                       lst
                   )
               )
           )
           (princ "\nRotate about [X/Y/Z] <Exit>: ")
           (while
               (setq axs
                   (cdr
                       (assoc (grread nil 10)
                          '(
                               ((2 120) 1.0 0.0 0.0)
                               ((2 088) 1.0 0.0 0.0)
                               ((2 121) 0.0 1.0 0.0)
                               ((2 089) 0.0 1.0 0.0)
                               ((2 122) 0.0 0.0 1.0)
                               ((2 090) 0.0 0.0 1.0)
                           )
                       )
                   )
               )
               (foreach itm lst
                   (vlax-invoke (car itm) 'rotate3d (cdr itm) (mapcar '+ (cdr itm) axs) ang)
               )
           )
       )
   )
   (princ)
)

 

Link to post
Share on other sites

@rlx  The program 3drblk appears to rotate the blocks about an axis parallel to the world x, y, or z axis.  I think the OP wants the blocks to rotated about the block's local axis but he hasn't made that clear.  He may in fact may want to define a local axis with 2 points.  Having a copy of the block would help  to understand the requirements.

Link to post
Share on other sites
rlx
 

@lrm , you maybe right , only tested it on a flog of flat-world symbols because I have no 3D symbols. They all fell over at the x-axis so was kinda hoping this is it... awell it was worth a shot. Just not experiece with 3D I'm afraid 🙄

 

I was about to experiment with this when I saw Lee's code , hoping I could retrieve entmatrix for each item in selectionset and then feed this to your command. But I guess , beeing somewhat of a resident of flat-world , better leave this to the inhabitants of 3D-world 🤓

 

; Transpose a matrix Doug Wilson
(defun trp ( m )   (apply 'mapcar (cons 'list m)))
; Apply a transformation matrix to a vector by Vladimir Nesterovsky
(defun mxm ( m n ) ((lambda ( a ) (mapcar '(lambda ( r ) (mxv a r)) m)) (trp n)))
; Multiply two matrices by Vladimir Nesterovsky
(defun mxv ( m v ) (mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m))

; RefGeom (gile)
; test : (setq pl (RefGeom (car (entsel)))) only blocks?
(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 '(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)))))))
  )
)

; https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/get-entities-inside-a-block/td-p/2644829
; Entmatrix returns a list which first item is the 3X3 tranformation matrix and second item the insertion point
; of a block refernce in its owner (space or block definition)
(defun EntMatrix ( ename / e a n)
  (setq    e (entget ename) a (cdr (assoc 50 e)) n (cdr (assoc 210 e)))
  (list (mxm (mapcar (function (lambda (v) (trans v 0 n T))) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))
         (mxm (list (list (cos a) (- (sin a)) 0.0) (list (sin a) (cos a) 0.0) '(0.0 0.0 1.0))
          (list (list (cdr (assoc 41 e)) 0.0 0.0) (list 0.0 (cdr (assoc 42 e)) 0.0)
            (list 0.0 0.0 (cdr (assoc 43 e))))))    (trans (cdr (assoc 10 e)) n 0)))

 

Link to post
Share on other sites
dr.hybride
Posted (edited)

hello everyone thank you all

i'm more confortable in VBA, this why i did in VBA , if someone can to translate in lisp.

 

 Public Sub Rotate3D_Exp()
  Dim ent As AcadEntity
  Dim vPt As Variant

On Error Resume Next

  ' Get the object to rotate
  ThisDrawing.Utility.GetEntity ent, vPt, vbLf + "Select the block to rotate: "

 ' Make sure an object was selected
  If Err = 0 Then
    ' Check to see if the selected object was a block reference
    If ent.ObjectName = "AcDbBlockReference" Then
      Dim blkRef As AcadBlockReference
      Set blkRef = ent
      
      ' Check to see if the block reference was an instance of the MYBLOCK definition
      If blkRef.EffectiveName = "Portique shematique" Then
       
        ' Define the rotation axis
        Dim rotatePt1(0 To 2) As Double
        Dim rotatePt2 As Variant
        Dim rotateAngle As Double
        
        anglebloc = blkRef.Rotation
        'anglebloc = blkRef.Rotation * 3.141592 / 180
        
        'rotatePt1 = -3: rotatePt1(1) = 4: rotatePt1(2) = 0
        rotatePt1(0) = blkRef.InsertionPoint(0)
        rotatePt1(1) = blkRef.InsertionPoint(1)
        rotatePt1(2) = blkRef.InsertionPoint(2)
        
      rotatePt2 = ThisDrawing.Utility.PolarPoint(blkRef.InsertionPoint, anglebloc, 1)
       
        rotateAngle = 90
        rotateAngle = rotateAngle * 3.141592 / 180#
    
        ' Rotate the block reference
        blkRef.Rotate3D rotatePt1, rotatePt2, rotateAngle
      End If
    End If
  End If
End Sub 

 

 

Edited by CADTutor
Moved code to code block
Link to post
Share on other sites

It looks like your VBA code rotates the block by 90° about an axis defined by a line from the basepoint  to a point define by the the angle of the block.  As noted earlier, the angle parameter is the angle defined by the projection of the x-axis of the block onto the xy plane. 

 

Here are two versions of a vlisp program to rotate a block by 90° about an axis define by two points.

 

rot90x rotates a block by 90° about the x axis of the block.

rot90ang rotates a block by 90° about the line define by the x axis of the block projected to the XY plane.  This should be similar to your VBA program.

 

(defun c:rot90x	(/ blk xdir basept refpt)
; rotates a block by 90° about its x axis.  
  (setq blk (cdr (nentsel)))
  (if (= (length blk) 1)
    (princ "\nError, object not a block.")
    (progn
      (setq xdir   (nth 0 (nth 1 blk))
	    basept (nth 3 (nth 1 blk))
	    refpt  (mapcar '+ basept xdir)
      )
      (command "_rotate3d" basept "" "2" basept "_non" refpt 90.0)
    )
  )
  (princ)
)

(defun c:rot90ang (/ blk xdir basept refpt)
; rotates a block by 90° about its x axis prject to the WCS xy plane.  
  (setq blk (cdr (nentsel)))
  (if (= (length blk) 1)
    (princ "\nError, object not a block.")
    (progn
      (setq xdir   (nth 0 (nth 1 blk))
	    basept (nth 3 (nth 1 blk))
	    refpt  (mapcar '+ basept xdir)
	    refpt  (list (nth 0 refpt) (nth 1 refpt) (nth 2 basept))
      )
      (command "_rotate3d" basept "" "2" basept "_non" refpt 90.0)
    )
  )
  (princ)
)

 

rotate block in 3D.lsp

Link to post
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
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...