// curve.cpp -- base class for polyline data // // Written by Frederic Bouvier, started October 2001. // // Copyright (C) 2001 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: curve.cpp,v 1.18 2005/05/09 07:01:50 fredb Exp $ #ifdef _MSC_VER #pragma warning ( disable : 4786 4503 ) #define _USE_MATH_DEFINES #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "curve.hpp" #include "mainwin.hpp" #include "triobject.hpp" #include "tile.hpp" #include FGSD_Curve::FGSD_Curve() : FGSD_BaseObject( 0, FGSD_BaseObject::Curve ) , _type( UnSet ) , _opened( true ) , _selected( false ) , _minx( 1000.0 ) , _miny( 1000.0 ) , _maxx( -1000.0 ) , _maxy( -1000.0 ) , _height( 0.0 ) , _water( false ) , _embedded( false ) , _new( false ) { _curPoint = (size_t)-1; _mousePoint = (size_t)-1; _mouseEdge = (size_t)-1; } FGSD_Curve::FGSD_Curve( FGSD_BaseObject::ObjectType __type ) : FGSD_BaseObject( 0, __type ) , _type( UnSet ) , _opened( true ) , _selected( false ) , _minx( 1000.0 ) , _miny( 1000.0 ) , _maxx( -1000.0 ) , _maxy( -1000.0 ) , _height( 0.0 ) , _water( false ) , _embedded( false ) , _new( false ) { _curPoint = (size_t)-1; _mousePoint = (size_t)-1; _mouseEdge = (size_t)-1; } void FGSD_Curve::save( SGPropertyNode *__node ) { SGPropertyNode *n = __node->getChild( "opened", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setBoolValue( _opened ); n = __node->getChild( "type", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); switch ( _type ) { case UnSet: n->setStringValue( "UnSet" ); break; case Curve2D: n->setStringValue( "Curve2D" ); break; case Curve2D5: n->setStringValue( "Curve2D5" ); break; case Curve3D: n->setStringValue( "Curve3D" ); break; } n = __node->getChild( "material", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setStringValue( _material.c_str() ); n = __node->getChild( "water", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setBoolValue( _water ); n = __node->getChild( "embedded", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setBoolValue( _embedded ); n = __node->getChild( "height", 0, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setDoubleValue( _height ); size_t nb = _pointList.size(); for ( size_t i = 0; i < nb; i++ ) { n = __node->getChild( "lon", i, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setDoubleValue( _pointList[ i ].x() ); n = __node->getChild( "lat", i, true ); n->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); n->setDoubleValue( _pointList[ i ].y() ); } } bool FGSD_Curve::load( SGPropertyNode *__node ) { bool ret = false; SGPropertyNode *node = __node->getChild( "opened" ); if ( node ) { _opened = node->getBoolValue(); node = __node->getChild( "type" ); if ( node ) { std::string type = node->getStringValue(); if ( type == "Curve2D" ) _type = Curve2D; else if ( type == "Curve2D5" ) _type = Curve2D5; else if ( type == "Curve3D" ) _type = Curve3D; else _type = UnSet; } node = __node->getChild( "height" ); if ( node ) _height = node->getDoubleValue(); node = __node->getChild( "material" ); if ( node ) _material = node->getStringValue(); node = __node->getChild( "water" ); if ( node ) _water = node->getBoolValue(); node = __node->getChild( "embedded" ); if ( node ) _embedded = node->getBoolValue(); std::vector cLon = __node->getChildren( "lon" ); std::vector cLat = __node->getChildren( "lat" ); if ( cLon.size() == cLat.size() ) { size_t i, nb = cLon.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode *lon = cLon[ i ]; SGPropertyNode *lat = cLat[ i ]; if ( lon->getIndex() == lat->getIndex() ) { Point3D p( lon->getDoubleValue(), lat->getDoubleValue(), 0.0 ); _pointList.push_back( p ); } else break; } if ( i == nb ) ret = true; } } return ret; } void FGSD_Curve::draw( double alpha, bool lines, DrawType drawType, double minx, double maxx, double miny, double maxy, double zLevel ) { // Save previous state glPushAttrib( GL_CURRENT_BIT | GL_POINT_BIT | GL_LINE_BIT ); glColor4f( 1.0, 0.0, 1.0, alpha ); if ( _pointList.size() > 1 ) { if ( _selected ) { glPointSize( 6.0 ); glBegin( GL_POINTS ); for ( size_t pi = 0; pi < _pointList.size(); ++pi ) glVertex2d( _pointList[ pi ].x(), _pointList[ pi ].y() ); glEnd(); } glLineWidth( 1.0 ); glPointSize( 1.0 ); glBegin( GL_LINE_STRIP ); if ( !_opened ) { Point3D p = _pointList.back().p; if ( _selected && _curPoint == 0 ) glColor4f( 0.0, 1.0, 1.0, alpha ); glVertex2d( p.x(), p.y() ); } for ( size_t pi = 0; pi < _pointList.size(); ++pi ) { if ( _selected && pi == _curPoint && pi != 0 ) { glEnd(); glColor4f( 0.0, 1.0, 1.0, alpha ); glBegin( GL_LINE_STRIP ); size_t prev = pi; --prev; glVertex2d( _pointList[ prev ].x(), _pointList[ prev ].y() ); } glVertex2d( _pointList[ pi ].x(), _pointList[ pi ].y() ); if ( _selected && pi == _curPoint ) { glEnd(); glColor4f( 1.0, 0.0, 1.0, alpha ); glBegin( GL_LINE_STRIP ); glVertex2d( _pointList[ pi ].x(), _pointList[ pi ].y() ); } } glEnd(); if ( _selected ) { glColor4f( 0.0, 1.0, 1.0, alpha ); glPointSize( 6.0 ); glBegin( GL_POINTS ); glVertex2d( _pointList[ _curPoint ].x(), _pointList[ _curPoint ].y() ); glEnd(); } } else if ( _pointList.size() == 1 ) { size_t pi = 0; glPointSize( 6.0 ); glBegin( GL_POINTS ); glVertex2d( _pointList[ pi ].x(), _pointList[ pi ].y() ); glEnd(); } // Restore previous state glPopAttrib(); } bool FGSD_Curve::propertiesUnderMouse( double lon, double lat, double &height, std::string &material, std::string &airportID ) const { return false; } bool FGSD_Curve::objectUnderMouse( double lon, double lat, double zLevel ) { double xscale = 0.0002 / zLevel; double yscale = xscale * cos( lat * M_PI / 180 ); double minx = lon - xscale; // if ( minx < _minx ) minx = _minx; double miny = lat - yscale; // if ( miny < _miny ) miny = _miny; double maxx = lon + xscale; // if ( maxx > _maxx ) maxx = _maxx; double maxy = lat + yscale; // if ( maxy > _maxy ) maxy = _maxy; bool ret = false; _mousePoint = (size_t)-1; Point3D p1( lon, lat, 0 ); Point3D p0 = _pointList.back().p; for ( size_t pi = 0; pi < _pointList.size(); ++pi ) { Point3D p = _pointList[ pi ].p; if ( minx <= p.x() && p.x() < maxx && miny <= p.y() && p.y() < maxy ) { _mousePoint = pi; ret = true; break; } else if ( pi != 0 || !_opened ) { Point3D v0 = p - p0; double l0 = p0.distance3Dsquared( p ); Point3D v = p1 - p0; double a = ( v0.x() * v.x() + v0.y() * v.y() ) / l0; double b = ( v0.x() * v.y() - v0.y() * v.x() ) / l0; if ( a >= 0 && a < 1 && fabs( b ) < 0.02 ) { _mouseEdge = pi; ret = true; break; } } p0 = p; } return ret; } bool FGSD_Curve::visible( double minx, double maxx, double miny, double maxy ) const { return _maxx >= minx && _minx < maxx && _maxy >= miny && _miny < maxy; } bool FGSD_Curve::visible( double lon, double lat ) const { return lon >= _minx && lon < _maxx && lat >= _miny && lat < _maxy; } std::string FGSD_Curve::getName() const { return std::string(); } void *FGSD_Curve::convertTo( FGSD_BaseObject::ObjectType __type ) { return __type == FGSD_BaseObject::Curve ? this : 0; } bool FGSD_Curve::checkForCrossingSegments( const Point3D &A, const Point3D &B, size_t moving ) const { bool ret = true; Point3D V = B - A; double AyVx = A.y() * V.x(); double AxVy = A.x() * V.y(); PointList::const_iterator pi = _pointList.begin(); PointList::const_iterator opi = pi++; size_t i = 1; for ( ; ret && pi != _pointList.end(); opi = pi++, i++ ) { if ( i != moving && ( i - 1 ) != moving ) { Point3D C = opi->p; Point3D W = pi->p - C; double denom = V.y() * W.x() - V.x() * W.y(); if ( denom != 0 ) { double t = ( C.y() * W.x() - A.y() * W.x() - C.x() * W.y() + A.x() * W.y() ) / denom; if ( t >= 0.0 && t < 0.999999 ) { double u = ( C.y() * V.x() - A.y() * V.x() - C.x() * V.y() + A.x() * V.y() ) / denom; if ( u >= 0.0 && u < 0.999999 ) ret = false; } } } } if ( !_opened && moving != 0 && moving != _pointList.size() - 1 ) { pi = _pointList.begin(); Point3D C = opi->p; Point3D W = pi->p - C; double denom = V.y() * W.x() - V.x() * W.y(); if ( denom != 0 ) { double t = ( C.y() * W.x() - A.y() * W.x() - C.x() * W.y() + A.x() * W.y() ) / denom; if ( t >= 0.0 && t < 0.999999 ) { double u = ( C.y() * V.x() - A.y() * V.x() - C.x() * V.y() + A.x() * V.y() ) / denom; if ( u >= 0.0 && u < 0.999999 ) ret = false; } } } return ret; } bool FGSD_Curve::insertPoint( double __lon, double __lat ) { if ( _curPoint == size_t(-1) && !_opened ) return false; bool ret = true; Point3D A( __lon, __lat, 0 ); if ( _pointList.size() <= 2 ) ret = true; else if ( _curPoint == 0 ) { // insertion at the beginning ret = checkForCrossingSegments( A, _pointList.front().p ); } else if ( _curPoint == (size_t)-1 || _curPoint == _pointList.size() - 1 ) { // insertion at the end ret = checkForCrossingSegments( A, _pointList.back().p ); } else { // insertion between two points ret = checkForCrossingSegments( A, _pointList[ _curPoint - 1 ].p ) && checkForCrossingSegments( A, _pointList[ _curPoint ].p ); } if ( ret ) { PointList::iterator it = _pointList.begin(); if ( _curPoint == (size_t)-1 || _curPoint == _pointList.size() ) it = _pointList.end(); else it += _curPoint; _pointList.insert( it, A ); if ( _minx > A.x() ) _minx = A.x(); if ( _maxx < A.x() ) _maxx = A.x(); if ( _miny > A.y() ) _miny = A.y(); if ( _maxy < A.y() ) _maxy = A.y(); } return ret; } /* double t = ( C.y() * W.x() - A.y() * W.x() - C.x() * W.y() + A.x() * W.y() ) / ( V.y() * W.x() - V.x() * W.y() ); double u = ( C.y() * V.x() - A.y() * V.x() - C.x() * V.y() + A.x() * V.y() ) / ( V.y() * W.x() - V.x() * W.y() ); */ bool FGSD_Curve::moveCurrentPoint( double __lon, double __lat ) { bool ret = false; if ( _mousePoint != (size_t)-1 ) { Point3D A( __lon, __lat, 0 ); if ( _pointList.size() <= 2 ) ret = true; else if ( _opened && _mousePoint == 0 ) { // moving point at the beginning ret = checkForCrossingSegments( A, _pointList[ _mousePoint + 1 ].p, _mousePoint ); } else if ( _opened && ( _mousePoint == (size_t)-1 || _mousePoint == _pointList.size() - 1 ) ) { // moving point at the end PointList::iterator it = _pointList.end(); --it; --it; ret = checkForCrossingSegments( A, it->p, _mousePoint ); } else { // moving point between two points size_t n = _mousePoint > 0 ? _mousePoint - 1 : _pointList.size() - 1; size_t m = _mousePoint < _pointList.size() - 1 ? _mousePoint + 1 : 0; ret = checkForCrossingSegments( A, _pointList[ n ].p, _mousePoint ) && checkForCrossingSegments( A, _pointList[ m ].p, _mousePoint ); } if ( ret ) { _pointList[ _mousePoint ] = A; if ( _minx > A.x() ) _minx = A.x(); if ( _maxx < A.x() ) _maxx = A.x(); if ( _miny > A.y() ) _miny = A.y(); if ( _maxy < A.y() ) _maxy = A.y(); } } return ret; } bool FGSD_Curve::removeMousePoint( bool selected ) { bool ret = false; size_t ind = selected ? _curPoint : _mousePoint; if ( ind != (size_t)-1 ) { if ( _pointList.size() > 2 && ( !_opened || ind != 0 || ind == _pointList.size() - 1 ) ) { // moving point between two points size_t n = ind > 0 ? ind - 1 : _pointList.size() - 1; size_t m = ind < _pointList.size() - 1 ? ind + 1 : 0; ret = checkForCrossingSegments( _pointList[ n ].p, _pointList[ m ].p, ind ); } else ret = true; if ( ret ) { PointList::iterator it = _pointList.begin(); if ( ind == (size_t)-1 || ind == _pointList.size() ) it = _pointList.end(); else it += ind; _pointList.erase( it ); ind = (size_t)-1; if ( _curPoint >= _pointList.size() ) _curPoint = (size_t)-1; } } return ret; } void FGSD_Curve::removePoint( size_t __index ) { if ( __index != size_t(-1) ) { PointList::iterator it = _pointList.begin() + __index; _pointList.erase( it ); if ( _mousePoint == __index ) _mousePoint = (size_t)-1; if ( _curPoint >= _pointList.size() ) _curPoint = (size_t)-1; } else if ( __index == size_t(-1) && !_opened ) { _opened = true; } else { size_t index = _pointList.size(); _pointList.pop_back(); if ( _curPoint >= _pointList.size() ) _curPoint = (size_t)-1; if ( _mousePoint == index - 1 ) _mousePoint = (size_t)-1; } } bool FGSD_Curve::tryToClose( double zLevel ) { bool ret = false; if ( _opened && _pointList.size() > 2 ) { Point3D p0 = _pointList.front().p; Point3D p = _pointList.back().p; double xscale = 0.0002 / zLevel; double yscale = xscale * cos( p0.y() * M_PI / 180 ); double minx = p0.x() - xscale; double miny = p0.y() - yscale; double maxx = p0.x() + xscale; double maxy = p0.y() + yscale; if ( minx <= p.x() && p.x() < maxx && miny <= p.y() && p.y() < maxy ) { _opened = false; _pointList.pop_back(); ret = true; } } return ret; } void FGSD_Curve::open() { if ( !_opened ) { _pointList.push_back( _pointList.front() ); _opened = true; } } void FGSD_Curve::changeCurrentPoint() { if ( _mousePoint != (size_t)-1 ) { if ( _mousePoint != _curPoint ) _curPoint = _mousePoint; else _curPoint = (size_t)-1; } else if ( _mouseEdge != (size_t)-1 ) { if ( _mouseEdge != _curPoint ) _curPoint = _mouseEdge; else _curPoint = (size_t)-1; } } bool FGSD_Curve::pointSelected() const { return _curPoint != (size_t)-1; } bool FGSD_Curve::mouseOnPoint() const { return _mousePoint != (size_t)-1; } void FGSD_Curve::embedInTiles( FGSD_MainWindow *mw ) { std::set tileSet; _embedded = true; FGSD_Tile *ot = 0; Vertex_handle ov, fv; size_t nb = _pointList.size(); for ( size_t i = 0; i < nb; i++ ) { FGSD_Tile *t = 0; Vertex_handle v; if ( _pointList[ i ].v == Vertex_handle() ) { Point3D &p = _pointList[ i ].p; if ( _type == Curve2D5 ) p.setz( _height ); t = mw->findTile( p.x(), p.y() ); FGSD_TriangleObject *o = t->getTerrain(); std::set::iterator it = tileSet.find( o ); if ( it == tileSet.end() ) tileSet.insert( o ); if ( ov == Vertex_handle() ) { v = o->embedPoint( p ); } else if ( t != ot ) { SGBucket ob = ot->getBucket(); bool top, bot, left, right; if ( t->adjacent( ob, top, bot, left, right ) ) { } v = o->embedPoint( p ); } else { v = o->embedPoint( p ); if ( v != Vertex_handle() ) o->embedEdge( ov, v ); } _pointList[ i ].t = t; _pointList[ i ].v = v; } ot = t; ov = v; if ( fv == Vertex_handle() ) fv = v; } if ( !_opened && ov != Vertex_handle() && fv != Vertex_handle() ) { FGSD_TriangleObject *o = ot->getTerrain(); o->embedEdge( ov, fv ); } for ( std::set::iterator it = tileSet.begin(); it != tileSet.end(); ++it ) { FGSD_TriangleObject *o = *it; o->recoverFaceData(); } }