Robert89 Posted February 15, 2018 Share Posted February 15, 2018 Hi everyone, First of all, thanks for the information given thus far, this forum has been both helpful and frustrating. It's like being surrounded by people who are running and jumping while I can barely crawl. I'm looking for a lisp routine to insert unique blocks from a csv. Every routine/app I've encountered is limited to 1 specific blocktype. The csv would contain the following info (not necessarily in this order): Blockname;x;y;z;layer;rotation;attribute1;attribute2;attribute3 Unique layers would be useful but not necessary, might not be worth the extra hassle. Really hoping I missed an existing routine. Thanks in advance! Quote Link to comment Share on other sites More sharing options...
pBe Posted February 15, 2018 Share Posted February 15, 2018 Hi everyone,I'm looking for a lisp routine to insert unique blocks from a csv. Just what do you mean by "limited to 1 specific blocktype" ? Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 15, 2018 Author Share Posted February 15, 2018 Just what do you mean by "limited to 1 specific blocktype" ? Sorry, not used to proper terminology. I meant 1 block per list execution. Everything I've come across allows you to insert a specific block on multiple insertion points. I'd like to specify a blockname on every insertion point. Hope that clears it up for you. Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 16, 2018 Share Posted February 16, 2018 (edited) 1st step is to convert the csv file to multiple lists, Then it easy to just pull out all the answers from the new list, something like this. ; ; thanks to Lee-mac for this defun (defun _csv->lst ( str / pos x lst lst2) (if (setq pos (vl-string-position 44 str)) (cons (substr str 1 pos) (_csv->lst (substr str (+ pos 2)))) (list str) ) ) (defun c:ins->csv ( / fo x) (setq fo (open (getfiled "Choose CSV file" "G:/AutoCAD/Lisp/" "CSV" ) "R") (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) (setq y (length lst)) (setq x (- y 1)) (repeat y (setq lst2 (nth x lst)) ;(setvar 'clayer (nth 6 lst2)) (command "insert" (nth 0 lst2) (strcat (nth 1 lst2)","(nth 2 lst2)","(nth 3 lst2)) 1 (nth 5 lst2) (nth 7 lst2) (nth 8 lst2)) (setq x (- x 1)) ) ) ; end defun Edited February 18, 2018 by BIGAL Quote Link to comment Share on other sites More sharing options...
pBe Posted February 16, 2018 Share Posted February 16, 2018 Sorry, not used to proper terminology. No need to apologize, its me who is not understanding the terminology (setq fo (getfiled "Choose CSV file" "" "CSV" "R") (setq lst '()) (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) Missing something there BIGAL (setq fo (getfiled "Choose CSV file" "" "CSV" 16)) [b](setq fo (open fo "R"))[/b] (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 16, 2018 Author Share Posted February 16, 2018 Thanks for your input. Encountering a few issues though... This is how I set-up my test csv: Block;x;y;z;scale;rotation;layer;att1;att2 DW_L_TL;0;0;0;1;;;;DW_L_TL;0;5;0;1;;;; DW_L_TL;0;10;0;1;;;; I've added a ")" changed the list order a bit and canceled the layer part for now: ; ; thanks to Lee-mac for this defun (defun _csv->lst ( str / pos ) (if (setq pos (vl-string-position 44 str)) (cons (substr str 1 pos) (_csv->lst (substr str (+ pos 2)))) (list str) ) ) (setq fo (getfiled "Choose CSV file" "" "CSV" 16)) (setq fo (open fo "R")) (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) (repeat (setq x (- (length lst) 1)) (setq lst2 (nth x lst)) [color="lime"];(setvar 'clayer (nth 6 lst2))[/color] (command "insert" (nth 0 lst2) (list (nth 1 lst2)(nth 2 lst2)(nth 3 lst2)) 1 (nth 5 lst2) (nth 7 lst2) (nth 8 lst2) (setq x (- x 1)) ) [color="lime"])[/color] This gives me the following error: insert Enter block name or [?] : DW_L_TL;0;5;0;1;;;; Warning: If you are trying to insert the file: DW_L_TL;0;5;0;1;;;;it must be inserted using the = syntax. Did I mess something up? It doesn't seem to recognize the column delimiters. Another thing I've noticed is that this routine adds every execution to the previous one, is there a way to "swipe" the current information? @BIGAL Blocks and layers both exist, for now anyway. Haven't figured out how to properly set-up my library yet, so don't want to get ahead of myself. Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 16, 2018 Share Posted February 16, 2018 (edited) Thanks Pbe just copy/pasted and typed it did not test as no user data. Robert89 will test later today now I have your sample csv, if reading this use -insert stops the file dialouge. Gone fishing for a little while, have to get the priorities right. I will add the layer and block check. Edited February 17, 2018 by BIGAL Quote Link to comment Share on other sites More sharing options...
pBe Posted February 17, 2018 Share Posted February 17, 2018 Thanks for your input. Encountering a few issues though... ... This gives me the following error: insert Enter block name or [?] : DW_L_TL;0;5;0;1;;;; Warning: If you are trying to insert the file: DW_L_TL;0;5;0;1;;;;it must be inserted using the = syntax. You are supplying "DW_L_TL;0;5;0;1;;;;" as the block name instead of just "DW_L_TL" 3 things _csv->lst sub routine is checking for ascii character 44 which represents the "," - Try to figure out the code for ";" that were used on your csv file as a delimiter. The specified number on repeat is 1 less than the list - Leave length lst as it is then try to subtract 1 on or before you assign variable lst2 from lst OR consider using foreach The coordinate specified on the comand line is a list with string elements - Either use strcat to build the list OR convert 2nd , 3rd & 4th element of lst2 to real number Other than that you're good to go Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 17, 2018 Share Posted February 17, 2018 Some more hints atof converts a string to real (chr x) v;s (ascci "A") then maybe a (OR function so you can look for ; or , Quote Link to comment Share on other sites More sharing options...
satishrajdev Posted February 17, 2018 Share Posted February 17, 2018 I was using this long back. It will work on any block as you select the reference block at start (DEFUN C:IMPORTBLK (/ *ERROR* INBLOCK STR->LIST A B BK C C1 D X) (VL-LOAD-COM) ;;********************************************************************************************;; ;;**************************************** UTILITIES ****************************************;; ;;********************************************************************************************;; (DEFUN *ERROR* (MSG) (IF (NOT (WCMATCH (STRCASE MSG T) "*BREAK,*CANCEL*,*EXIT*") ) (PRINC "") ) (PRINC) ) (DEFUN INBLOCK (POINT BLOCKNAME XSCALE YSCALE ZSCALE ROTATION) (VLA-INSERTBLOCK (VLA-GET-MODELSPACE (VLA-GET-ACTIVEDOCUMENT (VLAX-GET-ACAD-OBJECT)) ) (VLAX-3D-POINT POINT) BLOCKNAME XSCALE YSCALE ZSCALE ROTATION ) ) (DEFUN STR->LIST (STR / B) (FOREACH X (REVERSE (VL-STRING->LIST STR)) (COND ((EQ X 44) (SETQ B (CONS (LIST X) B))) (T (IF (NOT B) (SETQ B (CONS (LIST X) B)) (SETQ B (CONS (CONS X (CAR B)) (CDR B))) ) ) ) ) (MAPCAR '(LAMBDA (X) (VL-LIST->STRING (VL-REMOVE 44 X))) B) ) ;;********************************************************************************************;; ;;************************************** MAIN PRAGRAM ***************************************;; ;;********************************************************************************************;; (IF (AND (SETQ A (OPEN (GETFILED "Select Data File" "C:/" "CSV;TXT" 4) "r") ) (SETQ BK (VLAX-ENAME->VLA-OBJECT (CAR (ENTSEL "\nSelect Block : "))) ) ) (PROGN (SETQ C (WHILE (SETQ B (READ-LINE A)) (SETQ C (CONS (STR->LIST B) C)) ) ) (CLOSE A) (SETQ C (CDR (REVERSE C))) ; REMOVE HEADER (ACET-UI-PROGRESS-INIT "Plotting Blocks" (LENGTH C)) (FOREACH X C (SETQ D (INBLOCK (LIST (ATOF (CAR X)) (ATOF (CADR X)) (ATOF (CADDR X))) (VLA-GET-EFFECTIVENAME BK) 1 1 1 0 ) X (CDDDR X) ) (IF (EQ (VLA-GET-HASATTRIBUTES BK) :VLAX-TRUE) (MAPCAR '(LAMBDA (Y) (VLA-PUT-TEXTSTRING Y (CAR X)) (SETQ X (CDR X)) ) (VLAX-INVOKE D 'GetAttributes) ) ) (ACET-UI-PROGRESS-SAFE (IF (NOT C1) (SETQ C1 1) (SETQ C1 (1+ C1)) ) ) ) (ACET-UI-PROGRESS-DONE) ) ) (VL-CMDF "ZOOM" "E") (PRINC) ) Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 17, 2018 Author Share Posted February 17, 2018 You are supplying "DW_L_TL;0;5;0;1;;;;" as the block name instead of just "DW_L_TL" 3 things _csv->lst sub routine is checking for ascii character 44 which represents the "," - Try to figure out the code for ";" that were used on your csv file as a delimiter. The specified number on repeat is 1 less than the list - Leave length lst as it is then try to subtract 1 on or before you assign variable lst2 from lst OR consider using foreach The coordinate specified on the comand line is a list with string elements - Either use strcat to build the list OR convert 2nd , 3rd & 4th element of lst2 to real number Other than that you're good to go Took a while for my post to get through "customs", so I couldn't share my progress. 1. Figured that out, there was no specific reason for using ; just thought the routine required that character at first, changed it to ",". Aye, ; = 59 2. Can't get this to work, just trial and error cause I don't understand it yet. 3. This part works now So it's the "repeat" part which makes a mess of it atm. It's also not wiping the repeat variable causing it to add up every time I rerun the routine. Tried stopping it by localizing the variables, but that didn't help. Running it the first time gives me the first 2 lines, then 5, 8, etc. ; ; thanks to Lee-mac for this defun (defun _csv->lst ( str / pos x lst lst2) (if (setq pos (vl-string-position 44 str)) (cons (substr str 1 pos) (_csv->lst (substr str (+ pos 2)))) (list str) ) ) (setq fo (getfiled "Choose CSV file" "G:/AutoCAD/Lisp/" "CSV" ) (setq fo (open fo "R")) (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) (repeat (setq x (- (length lst) 1)) (setq lst2 (nth x lst)) ;(setvar 'clayer (nth 6 lst2)) (command "insert" (nth 0 lst2) (strcat (nth 1 lst2)","(nth 2 lst2)","(nth 3 lst2)) 1 (nth 5 lst2) (nth 7 lst2) (nth 8 lst2)) (setq x (- x 1)) ) Quote Link to comment Share on other sites More sharing options...
pBe Posted February 17, 2018 Share Posted February 17, 2018 So it's the "repeat" part which makes a mess of it atm. It's also not wiping the repeat variable causing it to add up every time I rerun the routine. Tried stopping it by localizing the variables, but that didn't help. Running it the first time gives me the first 2 lines, then 5, 8, etc. Make sure lst variable is localize, variable x is definitely "reset" (setq lst '("Robert89" "BIGAL" "satishrajdev" "pBe")) (repeat (setq x (length lst)) ; <-- repeat as the same number of items on the list (print (nth (setq x (1- x)) lst)) ; x is now 3 on the first run | fourth element of the list ; x is now 2 on the second run | third element of the list ; x is now 1 on the.... (princ) ) ;;; no need for index/counter | also wiping out values for lst variable ;;; (while (setq a (Car lst)) ; a as first element of the list (print a) (setq lst (Cdr lst)) ; lst is redefined as list less the first element (princ) ) or simply ;;; no need for counter ;;; (Foreach itm lst (print itm) (princ) ) HTH Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 18, 2018 Share Posted February 18, 2018 (edited) Because the list is made up of sub lists need to repeat for number of items in the master list but the inside list starts at zero. Just forgot all about that. CODE updated above in my 1st post Edited February 18, 2018 by BIGAL Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 18, 2018 Author Share Posted February 18, 2018 Thanks for the input! I won't be able to try your suggestions till thursday (network licence and vpn isn't working), but lets just say the plot is thickening. Because the list is made up of sub lists need to repeat for number of items in the master list but the inside list starts at zero. Just forgot all about that. CODE updated above in my 1st post Getting a bit sloppy there BIGAL Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 19, 2018 Share Posted February 19, 2018 Its sloppy because we need real data and a dwg to test code on. Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 19, 2018 Author Share Posted February 19, 2018 I was just kidding BIGAL, you're all doing me a solid, would be insane to complain about that. I'm restructering the way I work because another colleague is switching to AutoCAD (I was the only user). This means there's no relevant data to be shown yet, there's just some basic functionality we really need, the rest can (mostly) be shaped around it. He's a land surveyor, hence the need to directly import csv's. Quote Link to comment Share on other sites More sharing options...
Robert89 Posted February 20, 2018 Author Share Posted February 20, 2018 The following code seems to do the trick, thanks guys! Added "curlayer" to return currentlayer to pre-routine state. And some comments so I actually know what's going on. Is there anything to improve/streamline? ; ; thanks to Lee-mac for this defun (defun _csv->lst ( str / pos ) (if (setq pos (vl-string-position 44 str)) ;44 = "," delimiter (cons (substr str 1 pos) (_csv->lst (substr str (+ pos 2)))) (list str) ) ) (defun c:csvins ( / fo lst curlayer ) (setq fo (getfiled "Choose CSV file" "G:/AutoCAD/Lisp/" "CSV" ) ;File to open from (setq fo (open fo "R")) ;"R" = read (while (setq ans (read-line fo)) (setq lst (cons (_csv->lst ans) lst)) ) (setq curlayer (getvar 'clayer)) ;Save current layer (Foreach itm lst (setvar 'clayer (nth 6 itm)) ;Set "insertion" layer (command "insert" (nth 0 itm) ;blockname to insert (strcat (nth 1 itm)","(nth 2 itm)","(nth 3 itm)) ;x y z, strcat to combine 3 columns as string (nth 4 itm) ;scale (nth 5 itm) ;rotation (nth 7 itm) ;attribute 1 (nth 8 itm)) ;attribute 2 (setvar 'clayer curlayer) ;Return layer to old name (princ) ) ) ; end defun Quote Link to comment Share on other sites More sharing options...
pBe Posted February 20, 2018 Share Posted February 20, 2018 The following code seems to do the trick, thanks guys! Good for you Robert89 ... Is there anything to improve/streamline? What you need to consider are the following: A test to check if the expressions evalautes to a none nil value to continue to evaluate the next one. (if / cond / and ) Closing the file opened for access (open / close ) A check if the block to be inserted is found ( tblsearch / findfile ) A check if the layer specified exists / ( Layer Make / New / Set ) Below is for you to figure out: Set the current layer back to its pre-routine state only once Set the osnap value to avoid messing up insertion point for the block Look into the system variables that affect settings during insertion of blocks. HTH Quote Link to comment Share on other sites More sharing options...
BIGAL Posted February 21, 2018 Share Posted February 21, 2018 Like Pbe write a little defun that checks for a layer exists on the fly, save this defun into an autoload lisp file then its available for any code that you write. I have left a lot out so you can learn all the answers are in the links provided by Pbe. (defun laycheck ( layname / ) (if (= (tblsearch........ )(vlax:true) (princ "found") else make layer here ) ; example checks if layer exists if not make it (laycheck "fred") Quote Link to comment Share on other sites More sharing options...
halam Posted February 17, 2019 Share Posted February 17, 2019 (edited) perfect! for ; use character 059 https://ee.hawaii.edu/~tep/EE160/Book/chap4/subsection2.1.1.1.html Stil have some problems here using this code. The line for file to open does not return a result Edited February 17, 2019 by halam Quote Link to comment Share on other sites More sharing options...
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.