////////////////////////////////////////////////////// // Name: Graph.cpp // // Author: Joseph Carnahan // // Project: SimEx Visualization Module // // Date: 26 February 2004 // // Notes: // // Source file for the Graph class, which tracks // // the various objects that need to be graphed as // // well as the graph background, grid, and axes. // ////////////////////////////////////////////////////// #include "Graph.h" using namespace SimEx; // Default constructor - Creates an empty graph Graph::Graph() : // Initializers _background(0.0f, 0.0f, 0.0f), _xAxis(NULL), _yAxis(NULL), _zAxis(NULL), _xGrid(NULL), _yGrid(NULL), _zGrid(NULL), _3D(false) { GlSystem::setClearColor(_background); } // Command-line constructor - Parses the command-line // arguments and loads in input files and/or standard // input as indicated. Graph::Graph(int argc, char** argv) : // Initializers _background(0.0f, 0.0f, 0.0f), _xAxis(NULL), _yAxis(NULL), _zAxis(NULL), _xGrid(NULL), _yGrid(NULL), _zGrid(NULL), _3D(false) { using std::cin; // Take different actions based on the number of arguments switch (argc) { // If no arguments, read this object in from standard input case 1: cin >> *this; if (!cin.eof() && cin.fail()) printUsage(argv[0], "Unable to read in a Graph object from standard input"); break; // If two arguments, check if the first is "-i" case 3: if (strcmp(argv[1], "-i")) printUsage(argv[0], "Invalid argument"); // If so, try to use the second one as an input file if (!loadFromFile(argv[2])) printUsage(argv[0], "Unable to read in a Graph object from the given file"); break; // Otherwise, print an error message default: printUsage(argv[0], "Invalid number of arguments"); } // end switch GlSystem::setClearColor(_background); } // end command-line constructor // Prints usage instructions and exits the program. void Graph::printUsage(const char* programName, const char* message) { using std::cerr; using std::endl; using std::exit; // Default message static const char* DEFAULT_MESSAGE = "The SimEx visualization module"; if (programName) cerr << programName << ": "; if (message) cerr << message; else cerr << DEFAULT_MESSAGE; cerr << endl << "Usage:" << endl << " " << programName << " [gtk-options] [-i inputFile ]" << endl << "Omitting the \"-i\" option will cause the system to read " << "the graph" << endl << "description file from standard input." << endl; exit(1); } // end printUsage() // Destructor Graph::~Graph() { delete _xAxis; delete _yAxis; delete _zAxis; delete _xGrid; delete _yGrid; delete _zGrid; } // Given a file name, tries to load that file as a // description of a graph object bool Graph::loadFromFile(const char* fileName) { using std::ifstream; ifstream in(fileName); if (!in.fail()) in >> *this; return (in.eof() || (!(in.fail()))); } // end loadFromFile() // Given a file name, tries to write a description of // this graph object to that file bool Graph::saveToFile(const char* fileName) const { using std::ofstream; ofstream out(fileName); if (!out.fail()) out << *this; return (!out.fail()); } // end useFile() // Given a file name, tries to load that file as a // description of a graph object bool Graph::loadGraphObjectFromFile(const char* fileName) { using std::ifstream; ifstream in(fileName); if (!in.fail()) { GraphObject temp; in >> temp; if (in.eof() || (!(in.fail()))) { _objects.push_back(temp); } // end if-input-succeeded } // end if-file-opened return (in.eof() || (!(in.fail()))); } // end loadGraphObjectFromFile() // Given a graph object, appends it to the list of // attached graph objects bool Graph::addGraphObject(const GraphObject& target) { _objects.push_back(target); return true; } // end addGraphObject() // Given a pointer to a graph object, removes the // first attached graph object that matches the given // graph object bool Graph::removeGraphObject(const GraphObject& target) { unsigned int size = _objects.size(); for (unsigned int i = 0; i < size; i++) { if (_objects[i] == target) { _objects[i] = _objects[size-1]; _objects.pop_back(); return true; } // end if-match-found } // end for-each-element return false; } // end removeGraphObject() // Inspectors: const Color& Graph::getBackgroundColor() const { return _background; } bool Graph::get3D() const { return _3D; } // Returns a pointer to the selected axis Axis* Graph::getAxis(const Axis::AxisType& direction) { switch (direction) { case Axis::X: return _xAxis; case Axis::Y: return _yAxis; case Axis::Z: return _zAxis; } // end switch return NULL; } // end getAxis() const Axis* Graph::getAxis(const Axis::AxisType& direction) const { switch (direction) { case Axis::X: return _xAxis; case Axis::Y: return _yAxis; case Axis::Z: return _zAxis; } // end switch return NULL; } // end getAxis() // Returns a pointer to the selected grid Grid* Graph::getGrid(const Axis::AxisType& direction) { switch (direction) { case Axis::X: return _xGrid; case Axis::Y: return _yGrid; case Axis::Z: return _zGrid; } // end switch return NULL; } // end getGrid() const Grid* Graph::getGrid(const Axis::AxisType& direction) const { switch (direction) { case Axis::X: return _xGrid; case Axis::Y: return _yGrid; case Axis::Z: return _zGrid; } // end switch return NULL; } // end getGrid() // Returns a pointer to the graph objects vector* Graph::getGraphObjects() { return &_objects; } const vector* Graph::getGraphObjects() const { return &_objects; } // Mutators: bool Graph::setColor(const Color& newColor) { _background = newColor; GlSystem::setClearColor(_background); return true; } // end setColor() bool Graph::set3D(bool turnOn3D) { _3D = turnOn3D; GlSystem::set3D(_3D); return true; } // end set3D() // Sets the axis pointer to point to a copy of the given axis bool Graph::setAxis(const Axis::AxisType& type, const Axis* newAxis) { if (newAxis == NULL) { switch (type) { case Axis::X: delete _xAxis; _xAxis = NULL; return true; case Axis::Y: delete _yAxis; _yAxis = NULL; return true; case Axis::Z: delete _zAxis; _zAxis = NULL; return true; } // end switch } // end if-null else { switch (type) { case Axis::X: delete _xAxis; _xAxis = new Axis(*newAxis); GlSystem::setCameraTargetX((GLfloat)(_xAxis->getLowerBound()), (GLfloat)(_xAxis->getUpperBound())); return true; case Axis::Y: delete _yAxis; _yAxis = new Axis(*newAxis); GlSystem::setCameraTargetY((GLfloat)(_yAxis->getLowerBound()), (GLfloat)(_yAxis->getUpperBound())); return true; case Axis::Z: delete _zAxis; _zAxis = new Axis(*newAxis); GlSystem::setCameraTargetZ((GLfloat)(_zAxis->getLowerBound()), (GLfloat)(_zAxis->getUpperBound())); return true; } // end switch } // end else-make-a-copy return false; } // Sets the grid pointer to point to a copy of the given grid bool Graph::setGrid(const Axis::AxisType& type, const Grid* newGrid) { if (newGrid == NULL) { switch (type) { case Axis::X: delete _xGrid; _xGrid = NULL; return true; case Axis::Y: delete _yGrid; _yGrid = NULL; return true; case Axis::Z: delete _zGrid; _zGrid = NULL; return true; } // end switch } // end if-null else { switch (type) { case Axis::X: delete _xGrid; _xGrid = new Grid(*newGrid); return true; case Axis::Y: delete _yGrid; _yGrid = new Grid(*newGrid); return true; case Axis::Z: delete _zGrid; _zGrid = new Grid(*newGrid); return true; } // end switch } // end else-make-a-copy return false; } // Copies the given set of graph objects into the // attached list of graph objects bool Graph::setGraphObjects(const vector& newObjects) { _objects = newObjects; return true; } // end setGraphObjects() // Draw/update function void Graph::draw() const { GlSystem::applyCamera(); // Only draw the axes if other axes exist that give us an idea of where // to place each axis' label: if (_xAxis && _yAxis) { _xAxis->draw(Axis::X, ((float)(_yAxis->getUpperBound()) - (float)(_yAxis->getLowerBound())) / 100.0f); _yAxis->draw(Axis::Y, ((float)(_xAxis->getUpperBound()) - (float)(_xAxis->getLowerBound())) / 100.0f); } // end if-2D-or-3D if (_3D && _zAxis) { if (_xAxis) _zAxis->draw(Axis::Z, ((float)(_xAxis->getUpperBound()) - (float)(_xAxis->getLowerBound())) / 100.0f); else if (_yAxis) _zAxis->draw(Axis::Z, ((float)(_xAxis->getUpperBound()) - (float)(_xAxis->getLowerBound())) / 100.0f); } // end if-3D // Whatever happpens, draw the non-null grids if (_xGrid) _xGrid->draw(Axis::X, _xAxis, _yAxis, _zAxis); if (_yGrid) _yGrid->draw(Axis::Y, _xAxis, _yAxis, _zAxis); if (_3D && _zGrid) _zGrid->draw(Axis::Z, _xAxis, _yAxis, _zAxis); // Draw all the objects unsigned int size = _objects.size(); for (unsigned int i = 0; i < size; i++) { _objects[i].draw(_xAxis, _yAxis, _zAxis); } // end for-each-object } // end draw() // I/O Operators ostream& SimEx::operator<< (ostream& out, const Graph& thisGraph) { using std::endl; out << "# Graph background color:" << endl << thisGraph.getBackgroundColor() << "# Number of Dimensions:" << endl; if (thisGraph.get3D()) out << "3"; else out << "2"; out << endl << "# Axes:" << endl; if (thisGraph.getAxis(Axis::X)) out << "xaxis" << endl << *(thisGraph.getAxis(Axis::X)); else out << "null" << endl; if (thisGraph.getAxis(Axis::Y)) out << "yaxis" << endl << *(thisGraph.getAxis(Axis::Y)); else out << "null" << endl; if (thisGraph.getAxis(Axis::Z)) out << "zaxis" << endl << *(thisGraph.getAxis(Axis::Z)); else out << "null" << endl; out << "# Grids:" << endl; if (thisGraph.getGrid(Axis::X)) out << "xgrid" << endl << *(thisGraph.getGrid(Axis::X)); else out << "null" << endl; if (thisGraph.getGrid(Axis::Y)) out << "ygrid" << endl << *(thisGraph.getGrid(Axis::Y)); else out << "null" << endl; if (thisGraph.getGrid(Axis::Z)) out << "zgrid" << endl << *(thisGraph.getGrid(Axis::Z)); else out << "null" << endl; unsigned int size = thisGraph.getGraphObjects()->size(); out << "# Number of graph objects:" << endl << size << endl; if (size) { out << "# Graph objects (plots and curves):" << endl; for (unsigned int i = 0; i < size; i++) { out << (*(thisGraph.getGraphObjects()))[i]; } // end for-each-object } // end if-objects-not-empty return out; } // end operator<< istream& SimEx::operator>> (istream& in, Graph& thisGraph) { Color background; unsigned int numDimensions = 0; string tempString; Axis* tempXAxis = NULL; Axis* tempYAxis = NULL; Axis* tempZAxis = NULL; Grid* tempXGrid = NULL; Grid* tempYGrid = NULL; Grid* tempZGrid = NULL; unsigned int size = 0; GraphObject tempObject; vector tempList; VisIO::skipComments(in); in >> background; VisIO::skipComments(in); in >> numDimensions; // Get X Axis VisIO::skipComments(in); in >> tempString; if (tempString == "xaxis") { VisIO::skipComments(in); tempXAxis = new Axis(); in >> *tempXAxis; } // end if-axis-given // Get Y Axis VisIO::skipComments(in); in >> tempString; if (tempString == "yaxis") { VisIO::skipComments(in); tempYAxis = new Axis(); in >> *tempYAxis; } // end if-axis-given // Get Z Axis VisIO::skipComments(in); in >> tempString; if (tempString == "zaxis") { VisIO::skipComments(in); tempZAxis = new Axis(); in >> *tempZAxis; } // end if-axis-given // Get X Grid VisIO::skipComments(in); in >> tempString; if (tempString == "xgrid") { VisIO::skipComments(in); tempXGrid = new Grid(); in >> *tempXGrid; } // end if-grid-given // Get Y Grid VisIO::skipComments(in); in >> tempString; if (tempString == "ygrid") { VisIO::skipComments(in); tempYGrid = new Grid(); in >> *tempYGrid; } // end if-grid-given // Get Z Grid VisIO::skipComments(in); in >> tempString; if (tempString == "zgrid") { VisIO::skipComments(in); tempZGrid = new Grid(); in >> *tempZGrid; } // end if-grid-given VisIO::skipComments(in); in >> size; // Read in the objects for (unsigned int i = 0; i < size; i++) { VisIO::skipComments(in); in >> tempObject; tempList.push_back(tempObject); // Check for premature failure of input: if ((i < (size-1)) && in.fail()) { return in; } } // end for-all-but-last-object if (in.eof() || (!(in.fail()))) { thisGraph.setColor(background); if (numDimensions == 3) thisGraph.set3D(true); else thisGraph.set3D(false); thisGraph.setAxis(Axis::X, tempXAxis); thisGraph.setAxis(Axis::Y, tempYAxis); thisGraph.setAxis(Axis::Z, tempZAxis); thisGraph.setGrid(Axis::X, tempXGrid); thisGraph.setGrid(Axis::Y, tempYGrid); thisGraph.setGrid(Axis::Z, tempZGrid); thisGraph.setGraphObjects(tempList); if (tempXAxis) GlSystem::setCameraTargetX((GLfloat)(tempXAxis->getLowerBound()), (GLfloat)(tempXAxis->getUpperBound())); if (tempYAxis) GlSystem::setCameraTargetY((GLfloat)(tempYAxis->getLowerBound()), (GLfloat)(tempYAxis->getUpperBound())); if (tempZAxis) GlSystem::setCameraTargetZ((GLfloat)(tempZAxis->getLowerBound()), (GLfloat)(tempZAxis->getUpperBound())); } // end if-no-error-occured return in; } // end operator>>