Problem bei Stringstream und Einlesung



  • Hallo,
    es geht darum, dass ich Datenblöcke habe, die so aufgebaut sind:

    usemtl HAND
    f 1 2 3
    f 2 3 4
    f 3 4 5
    usemtl KOPF
    f 3 2 1
    f 6 5 4
    f 9 8 7
    f 1 2 3
    f 2 3 4
    f 3 4 5
    

    Es kommt also ein "usemtl [Objectname]" vor und darauf folgen verschiedene Anzahlen von Indices (Faces). Der bisherige Parser (Code im unteren Abschnitt) soll nun durch das File gehen, checken ob ein "usemtl" vorkommt und ab da bis zum nächsten usemtl alle Faces einlesen. Und joa, dass war's im Prinzip schon, dass will noch nicht so ganz funktionieren. Wichtig ist halt nur, dasss wirklich bis zum nächsten "usemtl" alle Faces eingelesen werden und der komplette Datenblock in den Vector zurückgepusht werden wird. Wie dem auch sei, hier der aktuelle Code:

    #include <windows.h> 
    #include <math.h> 
    #include <stdio.h> 
    #include <stdarg.h>
    #include <iostream>
    #include <conio.h>
    #include <stdlib.h>
    #include <vector>
    #include <fstream>
    #include <string>
    #include <string.h>
    #include <sstream>
    #include <iostream>
    
    class Vector3
    {
    public:
    	Vector3();
    	~Vector3();
    
    	float x;
    	float y;
    	float z;
    };
    
    struct Face
    {
    	Face()
    	{
    		vertexIndex[0] = vertexIndex[1] = vertexIndex[2] = 0xfffffff;
    	}
    	std::string mtlName;
    	std::string vertexIndex[3];
    };
    
    std::string const getWord(std::string Line, int Pos) 
    {
    	std::vector<std::string> Vec;
    	std::stringstream ss(Line);
    	std::string Word, a;
        while(ss >> Word)
        Vec.push_back(Word);
    
    	return (Pos+1 > Vec.size() ? "" : Vec[Pos] );
    }
    
    int main(void)
    {
    	std::ifstream File;
    	std::string Line;
    	unsigned int numFaces=0;
    	std::vector<Face> FaceBlock;
    
    	File.open("3005.obj",std::ios::in);
    
    	if(File.fail()) std::cout<<"File loading failed!";
    
    	while(!File.eof())
    	{
    		getline(File, Line);
    
    		std::string const l = getWord(Line,0);
    
    		if(l=="usemtl") std::cout<<"New Material!"<<std::endl;
    		{
    			Face face;
    			face.mtlName = getWord(Line,1);
    
    			while(!File.eof())
    			{
    				getline(File, Line);
    				/*std::vector<float> x;
    				 std::vector<float> y;
    				 std::vector<float> z;*/
    				//std::vector<Vector3> FaceCoords;
    				std::string const nl = getWord(Line,0);
    
    				if(nl=="f")
    				{
    					/*FaceCoords.x = convertToFloat(getWord(Line,1));
    					  FaceCoords.y = convertToFloat(getWord(Line,2));
    					  FaceCoords.z = convertToFloat = convertToFloat(getWord(Line,3));*/
    
    					/*x = getWord(Line,1);
    				      y = getWord(Line,2);
    					  z = getWord(Line,3);*/
    
    					Face face;
    
    					face.vertexIndex[0] = getWord(Line,1); //<- x
    					face.vertexIndex[1] = getWord(Line,2); //<- y
    					face.vertexIndex[2] = getWord(Line,3); //<- z
    
    					face;
    
    					++numFaces;
    					for(int i=0; i < 3; i++)
    					{
    						std::cout<<face.vertexIndex[i];
    					}
    
    				if(nl=="usemtl") std::cout<<"New material-actual     Facenumber:"<< numFaces <<std::endl;
    				{
    					FaceBlock.push_back(face);
    					std::cout<<FaceBlock[0].mtlName;
    					break;
    				}
    				}
    			}
    
    		}
    	}
    
    	//std::cout<<"Total number of Faces:"<< numFaces;
    	getch();
    }
    

    Kann den Code leider nicht bearbeiten, also bitte erbarmen wegen den Einrückungen. Das Problem ist nun, dass er mir nur jeden zweiten Face-Index ausliesst und ein neues "newmtl" scheint er auch nicht zu finden.
    Einer ne Idee?

    ich danke im Voraus! 🙂



  • Hey Leute übertreibt nicht mit den Antworten^^.



  • Mal eine andere Frage, ist es möglich die Datei in einem anderem Format aufzubauen?Sowas wie CSV Format, ich denke das macht die Geschichte des Einlesens etwas einfacher oder lieg ich da falsch?



  • Hey,
    nein, leider nicht. Die Datei steht schon in einer Datei (OBJ). Trotzdem danke für den Hinweis.



  • Wenn man einen Block mit 'usemtl', dem Namen und den folgeden Faces als 'Faceblock' bezeichnet, dann ist in der Datei mehr als ein Faceblock abgelegt. Mindestens das sollte sich in Deinem Programm wiederfinden lassen.
    Als Strukturen sind also notwendig:

    struct Face
    {
        Face()
        {
            vertexIndex[0] = vertexIndex[1] = vertexIndex[2] = 0;
        }
        friend std::istream& operator>>( std::istream& in, Face& f )
        {
            return in >> f.vertexIndex[0] >> f.vertexIndex[1] >> f.vertexIndex[2];
        }
    
        int vertexIndex[3];
    };
    
    struct FaceBlock
    {
        FaceBlock()
            : mtlName()
            , m_faces()
        {}
        std::string mtlName;
        std::vector< Face > m_faces;
    };
    

    Face habe ich gleich mal mit einer Einlesefunktion versehen.

    Daneben wäre dann ein Container (vector) von Faceblocks notwendig, der den Inhalt aufnimmt. Alles zusammen kann dann so aussehen:

    std::vector< FaceBlock > faceBlocks; 
        std::ifstream File("3005.obj");
        FaceBlock fb;
        bool first = true;
        for( std::string wort; File >> wort; )
        {
            if( wort == "usemtl" )
            {
                if( !first )
                {
                    faceBlocks.push_back( fb );
                    fb.m_faces.clear();
                }
                first = false;
                File >> fb.mtlName;                
            }
            else if( wort == "f" )
            {
                // if( first ) // evt. prüfen, ob vorher auch ein 'usemtl' gelesen wurde
                //     File.setstate( std::ios_base::failbit );
                Face face;
                if( File >> face )
                    fb.m_faces.push_back( face );
            }
            else // ggf. weitere Token auswerten (dann zuletzt gelesenen Faceblock nicht vergessen!)
                File.setstate( std::ios_base::failbit ); // ansonsten ist das ein Fehler
        }
        if( !first && File.eof() )
            faceBlocks.push_back( fb ); // letzten Faceblock übernehmen
        else
            std::cerr << "Fehler beim Lesen " << std::endl;
    

    Die Lösung ist erstmal 'straight forward' - sie taugt nicht unbedingt dazu, ein OBJ-File in voller Schönheit einzulesen. Aber ich wollte es hier nicht gleich übertreiben.

    Gruß
    Werner


Anmelden zum Antworten