Jef! Posted March 5, 2014 Posted March 5, 2014 (edited) From Adesk documentation, this is the structure of dictnext (dictnext ename [rewind]) I have a function who retrieves the ename of a dict (defun getdictEname (dictName / tmp) (if (setq tmp (dictsearch (namedobjdict) dictName)) (cdr (assoc -1 tmp)) ) ) It works and retrieves the correct dict Ename (setq DGNDictEName (getdictEname "ACAD_DGNLINESTYLECOMP")) I even double checked with (entget (namedobjdict)). So good so far. Now trying to feed it to dictnext (with T to rewind to 1rst entry) and it don't work. Command: (setq dgntodel (dictnext DGNDictEName T))nil Command: !DGNDictEName If someone would be kind enough to tell me what I missed, I'd appreciate.Thanks Edited March 6, 2014 by Jef! Quote
Hippe013 Posted March 5, 2014 Posted March 5, 2014 You are using dictnext correctly. Your dictionary doesn't contain any entries. Quote
Hippe013 Posted March 5, 2014 Posted March 5, 2014 BTW. I love your avatar! I seriously busted out laughing when I saw it? Has Lee Mac seen it by chance? HA HA HA! Quote
Lee Mac Posted March 5, 2014 Posted March 5, 2014 BTW. I love your avatar! I seriously busted out laughing when I saw it? Has Lee Mac seen it by chance? HA HA HA! :lol: Quote
Jef! Posted March 5, 2014 Author Posted March 5, 2014 Actually it does (and tons of em) because if I use (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP"), in history I see lots appear 1 by 1 very fast, it slows down gradually and after maybe 15 seconds it completely stop and freeze my cad. Quote
Jef! Posted March 5, 2014 Author Posted March 5, 2014 As for my avatar, Thanks! I totally took it on purpose. I got the suit, and I'm learning the technic... It also shows where I'm heading =) Quote
Jef! Posted March 5, 2014 Author Posted March 5, 2014 Heres a printscreen showing the dictnext returning nil while the namedobjdict says otherwise.. (If I understood correctly how they work) Quote
Jef! Posted March 6, 2014 Author Posted March 6, 2014 Since I absolutely need that for my project, I'm bumping the thread. I like to fully understand one thing before going to the next one, and actually I have a doubt about my understanding of dictnext and/or (dictsearch (namedobjdict)). Any comments and guidance is still very welcome. Quote
Hippe013 Posted March 6, 2014 Posted March 6, 2014 Try running your code on an existing ACAD dictionary. I noticed that all of your entries in your dictionary are under the assoc 3. This seems odd. All of your entries are immediately under the root. In looking at, let's say, the ACAD_LAYOUT dictionary this isn't the case. Dictnext works properly on that dictionary. This is just a guess, but I would assume you are a having troubles due to the structure of your dictionary. Maybe try adding a few entries using the dictadd and then try dictnext on that modified dictionary. Quote
cwake Posted March 6, 2014 Posted March 6, 2014 It is normal for dictionary entries to be in pairs, where the 3 group code identifies the data, and the following group code being an ename pointing to additional dictionary data. If you know the data identifier that you're looking for, your next step would usually be another dictsearch of the data returned in step 1. But I think you're going to have to post more information about what data you're trying to extract, possibly including a sample drawing as well. Alternatively, you can learn a lot about dictionary structure using dictedit. I think there's a link to it here. http://www.cadtutor.net/forum/showthread.php?48655-How-to-completely-delete-a-table-data-link Quote
Jef! Posted March 6, 2014 Author Posted March 6, 2014 Thanks for trying to help. Ill try to answer all your queries and questions. Actually I'm hunting complex line types. Complex line types cant be purged with purge command, and I have a sample "empty" file that contain so much dgn comp line types that with no layouts and nothing in model, all purged. The dwg is more than 10 megabytes in size. The thing is that even if you drew 1 entity in that "empty" drawing (line, circle, block, anything), and copy that entity to another drawing, it automatically import all DGN complex line types. They follow each entity, are cumulative and cant be purged with traditional purge. What make file size skyrocket are the anonymous *A blocks that contain custom strokes. They cant be purged because they are reference by dgn comp line types, who cant be purged. joy-joy. I know that some tools are available already (pdi.fas to name one) but it has to be loaded, run, and as it remove entire dictionaries, if the user remove the wrong dictionary, it can corrupt the file and make it unrecoverable. And if the tool is not systematically run this "cancer" can come back by the back door and spread very fast. What I'm making is a tool (dcl) that detects many things things (line weigths, available plot style table , active plot styles, dim styles, presence of complex line types, and much more), gives the user feedback about what is "wrong" and enable him to fix stuff with the click of a button. (retrieves standard.stb file from network is not available locally, convert from ctb to stb if not stb, apply standard.stb to all layouts, apply the correct plotstyle, correct line weigths, etc ) My ultimate goal is to remove complex line types (by "myself") , count how many were removed to give back feedback to the user to maybe eventually find the exact source (which supplier). Complex line types are not native from autocad (most of them I think). @Hippie013, The "ACAD_DGNLINESTYLECOMP" dictionnary is indeed in the main dictionary. The reason why (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP") freeze and crash it is because there are few thousands entries in that dictionary. That's why I opted for the get the 1rst entry, remove it, get the next entry, remove it, and so on. Here'S what I made so far (defun getdictname (dictName) (if (setq tmp (dictsearch (namedobjdict) dictName)) (cdr (assoc -1 tmp)) ) ) ;;detects dgnlinestylecomp (if (setq DGNDict (getdictname "ACAD_DGNLINESTYLECOMP")) (progn (setq dgntodel (dictnext DGNDict T));[color=red]<-that one always return NIL (?)[/color] (setq counter 0) (while dgntodel (setq counter (+ 1 counter)) (dictremove DGNDict dgntodel) (prompt (strcat counter " " dgntodel " was removed")) (setq dgntodel (dictnext DGNDict)) ) ) (princ "nope!") ) Since my complex line types full empty drawing test file has a size too big to upload here, heres the link to grab it in my dropbox. https://dl.dropboxusercontent.com/u/74035730/dgn%20comp%20line%20types/empty%20with%20dgn%20complex.dwg In the mean time ill look at what you linked cwake Quote
Jef! Posted March 6, 2014 Author Posted March 6, 2014 interesting fact. While I thought that I had to remove each entry individually within the "ACAD_DGNLINESTYLECOMP", reading the post you linked I found out I could directly remove the "ACAD_DGNLINESTYLECOMP" dictionary with (dictremove (namedobjdict) "ACAD_DGNLINESTYLECOMP") An interesting alternative. That way I might be able to tell how many line types and anonymous blocks were purged. The only downside is that I'm not sure I could tell how many complex line types were suppressed, as many complex line types could use the same base line type, with the same custom strokes but used in a different pattern. Maybe there is a way to count the number of dgn complex line style within the dictionary "ACAD_DGNLINESTYLECOMP" before removing it.. (starting to dig) Quote
Jef! Posted March 7, 2014 Author Posted March 7, 2014 That one is driving me totally crazy. Told myself "I can easily find out how many comp dgn there are in my drawing) (defun c:dgncompcounter ( / );tmp nthcounter dgncounter) (setq dgncounter 0) (setq nthcounter 0) (setq tmp "notnil") (while tmp (setq tmp (nth nthcounter (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP"))) (if (= (car tmp) 3) (progn (setq dgncounter (+ 1 dgncounter)) (princ (strcat "\n dgn count at "(itoa dgncounter) ". (complex line tyne named: "(cdr tmp) " detected)" )) ) ;(print (strcat "none were fount on entry number ")) ) (setq nthcounter (+ 1 nthcounter)) ;(princ (strcat "\nchecking entry numb "(itoa nthcounter))) ;(if (< nthcounter 50)(alert "next while")) ) (princ (strcat "\n"(itoa dgncounter) " complex linetypes have been found" " and for information the number of entries checked is "(itoa nthcounter) )) ) on Cad 2013: insta crash withing 5 first entries checkup. If I uncomment the alert line, as long as I hit the ok button it keeps going. Cad 2014 with the alert commented, it can check 200 to 300 entries, detecting/retrieving/princ-ing around 60 dgn comp line styles names. It always end up freezing but never at the same entry number. It is a lot slower than I expected. I know this can be done, pdi does it, and so does the standard purge dialog when we check "view items you cannot purge".... (and instantly I should add.) This is a time where thousands of seconds count. I think I'll try a foreach approach tomorrow, or any other suggested (if any) [/end of subliminal message] =) maybe more (vlax-safearray-fill filter_code '(?)) (vlax-safearray-fill filter_value '("3")) ? sslength? vla-get-count? no because this would not be a selection set? I need to count the # of time (car (nth nthcounterforallthe10000entries (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")))) equals 3 (and there are a total of more than 2800). Arg/lol. Quote
cwake Posted March 7, 2014 Posted March 7, 2014 (edited) I'm not sure where to start Jef eventually find the exact source (which supplier). The problem you describe would most likely come from a Bentley product... likely Microstation. So you could start there in finding the source. The only downside is that I'm not sure I could tell how many complex line types were suppressed If the number of linestyles present is important to you (using LISP), use (defun c:dgncompcounter ( / dict) (if (setq dict (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")) (length (vl-remove-if-not '(lambda ( x ) (= (car x) 3)) dict)) ) ) Here's a couple of references I found... The first is the most important because it is an Autodesk fix that saves you the bother of having to fix it yourself. http://knowledge.autodesk.com/support/autocad/downloads/caas/downloads/content/autocad-C2-AE-dgn-hotfix.html If you really want to try to apply yourself to using LISP, the second link isn't LISP but describes the programmatic process you would use. http://through-the-interface.typepad.com/through_the_interface/2012/12/purging-unwanted-dgn-linestyle-data-from-an-autocad-drawing-using-net.html I can get the 10.1MB drawing down to 32.5KB using LISP by eradicating the dictionary... but it would be irresponsible for me to post code because in it I haven't checked any dependencies within the drawing. The Autodesk version gets it down to 29.0KB without even breaking a sweat... Edited March 7, 2014 by cwake Quote
Jef! Posted March 7, 2014 Author Posted March 7, 2014 Hi Cwake, thanks for the input and the code! To make a short story, I can also eradicate the dictionary. We use PDI at the moment, which is supressing the dictionary with brute force, and is far less sophisticated than Kean's hotfix.. but we rely upon all the users to run it to avoid the spreading and using 100 to 1000 time more space on the server. I'm trying to control the cad environment without having the privileges of and control over IT. I totally agree that Kean's hotfix is the best way to deal with dgn issues, but I cant go to all our workstations to log in, and I'm not sure I could run netload, unblock the security of the dll... and would still rely on everyone to use the command "dgnpurge". Since we never use dgn complex lt, we don't mind about the brute force of PDI.fas. The fact that pdi.fas can remove any dictionary is kind of worrying. If we are ok about PDI using a chainsaw to remove dgn dictionary without checking the dependencies, well I can do it on my own... and instead of running it systematically and automatically, my interface will show that "You have 1523 complex line types" and allow the user to supress them clicking on 1 button. Showing the user the status and the problem(s) and enabling them to correct them with 1 click. That's my goal, and thanks to you I'm 1 step closer =) me => I need to count the # of time (car (nth nthcounterforallthe10000entries (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")))) equals 3 Cwake => (setq dict (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")) (length (vl-remove-if-not '(lambda ( x ) (= (car x) 3)) dict)) ) My brain talk LISP language, but still has a tiny tiny tiny English accent, that's all Quote
cwake Posted March 7, 2014 Posted March 7, 2014 (edited) My brain talk LISP language, but still has a tiny tiny tiny English accent, that's all That's awesome Jef! Love your humour. It's a pity that IT doesn't support you on this one. You could still use your LISP skills to run dgnpurge on the user's machines... but you have to be allowed to make it available there first. In that case I'll compare a couple of alternative options to do the same thing (count the dictionary references). Usually I prefer AutoLISP over Visual LISP but on these big bloated drawings there is actually a speed advantage to Visual LISP. (defun c:dgncompcounter ( / dict ) (if (setq dict (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")) (length (vl-remove-if-not '(lambda ( x ) (= (car x) 3)) dict)) ) ) (defun c:dgncompcounter2 ( / count ) (vlax-for x (vla-get-dictionaries (vla-get-activedocument (vlax-get-acad-object))) (if (and (vlax-property-available-p x "NAME") (= (vla-get-name x) "ACAD_DGNLINESTYLECOMP") ) (setq count (vla-get-count x)) ) ) count ) (defun c:dgncompcounter3 ( / count dict ) (if (setq dict (dictsearch (namedobjdict) "ACAD_DGNLINESTYLECOMP")) (progn (setq count 0) (foreach x dict (if (= (car x) 3) (setq count (1+ count)) ) ) count ) ) ) And the BENCHMARK speed comparison: _$ (benchmark '((c:dgncompcounter) (c:dgncompcounter2) (c:dgncompcounter3))) Benchmarking ............Elapsed milliseconds / relative speed for 512 iteration(s): (C:DGNCOMPCOUNTER2)......1622 / 13.74 <fastest> (C:DGNCOMPCOUNTER)......17004 / 1.31 (C:DGNCOMPCOUNTER3).....22292 / 1 <slowest> Edited March 7, 2014 by cwake Quote
Lee Mac Posted March 8, 2014 Posted March 8, 2014 (defun c:dgncompcounter2 ( / count ) (vlax-for x (vla-get-dictionaries (vla-get-activedocument (vlax-get-acad-object))) (if (and (vlax-property-available-p x "NAME") (= (vla-get-name x) "ACAD_DGNLINESTYLECOMP") ) (setq count (vla-get-count x)) ) ) count ) This could also be written: (defun c:dgncompcounter4 ( / dic ) (if (not (vl-catch-all-error-p (setq dic (vl-catch-all-apply 'vla-item (list (vla-get-dictionaries (vla-get-activedocument (vlax-get-acad-object))) "acad_dgnlinestylecomp" ) ) ) ) ) (vla-get-count dic) ) ) Quote
Jef! Posted March 11, 2014 Author Posted March 11, 2014 Hi there! I just saw your 2 replies. Glad you appreciated my humour Cwake. Thanks for the additional feedback, ways to skin the cat (poor cat.. at least it still have few lives left) and benchmarks. I would have been curious to see Lee's #4 dgn counter timer, he usually score nice on benchmarks. =) Anyway ATM I have a very bloated drawing and it has around 15 000 complex line types. The DGNcompcounter1 return the qty in what it feels like less than .1 sec (I cannot notice at naked eye the difference between #1 and #2). I'll take the #2 anyway, 10 times faster seems not negligible. For the IT support, I can understand that its not obvious to support installations that include modifying dll files. And I prefer not to be relying onto that, that way if 1 drive blow and IT have to reinstall, and forget to modify dll, my lsp would fail. Quote
Recommended Posts
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.