Daniel Corona Daniel Corona - 2 months ago 5
Python Question

Reading .obj file and split lines

I made a simple code to read a .obj file that looks like this

g cube

v 0.0 0.0 0.0
v 0.0 0.0 1.0
v 0.0 1.0 0.0
v 0.0 1.0 1.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 1.0 1.0 0.0
v 1.0 1.0 1.0

f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1


And the python code looks like this

class objeto():
def __init__(self, obj = None):
if obj:
self.cargar_obj(obj)

def cargar_obj(self, archivo):
with open(archivo, 'r') as obj:
datos = obj.read()

lineas = datos.splitlines()
self.vertices = []
self.superficies = []

for linea in lineas:
elem = linea.split()
if elem:
if elem[0] == 'v':
v = vertice(float(elem[1]), float(elem[2]), float(elem[3]))
self.vertices.append(v)
elif elem[0] == 'f':
vs = []
for i in range(1, len(elem)):
vs.append(self.vertices[int(elem[i].split('/'))])

f = cara(vs)
self.superficies.append(f)
else:
pass


The problem appears to be this line:

vs.append(self.vertices[int(elem[i].split('/'))])


because when I try to run the code, the followed TypeError appears

int() argument must be a string, a bytes-like object or a number, not 'list'


I'm a newbie in Python, so I don't seem to get around this error, can somebody give me some advice? Thanks.

I'm using Python 3.x, and ipython to run .py files

Answer

Recreate your case with one line:

In [435]: line='f  1//2  7//2  5//2'
In [436]: elem = line.split()
In [437]: elem
Out[437]: ['f', '1//2', '7//2', '5//2']
In [438]: elem[0]
Out[438]: 'f'

split on / behaves as I expect:

In [439]: for i in range(1,len(elem)):
     ...:    print(elem[i].split('/'))
     ...:    
['1', '', '2']
['7', '', '2']
['5', '', '2']

Your code has problems applying int to that list of strings:

In [440]: for i in range(1,len(elem)):
     ...:    print(int(elem[i].split('/')))
     ...
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'

So we need to apply int() to the individual strings, not the list. But now the empty string is giving me problems.

In [441]: for i in range(1,len(elem)):
     ...:    print([int(e) for e in elem[i].split('/')])
     ...:        
ValueError: invalid literal for int() with base 10: ''

The rest is left as an exercise for the reader.

Couldn't resist:

[int(e) for e in elem[i].replace('//','/').split('/')]
[int(e) for e in elem[i].split('/') if e]