text output from Celestia

All about writing scripts for Celestia in Lua and the .cel system
Topic author
Malenfant
Posts: 1412
Joined: 24.08.2005
With us: 19 years 3 months

text output from Celestia

Post #1by Malenfant » 14.11.2005, 09:21

So apparently you can get Celestia to output to a text file using the I/O functions in Lua?

I was trying to figure out how to do it from the Lua manual but just couldn't get anything to work - all I was trying to do was a simple 'hello world' to a text file. And yes, I had set the ScriptSystemAccessPolicy in the celestia.cfg file to "allow".

Code: Select all

file.open("test.txt",w)
text = "Hello, Universe!"
file.write(text)
file.close()


I can't figure out why that doesn't work (as usual, the Lua 5.0 manual is pretty damn useless for explaining things and giving examples...). Anyone know how to do this?
My Celestia page: Spica system, planetary magnitudes script, updated demo.cel, Quad system

maxim
Posts: 1036
Joined: 13.11.2003
With us: 21 years
Location: N?rnberg, Germany

Post #2by maxim » 14.11.2005, 14:35

This piece of code should work:

Code: Select all

text = "Hello, Universe!"

celestia:requestsystemaccess()
wait(1.0)

celestia:print ("Opening file...", 1, -1, -1, 1, 4)
wait(1.0)
myfile = io.open("test.txt","w")
celestia:print ("Outputting data...", 1, -1, -1, 1, 4)
wait(1.0)
myfile:write(text)
myfile:close()
celestia:print ("Done!", 3, -1, -1, 1, 4)
wait(3.0)


First note, that you have to call 'requestsystemaccess()' before using any system library functions. Second, there is no library 'file' the only IO library is 'io', so you have to call 'io.open' first - and you have to remember the file handle you'll get back. And also note that the mode has to be written in quotation marks.

Now you can write to the file - either by using the library call 'io.write()' or the synonym 'myfile:write()' ('myfile' is the name of the filehandle in this case). Note that the separator character here is ':' not '.'

maxim
Get my stuff from celestia.ziegelstein.net

maxim
Posts: 1036
Joined: 13.11.2003
With us: 21 years
Location: N?rnberg, Germany

Post #3by maxim » 14.11.2005, 14:42

BTW,

some time ago I made some configuration files for syntax highlighting available. If you use Ultraedit or JEdit, they may make your CELX code better readable.
You can find them here: http://216.231.48.101/forum/viewtopic.php?t=7535

maxim
Get my stuff from celestia.ziegelstein.net

Topic author
Malenfant
Posts: 1412
Joined: 24.08.2005
With us: 19 years 3 months

Post #4by Malenfant » 14.11.2005, 17:00

[quote="maxim"]This piece of code should work:

Code: Select all

text = "Hello, Universe!"

celestia:requestsystemaccess()
wait(1.0)

celestia:print ("Opening file...", 1, -1, -1, 1, 4)
wait(1.0)
myfile = io.open("test.txt","w")
celestia:print ("Outputting data...", 1, -1, -1, 1, 4)
wait(1.0)
myfile:write(text)
myfile:close()
celestia:print ("Done!", 3, -1, -1, 1, 4)
wait(3.0)


Thanks! That worked, at least for printing "Hello, Universe!". But what are all the numbers for? They don't show up in the text file. And is there any way of controlling where the text file is saved to? It seems to end up in the default Celestia directory.

And I really don't get why some commands require ':' and others require '.' as separators - it seems very inconsistent.
My Celestia page: Spica system, planetary magnitudes script, updated demo.cel, Quad system

maxim
Posts: 1036
Joined: 13.11.2003
With us: 21 years
Location: N?rnberg, Germany

Post #5by maxim » 14.11.2005, 20:10

You can ommit the 'wait()' and the 'celestia:print()' commands. They are for convenience only. The numbers are for positioning the text on the screen and the duration. Altering the target directory should be possible using the usual path declarators - 'extras/myfile.txt' for example, or '../myfile.txt'.

maxim
Get my stuff from celestia.ziegelstein.net

cpotting
Posts: 164
Joined: 18.03.2004
Age: 63
With us: 20 years 8 months
Location: Victoria, BC Canada

Post #6by cpotting » 14.11.2005, 20:29

Malenfant wrote:Thanks! That worked, at least for printing "Hello, Universe!". But what are all the numbers for? They don't show up in the text file.
Assuming that you mean the numbers in commands

Code: Select all

celestia:print ("Opening file...", 1, -1, -1, 1, 4)

Code: Select all

celestia:print ("Outputting data...", 1, -1, -1, 1, 4)

and

Code: Select all

celestia:print ("Done!", 3, -1, -1, 1, 4)

These have nothing to do with the printing to the file. Maxim included these so the script would display what it is doing and as a sort of "in-code" documentation.

Note that all three of these are celestia:print() commands. These are like the celestia:flash() commands - they present the text on the screen. The first number is the number of seconds to leave the text on the screen (just like in flash()). The next two numbers indicate where on the screen the text should be placed: the first -1 indicates to the left of screen, the second indicates at the bottom, hence -1, -1 means at the bottom left of the screen. The next two are "fine-tuning" and indicate how many characters and lines to offset the print position by. Using these four values allows you (with some twiddling and hair-pulling) to place the text anywhere you want on the screen.

And is there any way of controlling where the text file is saved to? It seems to end up in the default Celestia directory.
You would have to include the path in the filename used with io.open(). e.g.

Code: Select all

io.open("C:/mydirectory/myfile.txt", "w")


And I really don't get why some commands require ':' and others require '.' as separators - it seems very inconsistent.
a) The simple answer:
'Cause that's the way it is!

b) The more detailed answer:
At first, there may seem to be an inconsistency, but it relates to object oriented programming techniques as opposed to traditional methods of accessing "structures" and "libraries". What seems inconsistent at first will become second-nature soon enough, and even make sense at some point.

Let's begin with the ".". You will find this is used mainly in two places: when accessing "libraries" and when extracting information from "tables". The use of a period to do this is a left-over (or "legacy") from the days of C and other similar languages. C has "libraries" and something close to a "table" called a "structure" and both of these used the period to get at stuff "inside" them.

But, what is a "library"? It is a group of related programming routines that have been bundled together and put in a single place where you can get at them. There is an io library that contains routines to open files, write to files, read from files, etc. Likewise, there is a math library that contains routines to do absolute values, sine functions, square roots and other things; and you call them by
a) opening the math library (which you don't have to do in CELX - the math library is already opened for you. But you do have to open the io library yourself by calling celestia:requestsystemaccess())
b) calling the function you want such as math.abs(), math.sin() or math.sqrt().
But why always put the "math" in front? Simple - to distinguish it from any other routines that may be in other libraries. There is no abs() in the io library, but if there were then calling abs() would be confusing - which to you want? So you would call io.abs() as opposed to math.abs().

Okay, so what is a table? I don't know if you are familiar with arrays or not.
If you are, a table is a single-dimension array where each element of the array can contain any variable type.
If you don't know what an array is, think of it tables this way: you know that a variable can hold value. Well a table can hold several variables. Each variable has it's own name in the table. So instead of

Code: Select all

me_x = 1
me_y = 7
me_z = -2
him_x = 18
him_y = 2
him_z = 1

we could group the data into two tables:

Code: Select all

me =  { x = 1, y = 7, z = -2 }
him = { x = 18, y = 2, z = 1 }

now to get at the y value of him we would use him.y
If does not seem to make much sense right now, don't worry. As you continue to create more scripts you will find situations where it will make a lot of sense to group the variables together in tables.

At any rate, the important thing is that "." is used to specify the routine in a library (library.routine) or the element in a table (table.element).

Now, on to the ":". This is a little trickier unless you are familiar with OOP (Object Oriented Programming). Without delving too deep into this dark and mysterious world, in OOP an object is a representation of a "thing" - a "noun". The Celestia code is made up almost entirely of objects that call each other and pass information back and forth in order to make all those lovely little lights and coloured balls appear on the screen :wink:. CELX has the ability to get at a few of different types of objects in Celestia. In particular CELX can see
    celestia - an object that represents the entire simulation being run.
    observer - an object that represents a single "view" within the simulation
    object - an object that represents a celestial body (e.g. Jupiter or Earth)
    position - an object that represents the position of something
... and few others that we don't need to get into here.

Now, as you can imagine, an object has a lot of information within it that we might like to get at. For instance, an observer object knows where in space that view is looking from, what direction it is facing, what it's current field of view is. An object can also do things. An observer object can go to a new position in space, it can change its field of view, it can look in a new direction. But how do we get at that information? How do we get an object to do something?

Well, you get at the information by calling a routine associated with the object, and likewise, you get the object to do things by calling a routine associated with the object. The format for doing this is object:routine(). So to get the position of the active observer

Code: Select all

-- call the celestia object's getobserver() routine
active_observer = celestia:getobserver()
-- returns an observer object which we will store in active_observer

-- call the observer object's getposition routine
observer_position = active_observer:getposition()
-- returns a position object which we will store in observer_position


Okay, so why ":" and not ".". Well, because that is the convention for calling routines associated with objects. If you ever plunge deeper into to world of OOP then you will see that there are practical reasons for this difference, but it would be nearly impossible to itemize them without this becoming a 2Mb post.


I hope that wasn't too overblown an answer. I thought you might like a little background and understanding. Afterall, the more you understand about how Lua and Celx do what they do, the better you can make them do what you want.
Clive Pottinger
Victoria, BC Canada

Topic author
Malenfant
Posts: 1412
Joined: 24.08.2005
With us: 19 years 3 months

Post #7by Malenfant » 14.11.2005, 20:38

OK, thanks, that was somewhat useful :). I hadn't delved into positioning of text yet, which is why I didn't know what the numbers were.

I am vaguely familiar with OOP, but I was familiar with the '.' separator (isn't that what Java uses all the time?) But now you've explained the difference that makes more sense to me.
My Celestia page: Spica system, planetary magnitudes script, updated demo.cel, Quad system


Return to “Scripting”