Jump to content

Recommended Posts

Posted

I have some polylines that are long and curved. I need to place nodes at certain points on these lines. I have a table in excel telling me how far down each line to place a node. There is nothing common about the lengths in which the nodes need to be placed. Is there a way to create a LISP Routine to important the information for the excel spreadsheet and place nodes at the points specified? If so does anyone have one done? This is a 2D object. The lines are thousands of segments based off of a survey and have now been joined into one polyline. Sorry if I'm not explaining myself very well. I'm very new to LISP Routines but I would love to learn to use these as I see how beneficial that could be. I take a lot of surveys and create drawings based on these surveys and need to insert markers throughout the drawings that I create, any help would be much appreciated.

  • Replies 28
  • Created
  • Last Reply

Top Posters In This Topic

  • kilc6887

    12

  • Lee Mac

    10

  • alanjt

    4

  • JPlanera

    3

Top Posters In This Topic

Posted

JPLANERA,

 

That LISP really will help quite a bit. Rather than being prompted to enter a specific number to measure, which is what I can do with that LISP now, is there a way to insert a number table in the code or reference a number table in the code where it can then label all of the numbers that I have put in there?

Posted

I have the numbers in columns in excel. I could put them into anything though.

Posted

THe good news is that YES it can do what you ask... THe bad news is that I dont know how to do it... check out the LISP forum on this site for more info..

Posted

Ah lee mac has found you... you are in good hands! 8)

Posted

I've only recently learned of LISP programming and the potential to help me is unbelievable. Can you point me toward good tutorials, books, whatever I need to learn to use LISP Routines more independently?

Posted
I have the numbers in columns in excel. I could put them into anything though.

 

Are we talking one file per object or would multiple objects be labelled from the same file? And these numbers are distances along the curves at which a point (node) should be placed? Would you need to select a basepoint on the curve from which the numbers are measured?

Posted
I've only recently learned of LISP programming and the potential to help me is unbelievable. Can you point me toward good tutorials, books, whatever I need to learn to use LISP Routines more independently?

 

There are quite a few good links here - some may not work now however since the AUGI site went skewy.

 

Oh, and I couldn't forget to mention here also :P

Posted

I have columns labeled A through J, each column corresponds with a specific line. I think for now it would be easier to assign a single column to a single polyline so that I can understand the process. Yes, I would want a node placed at each distance per cell in the excel file. Yes I have a base point, origin of the line, that I would want each of these distance to be measured from.

Posted

One file per object would work just fine for me. I have several columns with distances in feet and I'd like a node placed at each specified distance. The point of origin would be the beginning of the line. I do have several different columns and several different lines to apply these changes to, but I think I'd rather do them individually, at least to start with, so that I can better understand the process and learn how to manipulate the code to get the desired effect.

Posted

Ok, things are slightly more difficult when the data is in its own column as files like to be read line by line, but it can be done of course.

 

To read the CSV, I'd start with something like this (to be fed with a filename):

 

(defun _ReadCSV ( filename / file line lst )

 (if (and (setq filename (findfile filename))
          (setq file (open filename "r")))
   (progn
     (while (setq line (read-line file))
       (setq lst (cons (LM:str->lst line ",") lst))
     )
     (setq file (close file))
   )
 )

 (reverse lst)
)


;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos ) (vl-load-com)
 ;; © Lee Mac 2010
 (if (setq pos (vl-string-search del str))
   (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del))
   (list str)
 )
)

My str->lst sub taken from here.

 

The above will return a list of lists, each representing a row in the CSV file:

 

(("Row1ColA" "Row1ColB" Row1ColC") ("Row2ColA" "Row2CB" ... ) ... )

 

We could 'transpose' this if you like to make the data more manageable:

 

(apply 'mapcar (cons 'list <list>))

 

Which would return something like:

 

(("Row1ColA" "Row2ColA" ... ) ("Row1ColB" "Row2ColB" ... ) ...)

 

Which we could work with.

Posted

Okay, I am going to give that a try as soon as I get back in the office. Thanks again for your help, I really do appreciate it. Man, things sure can be a lot easier when you're able to automate them!

Posted

This'll give you something a little more concrete to test:

 

(defun c:test ( / _ReadCSV fname data ) (vl-load-com)
 
 (defun _ReadCSV ( filename / file line lst )

   (if (and (setq filename (findfile filename))
            (setq file (open filename "r")))
     (progn
       (while (setq line (read-line file))
         (setq lst (cons (mapcar 'distof (LM:str->lst line ",")) lst))
       )
       (setq file (close file))
     )
   )

   (reverse lst)
 )

 (if (and (setq fname (getfiled "Select File to Read" "" "csv" 16))
          (setq data (_ReadCSV fname))
     )
   (print (apply 'mapcar (cons 'list data)))
 )

 (princ)
)


;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos ) (vl-load-com)
 ;; © Lee Mac 2010
 (if (setq pos (vl-string-search del str))
   (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del))
   (list str)
 )
)

The above will read your CSV file and print the data to the command line. I have converted the data strings into doubles and 'transposed' the data such that each list in the data list is a column of your CSV.

 

Don't worry about the possible 'nil' values appearing in the lists - these may be due to the columns being different lengths.

 

If you're not sure how to run the program, see here.

 

Lee

Posted

That second file that you put up worked great. I just took a list of numbers out of the main excel file and saved them as a CSV and it was able to pull them up onto the command line. Now I'm not sure how to integrate this program into the lisp routine that you gave me previously. How do I combine them to achieve the desired effect?

Posted

Try something like this:

 

(defun c:test ( / _ReadCSV Alpha++ fname data l e p col ) (vl-load-com)
 ;; Example by Lee Mac 2010 - www.lee-mac.com
 
 (defun _ReadCSV ( filename / file line lst )

   (if (and (setq filename (findfile filename))
            (setq file (open filename "r")))
     (progn
       (while (setq line (read-line file))
         (setq lst (cons (mapcar 'distof (LM:str->lst line ",")) lst))
       )
       (setq file (close file))
     )
   )

   (reverse lst)
 )

 (defun Alpha++ ( s / p c )
   (if (eq "" s) "A"
     (if (eq "Z" (setq p (substr s 1 (1- (strlen s))) c (substr s (strlen s))))
       (strcat (Alpha++ p) "A")
       (strcat p (chr (1+ (ascii c))))
     )
   )
 )

 (if (and (setq fname (getfiled "Select File to Read" "" "csv" 16))
          (setq data (_ReadCSV fname))
          (setq data (apply 'mapcar (cons 'list data)) col "A")
     )
   (while (setq l (car data))

     (if (and (setq l (vl-remove 'nil l))
              (setq e (car (entsel (strcat "\nSelect Object for Data in Column " col " <Skip> : "))))
              (LM:isCurveObject e)
         )
       (foreach d l
         (if (setq p (vlax-curve-getPointatDist e d))
           (entmake (list (cons 0 "POINT") (cons 10 p)))
         )
       )
     )
     (setq data (cdr data) col (Alpha++ col))
   )      
 )

 (princ)
)


;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos ) (vl-load-com)
 ;; © Lee Mac 2010
 (if (setq pos (vl-string-search del str))
   (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del))
   (list str)
 )
)

;;------------------=={ Is Curve Object }==-------------------;;
;;                                                            ;;
;;  Returns True if supplied ename argument is a CurveObject  ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  ent - Entity name to test                                 ;;
;;------------------------------------------------------------;;
;;  Returns:  T if ename points to a CurveObject, else nil    ;;
;;------------------------------------------------------------;;

(defun LM:isCurveObject ( ent )
 ;; © Lee Mac 2010
 (not
   (vl-catch-all-error-p
     (vl-catch-all-apply
       (function vlax-curve-getEndParam) (list ent)
     )
   )
 )
)

It will read all your data, not just a single column.

Posted

Wow, that is amazing. Okay, it seems to work fine other then it is importing the file in inches rather then decimal feet. I know I can change that in excel without too much work, but is there a way to change the programming to set units?

Posted
Wow, that is amazing. Okay, it seems to work fine other then it is importing the file in inches rather then decimal feet. I know I can change that in excel without too much work, but is there a way to change the programming to set units?

 

It currently uses the distof function to make the conversion from string to real. Provided with no 'mode' argument, this function will use the current settings of your LUNITS system variable.

 

Perhaps change this line:

 

(mapcar 'distof (LM:str->lst line ","))

 

to

 

(mapcar '(lambda ( x ) (* 12. (distof x))) (LM:str->lst line ","))

 

This will multiply the values by 12 to convert them to inches.

Posted

I'm not sure what I'm doing wrong but I can't get the file to run after making that change. I'm sure I've messed up the parenthesis or something, but I've tried several different changes, but it still doesn't run. says

 

bad argument type: numberp: nil

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...