Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

HELP, autolisp, newbie

7 views
Skip to first unread message

Malcolm Robert Dingle

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
Hi all

I have no experience with AutoCad nor with AutoLisp, only what I have picked
up in the last week, so perhaps my question will seem trivial.

I am trying to write a lisp program to read in the defining parameters of a
cylinder from a file and to then display it. The cylinder is to be diplayed
as a solid which is why I am not using DXF. There may be any number of
cylinders in the file and the parameters are stored in ascii.

eg
name1
10 30 40 (1st end point)
20 (radius)
30 20 50 (2nd end point)
name2
...

I have figured out how to display a cylinder using a lisp prog; thats easy.
What I can't do is figure out how to read in the info from a file. Obviously
a loop is required so if I can read in one cylinder I can read in all of
them.

I am looking at using (read-line) to read in a line from the file. However
this reads input as a string. If I then used (read) on the string the first
value in the string would be returned as a int/float (in this example it
would return 10) but I can't see how to read the other values (ie 30 and
40). Is it not possible to tell it to read the second value in the string?

I would really appreciate it if someone could write the (very short I know
:( ) loop to do this in lisp and explain to me how it is done. I suspect
that I am looking at the wrong commands. I come from a C background where I
am used to having more options for reading input from a file than I can
count :-) so being able to find only a couple of commands to read from a
file seems a little foreign to me.

Thank you for any help which is forthcoming.

Cheer

--
-----------------------------------------------------------
Malcolm Dingle
Room 513 Menzies Building
University of Cape Town
Cape Town
South Africa
650-2674
------------------------------------------------------------

HK

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
>I am trying to write a lisp program to read in the defining parameters of a
>cylinder from a file and to then display it. The cylinder is to be diplayed
>as a solid which is why I am not using DXF. There may be any number of
>cylinders in the file and the parameters are stored in ascii.
>
>eg
>name1
>10 30 40 (1st end point)
>20 (radius)
>30 20 50 (2nd end point)
>name2
>....

>
>I have figured out how to display a cylinder using a lisp prog; thats easy.
>What I can't do is figure out how to read in the info from a file. Obviously
>a loop is required so if I can read in one cylinder I can read in all of
>them.
>
>I am looking at using (read-line) to read in a line from the file. However
>this reads input as a string. If I then used (read) on the string the first
>value in the string would be returned as a int/float (in this example it
>would return 10) but I can't see how to read the other values (ie 30 and
>40). Is it not possible to tell it to read the second value in the string?
>
>I would really appreciate it if someone could write the (very short I know
>:( ) loop to do this in lisp and explain to me how it is done. I suspect
>that I am looking at the wrong commands. I come from a C background where I
>am used to having more options for reading input from a file than I can
>count :-) so being able to find only a couple of commands to read from a
>file seems a little foreign to me.

; STRTOLST takes a string and converts it to a list of numbers
(defun STRTOLST (TXT / LISTOUT CT CHRSTR)
(if TXT (progn
(setq LISTOUT (list (atof TXT)) ; gets first number
CT 1)
(while (/= (setq CHRSTR (substr TXT CT 1)) "")
(if (= CHRSTR " ")
(setq CT (1+ CT)
LISTOUT (cons (atof (substr TXT CT)) LISTOUT) )
)
(setq CT (1+ CT))
)
(reverse LISTOUT)
))
)


ex:
(defun CYLINDER_ROUTINE (/ TXT OFILE)
(setq OFILE (open YOURFILE "r"))
(while (setq TXT (read-line OFILE))
...
...
(setq PT1 (strtolst (read-line OFILE))
RADIUS (atof (read-line OFILE))
PT2 (strtolst (read-line OFILE))
)
)
)

Peter Horvath P.hD.

unread,
Apr 11, 1996, 3:00:00 AM4/11/96
to mal...@foxbat.sur.uct.ac.za
Dear Malcolm,

the sequence you need:

(while (setq lin (read-line inf)) ; it reads from the file "inf"

; opened for reading while there is something in the file. The
; string read is bound to atom lin (that can be anything else of
; course).

(setq lst (read (strcat "(" lin ")"))) ; in this line the

; string in "lin" is concataneted with an opening parenthese and
; a closing one, too, and only the extended string is given to
; function "read" that reads from opening parenthese to closing
; parenthese as it is cumpolsory for it in every LISP. Now you
; have your data in a list, you can do everything with them using
; the list handling functions. You can generate your cyclinders
; either directly here inside of this loop.

)

Greetings:

Peter Horvath
(originally from Hungary)


Vladimir Nesterovsky

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
mal...@foxbat.sur.uct.ac.za (Malcolm Robert Dingle) wrote:

>Hi all

>I am looking at using (read-line) to read in a line from the file. However
>this reads input as a string. If I then used (read) on the string the first
>value in the string would be returned as a int/float (in this example it
>would return 10) but I can't see how to read the other values (ie 30 and
>40). Is it not possible to tell it to read the second value in the string?

> I come from a C background where I


>am used to having more options for reading input from a file than I can
>count :-) so being able to find only a couple of commands to read from a
>file seems a little foreign to me.

Hello,
You do have more options for input. Consider doing fgets()
and then converting parts of string by atoi() etc { in C }.
You can do the same in LISP with
(setq line (read-line file)) and (atoi (substr line 1 5)), or
(atof (substr line 7)) etc.
Of course it's only good for file in fixed format, for free
format you need to parse the string {like strtok() in C do},
breaking it on spaces {and/or commas etc} and converting
the string into list of strings==tokens, then apply whatever
function you want on elements of this list { these strings
may represent INTs, REALs, STRs, SYMs etc} with MAPCAR or smtng.
Here is general parsing function in LISP:

;;
;; (C.) 1996 by Vladimir Nesterovsky<vne...@netvision.net.il>
;; USE THESE FUNCTIONS FOR ANY NON-PROFITABLE PURPOSE WHILE
;; KEEPING THIS NOTICE. NO WARRANTIES ARE GIVEN WHATSOEVER.
;;

;; strtol convert string of chars into list of 1-char strings
(defun strtol ( s / lst c )
(repeat (setq c (strlen s))
(Setq lst (cons (substr s c 1) lst)
c (1- c)
))
lst
)

;; helper function
(defun strp(s)(and(='STR(type s))(/= s "")))

;; STRTOK - break strng on char if it's in chs (char-string).
;; Like "C" strtok() break string to tokens delimited by one
;; OR MORE chars.
;; parse free format -- no empty tokens --
;; (strtok " 1,, 2, 3,")->{"1" "2" "3"}
(defun strtok(strng chs / len c l s cnt chsl )
(setq chsl (strtol chs))
(setq len (strlen strng) s "" cnt (1+ len))
(while (> (setq cnt (1- cnt)) 0)
(setq c (substr strng cnt 1))
(if (member c chsl)
(if (strp s)
(setq l (cons s l) s "")
)
(setq s (strcat c s))
)
)
(if (strp s)
(cons s l)
l
)
)

If you want to catch null tokens too, like
"1,,3,4" -->> { "1" "" "3" "4" }, you'll need this:

;;STRPARSE FOR PARSING STRING (and keeping null tokens)
(defun strparse(strng chs / len c l s chsl cnt );;delim==one-of-chs.
(setq chsl (strtol chs))
(setq len (strlen strng) s "" cnt (1+ len))
(while (> (setq cnt (1- cnt)) 0)
(setq c (substr strng cnt 1))
(if (member c chsl)
(if (/= cnt len);; "1,2," -> ("1" "2") and not ("1" "2" "")
(setq l (cons s l) s "")
)
(setq s (strcat c s))
)
)
(cons s l) ;; ",1,2" -> ("" "1" "2")
)

So now, armed with this string manipulation functions, you may
(setq line (read-line file)
lst (strtok line ", ")
nums (mapcar 'atoi lst))
etc.

Possible improvements: do C_STRTOK() and C_STRPARSE()
in ADS and export them to LISP from there. It must be
much much faster.

Best wishes,
==Vladimir Nesterovsky /LISP/C/C++/ADS.....
(defun str_rev(s)(apply 'strcat (reverse (strtol s))))


=Vladimir Nesterovsky LISP/C/C++ etc
==(defun strf(s field)(vpn_printf "%.*s" field s))


John Bower

unread,
Apr 13, 1996, 3:00:00 AM4/13/96
to
In <4kd9ea$2...@groa.uct.ac.za> mal...@foxbat.sur.uct.ac.za (Malcolm

Robert Dingle) writes:
>
>Hi all
>
>I have no experience with AutoCad nor with AutoLisp, only what I have
picked
>up in the last week, so perhaps my question will seem trivial.
>
>I am trying to write a lisp program to read in the defining parameters
of a
>cylinder from a file and to then display it. The cylinder is to be
diplayed
>as a solid which is why I am not using DXF. There may be any number of
>cylinders in the file and the parameters are stored in ascii.
>
>eg
>name1
>10 30 40 (1st end point)
>20 (radius)
>30 20 50 (2nd end point)
>name2
>...
>
>I have figured out how to display a cylinder using a lisp prog; thats
easy.
>What I can't do is figure out how to read in the info from a file.
Obviously
>a loop is required so if I can read in one cylinder I can read in all
of
>them.
>
>I am looking at using (read-line) to read in a line from the file.
However
>this reads input as a string. If I then used (read) on the string the
first
>value in the string would be returned as a int/float (in this example
it
>would return 10) but I can't see how to read the other values (ie 30
and
>40). Is it not possible to tell it to read the second value in the
string?
>
>I would really appreciate it if someone could write the (very short I
know
>:( ) loop to do this in lisp and explain to me how it is done. I
suspect
>that I am looking at the wrong commands. I come from a C background

where I
>am used to having more options for reading input from a file than I
can
>count :-) so being able to find only a couple of commands to read from
a
>file seems a little foreign to me.
>
>Thank you for any help which is forthcoming.
>
>Cheer
>
>--
>-----------------------------------------------------------
>Malcolm Dingle
>Room 513 Menzies Building
>University of Cape Town
>Cape Town
>South Africa
>650-2674
>------------------------------------------------------------

Well, reading your note, I assume you know:
1 how to open a file
2 read each line of text
3 create a autocad command based on that info
4 you have several cylinder definitions in one file

so roughly, I'd try this:

>name1 <----------- don't know if you use name in Acad dwg
>10 30 40 (1st end point) <--------- change to 10,30,40 just as you
>20 (radius) would type it at the command prompt


>30 20 50 (2nd end point)
>name2

>10 10 10
>15
>20,20,20
>end of file <-----signals end of file in loop below

(setq fpr (open "asciifil.txt" "r")
(setq name (read-line fpr))
(while a
(setq
pt1 (read-line fpr)
radius (atof (read-line fpr)); (atof: "ascii to float")
pt2 (read-line fpr)
name (read-line fpr)
);setq
(command "solcyl" pt1 radius pt2) ; (don't know this command's syntax)
(if (= name "end of file") setq a nil)
); while

This is perhaps a "dorky" program but I think it will work, it's been
about 2 years since I've done much Lisp so I'm rusty. I think that for
the pt1 and pt2 parts of the solcyl command (not sure if this is the
exact command name) can be strings, since it has commas in them, just
reformat the input file for ease, those spaces between the numbers will
zap you otherwise. In any event, here are the commands you need:

atof (converts string var to real number (float))
atoi (converts sting var to interger)
itoa (converts interget to string (ascii))
syntax: (atof sting), (atoi sting), (itoa interger)

Let me know if this works (email me if you need more help)

John


ca...@autodesk.com

unread,
Apr 17, 1996, 3:00:00 AM4/17/96
to

> There may be any number of
> cylinders in the file and the parameters are stored in ascii.
>
> eg
> name1
> 10 30 40 (1st end point)
> 20 (radius)
> 30 20 50 (2nd end point)
> name2
> ....
>

G'Day Malcolm -- I was in your beautiful city a year ago and I had a
wonderful dream that I was the only man in all of Cape Town, and women
would wave at me on the street and call my name. It was so funny that I
woke up myself by laughing too loud.

But about this AutoLISP problem ...

As Peter says, you can easily create a list by STRCAT'ing parenthesis on
the front and back of the string you get from READ-LINE. That assumes
that you will either add paren's to some lines and not to others, or add
them to all lines and cope with the results. Or you could simply put
parenthesis on the point lists in the source file, and then apply READ to
all lines.

You could also build a single list in the souce file, as in

("name1" (10 30 50) 20 (30 20 50))

which would require only one read-line -- which is much faster than
several file reads. Then pull out parts of the list for individual
operations using CAR, CADR, etc.

The format of the source really depends on how you're creating the
objects. If you're using COMMAND, as in (command "_circle" ...), then the
parameters could be comma delimited, as in "10,30,40". In this case, the
READ-LINE of the point data would be acceptable as input for something
like (command "_circle" (read-line fn) (read-line fn)).

You might also look at ENTMAKE as an alternative. You could build an
association list in the source file, something like

((0 . "CIRCLE") (10 10 30 40) (50 . 20))

and then just (entmake (read (read-line fn))). Cheers -- Carl


ca...@autodesk.com

unread,
Apr 20, 1996, 3:00:00 AM4/20/96
to

Vladimir -- I don't know if this will interest you, but here's a string
parsing routine that I hacked out a few years ago. It looks long an
convoluded, and would seem to be very slow, but I found that it is
usually faster than most parsing routines that I have seen. By
eliminating the WHILE function and instead using REPEAT, I believe that
fewer conditional tests reduces the overhead required to dismantle the
string. I thought you might be interested in reviewing it, at least, or
maybe find a better solution. Cheers. --Carl


;;;--- delimit --------------------------------------------
;;; break a <line> of text into a list of words
;;; using <by> as the delimiter
;;;
;;; <bits> codes:
;;; bit 1 == on none found, return whole string (0 returns NIL), SDF
;;; bit 2 == CDF, allow null strings between delimiters
;;; bit 4 == only words found between matching delimiter pairs
;;;

(defun delimit (line by bits / ifbit i j index words)

(defun ifbit (x y)
(= x (logand x y))
)

(cond

;; check for existence of at least one <by> character
((not (wcmatch line (strcat "*" by "*")))
(if (ifbit 1 bits)
(setq index (list (cons 1 (strlen line))))
)
)

;; find only words between
;; matching pairs of delimiters
((ifbit 4 bits)
(setq i 0)
(repeat (1+ (strlen line))
(setq i (1+ i))
(if (= by (substr line i 1))
(if j
(setq index
(cons
(cons j (- i j))
index
)
j nil
)
(setq j (1+ i))
)
)
)

(if (and
(not index)
(ifbit 1 bits)
)
(setq index (list (cons 1 (strlen line))))
)

);

;; allow nulls between delimiters
;; use for comma delimited files
((ifbit 2 bits)
(setq i 1 j 0)
(repeat (1+ (strlen line))
(setq j (1+ j))
(if (= by (substr line j 1))
(setq index
(cons
(cons i (- j i))
index
)
i (1+ j)
)
)
);repeat

(if (and (/= i j)); return rest of the line
(setq index (cons (cons i (- j i)) index))
)

(if (and
(= 1 (length index))
(not (ifbit 1 bits))
)
(setq index nil)
)

);not pairs only


;; no nulls, strip extra delimiters
;; use this option for space-delimited files
((not (ifbit 2 bits))
(setq i 1 j 0)
(repeat (1+ (strlen line))
(setq j (1+ j))
(if (= by (substr line j 1))
(if (= j i)
(setq i (1+ j))
(setq index
(cons
(cons i (- j i))
index
)
i (1+ j)
)
)
)
);repeat

(if (and (/= i j)); return rest of the line
(setq index (cons (cons i (- j i)) index))
)

(if (and
(= 1 (length index))
(not (ifbit 1 bits))
)
(setq index nil)
)

);not pairs only


;; last cond is error message
(T (princ "Error: invalid bit code in delimit"))
)

(foreach x index
(setq words
(cons
(substr line (car x) (cdr x))
words
)
)
)
)
;;; --- end ----------------------------------------------

0 new messages