如何使用Fortran从*.obj文件中读取人脸信息
How to use Fortran to read the face information from a *.obj file
问题
现代 Fortran 如何在条目之间使用双正斜杠导航文件,如 *.obj 格式?目标是提取顶点索引(第一个条目)并忽略顶点法线索引(第二个条目)。
例子
例如,对于这个片段,
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
目标是创建一个这样的数组:
face ( 1 ) = [297, 298, 296]
face ( 2 ) = [296, 298, 295]
face ( 3 ) = [384, 385, 382]
face ( 4 ) = [384, 382, 383]
采用更丰富的格式(如
)的答案加分
f a//b//c d//e//f g//h//i j//k//l
其他帖子
[How to get Wavefront .obj file with 3 faces (traingle) points to a deleted blog. This post [How to read numeric data from a string in FORTRAN 的答案不相关。
参考资料
关于*.obj 格式的三个参考资料:
Object Files (.obj), B1. Object Files (.obj), Wavefront .obj file
正如评论中所建议的那样,我们可以使用 sed
等将 /
替换为 space。我们还可以在 Fortran 中一个一个地扫描每个字符(见下文)。然后我们将所有整数读入 vals
和 select 所需的部分作为 vals( 1:6:2 )
。通过将 1:6:2 更改为 1:12:3 等,类似的方法可用于 f a//b//c d//e//f ...
等
[test.f90]
program main
implicit none
character(100) buf
integer vals(10), ios, i
open(10, file="test.dat", status="old")
do
read(10, "(a)", iostat=ios) buf
if (ios /= 0) exit
do i = 1, len(buf)
if (buf(i:i) == "/") buf(i:i) = " " !! replace "/" by " "
enddo
read(buf(2:), *) vals( 1:6 ) !! read all items
print *, vals( 1:6:2 ) !! select items 1, 3, 5
enddo
close(10)
end
[test.dat]
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
$ gfortran test.f90 && ./a.out
297 298 296
296 298 295
384 385 382
384 382 383
只是为了好玩,下面是 Python 中的类似代码,由于 replace()
和 split()
,它更短了。如果我们有一些类似的套路,我猜上面的代码可能也会变得更短。
dat = []
for line in open("test.dat").readlines():
dat.append( line[1:] .replace("/", " ") .split() [::2] )
import numpy as np
face = np.array(dat, dtype=int)
print(face)
$ python test.py
[[297 298 296]
[296 298 295]
[384 385 382]
[384 382 383]]
问题
现代 Fortran 如何在条目之间使用双正斜杠导航文件,如 *.obj 格式?目标是提取顶点索引(第一个条目)并忽略顶点法线索引(第二个条目)。
例子
例如,对于这个片段,
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
目标是创建一个这样的数组:
face ( 1 ) = [297, 298, 296]
face ( 2 ) = [296, 298, 295]
face ( 3 ) = [384, 385, 382]
face ( 4 ) = [384, 382, 383]
采用更丰富的格式(如
)的答案加分f a//b//c d//e//f g//h//i j//k//l
其他帖子
[How to get Wavefront .obj file with 3 faces (traingle) points to a deleted blog. This post [How to read numeric data from a string in FORTRAN 的答案不相关。
参考资料
关于*.obj 格式的三个参考资料: Object Files (.obj), B1. Object Files (.obj), Wavefront .obj file
正如评论中所建议的那样,我们可以使用 sed
等将 /
替换为 space。我们还可以在 Fortran 中一个一个地扫描每个字符(见下文)。然后我们将所有整数读入 vals
和 select 所需的部分作为 vals( 1:6:2 )
。通过将 1:6:2 更改为 1:12:3 等,类似的方法可用于 f a//b//c d//e//f ...
等
[test.f90]
program main
implicit none
character(100) buf
integer vals(10), ios, i
open(10, file="test.dat", status="old")
do
read(10, "(a)", iostat=ios) buf
if (ios /= 0) exit
do i = 1, len(buf)
if (buf(i:i) == "/") buf(i:i) = " " !! replace "/" by " "
enddo
read(buf(2:), *) vals( 1:6 ) !! read all items
print *, vals( 1:6:2 ) !! select items 1, 3, 5
enddo
close(10)
end
[test.dat]
f 297//763 298//763 296//763
f 296//764 298//764 295//764
f 384//765 385//765 382//765
f 384//766 382//766 383//766
$ gfortran test.f90 && ./a.out
297 298 296
296 298 295
384 385 382
384 382 383
只是为了好玩,下面是 Python 中的类似代码,由于 replace()
和 split()
,它更短了。如果我们有一些类似的套路,我猜上面的代码可能也会变得更短。
dat = []
for line in open("test.dat").readlines():
dat.append( line[1:] .replace("/", " ") .split() [::2] )
import numpy as np
face = np.array(dat, dtype=int)
print(face)
$ python test.py
[[297 298 296]
[296 298 295]
[384 385 382]
[384 382 383]]