Dynamic attribute alignment?

Dynamic attribute alignment?

murmanator
Advocate Advocate
2,108 Views
4 Replies
Message 1 of 5

Dynamic attribute alignment?

murmanator
Advocate
Advocate

I have a few simple blocks with a single attribute. I use an Auto Rotate program to insert the blocks and have them snap to a line or arc. The basic idea is that the block is then aligned to the line/arc and I dont need to rotate it further. In this function, I use (AlignAtts (ENTLAST) 0.0) to set the attribute to "proper" alignment. In my current situation, this is working great as long as the line Im snapping to is vertical. If it is anything other than vertical the attribute aligns to zero and is not aligned correctly with the rest of the block.

 

Its difficult to describe. Ive attached an image to illustrate. On the vertical line, the attribute looks great. On the horizontal and diagonal lines, the attribute is not aligned to the block (circled in red). The desired alignment is shown in the blocks circled in green.

 

Is there a way to accomplish what Im trying to do in LISP? I would describe it as a dynamically controlled attribute alignment. Something would need to detect what the rotation is of the block and align the attribute accordingly. Below is copied the program Im using to insert the block and Ive attached the block as well. 

 

(defun C:PE-CONTROLLER () (PE-CONTROLLER))
(defun PE-CONTROLLER ()
(GV)
(SETVAR 'CLAYER "PLUMBING-EQUIP")
(AutoRotateBlock "PE_CONTROLLER" nil 0)
(AlignAtts (ENTLAST) 0.0)
(SV)
)

 

Thank you

0 Likes
Accepted solutions (1)
2,109 Views
4 Replies
Replies (4)
Message 2 of 5

Anonymous
Not applicable
Accepted solution

The code that you provided doesn't really provide enough information to give you a working routine. "AlignAtts" is a function call, but I'll try to fill in the gaps.

 

First off, your function call doesn't really need to include the rotation value, because the angle would be dependent on the insert rotation value of the block, the dynamic rotation value, or a combination of the two. I would highly suggest that you remove the dynamic rotation value or be prepared to run into attributes that are upside down after being adjusted. Otherwise this code might need to be manipulated further to account for the dynamic angle value and standard block rotation … my head hurts thinking about that eval. LOL!

 

Either way, I've written this solution based on the block as you posted it, which includes the dynamic rotation set at 270 and remarked out code based on the dynamic rotation being set to 0 or removed. I've also add a simple test before calling AlignAtts to make sure the block had attributes. There are other limitations, in that this is designed based on initial insert, so it would likely require addition math to correct the rotation of the attribute, should it be inserted and manipulated (eg. eval att rotation and replace with block rotation val if they weren't the same or expected value).

 

(defun c:pe-controller ( / )
;[code]
(if (= (vla-get-hasattributes (vlax-ename->vla-object (entlast))) :vlax-true) (AlignAtts (entlast))) ;alignatts function call
;[code]
)

(defun AlignAtts (object / obj_name obj_rotation att rotation_val) (setq obj_name (vlax-ename->vla-object (ENTLAST))) (setq obj_rotation (* 180 (/ (vla-get-rotation obj_name) pi))) (foreach att (append (vlax-invoke obj_name 'GetAttributes) (vlax-invoke obj_name 'GetConstantAttributes)) (if (= (vla-get-TagString att) "CONT") (setq att_rotation (* 180 (/ (vla-get-rotation att) pi)))) ) ;;;coded based on block as provided, dynamic rotation value set to 2700 (cond ((or (= 0 obj_rotation) (< obj_rotation 180)) (setq rotation_val nil)) ((and (> obj_rotation 180) (< obj_rotation 360)) (setq rotation_val (- att_rotation 180))) ) ;;;coded based on no dynamic rotation value or set to 0 ;(cond ((or (= 0 obj_rotation) (< obj_rotation 90)) (setq rotation_val nil)) ; ((and (> obj_rotation 90) (< obj_rotation 270)) (setq rotation_val (- att_rotation 180))) ; ((and (> obj_rotation 270) (< obj_rotation 360)) (setq rotation_val nil)) ;) (if (/= rotation_val nil) (foreach att (append (vlax-invoke obj_name 'GetAttributes) (vlax-invoke obj_name 'GetConstantAttributes)) (vla-put-rotation att (* pi (/ rotation_val 180.0))) ) ) )

 

Good luck.

Message 3 of 5

CodeDing
Advisor
Advisor

@murmanator ,

 

It looks like @Anonymous  has written a very good code for you.

 

Mine takes the "AutoLISP" approach and accounts for your included dynamic rotation, HOWEVER you must edit your "Flip state1" position inside your block to here:

image.png

And, here is some sample outputs:

image.png

You can edit the code as you wish because it currently asks if the user would like to "Flip" the end result... Since the text always comes in as a readable fashion, this is not entirely necessary because the insertion technique follows these rules:

- When ALIGN pt 2 is RIGHT of ALIGN pt 1, then text will appear on RIGHT.

- When  ALIGN pt 2 is LEFT of ALIGN pt 1, then text will appear on LEFT.

Best,

~DD

 

(defun c:TEST ( / e angP1 angP2 snapPt angRad osm flipped)
;;get inputs from user
(setq flipped nil)
(initget 1) (setq e (car (entsel "\nSelect PE_CONTROLLER block: ")))
(initget 1) (setq angP1 (getpoint "\nSelect ALIGN pt 1: "))
(initget 1) (setq angP2 (getpoint angP1 "\nSelect ALIGN pt 2: "))
(initget 1) (setq snapPt (getpoint "\nSelect SNAP pt: "))
(setq osm (getvar 'OSMODE))
(setvar 'OSMODE (logior 16384 osm))
;;get angle (in radians) that is perpendicular to alignment
(cond
  ((>= (cadr angP2) (cadr angP1))
    (if (< (angle angP1 angP2) (* pi 0.5))
      (setq angRad (+ (angle angP1 angP2) (* pi 1.5)))
      (setq angRad (- (angle angP1 angP2) (* pi 0.5)))
    );if
  );cond Q1/Q2
  ((< (cadr angP2) (cadr angP1))
    (if (>= (angle angP1 angP2) (* pi 1.5))
      (setq angRad (- (angle angP1 angP2) (* pi 1.5)))
      (setq angRad (+ (angle angP1 angP2) (* pi 0.5)))
    );if
  );cond Q3/Q4
);cond
;;set flip state
(if (>= (car angP2) (car angP1))
  (setq flipped t)
);if
;;set block property values
(setpropertyvalue e "Position/X" (car snapPt))
(setpropertyvalue e "Position/Y" (cadr snapPt))
(setpropertyvalue e "AcDbDynBlockPropertyAngle1" angRad)
(if flipped (setpropertyvalue e "AcDbDynBlockPropertyFlip state1" 1) (setpropertyvalue e "AcDbDynBlockPropertyFlip state1" 0))
;;user flip?
(initget "No Yes")
(setq ans (cond ((getkword "\nFlip? [No/Yes]<No>: ")) ("No")))
(if (eq "Yes" ans) (if flipped (setpropertyvalue e "AcDbDynBlockPropertyFlip state1" 0) (setpropertyvalue e "AcDbDynBlockPropertyFlip state1" 1)))
;;end user flip
(setvar 'OSMODE osm)
(princ)
);defun
Message 4 of 5

Anonymous
Not applicable

I tried to steer clear of the dynamic tools, because I would've been guessing whether the box was capable of having the hardware location flipped or how important it was in general. It's possible that the box might represent owner purchased boxes and they might all be righthanded or lefthanded. In effect, if the insert method is accounting for each approach, the code I provided would need to be adjusted as well. LOL!

 

I would reconsider how the dynamic block is setup and eliminate the need for a lisp routine to handle the flipstate, alignment, or attribute rotation. If you add in an alingnment tool to the block, it would replace the dynamic rotation and embed a permanent alignment capability after insertion. Or you could re-associate the rotation with just the attribute and limit it to 0 or 180. I would then change the flipstate to bisect the panel and address the handing of the panel.

 

It's been awhile since I've looked at dynamic blocks, but you could still use one of the two provide codes to change the dynamic rotation of the attribute. Either way does the trick ... AutoCAD, 101 ways to skin a cat. LOL!

 

Message 5 of 5

murmanator
Advocate
Advocate

Thank you all for the replies, apologies for late response... The AllignAtts solution worked perfectly. I just renamed that function so it wouldnt effect any other programs using AllignAtts. Thank you so much!