TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: OcCad on October 31, 2007, 03:08:21 PM
-
[Backround] We typically xref all our details to paperspace as to ignore multiple scales on one sheet and creating lots of viewports in paper space. We keep each detail in a separate file, each of which we can paste on any drawing, copy to other projects, and manage as a separate component. It also makes it easy for multiple users to work on details that appear on the same sheet.
I am curious to find a way to create a lisp routine that will access a variable within the xref to scale it down from 1:1 to paperspace scale. I have done a lot of research and it seems as if there is no way (not even through ObjectDBX) to access the dimscale of an unopened drawing.
Also there has been mention of creating dictionaries/libraries that hold the dimscale value (whether it be xdata or xrecords) for all our details in our typical detail library so that they may be accessed later from a lisp routine but would that work for project specific details created later?
Lastly, there has been some light as to opening the xref through DBX, scanning it for a block's scale factor (detail border typically used) and then using that as my variable. Only thing is that I dont know how to, after inserting, find the scale of a nested block with a known name.
My desired result would be to browse for a drawing, attach it through the normal dialouge box (with options such as overlay or attach), after insertion the xref to scale down, then at completion for the command line to tell me what was inserted and to what scale. I'm open to all suggestions. Thank you in advance
-
What about blocks that react to the drawing's annotations scale??
Oh....wait... what version of AutoCAD are you using??!?
-
One thought I have had, since our workflow is similar, is to select a piece of text/mtext in the block/xref that has(is) the scale factor and scale it from there. Not quite as nice as being able to scale it as it's attached.
Another method would be to have a block inserted in the detail xref that contains the scale factor, either as an attribute value, or possibly as xdata. This scale could then be found and used by your insertion routine.
-
Lastly, there has been some light as to opening the xref through DBX, scanning it for a block's scale factor (detail border typically used) and then using that as my variable. Only thing is that I dont know how to, after inserting, find the scale of a nested block with a known name.
Here's some code which demonstrates use of the XrefDatabase object. It does not use ObjectDBX.
Program flow might be something like this.
1. Check the active drawing for any existing xrefs and make a list of xref names.
Assign symbol exnamelst to that list.
2. Xref all the details.
3. Step through the blocks collection again looking new xrefs using the existing
xref name list to eliminate those as below.
Totally untested, but I hope it offers some ideas.
(setq blocks
(vla-get-blocks
(vla-get-activedocument
(vlax-get-acad-object))))
(vlax-for xref blocks
(if
(and
(eq acTrue (vla-get-IsXRef xref))
(not (vl-position (vlax-get xref 'Name) exnamelst))
)
(vlax-for blk (vla-get-blocks (vlax-get xref 'XrefDatabase))
(if
(and
(eq "KnownBorderName" (vlax-get blk 'Name))
(equal (setq xscale (vlax-get blk 'XScaleFactor))
(vlax-get blk 'YScaleFactor)
1e-4
)
)
(progn
(setq xscale (/ 1.0 xscale))
(vlax-put xref 'XScaleFactor xscale)
(vlax-put xref 'YScaleFactor xscale)
(vlax-put xref 'ZScaleFactor xscale)
)
)
)
)
)
If the "KnownBorderName" block is found in an xref, the xref in the active drawing should be scaled
by the inverse of its scale factor.
-
Matt W: We use AutoCAD2008 but our detail library has been compiled over the years so they have not been updated with annotative blocks.
Mkweaver: in our most updated typical details we do have a line of text within our detail border that has the scale factor within parenthesis. Only thing is that the entire detail library has yet to be completely updated so the older ones do not. Also our borders are either blocks or dynamic blocks so how would we scan for a line of text? If they were attriburtes, would seem a bit easier.
Joe: How am i to use this code? If i just insert it within what I have already "xscale" does not return me a value? May you please explain more?
(defun c:xrs ()
(vl-load-com)
(command "-layer" "make" "S-ANNO-XREF" "color" "7" "" "ltype" "continuous" "" "s" "" "")
(INITDIA)
(command "xattach" pause)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 2 EntData)))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
(setq blocks
(vla-get-blocks
(vla-get-activedocument
(vlax-get-acad-object))))
(vlax-for xref blocks
(if
(and
(eq acTrue (vla-get-IsXRef xref))
(not (vl-position (vlax-get xref 'Name) exnamelst))
)
(vlax-for blk (vla-get-blocks (vlax-get xref 'XrefDatabase))
(if
(and
(eq "Detail-Bdr" (vlax-get blk 'Name))
(equal (setq xscale1 (vlax-get blk 'XScaleFactor))
(vlax-get blk 'YScaleFactor)
1e-4
)
)
(progn
(setq xscale (/ 1.0 xscale))
(vlax-put xref 'XScaleFactor xscale)
(vlax-put xref 'YScaleFactor xscale)
(vlax-put xref 'ZScaleFactor xscale)
)
)
)
)
)
(command "scale" EntName "" InsPoint xscale)
;;after the insert
(setq EL (entget (entlast)))
(prompt (strcat "\nInserted " (cdr (assoc 2 EL)) " at scale " (rtos (* 12 (cdr (assoc 41 EL)))) " = 1' "))
(princ)
)
And if anyone can shed some light on how I might ObjectDBX to search for "Detail-bdr" with if/thens for three possible names that would be great.
-
Do you know how to use ActiveX controls within lisp? You will need to know this to use ObjectDBX.
ps. Welcome to theSwamp.
-
T: No idea :-(
-
T: No idea :-(
Check out the .doc file attached in the first post here. (http://www.theswamp.org/index.php?topic=6697.0) This will help you get started, and once you do that then you can search for 'ObjectDBX' as there are a lot of examples here using it. When you don't understand something post back and I'm sure someone will help you through those parts.
The theory to this community is to teach instead of give code.
-
Hey, I wanna live not eat for a day. Thanks a bunch! :wink:
-
Hey, I wanna live not eat for a day. Thanks a bunch! :wink:
You will get along fine here then. You're welcome.
-
Okay... I'm still pretty fresh to Lisp so with VBA and ActiveX and ObjectDBX things are getting a bit overwhelming. The post covers an example of copying a block from xref into current drawing and it seems as if all the "vla-... " commands are a whole other story. It leads me as far as acquiring my desired blocks but I'm confused about where to go from there. Is there another resource that can give me a list of possible commands like (vla-get-scale, vla-get-scalefactor)? Within Lisp I only know them as group codes like 41,42,43
-
In the help, get to 'Developer Documentation' -> ActiveX and VBA reference -> Properties...
It can be a little confusing going from the help to lisp, but once you know what you are looking for the help is really nice. For instance 'vla-get-ScaleFactor' is a call to 'get' the property 'ScaleFactor' of an object. So in the help you would look under the property section for 'ScaleFactor'.
Here is a simple routine that will let you select an entity and will print out what ActiveX controls are available.
(defun c:DList ()
(vlax-dump-object
(vlax-ename->vla-object
(car
(entsel "\n Select entity to see all properties and methods: ")
)
)
T
)
(textscr)
(princ)
)
-
Okay this is what i've put together so far but it is giving me a ; error: ActiveX Server returned an error: Parameter not optional."
(defun c:xrs ()
(command "-layer" "make" "S-ANNO-XREF" "color" "7" "" "ltype" "continuous" "" "s" "" "")
(INITDIA)
(command "xattach" pause)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 2 EntData)))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
(vl-load-com)
(setq dwgName InsName)
(setq dbxDoc (vla-GetInterfaceObject (vlax-get-acad-object)
ObjectDBX.AxDbDocument.16))
(vlax-invoke dbxDoc "Open" dwgName)
(setq dbxBlocks (vla-get-blocks dbxDoc))
(setq dbxBlock (vla-item dbxBlocks "Detail Bdr"))
(setq dbxBscale (vla-get-xscalefactor dbxBlock))
(vlax-release-object dbxDoc)
(setq dbxDoc nil)
(command "scale" EntName "" InsPoint (/ 1 dbxScale))
;;after the insert
(setq EL (entget (entlast)))
(prompt (strcat "\nInserted " (cdr (assoc 2 EL)) " at scale " (rtos (* 12 (cdr (assoc 41 EL)))) " = 1' "))
(princ)
)
p.s. loved that code by the way
-
OcCad,
Welcome to the swamp, been a busy day for me.
Looks like you are in good hands.
-
This line is what I think is causing the problem.
(setq dbxBscale (vla-get-xscalefactor dbxBlock))
The reason is that you found the blocks definition, not where it is inserted, so it has no scale property. To find out where it is inserted there are a few ways to go. Here is one that might be easier for you at the moment.
Once you get the block here
(setq dbxBlock (vla-item dbxBlocks "Detail Bdr"))
Convert the object to an ename
(setq dbxEname (vlax-vla-object->ename dbxBlock))
Now we want to get the dxf code information from it
(setq dbxEntData (entget dbxEname))
Now all the codes 331 are the inserts associated with the block, so to get the scale use
(setq dbxBlockInsert (cdr (assoc 331 dbxEntData)))
(setq dbxScale (cdr (assoc 41 (entget dbxBlockInsert))))
Hope that makes sense.
-
I'm still getting the same return. When I try to see where it gets messed up it seems its as if its here:
(setq dwgName InsName)
;create an ObjectDBX Document
(setq dbxDoc (vla-GetInterfaceObject (vlax-get-acad-object)
ObjectDBX.AxDbDocument.16))
(vlax-invoke dbxDoc "Open" dwgName)
;get the desired block
"dwgName" will return a value however "dbxDoc" returns nil as does "dbxBlocks."
-
is dbx server registered?
version of Acad?
-
See if this will get what you are looking for. It's what I use courtesy of Jeff M.
(setq dbxApp
(if (< (atoi (setq oVer (substr (getvar "acadver") 1 2))) 16)
(vla-GetInterfaceObject (vlax-get-acad-object) "ObjectDBX.AxDbDocument")
(vla-GetInterfaceObject (vlax-get-acad-object) (strcat "ObjectDBX.AxDbDocument." oVer))
)
)
What version of Cad are you on?
-
AC 2008
-
if still getting an error, then register dbx server
((lambda (v)
(if (not
(vl-registry-read
(strcat "HKEY_CLASSES_ROOT\\ObjectDBX.AxDbDocument." v "\\CLSID")
)
)
(startapp "regsvr32.exe"
(strcat "/s \"" (findfile (strcat "AxDb" v ".dll")) "\"")
)
)
)
(substr (getvar "ACADVER") 1 2)
)
-
still...
"; error: ActiveX Server returned an error: Parameter not optional" :-(
-
If you're using 2008 object dbx should already be registered:
( (lambda ( version )
(vl-registry-read
(strcat "HKEY_CLASSES_ROOT\\ObjectDBX.AxDbDocument"
(if (eq 15 version)
"\\CLSID"
(strcat "." (itoa version) "\\CLSID")
)
)
)
)
(atoi (getvar "acadver"))
)
=> "{49998808-648A-4A9C-A7A5-B1672775D9AB}"
-
May you know what parameter is registering as not optional?
-
Copy/paste the last code I posted to the command line, and post back what it returns.
-
put it this way
(setq dbxDoc (vla-GetInterfaceObject
(vlax-get-acad-object)
(strcat "ObjectDBX.AxDbDocument." (substr (getvar "acadver") 1 2))
)
)
what value doe's (findfile dwgName) return?
-
TW: #<VLA-OBJECT IAxDbDocument 11150390>
(defun c:xrs ()
(command "-layer" "make" "S-ANNO-XREF" "color" "7" "" "ltype" "continuous" "" "s" "" "")
(INITDIA)
(command "xattach" pause)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 2 EntData)))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
(vl-load-com)
;Register DBX Server
(setq dbxApp
(if (< (atoi (setq oVer (substr (getvar "acadver") 1 2))) 16)
(vla-GetInterfaceObject (vlax-get-acad-object) "ObjectDBX.AxDbDocument")
(vla-GetInterfaceObject (vlax-get-acad-object) (strcat "ObjectDBX.AxDbDocument." oVer))
)
)
(setq dwgName InsName)
;create an ObjectDBX Document
(setq dbxDoc (vla-GetInterfaceObject (vlax-get-acad-object)
ObjectDBX.AxDbDocument.16))
(vlax-invoke dbxDoc "Open" dwgName)
;get the desired block
(setq dbxBlocks (vla-get-blocks dbxDoc))
(setq dbxBlock (vla-item dbxBlocks "Detail Bdr"))
(setq dbxEname (vlax-vla-object->ename dbxBlock))
(setq dbxEntData (entget dbxEname))
(setq dbxBlockInsert (cdr (assoc 331 dbxEntData)))
(setq dbxScale (cdr (assoc 41 (entget dbxBlockInsert))))
(vlax-release-object dbxDoc)
(setq dbxDoc nil)
(command "scale" EntName "" InsPoint (/ 1 dbxScale))
;;after the insert
(setq EL (entget (entlast)))
(prompt (strcat "\nInserted " (cdr (assoc 2 EL)) " at scale " (rtos (* 12 (cdr (assoc 41 EL)))) " = 1' "))
(princ)
)
-
In the code replace all the calls to 'dbxDoc' to 'dbxApp' and then remove (or comment out) the portion of the code that assigns 'dbxDoc' as you don't need it. The way I show (or VovKa shows) is a better way to get it.
-
Thats closer. Now no nils up until "dbxblocks"
-
Thats closer. Now no nils up until "dbxblocks"
Did you change the call to the new variable? The easiest way is to do a find/replace on the whole file. That is if you are using Notepad, or some other program that works like that. How are you editing your file?
-
one more error:
insted of
(setq InsName (cdr (assoc 2 EntData)))
write
(setq InsName (cdr (assoc 1 (tblsearch "BLOCK"(cdr (assoc 2 EntData))))))
-
Im using notepad and I used a find/replace. I even rewrote your code with Vovka's and then rereplaced dbxApp with dbxDoc. Still same error with a parameter not being optional and nils starting at dbxblocks
Is this line in the code correct?
"(vlax-invoke dbxDoc[or dbxAPP] "Open" dwgName)"
when entered into command line it returns nil (dbxDoc or dbxAPP used not both)
-
Are you trying to open a drawing that someone already has open? You can't use ODBX if the drawing is open by anyone. Maybe the open isn't working. To test type
(vla-get-Name dbxApp)
Upon looking at the code I don't think the file is being open since you don't give it a whole path, not even a drawing name. You are getting the name of the block/xref, not the path to it. If the name is the same as the file name, then try
(vla-Open dbxApp (findfile (strcat dwgName ".dwg")))
-
I am the only one in the drawings that I am working with and no they are not open.
I thought the same about the full path and Vovka also posted instead of
(setq InsName (cdr (assoc 2 EntData)))
write
(setq InsName (cdr (assoc 1 (tblsearch "BLOCK"(cdr (assoc 2 EntData))))))
when(vla-get-Name dbxApp)
is entered i only get ""
and with (vla-Open dbxApp (findfile (strcat dwgName ".dwg")))
i get "; error: ActiveX Server returned an error: Parameter not optional."
-
Same error with this?
(vla-Open dbxApp (findfile (strcat dwgName ".dwg")) :vlax-false)
The ".dwg" is not already added is it?
-
Throwing darts, how about this?
(vlax-invoke-method 'open dbxApp (findfile (strcat dwgName ".dwg")))
-
the whole code:
(defun c:xrs ()
(command "-layer"
"make"
"S-ANNO-XREF"
"color"
"7"
""
"ltype"
"continuous"
""
"s"
""
""
)
(INITDIA)
(command "xattach" pause)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 1 (tblsearch "BLOCK"(cdr (assoc 2 EntData))))))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
(vl-load-com)
(setq dwgName InsName) ;create an ObjectDBX Document
(setq dbxDoc (vla-GetInterfaceObject
(vlax-get-acad-object)
(strcat "ObjectDBX.AxDbDocument." (substr (getvar "acadver") 1 2))
)
)
(vlax-invoke dbxDoc "Open" dwgName) ;get the desired block
(setq dbxBlocks (vla-get-blocks dbxDoc))
(setq dbxBlock (vla-item dbxBlocks "Detail Bdr"))
(setq dbxEname (vlax-vla-object->ename dbxBlock))
(setq dbxEntData (entget dbxEname))
(setq dbxBlockInsert (cdr (assoc 331 dbxEntData)))
(setq dbxScale (cdr (assoc 41 (entget dbxBlockInsert))))
(vlax-release-object dbxDoc)
(setq dbxDoc nil)
(command "scale" EntName "" InsPoint (/ 1 dbxScale))
;;after the insert
(setq EL (entget (entlast)))
(prompt (strcat "\nInserted "
(cdr (assoc 2 EL))
" at scale "
(rtos (* 12 (cdr (assoc 41 EL))))
" = 1' "
)
)
(princ)
)
-
"dbxBlockInsert" returns nil.
"(cdr (assoc 331 dbxEntData))" returns nil
And what was it that was stopping me from opening it in ODBX before?
-
Type '!dbxEntData' at the command line after the code is ran, and post what it returns.
-
((-1 . <Entity name: 78d61380>) (0 . "INSERT") (330 . <Entity name: 7ed8bc40>)
(5 . "5EA8") (100 . "AcDbEntity") (67 . 1) (410 . "TYPICAL STEEL DETAILS") (8 .
"S-ANNO-XREF") (100 . "AcDbBlockReference") (2 . "042200-0101-3") (10 15.3858
6.88422 0.0) (41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 0.0) (70 . 0) (71 . 0) (44
. 0.0) (45 . 0.0) (210 0.0 0.0 1.0))
-
That isn't the correct block. Try closing the current drawing, and then run the code again, and post what is returned again.
-
i simulated your conditions: created the dwg with block "Detail Bdr", saved it, created new dwg a ran your program. all went with no errors.
-
tw:
((-1 . <Entity name: 7d763f18>) (0 . "BLOCK_RECORD") (5 . "63") (102 .
"{ACAD_XDICTIONARY") (360 . <Entity name: 7d763f20>) (102 . "}") (330 . <Entity
name: 7d763c08>) (100 . "AcDbSymbolTableRecord") (100 . "AcDbBlockTableRecord")
(2 . "Detail Bdr") (360 . <Entity name: 7d75a010>) (340 . <Entity name:
0>) (70 . 1) (280 . 1) (281 . 1))
-
That makes it look like the block is not inserted in the drawing any place. It should look like this.
((-1 . <Entity name: 7ed2d0c0>) (0 . "BLOCK_RECORD") (330 . <Entity name:
7ed10c08>) (5 . "C8") (100 . "AcDbSymbolTableRecord") (100 .
"AcDbBlockTableRecord") (2 . "Det-Bub") (360 . <Entity name: 7ed2d0e8>) (340 .
<Entity name: 0>) (102 . "{BLKREFS") [color=red](331 . <Entity name: 7ed2d118>) (331 .
<Entity name: 7ed2d240>) (331 . <Entity name: 7ed2d360>) (331 . <Entity name:
7ed2d380>) (331 . <Entity name: 7ed2d3a0>) (331 . <Entity name: 7ed2d400>) (331
. <Entity name: 7ed2d420>) (331 . <Entity name: 7ed2d440>) (331 . <Entity name:
7ed2d460>) (331 . <Entity name: 7ed2d480>) (331 . <Entity name: 7ed2d4f8>)[/color] (102
. "}"))
Notice all the code 331s. Those are the inserted block entities.
-
Vovka: I ran the same test (test detail, test sheet) and it too worked for me. But for some reason when i went to go pull from the detail library it says "; error: bad argument type: lentityp nil"
I xopen the detail from the detail library (read only if that matters) and list the detail bdr and it lists fine...
-
Entire list of Detail Bdr from within detail library
BLOCK REFERENCE Layer: "0"
Space: Model space
Handle = 72bf
Block Name: "Detail Bdr"
Anonymous Name: "*U6"
at point, X= 0'-0" Y= 0'-0" Z= 0'-0"
X scale factor: 16.0000
Y scale factor: 16.0000
rotation angle: 0.00
Z scale factor: 16.0000
InsUnits: Inches
Unit conversion: 1.0000
Scale uniformly: Yes
Allow exploding: Yes
Height: 9'-4"
Width: 9'-4"
Visibility: Show Detail Bubble
ATTRIBUTE Layer: "S-TEXT"
Space: Model space
Handle = 72c0
Style = "Text"
Annotative: No
Font file = architxt.shx
start point, X=1'-5 1/16" Y=0'-2 3/16" Z= 0'-0"
height 0'-2"
value
tag REF
rotation angle 0.00
width scale factor 0.8500
obliquing angle 15.00
flags normal
generation normal
ATTRIBUTE Layer: "S-LITE"
Space: Model space
Handle = 72c1
Style = "Text"
Annotative: No
Font file = architxt.shx
end point, X= 8'-3" Y=0'-3 5/16" Z= 0'-0"
Press ENTER to continue:
height 0'-1"
value MSNR-00_A (16)
tag FILENAME
rotation angle 0.00
width scale factor 1.0000
obliquing angle 15.00
flags normal
generation normal
ATTRIBUTE Layer: "S-TEXT"
Space: Model space
Handle = 72c2
Style = "Text"
Annotative: No
Font file = architxt.shx
center point, X=4'-10 1/4" Y=0'-2 3/16" Z= 0'-0"
height 0'-2"
value 3/4" = 1'-0"
tag SCALE
rotation angle 0.00
width scale factor 0.8500
obliquing angle 15.00
flags normal
generation normal
ATTRIBUTE Layer: "S-TEXT-TB"
Space: Model space
Handle = 72c3
Style = "TEXTTB"
Annotative: No
Font file = archisel.shx
center point, X=4'-10 1/4" Y=1'-1 15/16" Z= 0'-0"
height 0'-4"
value TYPICAL MASONRY WALL
tag DETAILTOP
rotation angle 0.00
width scale factor 0.8500
obliquing angle 15.00
flags normal
generation normal
ATTRIBUTE Layer: "S-TEXT-TB"
Space: Model space
Press ENTER to continue:
Handle = 72c4
Style = "TEXTTB"
Annotative: No
Font file = archisel.shx
center point, X=4'-10 1/4" Y=0'-8 5/16" Z= 0'-0"
height 0'-4"
value CONTROL JOINT
tag DETAILBOTTOM
rotation angle 0.00
width scale factor 0.8500
obliquing angle 15.00
flags normal
generation normal
ATTRIBUTE Layer: "S-ANNO-TEXT-TB"
Space: Model space
Handle = 72c5
Style = "TEXTTB"
Annotative: No
Font file = archisel.shx
center point, X=1'-0 1/2" Y=0'-7 11/16" Z= 0'-0"
height 0'-2"
value ?
tag DETAILNO
rotation angle 0.00
width scale factor 1.0000
obliquing angle 0.00
flags normal
generation normal
ATTRIBUTE Layer: "S-TEXT-TB"
Space: Model space
Handle = 72c6
Style = "TEXTTB"
Annotative: No
Font file = archisel.shx
fit between point, X= 0'-9" Y=0'-4 1/2" Z= 0'-0"
and point, X= 1'-4" Y=0'-4 1/2" Z= 0'-0"
height 0'-2"
value S?.??
tag SHEETNO
rotation angle 0.00
width scale factor 1.0748
Press ENTER to continue:
obliquing angle 0.00
flags normal
generation normal
END SEQUENCE Layer: "0"
Space: Model space
Handle = 72c7
-
Okay. I see the problem. It is a dynamic block, so the way I was using will not work. You will have to search the whole drawing to find the correct block. You will have to check the property 'EffectiveName' since that is the name of the block before you make any dynamic changes.
(vlax-for lo (vla-get-Layouts dbxDoc)
(vlax-for obj (vla-get-Block lo)
(if
(and
(= (vla-get-ObjectName obj) "AcDbBlockReference")
(= (strcase (vla-get-EffectiveName obj)) "DETAIL BDR")
)
(setq dbxScale (vla-get-XScaleFactor obj))
)
)
)
This will replace all of this.
(setq dbxBlocks (vla-get-blocks dbxDoc))
(setq dbxBlock (vla-item dbxBlocks "Detail Bdr"))
(setq dbxEname (vlax-vla-object->ename dbxBlock))
(setq dbxEntData (entget dbxEname))
(setq dbxBlockInsert (cdr (assoc 331 dbxEntData)))
(setq dbxScale (cdr (assoc 41 (entget dbxBlockInsert))))
-
TW: Hmmm... Strange because when I did the test detail/test sheet I spoke to Vovka about the detail was just a drawing containing that dynamic block. But i will try your recent post as well
-
The problem is when you change the dynamic properties it changes the block to an anonymous block, so it does not really reference the block definition anymore. It may, but not in the way the old style blocks referenced the block definition. I just learned that by looking at what you posted since I haven't dug into '08 yet.
-
what is a dynamic block? :)
i use autocad 2004, so no dynamic blocks at all :0
-
what is a dynamic block? :)
i use autocad 2004, so no dynamic blocks at all :0
A dynamic block is a block that change it's appearance. So if you have blocks that are similar, you can create one block with different views. They can get real complex, but that is a simple explanation. Started in '06 I think.
-
OcCad,
If the block is inserted in paper space, then you have to use ObjectDBX to get this information, but if it is inserted into model space no need to go the ObjectDBX route since all objects in model space are brought over in the xref. You just need to search the blocks definition for the block you want to check. This will make the program faster, and won't matter if anyone has the xref'ed drawing open.
-
thanks guys! And if i wanted to expand the list of blocks to search for, would this be the correct way to do it?
(vlax-for lo (vla-get-Layouts dbxDoc)
(vlax-for obj (vla-get-Block lo)
(if
(and
(= (vla-get-ObjectName obj) "AcDbBlockReference")
(if(null (= (strcase (vla-get-EffectiveName obj)) "Detail Bdr"))
(progn ;else
(if (null (= (strcase (vla-get-EffectiveName obj)) "Detail Bdr2"))
(progn ;else
(= (strcase (vla-get-EffectiveName obj)) "Detail Bdr3")
);if
);if
);and
(setq dbxScale (vla-get-XScaleFactor obj))
);if
)
)
-
The way I would do it, is make a list of all the block names you want to search for, and then just test the block name against the list.
(vl-position (strcase (vla-get-Name blk)) '("DETAIL BDR" "DETAIL BDR2" "DETAIL BDR3")
Don't forget that lisp is case sensitive (most of the time).
You're welcome. Hope you learned something along this first journey.
-
Perfect! Thank you everybody for all your contribution.
Vovka & T. Willey may I get your Names so that I may log it into the lisp
-
Perfect! Thank you everybody for all your contribution.
Vovka & T. Willey may I get your Names so that I may log it into the lisp
That is my name. T. = Tim (in the signature) Willey = Willey. :wink:
Glad you got something that works for you. Now you should make all your variables local. Very good idea.
-
Yeah, I learned that I have a lot to learn :-D
-
Okay, I'm having some trouble with older details and i feel its because of the fact that my detail borders are no longer dynamic blocks
Right now in DBX I'm looking for my desired block like this (vlax-for LO (vla-get-Layouts dbxDoc)
(vlax-for Obj (vla-get-Block LO)
(if
(and
(= (vla-get-ObjectName Obj) "AcDbBlockReference")
(= (vl-position (strcase (vla-get-EffectiveName Obj)) '("Detail Bdr" "DTLTITLE" "DET-TITLE")))
);and
(setq dbxScale (vla-get-XScaleFactor Obj))
):if
)
)
(princ)
but for some reason with this block even though my effective scale factor is 12.0 it scale my drawing up to 1'-4"=1'-0" (reading an effective scale factor of 0.75). with the properties listed below can you see why?
Command: dlist
Select entity to see all properties and methods:
; IAcadBlockReference: AutoCAD Block Reference Interface
; Property values:
; Application (RO) = #<VLA-OBJECT IAcadApplication 00d74d3c>
; Document (RO) = #<VLA-OBJECT IAcadDocument 01b95dc0>
; EffectiveName (RO) = "DTLTITLE"
; Handle (RO) = "3045"
; HasAttributes (RO) = -1
; HasExtensionDictionary (RO) = 0
; Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 0f96c49c>
; InsertionPoint = (51.6009 22.2771 0.0)
; InsUnits (RO) = "Unitless"
; InsUnitsFactor (RO) = 1.0
; IsDynamicBlock (RO) = 0
; Layer = "TITLINE"
; Linetype = "BYLAYER"
; LinetypeScale = 1.0
; Lineweight = -1
; Material = "ByLayer"
; Name = "MSMTITLE"
; Normal = (0.0 0.0 1.0)
; ObjectID (RO) = 2105865832
; ObjectName (RO) = "AcDbBlockReference"
; OwnerID (RO) = 2107587600
; PlotStyleName = "ByLayer"
; Rotation = 0.0
; TrueColor = #<VLA-OBJECT IAcadAcCmColor 0f952410>
; Visible = -1
; XEffectiveScaleFactor = 12.0
; XScaleFactor = 12.0
; YEffectiveScaleFactor = 12.0
; YScaleFactor = 12.0
; ZEffectiveScaleFactor = 12.0
; ZScaleFactor = 12.0
; Methods supported:
; ArrayPolar (3)
; ArrayRectangular (6)
; ConvertToAnonymousBlock ()
; ConvertToStaticBlock (1)
; Copy ()
; Delete ()
; Explode ()
; GetAttributes ()
; GetBoundingBox (2)
; GetConstantAttributes ()
; GetDynamicBlockProperties ()
; GetExtensionDictionary ()
; GetXData (3)
; Highlight (1)
; IntersectWith (2)
; Mirror (2)
; Mirror3D (3)
; Move (2)
; ResetBlock ()
; Rotate (2)
; Rotate3D (3)
; ScaleEntity (2)
; SetXData (2)
; TransformBy (1)
; Update ()
-
Is the block annotative?
-
not
(= (vl-position (strcase (vla-get-EffectiveName Obj)) '("Detail Bdr" "DTLTITLE" "DET-TITLE")))
but
(vl-position (strcase (vla-get-EffectiveName Obj)) '("DETAIL BDR" "DTLTITLE" "DET-TITLE"))
-
But I thought Lisp was cAsE sensitive... And in our dynamic block "Detail Bdr" thats how it lists
-
But I thought Lisp was cAsE sensitive... And in our dynamic block "Detail Bdr" thats how it lists
It is, that is why we use this line
(strcase (vla-get-EffectiveName Obj))
This tells it to make the name all capitol letters.
-
Alright... one, there hasn't been a problem with the dynamic block so far that I list as "Detail Bdr" and two, would changing the case of the dynamic block fix the issue I'm having with "DTLTITLE" scaling by an xeffectivescale factor of 0.75 when it lists 12.0?
-
Post the whole code you are using so we can see what you are working with.
-
"DTLTITLE" & "DET-TITLE" are not dynamic blocks
(defun c:xas (/ EntName EntData InsName InsScale InsPoint DwgName dbxDoc LO Obj dbxScale EL)
(command "-layer" "make" "S-ANNO-XREF" "color" "7" "" "ltype" "continuous" "" "s" "" "")
(INITDIA)
(command "xattach" pause)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 1 (tblsearch "BLOCK"(cdr (assoc 2 EntData))))))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
(princ)
(vl-load-com)
(setq dwgName InsName)
(setq dbxDoc (vla-GetInterfaceObject
(vlax-get-acad-object)
(strcat "ObjectDBX.AxDbDocument." (substr (getvar "acadver") 1 2))
)
)
(vlax-invoke dbxDoc "Open" dwgName)
(princ)
(vlax-for LO (vla-get-Layouts dbxDoc)
(vlax-for Obj (vla-get-Block LO)
(if
(and
(= (vla-get-ObjectName Obj) "AcDbBlockReference")
(= (vl-position (strcase (vla-get-EffectiveName Obj)) '("DETAIL BDR" "DTLTITLE" "DET-TITLE")))
);and
(setq dbxScale (vla-get-XScaleFactor Obj))
):if
)
)
(princ)
(vlax-release-object dbxDoc)
(setq dbxDoc nil)
(command "scale" EntName "" InsPoint (/ 1 dbxScale))
(princ)
(setq EL (entget (entlast)))
(prompt (strcat "\nInserted " (cdr (assoc 2 EL)) " at scale " (rtos (* 12 (cdr (assoc 41 EL)))) " = 1' "))
(princ)
)
-
This line is not correct
(= (vl-position (strcase (vla-get-EffectiveName Obj)) '("DETAIL BDR" "DTLTITLE" "DET-TITLE")))
It should be (like we posted before)
(vl-position (strcase (vla-get-EffectiveName Obj)) '("DETAIL BDR" "DTLTITLE" "DET-TITLE"))
'vl-position' searches a list for the item supplied, so here it is searching the list you supply for the the name of the block you supply. If it finds it, then it returns the postion, if it doesn't find it it returns nil.
-
Shveet! Thanks
-
Hey Gurus,
This code seems to work fine on my computer but now when I try to load it onto other peoples computer I'm getting an "exception occured" when they try to run it and can't figure out from where or even why. Could it be because some settings are diff on mine than theirs?...
=======================================================================
;;;
;;; XrefAttachScale.lsp
;;;
;;; Created by Alex J. Ruiz
;;; Help from Tim Willey & Vovka
;;; 11.01.2007
;;;
;;; Tested on r2008
;;;
=======================================================================
;;; Function to attach xref at a scale governed by nested title block
;;; Type xas in commandline to run
=======================
;;;Error definition
=======================
;(defun xrperr (msg)
; (if ce (setvar "cmdecho" ce))
; (if v_r (setvar "visretain" v_r))
; (if r_a (setvar "regenmode" r_a))
; (setq *error* orgerr) ;reset previous error def.
; (princ "\nCommand cancelled!")
; (prompt "\n ")
; (princ)
;
;);end defun
=================
;;;Main Program
=================
(defun c:xas (/ lyr lyrdata lyrlock EntName EntData InsName InsScale InsPoint DwgName dbxDoc LO Obj dbxScale EL)
(setq orgerr *error* *error* xrperr)
=======================
;;;Test for layer Xref
=======================
(setq lyr "S-ANNO-XREF")
(if (tblsearch "LAYER" lyr)
(progn
(setvar "clayer" lyr)
(setq lyrdata (entget (tblobjname "layer" lyr)))
(setq lyrlock (cdr (assoc 70 lyrdata)))
);progn
(command "-layer" "make" lyr "color" "7" "" "ltype" "continuous" "" "s" lyr "")
);if
(princ)
(if (= lyrlock 4)
(progn
(initget 0 "Yes No")
(setq lock (cond ((getkword "\nThe layer S-ANNO-XREF is locked. Would you like to unlock it now? <Yes>: "))
("Yes")))
(cond
((= lock "Yes")
(command "-layer" "unlock" lyr "")
)
((= lock "No")
(setq lyrlock 4)
)
);cond
);progn
);if
============================
;;;Xattach command with Box
============================
(INITDIA)
(command "xattach" PAUSE)
(setq EntName (entlast))
(setq EntData (entget EntName))
(setq InsName (cdr (assoc 1 (tblsearch "BLOCK"(cdr (assoc 2 EntData))))))
(setq InsScale (cdr (assoc 41 EntData)))
(setq InsPoint (cdr (assoc 10 EntData)))
; (if (= nil Inspoint)
; (setq InsPoint "0,0,0")
; );if
; (setq InsPoint (getpoint "\nSpecify point of insertion: "))
(princ)
(setq dwgName InsName)
====================
;;;Open Dwg in ODBX
====================
(vl-load-com)
(setq dbxDoc (vla-GetInterfaceObject
(vlax-get-acad-object)
(strcat "ObjectDBX.AxDbDocument." (substr (getvar "acadver") 1 2))
)
)
(vlax-invoke dbxDoc "Open" dwgName)
(princ)
==========================
;;;Get the Desired Blocks
==========================
(vlax-for LO (vla-get-layouts dbxDoc)
(vlax-for Obj (vla-get-Block LO)
(if
(and
(= (vla-get-ObjectName Obj) "AcDbBlockReference")
(vl-position (strcase (vla-get-EffectiveName Obj))
'("MI DETAIL TITLE"
"MSMTITLE"
"MSMDTITLE"
"MI-DET-TITLE"
"MI DETAIL TITLE1"))
)
(setq dbxScale (vla-get-XScaleFactor Obj))
)
)
)
(princ)
=====================
;;;Close Dwg in ODBX
=====================
(vlax-release-object dbxDoc)
(setq dbxDoc nil)
==============
;;;Scale Xref
==============
(command "scale" EntName "" InsPoint (/ 1 dbxScale))
(princ)
====================
;;;After the Insert
====================
; (if (= lyrlock 4)
; (command "-layer" "lock" lyr "")
; (setq lyrlock 0)
; );if
(setq EL (entget (entlast)))
(prompt (strcat "\nAttached \"" (cdr (assoc 2 EL)) "\" at " (rtos (* 12 (cdr (assoc 41 EL)))) "=1'-0\" scale"))
; (setq *error* orgerr orgerr nil)
(princ)
)
;; / lyr lyrdata lyrlock EntName EntData InsName InsScale InsPoint DwgName dbxDoc LO Obj dbxScale EL
-
The code isn't too long, so I would just test it piece by piece until I found what was giving the error. Or you might be able to use vlide to watch it run on their computer, but I don't know how to do that, as I don't use vlide to code in.
If I have some time I will look through it a little more thorough.
-
Tim,
I did break it apart piece by piece and it got "nils" beginning at the variable LO. I did not check dbxDoc (which I really should have) but still around that area.
-
LO will always be nil, unless you check it within the vlax-for loop. It is kind of like a local variable.
I remember this routine now. I would write it different, as there is not need to open the drawing with ObjectDBX since the blocks you are checking for are within model space, and therefor would be within the block definition (xref definition).
-
I doubt this is the problem but FYI the dxf code 70 is a bit code value and therefore this test may fail.
(if (= lyrlock 4)
When in fact the layer is locked.
-
CAB,
It's a direction I tested but took it out with the semi's
-
You took this out?
(if (= lyrlock 4)
(progn
(initget 0 "Yes No")
(setq lock (cond ((getkword "\nThe layer S-ANNO-XREF is locked. Would you like to unlock it now? <Yes>: "))
("Yes")))
(cond
((= lock "Yes")
(command "-layer" "unlock" lyr "")
)
((= lock "No")
(setq lyrlock 4)
)
);cond
);progn
);if
Just change this
(if (= lyrlock 4)
to this
(if (= (logand 4 lyrlock) 4)
-
hehe... forgot about that :lol:
-
See if this works for you.
Edit: Updated code, shown in read.
Edit: Updated code, shown in read. Tested and works, as long as the block that is being searched for is in model space.
(defun c:xas (/ ActDoc LayCol BlkCol xLay OldLay LayObj LockOpt Ent Obj BlkDefObj BlkDefLen cnt xScale tempObj Pos)
(setq ActDoc (vla-get-ActiveDocument (vlax-get-Acad-Object)))
(setq LayCol (vla-get-Layers ActDoc))
(setq BlkCol (vla-get-Blocks ActDoc))
(setq xLay "S-ANNO-XREF")
(setq OldLay (getvar 'CLayer))
(if (vl-catch-all-error-p (setq LayObj (vl-catch-all-apply 'vla-Item (list LayCol xLay))))
(setq LayObj (vla-Add LayCol xLay))
)
(setvar 'CLayer xLay)
(if (equal (vla-get-Lock LayObj) :vlax-true)
(progn
(initget 0 "Yes No")
(setq LockOpt
(cond
((getkword "\nThe layer S-ANNO-XREF is locked. Would you like to unlock it now? <Yes>: "))
(T "Yes")
)
)
(if (= LockOpt "Yes")
(vla-put-Lock LayObj :vlax-false)
)
)
)
(InitDia)
(command "_.xattach" pause)
(if
(and
(setq Ent (entlast))
(setq Obj (vlax-ename->vla-object Ent))
(= (vla-get-ObjectName Obj) "AcDbBlockReference")
(equal (vla-get-IsXref (setq BlkDefObj (vla-Item BlkCol (vla-get-Name Obj)))) :vlax-true)
(setq BlkDefLen (vla-get-Count BlkDefObj))
(setq cnt 0)
)
(while
(and
(not xScale)
(< cnt BlkDefLen)
)
(setq tempObj (vla-Item BlkDefObj cnt))
(if
(and
(= (vla-get-ObjectName tempObj) "AcDbBlockReference")
[color=red](setq Pos (vl-string-search "|" (vla-get-EffectiveName tempObj)))[/color]
(vl-position
[color=red](strcase
(substr
(vla-get-EffectiveName tempObj)
(+ 2 Pos)
)
)[/color]
'("MI DETAIL TITLE"
"MSMTITLE"
"MSMDTITLE"
"MI-DET-TITLE"
"MI DETAIL TITLE1"
)
)
)
(setq xScale (vla-get-XScaleFactor tempObj))
(setq cnt (1+ cnt))
)
)
)
(if xScale
(progn
[color=red](vlax-invoke Obj 'ScaleEntity (vlax-get Obj 'InsertionPoint) (/ 1 xScale))[/color]
(prompt
(strcat
"\nAttached \""
(vla-get-Name Obj)
"\" at "
[color=red](rtos (* 12 (/ 1 xScale)))[/color]
"=1'-0\" scale"
)
)
)
)
(if (= LockOpt "Yes")
(vla-put-Lock LayObj :vlax-true)
)
(setvar 'CLayer OldLay)
(princ)
)
-
Guys, I found it!
Apparantly there is an exception that occurs when one chooses relative path versus full path. When full path is selected the code works fine. Tim I will see how the code above works and if it has the same issue
-
Glad you found it, but the new one won't matter because it doesn't use the path for anything (which sould make it faster). The problem was that if it's not a real path, then it doesn't know where to find the drawing, so it can't open it up in the ObjectDBX app. That would be an easy fix, you would just need to add a 'findfile' call here.
(setq dwgName InsName)
Change to
(setq dwgName (findfile InsName))
-
Tim,
Your code for some reason did not scale down. I will also look into it and see what I can find. Either way thank you for another great example on how to code. I also have a new function to read up on
-
Tim,
Your code for some reason did not scale down. I will also look into it and see what I can find. Either way thank you for another great example on how to code.
You're welcome. I have fixed what could be the problem (in the other post), as I didn't test it because I don't have your blocks, but I will here soon just to make sure what I posted works. :-)
Edit: After looking at the code, you may have to go the ObjectDBX route. It looks like you are looking for title block blocks, and those are typically in a paper space layout, which wouldn't be in the block definition.
-
They are detail title blocks and are in the block definitions we use
-
They are detail title blocks and are in the block definitions we use
But they would need to be inserted in model space in the xref, or the new code won't work.
ps. I updated the code after testing it. The problem was with searching for the name. I forgot that when you search the way I do now it adds the xref to the name, so I had to change the way I looked at the blocks name.
-
Sorry, i wasn't very clear the first time. Everything within the detail xref is in model space. Wow, i can tell how much faster your code is. Probably fractions of a second but very noticible non-the-less. Terrific
Lisp now reads...
=======================
;;; Overhauled by Tim Willey
;;; 12.19.2007
=======================
:-D
-
Sorry, i wasn't very clear the first time. Everything within the detail xref is in model space. Wow, i can tell how much faster your code is. Probably fractions of a second but very noticible non-the-less. Terrific
Lisp now reads...
=======================
;;; Overhauled by Tim Willey
;;; 12.19.2007
=======================
:-D
You're welcome.
ObjectDBX is fast, but you still have to load the drawing (but at least not in the editor), but if you don't have to load the drawing why should we, and if we don't then it will be faster, which is the route I took in the second version.
-
Now is there any way to bypass the scale or rotation setting in the xref dialogue box or even make sure those two are always unchecked?
-
Now is there any way to bypass the scale or rotation setting in the xref dialogue box or even make sure those two are always unchecked?
If this routine was for me, I wouldn't even use the command 'xattach', I would do it all with code, but I didn't know if you liked to see the options the command has to offer or not. If you just want to attach a file at a certain point with almost all options always the same, then I would just code up something like that.
-
Only problem is that I have no idea how to do dialogue boxes yet.
-
Only problem is that I have no idea how to do dialogue boxes yet.
You don't need a dialog box. I would use the standard lisp function 'GetFiled'.
-
Schhhhhhhhvvvvvvvvvvveeeeeeeeeeet! Thats two today. I can have fun with this one. I'll see if i can learn how to incorporate it.
....wait. Actually I could of just went through the -xref command, no?
-
Schhhhhhhhvvvvvvvvvvveeeeeeeeeeet! Thats two today. I can have fun with this one. I'll see if i can learn how to incorporate it.
....wait. Actually I could of just went through the -xref command, no?
Yes if you knew where the file would be.
-
How would you use getfiled then to attach the drawing? And is there a way for the dia to remember the last folder that I was in?
-
How would you use getfiled then to attach the drawing?
You don't use it to attach the file (xref), but to get the location of the file. Once you have that, then you know what you are going to attach, and you can use the 'AttachExternalReference' method on the space (tab) you want to add the xref. This might be a little more advance stuff than what you are using right now, but it isn't that hard. I would go that ActiveX route.
And is there a way for the dia to remember the last folder that I was in?
Depends on what you want it to remember, and how you want it to remember. If you want it to remember within the same drawing, then you just make the directory a global variable. If you want it to be know in all drawings that are opened, or going to be opened, then you make it a global variable, and use the 'vl-propagate' function to send it to all drawings. These are both ways to keep it known in the current Acad session. If you want it to be known past that, then you have to write it to a file or the registry.
-
Okay, and one more question.
What about the option to make the xref relative?
Make it two... How long have you being writing code? (gives me something to look foward to)
-
Okay, and one more question.
What about the option to make the xref relative?
From what I have seen about that, it is how the path is stored within the drawing. So it depends on how far you want the relative path to go. If you want it one folder back, I think you would just put the path like
..\Xrefs\Xref.dwg
But you may need to test to make sure.