Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I read in two different types of data from one line (OSG obj) 2

Status
Not open for further replies.

Ricky32

Programmer
Sep 24, 2004
4
US
I'm using version 5.8.4

I am reading in .obj files which have coordinates for osg. The files look something like this:

v 1780.799897 -87.839999 279.996001
v 1804.990322 -87.839999 279.996001
v 1804.990121 -131.058317 279.996001
vn 1.000000 -0.000000 0.000000
vn 0.995644 -0.093240 0.000000
vn 0.965925 -0.258823 0.000000
f 2//3 30//3 3//4
f 32//4 3//4 30//3
f 3//4 32//4 12//5

The lines with v, are just vertices, no problem with those.
The lines that start with vn are normal vertices, again not the point here.
The lines that start with f are the faces. Here is the start of my problem.

As you can see the face lines have coords separated by "//". The number before the "//" is a reference to a vertice. The number after the "//" is a reference to a normal vertice.

So a face line has: v//vn v//vn v//vn

I am trying to run a script that will seperate this data, but no luck so far:

I would like to be able to output all the v's and then all the vn's of one line, ie:

f v1//vn1 v2//vn2 v3//vn3

The output would give me:
vertices: v1 v2 v3
normal vertices: vn1 vn2 vn3

I have used the approach of changing the Default Input Record Separator ($/) throughout a loop, but no luck with that

Here is a test file I used (match.obj):
f 1//2 2//4 3//5
f 5//4 9//6 9//10
f 85//100 22//299 330//400


Here's a basic script I started out with:

Code:
use strict;
use warnings;

$STUFF="c:/scripts/match.obj";

open STUFF or die "Cannot open $STUFF for read :$!";

$/="//";             #change default input record seperator
while (<STUFF>) {
$/="//";
$v1=<STUFF>;
$/=" ";
$vn1=<STUFF>; 
$/="//";
$v2=<STUFF>; 
$/=" ";
$vn2=<STUFF>;
$/="//";
$v3=<STUFF>;
$vn3=<STUFF>; 

print $v1, $v2, $v3;
print "\n";
print $vn1, $vn2, $vn3;
print "\n";
}

And it's giving me a "global symbol: requires explicit package" error.

I am new to Perl, so be patient. I'm sure there are much better/efficient ways to do this, which is why I came here for some direction.

When I take out the use strict/warnings, I get the following output:

2 2//3//5//
4 5
f 4 9//
10
f 85//2//330//
100 299 400

As you can see it went fubar. However the v3 and vn3 (last two lines) are giving the right values, so something is working. Except the v3 is including the "//" and "f" which I need to get rid of.

Any ideas?

Or a steer in a better direction....
 
How's this? Uses a regex with /g modifier to capture the vertices and normal vertices in arrays.
Code:
#!perl
use strict;
use warnings;

while (<DATA>) {
    chomp;
    if (/^f/) {
        if (my @v = m|(\d+)//|g) {
            print "vertices: ", join(" ", map {'v'.$_} @v), "\n";
        }
        if (my @n = m|//(\d+)|g) {
            print "normal vertices: ", join(" ", map {'vn'.$_} @n), "\n";
        }
    }
}

__DATA__
f 1//2 2//4 3//5
f 5//4 9//6 9//10
f 85//100 22//299 330//400
Output:
Code:
vertices: v1 v2 v3
normal vertices: vn2 vn4 vn5
vertices: v5 v9 v9
normal vertices: vn4 vn6 vn10
vertices: v85 v22 v330
normal vertices: vn100 vn299 vn400


 
Another possible approach:

1. Get rid of leading f and following whitespace
2. Split resulting line on whitespace
3. Split each element of resulting array on //
4. Push resulting elements into appropriate arrays.

Code:
#!perl
use strict;
use warnings;

while (<DATA>) {
    chomp;
    if (s/^f\s+//) {
        my (@v, @n);
        for (split) {
            my ($v, $n) = split(/\/\//);
            push(@v, $v);
            push(@n, $n);
        }
        print "vertices: ", join(" ", map {'v'.$_} @v), "\n";
        print "normal vertices: ", join(" ", map {'vn'.$_} @n), "\n";
    }
}

__DATA__
f 1//2 2//4 3//5
f 5//4 9//6 9//10
f 85//100 22//299 330//400

Output same as before.
 
A bit of change on scope of the problem.

I've tried with the code that is shown to do this, but it's proving to not be efficient. There has to be a better way.

I am trying to now increase each vertice and normal vertice by a fixed number (an offset) and then display it as a f line so that the osg viewer can read it and display it.

Hence, go from:
f 1//2 2//4 3//5
f 5//4 9//6 9//10
f 85//100 22//299 330//400

and with an offset = 2 (add 2 to each value)

So output would be:
f 3//4 4//6 5//7
f 7//6 11//8 11//12
f 87//102 24//301 332//402

The offset most likely will not be the same for the vertices as it will for the normal vertices.

Seems simple enough.....at least I thought.



 
How's this?
Code:
#!perl
use strict;
use warnings;

while (<DATA>) {
    chomp;
    if (/^f/) {
        s|(\d+)//|($1 + 2) . "//"|eg; #vertices
        s|//(\d+)|"//" . ($1 + 2)|eg; #normal vertices
        print "$_\n";
    }
}
     
__DATA__
f 1//2 2//4 3//5
f 5//4 9//6 9//10
f 85//100 22//299 330//400
Output:
Code:
f 3//4 4//6 5//7
f 7//6 11//8 11//12
f 87//102 24//301 332//402
I'm adding 2 to both the vertices and normal vertices since that's what you showed in your example output. You'd need to adjust this if it's going to be different.

I have no idea what osg or an osg viewer is, by the way.

HTH


 
How about something like this;

while(<DATA>) { #data is: f 2//3 4//5 6//7

@line = split; # split all on whitespace
shift(@line); # Get rid of the f

($vert1, $vert2) = map {split(/\/\//)} @line;

$hash{$vert1} = $vert2;

}

Now you have a hash of vertex => normalvertex pairs and you can do what ever you like with them.

 
How about something like this;

while(<DATA>) { #data is: f 2//3 4//5 6//7

@line = split; # split all on whitespace
shift(@line); # Get rid of the f

foreach (@line) {

($vert1,$vert2) = split(/\/\//);

$hash{$vert1} = $vert2;

}

Now you have a hash of vertex => normalvertex pairs and you can do what ever you like with them.

 
Thanks again for the help, it's very much appreciated.

And your ideas were much more efficient/simpler then what I had done.
 
You're welcome.

You could do the replacement with one expression instead of two:
s|(\d+)//(\d+)|join("//", ($1 + 2, $2 + 2))|eg;

Here $1 represents the vertices and $2 the normal vertices.
Again, bear in mind that you may need to adjust the "+ 2".
 
greadey, your hash solution will lose data due to duplicate keys. And how would you print out the pairs in the original order?

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top