Reading text files

Reading text files

Anonymous
Not applicable
962 Views
13 Replies
Message 1 of 14

Reading text files

Anonymous
Not applicable
Hello there! I need some help with reading some text files with maxscript, as I don't know how to do this. This is the structure of the file I want to read:

attributes {
atrib1 float;
atrib2 float;
etc...
}

compound {
sphere {
centre 0 0 0;
radius .15
}
}


I got to this part where I don't know how to read the different atributes

on imp pressed do (
colopenname = getOpenFileName caption:"Open file" types:"file (*.tcol)|*.tcol|"
colname = openfile colopenname
if colname != undefined do
(
while not eof colname do
(
line = readLine colname --We start reading the file
if line == "TCOL1.0" do
(
format "TCOL 1.0\nStarted TCOL import\nName: %\n" colopenname to:listener
continue
)

line = readLine colname
if line == "attributes {" do
(
format "Importing atributes\n" to:listener
continue
if line == "mass" do (
massv = args as float
smass.value massv
format "Mass: %\n" massv to:listener
continue
)
continue
)

if line == "}" do
(
format "Finish\n" to:listener
continue
)
)
)
)


I can't get it to load one of the attributes (mass for example). I hope you can help me, or point me in the good direction!
0 Likes
963 Views
13 Replies
Replies (13)
Message 2 of 14

Steve_Curley
Mentor
Mentor
It would help if you provided the whole of the import file. You're testing for a "TCOL" line which isn't shown, referencing "Mass" which isn't shown and using Args which isn't defined in the provided code.

I hope it's the forum which has messed with the layout of that code because it's difficult to read as-is. Consistent indentation helps enormously in cases like this.

First off, assuming that the "TCOL" line is at the beginning of the import file, then that code cannot work.
You read a line, test for "TCOL" and if true jump to the while statement (because of the continue).
That reads the next line, the test for "TCOL" fails, the next line of code reads another line from the file, thus skipping the "Attributes" line entirely.

Assuming it ever found an "Attributes" line, it prints the attribute text then goes around the loop (continue) - there seems to be a missing closing parenthesis after that continue, which consistent indentation shows up quite clearly. Syntactically the "if line == "mass"" is contained within the "if line == "atributes"" (because of the missing ")" )and so can never execute (the continue kicks it back to the while loop). Effectively you have a "statement cannot be reached" error (though MXS doesn't report that kind of error).

There also seems to be an erroneous continue and ) after the "Mass" block - in that position you are terminating the loop - the entire code will cycle to EOF and the "if line == ")"" will never get executed (with a line from the file, only after an EOF).

This is what I think it should look like, but without the whole import file I'm just guessing at some things.

on imp pressed do
(
colopenname = getOpenFileName caption:"Open file" types:"file (*.tcol)|*.tcol|"
colname = openfile colopenname
if colname != undefined do
(
while not eof colname do
(
line = readLine colname --We start reading the file
if line == "TCOL1.0" do
(
format "TCOL 1.0\nStarted TCOL import\nName: %\n" colopenname to:listener
continue
)

-- this line should not be here
-- line = readLine colname
if line == "attributes {" do
(
format "Importing atributes\n" to:listener
continue
) -- this line is missing

if line == "mass" do
(
massv = args as float -- what is args ????
smass.value massv -- ???
format "Mass: %\n" massv to:listener
continue
)

-- continue -- i don't know what this is doing here '
-- ) -- this would terminate the while loop

if line == "}" do
(
format "Finish\n" to:listener
continue
)

) -- this ends the While loop
) -- this ends the "if colname" test
) -- this ends the function

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 3 of 14

Anonymous
Not applicable
Right, first of all, thank you for posting!

By the import file, you mean one example of the file I want to import, right? Here is one:

TCOL1.0

attributes {
mass 100;
friction 0.15;
linear_damping 0;
angular_damping 0.1;
linear_sleep_threshold 0.1;
angular_sleep_threshold 0.1;
ccd_motion_threshold 0.5;
ccd_swept_sphere_radius 0;
}

compound {
sphere {
centre 0 0 0;
radius 0.5;
}
}

This is just a simple example, there can be different primitives in the compound (box, cones, etc) and also there is a triangle mesh involved (with a number of vertex and faces, but i'm leaving that... need first to be able to import the easy thing)

I wasn't sure about how to do that (I'm nowhere near a programmer, just trying to learn and supposing things). So let me explain my idea (that I know now that is wrong, heh..)

the script would read the file, if it found the 'attributes' line then it would find attributes, for example 'mass' (there are more attributes, I just wanted to try with one) and change a spinner value with the float of the file, and continue to other lines.

Again, thank you!
0 Likes
Message 4 of 14

Steve_Curley
Mentor
Mentor
A few questions.

Which version of Max? Just in case it makes any difference to the coding (it can do, sometimes).

Are the Attributes fixed? i.e. are there always the same number of them and do they always have the same names?

Is the format of that file fixed? It would be a lot easier to code if we knew the object type before finding the attributes - especially if different objects have different (names and number of) atttributes.

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 5 of 14

Steve_Curley
Mentor
Mentor
It's getting a bit big to keep posting inline, so I attached the script instead.

It does work, though I've not done all the attributes and I've not addressed the "compound" section at all.

A few things to note.

Try to give variables names which represent their contents. Your original "colname" isn't a name - it's a FileStream value returned from openFile, so I changed it to "colStream".

Be careful choosing variable names - "line" is the constructor for an Editable Spline object, I renamed it to "inputLine".

You can't test the incoming lines like you were, unless the value, "mass" for example, is at the beginning of the line. " abc" does not equal "abc". The filterString function splits the "words" on a line into array elements making life a lot easier.

import_file.ms.zip


Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 6 of 14

Anonymous
Not applicable
3D Max 2009, and I guess 2010 in the future.

The attributes are fixed, yeah

About the format, I'm not sure if you understood how the file works, but the attributes are global for the file. This file is a collision file, that can have primitives and triangular meshes, the attributes are global for the file.

while thinking how to make the script, I didn't know how to save the attributes, normally I would use the properties of the object but as the file is usually made of more than one object, I think without going to complex you can't save the attributes, so I only want them to import and change the spinners.

Edit: thank you! I understand all you posted from this second post :) I'm going to try the script when I can. thank you, again :)

Edit2: Now that I've read your script, I understand it and got it to work :) The next problem is with the compound part, as when if it finds, for example, a sphere, inside the next brace there will be its properties (coordinates, radius..)... I'm not sure how to make that work 😕
0 Likes
Message 7 of 14

Anonymous
Not applicable
Anyone can help with the compounds? I'm stuck at how to make it read the attributes of a primitive inside a brace 😕

Also, another part that I need to read is a triangle mesh, an array of vertex and faces, here is a simple one, a plane:

trimesh {
vertexes {
-690.66 345.33 0;
690.66 345.33 0;
-690.66 -345.33 0;
690.66 -345.33 0;
}
faces {
0 1 3 0x0;
0 3 2 0x0;
}
}
0 Likes
Message 8 of 14

Steve_Curley
Mentor
Mentor
Firstly, this is a rather ambitious project if you aren't fully conversant with Maxscript in particular, and programming in general. Reading strings/values from files is a fairly basic procedure, creating (presumably) a mesh object from the vertices/faces read from the file is less basic. It is, however, covered fairly well in the Maxscript help (as are most things) - I assume that's what you want to do - create objects based on the file data?

There are problems with your current import file - the vertex numbers (for the faces) are 0 based, but Max requires them to be 1 based.
0 3 2 must be 1 4 3. This would be best corrected in whatever created the file, or it could be accounted for by the script, but one or the other needs to be done. I cheated and changed the file ;)
Also, I don't know what the "0x0"s are doing there - I ignored them.

You could deal with other object types in their own routines as I've done for the TriMesh.

Note. There may well be, probably are, better ways to do all this but you need someone with more MXS experience than I have to tell you what they are.

import_file_v2.zip


Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 9 of 14

Anonymous
Not applicable
Right, thanks. I'm aware of the ambition of this script, but I needed it for a project and I decided to try and get it to work, seems like I'm near finishing it with your help, hehe.

I found the help in the maxscript about writting and exporting data after I read your post - my bad, I should have looked better. I was aware there was help on creating objects using vertexes and faces array, but nothing about reading them.

About the vertex number problem, I solved it by just adding +1 to every vertex, I think that should do the work :)

I've finished almost everything, but there is a small problem now, with exporting the trimesh. I followed the How to example and got it to work, but the problem is that it is following a different syntax than the file I use, for example:

Should be, for the vertexes

0.254432 0.237778 0.368192;
but It exports
;

and with faces:

0 1 2 0x2;
0x2;

I don't know what to search for, or how is that called.

Another two small thing, first how could I check if a selected object is a editable poly or a mesh? and second, though this is more of a bonus, how could I do commented out lines such as /* to */ (different lines)?
0 Likes
Message 10 of 14

Steve_Curley
Mentor
Mentor
The format is a point3 value - it could be read using the readValue statement, but that will mess up the existing routines somewhat.
If you look up the mesh constructor it needs "vertices: faces:" which is why the sample code writes them out that way.

As for the comments, if they are on lines on their own like
/*
line
line
*/
Then treat it like any other entity - when you find the opening one call a function which does nothing but read lines until it finds the close of it.

For the geometry type, use the "classof" function.

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 11 of 14

Anonymous
Not applicable
Ignore the 0x2, they are the materials IDs set in hex, I'm not thinking in supporting them by now

Edit. I got how to do the vertex, but I'm not sure how to write out the face's vertex order as 0 0 0; instead of ;

Right, I got the classof function. I was using it for the objects, but I didn't know Editable_poly was a class itself.

another small thing... a If statement can have two possibilities: If Classof == editable_mesh or editable_poly ?
0 Likes
Message 12 of 14

Steve_Curley
Mentor
Mentor
Just write them out without the square brackets. They are coming out that way (in the How To code) because it is printing the vertex position as a single point3 value. To print them separately, get the point3 value then print the x, y and z portions separately.

format "%, %, %;\n" vert.x vert.y vert.z


Not quite - yes you can test 2 things in an if, but not without calling the function twice (unless you assign it to a variable).
 if (classof object == Editable_Mesh or classof object == Editable_Poly) then... 

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes
Message 13 of 14

Anonymous
Not applicable
Right, I finished the script, thanks again. I'm adding now another function where I need to access the property of a material assigned to face. I've done it with the primitives easily, but I can't find how to get the material name of a face, only its ID... trying searching the maxscript help and only found results about the ID 😕
0 Likes
Message 14 of 14

Steve_Curley
Mentor
Mentor
The Material ID (of a poly) is an index into an array which contains an index into the array of sub-materials which form a Multi SubObject Material. No, that isn't gibberish - it is "double-indexed". This is because MatID 3 doesn't have to be the third sub-material in the list (as an example).
You can see the effect of this in the image - ID3 is not the 3rd in the list, but the 6th.


Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

0 Likes