// tile.cpp -- a flightgear scenery tile // // Written by Frederic Bouvier, started February 2002. // // Copyright (C) 2002 Frederic Bouvier - fredb@users.sourceforge.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // $Id: tile.cpp,v 1.33 2005/05/14 10:03:20 fredb2 Exp $ #include #ifdef _MSC_VER #pragma warning( disable : 4786 4503 ) #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "tile.hpp" #include "objectstatic.hpp" #include "sdutil.hpp" #ifdef FAR #undef FAR #endif #include FGSD_Tile::FGSD_Tile( const SGBucket& b ) : _bucket( b ) , _modified( false ) , _object( 0 ) { } FGSD_Tile::~FGSD_Tile() { for ( ObjectList::iterator i = _objectList.begin(); i != _objectList.end(); i++ ) { FGSD_BaseObject *obj = *i; delete obj; } delete _object; } bool FGSD_Tile::load( const char *root, const char *base ) { bool ret = false, found_base = false; std::list pathList; FGSD_Util::splitPath( base, pathList, ';' ); std::string index_str = _bucket.gen_index_str(); for ( std::list::const_iterator it = pathList.begin(); it != pathList.end(); ++it ) { std::string current = *it; size_t l = current.size(), p = current.rfind( '/' ); if ( p == l-1 ) { current.erase( p ); l = p; } std::string path[2]; path[0] = current + "/Terrain"; path[1] = current + "/Objects"; if ( !FGSD_Util::isDir( path[0].c_str() ) ) { path[0] = current; path[1] = ""; } else if ( !FGSD_Util::isDir( path[1].c_str() ) ) { path[1] = ""; } for ( size_t i = 0; i < 2; i++ ) { if ( !path[i].empty() ) { bool has_base = false; SGPath _path = path[i]; _path.append( _bucket.gen_base_path() ); SGPath basename = _path; basename.append( index_str ); SGPath stg_name = basename; stg_name.concat( ".stg" ); sg_gzifstream in( stg_name.str() ); if ( in.is_open() ) { std::string token, name; while ( ! in.eof() ) { in >> token; if ( token == "OBJECT_BASE" ) { ret = true; in >> name >> ::skipws; if ( !found_base ) { found_base =true; has_base = true; SGPath custom_path = _path; custom_path.append( name ); _object = new FGSD_TriangleObject( this ); bool res = _object->load( custom_path.str().c_str(), true ); if ( !res ) { delete _object; _object = 0; } } } else if ( token == "OBJECT" ) { ret = true; in >> name >> ::skipws; if ( !found_base || has_base ) { SGPath custom_path = _path; custom_path.append( name ); if ( _object ) { _object->load( custom_path.str().c_str(), false ); } } } else if ( token == "OBJECT_STATIC" ) { ret = true; // load object info double lon, lat, elev, hdg; in >> name >> lon >> lat >> elev >> hdg >> ::skipws; std::string mat, id; double ground_elev = 0.0; if ( _object ) _object->propertiesUnderMouse( lon, lat, ground_elev, mat, id ); FGSD_ObjectStatic *obj = new FGSD_ObjectStatic( this, name, lon, lat, elev, hdg, false, ground_elev ); _objectList.push_back( obj ); } else if ( token == "OBJECT_SHARED" ) { ret = true; // load object info double lon, lat, elev, hdg; in >> name >> lon >> lat >> elev >> hdg >> ::skipws; std::string mat, id; double ground_elev = 0.0; if ( _object ) _object->propertiesUnderMouse( lon, lat, ground_elev, mat, id ); FGSD_ObjectStatic *obj = new FGSD_ObjectStatic( this, name, lon, lat, elev, hdg, true, ground_elev ); _objectList.push_back( obj ); } /* else if ( token == "OBJECT_TAXI_SIGN" ) { ret = true; } else if ( token == "OBJECT_RUNWAY_SIGN" ) { ret = true; } else if ( token == "RWY_LIGHTS" ) { ret = true; } */ else { // unknown or unsupported token in >> ::skipws; } } } } } } return ret; } void FGSD_Tile::drawGL( FGSD_BaseObject::ObjectType type, double alpha, bool fill, FGSD_BaseObject::DrawType drawType, double minx, double maxx, double miny, double maxy, double zLevel ) { if ( type == FGSD_BaseObject::TriangleObject && _object && _object->visible( minx, maxx, miny, maxy ) ) _object->draw( alpha, fill, drawType, minx, maxx, miny, maxy, zLevel ); else if ( type == FGSD_BaseObject::ObjectStatic ) { for ( ObjectList::iterator i = _objectList.begin(); i != _objectList.end(); ++i ) { FGSD_BaseObject *object = *i; if ( ( type == FGSD_BaseObject::NoType || object->type() == type ) && object->visible( minx, maxx, miny, maxy ) ) object->draw( alpha, fill, drawType, minx, maxx, miny, maxy, zLevel ); } } } bool FGSD_Tile::propertiesUnderMouse( double lon, double lat, double &height, std::string &material, std::string &airportID ) const { bool ret = false; if ( _object && _object->visible( lon, lat ) ) ret = _object->propertiesUnderMouse( lon, lat, height, material, airportID ); return ret; } FGSD_BaseObject *FGSD_Tile::objectUnderMouse( double lon, double lat, double zLevel ) { FGSD_BaseObject *ret = 0; FGSD_BaseObject::ObjectType lastType = FGSD_BaseObject::NoType; for ( ObjectList::const_iterator i = _objectList.begin(); i != _objectList.end(); ++i ) { FGSD_BaseObject *object = *i; bool over = object->objectUnderMouse( lon, lat, zLevel ); if ( over ) { FGSD_BaseObject::ObjectType type = object->type(); if ( type > lastType ) { ret = object; lastType = type; } } } if ( _object && lastType == FGSD_BaseObject::NoType && _object->objectUnderMouse( lon, lat, zLevel ) ) ret = _object; return ret; } void FGSD_Tile::getAirportList( std::vector &__aptList ) const { if ( _object ) _object->getAirportList( __aptList ); } bool FGSD_Tile::removeObject( FGSD_BaseObject *__object ) { bool ret = false; for ( ObjectList::iterator i = _objectList.begin(); i != _objectList.end(); ++i ) { FGSD_BaseObject *object = *i; if ( object == __object ) { ret = true; _modified = true; _objectList.erase( i ); break; } } return ret; } void FGSD_Tile::addObject( FGSD_BaseObject *__object ) { __object->reparent( this ); _objectList.push_back( __object ); _modified = true; } bool FGSD_Tile::positionInTile( double lon, double lat ) const { double w = _bucket.get_width(); double minx = _bucket.get_chunk_lon() + _bucket.get_x() * w; double h = _bucket.get_height(); double miny = _bucket.get_chunk_lat() + _bucket.get_y() * h; return lon >= minx && lat >= miny && lon < minx + w && lat < miny + h; } bool FGSD_Tile::saveTo( const std::string &outPath, const std::string &format, bool objectBase, bool object, bool objectStatic, bool objectShared, bool force ) { bool ret = false; if ( format == "TerraGear" ) { ret = saveToTerraGear( outPath, objectBase, object, objectStatic, objectShared, force ); } else if( format == "Ascii" ) { ret = saveToAscii( outPath, objectBase, object, objectStatic, objectShared, force ); } else { // Unsupported } return ret; } bool FGSD_Tile::saveToTerraGear( const std::string &outPath, bool objectBase, bool object, bool objectStatic, bool objectShared, bool force ) { bool ret = false; std::string index_str = _bucket.gen_index_str(); SGPath path; path = outPath; path.append( _bucket.gen_base_path() ); SGPath basename = path; basename.append( index_str ); SGPath stg_name = basename; stg_name.concat( ".stg" ); FGSD_Util::createPath( stg_name.str().c_str(), true ); std::ofstream out( stg_name.str().c_str() ); if ( out.is_open() ) { if ( objectBase ) { // First, the base terrain out << "OBJECT_BASE " << index_str << ".btg" << std::endl; } if ( object ) { // Second, the airport objects size_t nb = _object->nbObjects(); for ( size_t i = 0; i < nb; i++ ) { out << "OBJECT " << _object->objectName( i ) << ".btg" << std::endl; } } if ( objectStatic || objectShared ) { // Third, the static objects ObjectList::iterator it; for ( it = _objectList.begin(); it != _objectList.end(); ++it ) { FGSD_BaseObject *object = *it; FGSD_ObjectStatic *obj = (FGSD_ObjectStatic *)object->convertTo( FGSD_BaseObject::ObjectStatic ); if ( obj ) { obj->saveTo( out, path.str(), objectStatic, objectShared ); } } } ret = true; } if ( force || _object->isModified() ) { _object->save( outPath, objectBase, object ); } return ret; } bool FGSD_Tile::saveToAscii( const std::string &outPath, bool objectBase, bool object, bool objectStatic, bool objectShared, bool force ) { bool ret = false; std::string index_str = _bucket.gen_index_str(); SGPath path; path = outPath; path.append( _bucket.gen_base_path() ); SGPath basename = path; basename.append( index_str ); SGPath stg_name = basename; stg_name.concat( ".stg" ); FGSD_Util::createPath( stg_name.str().c_str(), true ); std::ofstream out( stg_name.str().c_str() ); if ( out.is_open() ) { if ( objectBase ) { // First, the base terrain out << "OBJECT_BASE " << index_str << ".asc" << std::endl; } if ( object ) { // Second, the airport objects size_t nb = _object->nbObjects(); for ( size_t i = 0; i < nb; i++ ) { out << "OBJECT " << _object->objectName( i ) << ".asc" << std::endl; } } if ( objectStatic || objectShared ) { // Third, the static objects ObjectList::iterator it; for ( it = _objectList.begin(); it != _objectList.end(); ++it ) { FGSD_BaseObject *object = *it; FGSD_ObjectStatic *obj = (FGSD_ObjectStatic *)object->convertTo( FGSD_BaseObject::ObjectStatic ); if ( obj ) { obj->saveTo( out, path.str(), objectStatic, objectShared ); } } } ret = true; } if ( force || _object->isModified() ) { _object->saveAscii( outPath, objectBase, object ); } return ret; } FGSD_ObjectStatic *FGSD_Tile::findStaticObject( const char *__name, double __lon, double __lat, double __elev, double __hdg ) { FGSD_ObjectStatic *ret = 0; ObjectList::iterator i; for ( i = _objectList.begin(); i != _objectList.end(); ++i ) { FGSD_BaseObject *object = *i; FGSD_ObjectStatic *obj = (FGSD_ObjectStatic *)object->convertTo( FGSD_BaseObject::ObjectStatic ); if ( obj && obj->getName() == __name && obj->getLon() == __lon && obj->getLat() == __lat && obj->getHeading() == __hdg ) { ret = obj; break; } } return ret; } void FGSD_Tile::recalcStaticObjectHeight() { ObjectList::iterator i; for ( i = _objectList.begin(); i != _objectList.end(); ++i ) { FGSD_BaseObject *object = *i; FGSD_ObjectStatic *obj = (FGSD_ObjectStatic *)object->convertTo( FGSD_BaseObject::ObjectStatic ); if ( obj ) { double height; std::string mat, aptid; bool ok = propertiesUnderMouse( obj->getLon(), obj->getLat(), height, mat, aptid ); if ( ok && height != obj->getElev() ) obj->changePosition( obj->getLon(), obj->getLat(), height ); } } } bool FGSD_Tile::adjacent( const SGBucket &b, bool &top, bool &bottom, bool &left, bool &right ) const { double tminx = _bucket.get_chunk_lon() + _bucket.get_x() * _bucket.get_width(); double tmaxx = _bucket.get_chunk_lon() + ( _bucket.get_x() + 1 ) * _bucket.get_width(); double tminy = _bucket.get_chunk_lat() + _bucket.get_y() * _bucket.get_height(); double tmaxy = _bucket.get_chunk_lat() + ( _bucket.get_y() + 1 ) * _bucket.get_height(); double minx = b.get_chunk_lon() + b.get_x() * b.get_width(); double maxx = b.get_chunk_lon() + ( b.get_x() + 1 ) * b.get_width(); double miny = b.get_chunk_lat() + b.get_y() * b.get_height(); double maxy = b.get_chunk_lat() + ( b.get_y() + 1 ) * b.get_height(); if ( tmaxy == miny ) top = true; else top = false; if ( tminy == maxy ) bottom = true; else bottom = false; if ( tmaxx == minx ) right = true; else right = false; if ( tminx == maxx ) left = true; else left = false; bool ret; if ( tminx == minx || tminy == miny ) ret = true; else ret = false; return ret; } bool FGSD_Tile::changeMaterial( const std::string &mat, double lon, double lat ) { bool ret = false; if ( _object->visible( lon, lat ) ) ret = _object->changeMaterial( mat, lon, lat ); return ret; }