Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Rounding Text to Less Decimal Places

10 REPLIES 10
Reply
Message 1 of 11
richdclemons
5791 Views, 10 Replies

Rounding Text to Less Decimal Places

I'm looking for a routine that will round a group of text from 6 decimals to 1 decimal place. Would anyone know where I can find one?

Thanks,
Richard C
10 REPLIES 10
Message 2 of 11
Anonymous
in reply to: richdclemons

Richard,

rtos is a rounding function.

(setq n (atof "3.275126"))

Command: (rtos n 2 1)
"3.3"
Command: (rtos n 2 2)
"3.28"
Command: (rtos n 2 3)
"3.275"
Command: (rtos n 2 4)
"3.2751"
Command: (rtos n 2 5)
"3.27513"

Joe Burke
Message 3 of 11
richdclemons
in reply to: richdclemons

I've used Diesel functions before, but I'm confused to how would I apply this rtos to the hundreds of numeric text that already exist in the drawing?
Message 4 of 11
ynotrobits
in reply to: richdclemons

I tried this out and it seems to work OK:

(defun C:TXT_DEC ( / ID_TEXT CNTR EN ENLIST OLD_TXT NEW_TXT )

(setq ID_TEXT(ssget "X" (list (cons 0 "TEXT")))) ;Identify all the text in the drawing

(If (BOUNDP 'ID_TEXT)(PROGN ;Was any text located?

(setq CNTR 1) ;Start the counter

(while (< CNTR (sslength ID_TEXT)) ;cycle through all the text entities

(setq EN(ssname ID_TEXT CNTR)) ;obtain the entity name

(setq ENLIST(entget EN)) ;Extract the dxf codes from the entity name

(setq OLD_TXT (CDR(assoc 1 ENLIST))) ; Extract the text string from the dxf codes

(IF (NUMBERP(ATOF OLD_TXT))(PROGN ; Check to see if the text string is a number

(setq NEW_TXT (RTOS(ATOF OLD_TXT)2 1)) ; Change the decimal precision

(setq ENLIST(subst(cons 1 NEW_TXT)(assoc 1 ENLIST)ENLIST))(entmod ENLIST) ;Substitute the revised text

)) ; End the text string = number test

(setq CNTR(+ CNTR 1)) ; Toggle the counter up

) ; End the while

)) ; End the selection set = TRUE test


(Princ)

) ; End the function


This is my first post where I've actually tried to help someone with code (I'm still a beginner) so let me know how it works out


---AJ

Edited by: ynotrobits on Jun 23, 2009 3:52 AM Edited by: ynotrobits on Jun 23, 2009 5:47 AM
Message 5 of 11
richdclemons
in reply to: richdclemons

AJ,



The code worked perfectly and fast. Good job for being a beginner. I haven't had time to read up and learn how to do code myself, but someday I will. Thank you for helping me out!



Richard
Message 6 of 11
ynotrobits
in reply to: richdclemons

That's great!

What I've recently learned in Lisp (with invaluable advice from other users) is to try and use entmod as much as possible. Before when I would try to do these types of things I would erase the original text and then use (Command "text" etc.) to print the new text.

By using subst and entmod, you can directly modify the database which runs so much quicker and cleaner.

If you'd like to have a confirmation message print at the end of the routine, you can exchange the last two lines:


(prin1)
)



...for these four lines:





(princ "\n ")
(princ "\n**Decimal text adjustment completed. ")

(prin1)
)

Good Luck,

A,J.
Message 7 of 11
Kent1Cooper
in reply to: richdclemons

Not bad! But I did notice one thing worth correcting:

The first item in a (ssget) selection set is item 0, not item 1, so you should set the CNTR variable to 0 at first. With that starting at 1, it won't process the first item in the selection set.

And a couple of quick streamlining suggestions [which I wouldn't have bothered to write about if not for wanting to point out the above -- they won't make it work better, but will shorten it slightly]:

When a list doesn't contain any variables or functions that need to be evaluated, but only fixed, known values [such as when you're sorting for a particular entity type], you can use the apostrophe prefix [don't-evaluate-this-but-just-take-it-as-it-is -- see the (quote) function], and put the list in there exactly as it would be in the entity data, instead of spelling out (list) and using (cons) to put it together. You can replace

(ssget "X" (list (cons 0 "TEXT")))

with just

(ssget "X" '((0 . "TEXT")))

Also, using (boundp) is kind of overkill to check whether ID_TEXT contains anything. You can just check whether it's not nil, by replacing

(If (BOUNDP 'ID_TEXT) (PROGN ....

with simply

(if ID_TEXT (PROGN ....

And it's a very small thing, but there's a function specifically for incrementing things up by one, which spares the need for one argument, and saves one whole code character! You can replace

(setq CNTR (+ CNTR 1))

with

(setq CNTR (1+ CNTR))

Keep up the good work.

--
Kent Cooper
Kent Cooper, AIA
Message 8 of 11
ynotrobits
in reply to: richdclemons

Kent,

Thanks for the corrections which are always appreciated. I forgot about about about "0" being the start point on a selection set. Using the quote makes sense as well. Thanks too for the info on Boundp,

You'll get a kick out of this:

Before I knew that you could test whether a variable was nil or not, I used to use "Command" to actually create a comparable entity ahead of any selection set I built so that I knew that the selection set would always find something. Sometimes these command lines and the subsequent "Ifs" could get fairly convoluted depending upon the complexity of the selection set.

Thus when I discovered Boundp, it solved so many problems for me that I became intensely loyal to it; I'm always happy typing Boundp because it reminds me of progress.

However, my goal is to become as efficient as possible so I'll set aside my trusty Boundp and test for nil succinctly as you described.

Thanks again

AJ Edited by: ynotrobits on Jun 23, 2009 7:51 PM
Message 9 of 11
Anonymous
in reply to: richdclemons

ynotrobits,

I'm glad to see this was a learning experience for you and Richard has what he needs.
We need more new people like you around here.

One thought in addition to what Kent said. ssget "x" should be used when there's no
question that's what the routine wants to do. I know that's what Richard asked for...
But it's not unlikely he will run into some situation where he would rather select
some objects. At that point the routine is useless.

Joe Burke
Message 10 of 11
ArchD
in reply to: richdclemons

I have a block with three attributes, point number, elevation, description, elevation with 10 decimal places. Could this code be made so that it reads the attributes, and finds any number longer than the hundredths, or tenths, then round them? I tried using the code posted by ynotrobits and it works, but I first have to burst all the attributes, then when I run it, it changes text, like the description to 0.0 and point numbers to 331 to 331.0.

An alternative would be to allow you to pick which items you want to round. That way I could burst the attributed block, then choose all the elevations with a decimal place to infinity and beyond, and have only those rounded off.

Any help would be much appreciated.
Archie Dodge
Applications Expert - Infrastructure Solutions Division
IMAGINiT Technologies
Message 11 of 11
Kent1Cooper
in reply to: richdclemons

You can have it round the value of only attributes with a certain tag, if that's always the same. Here's a routine that finds the attribute with a particular tag in selected blocks [though it does something different with it, but you should be able to adjust it]:

http://discussion.autodesk.com/forums/thread.jspa?messageID=6275258?

If the tag name of the attribute you want to round is *not* always the same, you could step through the attributes and check whether their content is numerical with decimal places, and only round it if it is.

If the content of an attribute is in a variable called 'value', then:

If it starts with any *non-numerical* character, which presumably the description would,

(atoi value)

will return 0. So

(zerop (atoi value))

will return T for non-numerical text [description] -- don't round that.

For *numerical* text, one thing you could do is to check whether the length of the string is the same after you've converted it to an integer and back to text:

(= (strlen value) (strlen (itoa (atoi value))))

will return T if the value represents an integer [point number], and nil if it has decimal places [elevation] -- round it only in the latter case.

Or, to combine:

{code}
(if
(and
(/= (atoi value) 0)
(/= (strlen value) (strlen (itoa (atoi value))))
); end and
(....apply rounding routine to value....)
); end if
{code}

though if an elevation might ever be 0.0000000000 exactly, that wouldn't round it, so you'd need to refine the check.

--
Kent Cooper


ArchD wrote...
I have a block with three attributes, point number, elevation, description, elevation with 10 decimal places. Could this code be made so that it reads the attributes, and finds any number longer than the hundredths, or tenths, then round them?.... Edited by: Kent1Cooper on May 24, 2010 3:14 PM
[simplified integer check code line slightly; added combined check]
Kent Cooper, AIA

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost