lisp to place a block based on RAW description

lisp to place a block based on RAW description

Bratz2
Collaborator Collaborator
601 Views
10 Replies
Message 1 of 11

lisp to place a block based on RAW description

Bratz2
Collaborator
Collaborator

I'm trying to find a lisp routing that can place a block (one that the cogo point has been assigned already) based on looking through that drawings RAW descriptions that are currently being used, and then allow me to place said blocks wherever I pick. So I can use this to help build a legend. I have a routine that I've gotten to work with placing text (mtext) based on these RAW descriptions, but I'm getting lost with Cogo points. So for my mtext routine it looks like this
'("CBOX" "\t\t\tCALL BOX" nil)
'("CCAB" "\t\t\tC.A.T.V. CABINET" nil)
'("CATVFLG" "\t\t\tC.A.T.V. FLAG" nil)
'("CHH" "\t\t\tC.A.T.V. HANDHOLE" nil)
'("CPED" "\t\t\tC.A.T.V. PEDESTAL" nil)
The first set is the raw description, the second set is the text that's placed within the editor. I was able to get one pre generated, but It keeps giving me an error and I'm not sure where to go and fix it. I've added that one here, in the hopes that maybe someone can help me out here. It would be greatly appreciated.


0 Likes
Accepted solutions (1)
602 Views
10 Replies
Replies (10)
Message 2 of 11

CodeDing
Advisor
Advisor

@Bratz2 ,

 

I did not read your lisp files to integrate, but here is how you could retrieve the block being used by a selected cogo point.

Note that this command does not account for the current scale of CoGo point block size. But that information can be found and accounted for in the CoGo point Style if you need to account for anything like that (most likely not if you're creating a legend). Also, this command will insert the block into Model Space, so you would need to account for whatever layout you're on if you want the block inserted into a layout space.

 

;; Cogo Block
;; Retrieves block being used by user-selected CoGo point,
;; then prompts user to select insertion point of block
(defun C:CB ( / ms cogo style blkName)
  (setq ms (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object))))
  (while (and (setq cogo (car (entsel "\nSelect CoGo Point: ")))
              (eq "AECC_COGO_POINT" (cdr (assoc 0 (entget cogo)))))
    (setq blkName nil)
    (setq cogo (vlax-ename->vla-object cogo))
    (setq style (vlax-get cogo 'Style))
    (if (= 2 (vlax-get style 'MarkerType))
      (setq blkName (vlax-get style 'MarkerSymbolName))
    ;else
      (progn (prompt "\nCoGo point does not use a named block.") (exit))
    );if
    (initget 1)
    (setq pt (getpoint "\nSelect Block Insert Point: "))
    (setq pt (apply 'vlax-3d-point pt))
    (vla-insertblock
      ms
      pt
      blkName
      1 ;<-- x Scale
      1 ;<-- y Scale
      1 ;<-- z Scale
      0 ;<-- Rotation
    );vla-insertblock
  );while
  (if cogo (prompt "\nMust select a CoGo Point. Try again."))
  (prompt "\nCB Complete.")
  (princ)
);defun

 

Best,

~DD

Message 3 of 11

Bratz2
Collaborator
Collaborator

This is very cool!! The issue is the legend is built in paper space, hence the need for it to "pass through" a list of RAW descriptions, and then allow the user to pick where they want them placed. I hope that makes sense. 

0 Likes
Message 4 of 11

Sea-Haven
Mentor
Mentor

I have something you may find this useful as a start it draws a  legend bit but looks for normal blocks. Needs Cogo points to be added, draws in model space. It is custom setup at moment so will try to find time to make back into a global legend, also does linetypes. Added to my to do list.

Message 5 of 11

CodeDing
Advisor
Advisor

@Bratz2 ,

 

This should be a good foundation. I'm not sure why you were trying to retrieve block names from Raw descriptions. That would make it extremely difficult since sometimes Raw Descriptions can have multiple descriptions, linework codes, and comments.

 

So if you're making a legend, then let's retrieve what blocks are actually being used by cogo points. Then we don't have to identify every Raw Description possible.

 

Here is a Lisp that automatically searches all points in drawing, retrieves their blocks, then asks you to pick a point (the top of the legend), then it creates the blocks straight downward. It has options for custom scaling, layering, and custom text (so you can add your Legend text). Hope it helps

 

((lambda ( / C3D)
  (setq	C3D (strcat "HKEY_LOCAL_MACHINE\\"
                    (if vlax-user-product-key
                      (vlax-user-product-key)
                      (vlax-product-key)
                    );if
            );strcat
        C3D (vl-registry-read C3D "Release")
        C3D (substr
              C3D
              1
              (vl-string-search "." C3D (+ (vl-string-search "." C3D) 1))
            );substr
        *C3D* (vla-getinterfaceobject
                (vlax-get-acad-object)
                (strcat "AeccXUiLand.AeccApplication." C3D)
              );vla-getinterfaceobject
        *C3DDoc* (vla-get-activedocument *C3D*)
  );setq
));lambda/eval

(defun c:LEGEND ( / cLayer num style blkName scale layer customText blkList doc cSpace pt pt3D blk ptMin ptMax fullSize halfSize ptMid sizeList spacingBetweenBlocks)
  (setq cLayer (getvar 'CLAYER))
  ;; Retrieve block names used by CoGo points and appropriate scales (if necessary)
  (vlax-for point (vlax-get *C3DDoc* 'Points)
    (setq num (itoa (vlax-get point 'Number)))
    (setq style (vlax-get point 'Style))
    (if (and style (= 2 (vlax-get style 'MarkerType)))
      (progn
        (setq blkName (vlax-get style 'MarkerSymbolName))
        ;; If unique scale factors, layering, or text are required based on block name, do so here..
        (cond
          ;((eq (strcase blkName) (strcase "Unique_Block_Name")) (setq scale 0.75 layer "MY-LAYER-NAME" customText "This is a Unique Block"))
          (t (setq scale 1.0 layer cLayer customText "-----"))
        );cond
        (if (not (assoc blkName blkList))
          (setq blkList (cons (list blkName scale layer customText) blkList))
        );if
      );progn
    ;else
      (if style (prompt (strcat "\nPoint # " num " does not use a Block as symbol..")))
    );if
  );vlax-for
  ;; Sort blocks by name, optional
  (setq blkList (vl-sort blkList '(lambda (b1 b2) (< (car b1) (car b2)))))
  ;; Get space info for inserting blocks
  (setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (setq cSpace (if (= (getvar 'cvport) 1) (vla-get-PaperSpace doc) (vla-get-ModelSpace doc)))
  ;; user determines location of block insertions
  (initget 1) (setq pt (getpoint "\nSelect Insertion Point: "))
  (setq pt3D (vlax-3d-point pt))
  (setq spacingBetweenBlocks 0.1) ;;<--- Set this spacing variable as necessary
  ;; insert blocks (align as necessary)
  (foreach blkData blkList
    (setq blkName (car blkData) scale (cadr blkData) layer (caddr blkData) customText (cadddr blkData))
    (setq blk
      (vla-insertblock
        cSpace
        pt3D
        blkName
        scale ;<-- x Scale
        scale ;<-- y Scale
        scale ;<-- z Scale
        0 ;<-- Rotation
      );vla-insertblock
    );setq
    (vlax-put-property blk 'Layer layer)
    ;; since we're stacking blocks, determine area, and prep for moving blocks
    (vla-GetBoundingBox blk 'ptMin 'ptMax)
    (setq ptMin (vlax-safearray->list ptMin) ptMax (vlax-safearray->list ptMax))
    (setq fullSize (- (cadr ptMax) (cadr ptMin)))
    (setq halfSize (* 0.5 fullSize))
    (if sizeList
      (progn
        ;; Use ptMid to place text next to blocks
        (setq ptMid (vlax-3d-point (polar pt (* 1.5 pi) (+ (apply '+ sizeList) halfSize))))
        (vla-move
          blk
          (vlax-3d-point ptMax)
          (vlax-3d-point (list (car ptMax) (cadr (polar pt (* 1.5 pi) (apply '+ sizeList)))))
        );vla-move
        (setq sizeList (cons (+ fullSize spacingBetweenBlocks) sizeList))
      );progn
    ;else
      (setq sizeList (cons (+ halfSize spacingBetweenBlocks) sizeList))
    );if
  );foreach
  (prompt "\nLEGEND Complete.")
  (princ)
);defun

 

Best,

~DD

Message 6 of 11

Bratz2
Collaborator
Collaborator

I was just trying to follow the same process as the 1st function of my work flow. Thank you for this, it does exactly what I needed it to do. It's much appreciated.

0 Likes
Message 7 of 11

Bratz2
Collaborator
Collaborator

This would be great to start. Any help provided would be extremely appreciated.

0 Likes
Message 8 of 11

Sea-Haven
Mentor
Mentor

 

Removed testing something. 

Option required remove post. 

 

Message 9 of 11

Bratz2
Collaborator
Collaborator

I tried getting it to keep track of the current layer, set to the layer i want the blocks on and then recall the original layer it was on, but I haven't had any luck

((lambda ( / C3D)
(setq C3D (strcat "HKEY_LOCAL_MACHINE\\"
(if vlax-user-product-key
(vlax-user-product-key)
(vlax-product-key)
);if
);strcat
C3D (vl-registry-read C3D "Release")
C3D (substr
C3D
1
(vl-string-search "." C3D (+ (vl-string-search "." C3D) 1))
);substr
*C3D* (vla-getinterfaceobject
(vlax-get-acad-object)
(strcat "AeccXUiLand.AeccApplication." C3D)
);vla-getinterfaceobject
*C3DDoc* (vla-get-activedocument *C3D*)
);setq
));lambda/eval

(defun c:LEGEND ( / cLayer num style blkName scale layer customText blkList doc cSpace pt pt3D blk ptMin ptMax fullSize halfSize ptMid sizeList spacingBetweenBlocks)
(setq currentLayer (getvar "CLAYER")) ;; Get the current layer
(setq targetLayer "G-ANNO-LEGN") ;; Specify the target layer name
;; Retrieve block names used by CoGo points and appropriate scales (if necessary)
(vlax-for point (vlax-get *C3DDoc* 'Points)
(setq num (itoa (vlax-get point 'Number)))
(setq style (vlax-get point 'Style))
(if (and style (= 2 (vlax-get style 'MarkerType)))
(progn
(setq blkName (vlax-get style 'MarkerSymbolName))
;; If unique scale factors, layering, or text are required based on block name, do so here..
(cond
;((eq (strcase blkName) (strcase "Unique_Block_Name")) (setq scale 0.75 layer "MY-LAYER-NAME" customText "This is a Unique Block"))
(t (setq scale 1.0 layer cLayer customText "-----"))
);cond
(if (not (assoc blkName blkList))
(setq blkList (cons (list blkName scale layer customText) blkList))
);if
);progn
;else
;(if style (prompt (strcat "\nPoint # " num " does not use a Block as symbol..")))
);if
);vlax-for
;; Sort blocks by name, optional
(setq blkList (vl-sort blkList '(lambda (b1 b2) (< (car b1) (car b2)))))
;; Get space info for inserting blocks
(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq cSpace (if (= (getvar 'cvport) 1) (vla-get-PaperSpace doc) (vla-get-ModelSpace doc)))
;; user determines location of block insertions
(initget 1) (setq pt (getpoint "\nSelect Insertion Point: "))
(setq pt3D (vlax-3d-point pt))
(setq spacingBetweenBlocks 0.1) ;;<--- Set this spacing variable as necessary
;; insert blocks (align as necessary)
(command "_.LAYER" "Set" G-ANNO-LEGN "") ;;ADDED
(foreach blkData blkList
(setq blkName (car blkData) scale (cadr blkData) layer (caddr blkData) customText (cadddr blkData))
(setq blk
(vla-insertblock
cSpace
pt3D
blkName
scale ;<-- x Scale
scale ;<-- y Scale
scale ;<-- z Scale
0 ;<-- Rotation
);vla-insertblock
);setq
(vlax-put-property blk 'Layer layer)
;; since we're stacking blocks, determine area, and prep for moving blocks
(vla-GetBoundingBox blk 'ptMin 'ptMax)
(setq ptMin (vlax-safearray->list ptMin) ptMax (vlax-safearray->list ptMax))
(setq fullSize (- (cadr ptMax) (cadr ptMin)))
(setq halfSize (* 0.5 fullSize))
(if sizeList
(progn
;; Use ptMid to place text next to blocks
(setq ptMid (vlax-3d-point (polar pt (* 1.5 pi) (+ (apply '+ sizeList) halfSize))))
(vla-move
blk
(vlax-3d-point ptMax)
(vlax-3d-point (list (car ptMax) (cadr (polar pt (* 1.5 pi) (apply '+ sizeList)))))
);vla-move
(setq sizeList (cons (+ fullSize spacingBetweenBlocks) sizeList))
);progn
;else
(setq sizeList (cons (+ halfSize spacingBetweenBlocks) sizeList))
);if
);foreach
(command "_.LAYER" "Set" currentLayer "") ADDED
(prompt "\nLEGEND Complete.")
(princ)
);defun

I wind up with ; error: ActiveX Server returned an error: Parameter not optional

0 Likes
Message 10 of 11

CodeDing
Advisor
Advisor
Accepted solution

@Bratz2 wrote:

I tried getting it to keep track of the current layer, set to the layer i want the blocks on and then recall the original layer it was on, but I haven't had any luck


You don't have to change the current layer at all.

Just change this line of code...

  (setq cLayer (getvar 'CLAYER))

...to this instead:

  (setq cLayer "G-ANNO-LEGN")

 

If you want, you can change the "cLayer" variable name to something like "blkLayer", just remember to update it everywhere in the code. But you can leave it as-is ant it will do what you desire. "cLayer" is basically the Default Block Layer (I just used the current layer which is why I named it that way).

 

Best,

~DD

Message 11 of 11

hosneyalaa
Advisor
Advisor

Can you attached example drawing

0 Likes