// inputwin.cpp -- window for importing and calibrating map fragments // // 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: inputwin.cpp,v 1.29 2005/05/09 07:01:52 fredb Exp $ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "inputwin.hpp" #include "messwin.hpp" #include "sdutil.hpp" #include "preferences.hpp" #include "mapfragment.hpp" #include "jpgimage.hpp" #ifdef HAVE_GIF_LIB_H #include "gifimage.hpp" #endif typedef FGSD_MapFragment::Contour::iterator MFCI; extern FGSD_Preferences generalPreferences; #include "new.xpm" #include "openf.xpm" #include "openi.xpm" #include "save.xpm" #include "marker.xpm" #include "contour.xpm" #include "rot_plus.xpm" #include "rot_moins.xpm" static struct _terra_data { const char *text; double size; int scale; } terra_resol[] = { { "256m", 51200.0, 18 }, { "128m", 25600.0, 17 }, { "64m", 12800.0, 16 }, { "32m", 6400.0, 15 }, { "16m", 3200.0, 14 }, { "8m", 1600.0, 13 }, { "4m", 800.0, 12 }, { "2m", 400.0, 11 }, { "1m", 200.0, 10 }, { "0.5m", 100.0, 9 }, { "0.25m", 50.0, 8 }, { 0 } }; static struct _terra_type { const char *text; int type; } terra_types[] = { { "Urban Areas", 4 }, { "Aerial Photo", 1 }, #ifdef HAVE_GIF_LIB_H { "Topo Map", 2 }, /* GIF images */ #endif { 0 } }; static const char *units[] = { "b", "Kb", "Mb", "Gb", "Tb", 0 }; Fl_Image *FGSD_InputWindow::_images[ NbImages ][ 2 ] = { { new Fl_Pixmap( new_xpm ), new Fl_Pixmap( new_xpm ) }, { new Fl_Pixmap( openf_xpm ), new Fl_Pixmap( openf_xpm ) }, { new Fl_Pixmap( openi_xpm ), new Fl_Pixmap( openi_xpm ) }, { new Fl_Pixmap( save_xpm ), new Fl_Pixmap( save_xpm ) }, { new Fl_Pixmap( marker_xpm ), new Fl_Pixmap( marker_xpm ) }, { new Fl_Pixmap( contour_xpm ), new Fl_Pixmap( contour_xpm ) }, { new Fl_Pixmap( rot_plus_xpm ), new Fl_Pixmap( rot_plus_xpm ) }, { new Fl_Pixmap( rot_moins_xpm ), new Fl_Pixmap( rot_moins_xpm ) } }; Fl_Menu_Item inputMenu [] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&New", FL_ALT+'n', &FGSD_InputWindow::new_cb }, { "&Open", 0, 0, 0, FL_SUBMENU }, { "&Fragment", FL_ALT + 'f', &FGSD_InputWindow::openFragment_cb }, { "&Image", FL_ALT + 'i', &FGSD_InputWindow::openImage_cb }, { 0 }, { "Fetch &terraserver-usa.com...", FL_ALT + 't', &FGSD_InputWindow::fetchTerraserverUsa_cb, 0, FL_MENU_DIVIDER }, { "&Save", FL_ALT+'s', &FGSD_InputWindow::save_cb }, { "S&ave As", FL_ALT+'a', &FGSD_InputWindow::saveAs_cb }, { "&Close", FL_ALT+'c', &FGSD_InputWindow::close_cb }, { 0 }, { 0 } }; FGSD_InputWindow::FGSD_InputWindow( int w, int h ) : _fragment( 0 ) , _posx( 0 ) , _posy( 0 ) , _visw( 0 ) , _vish( 0 ) , _zLevel( 1.0 ) , _modified( false ) , _modifiedImage( false ) , _dragging( false ) , _dragMove( false ) , _dragContour( false ) , _currentContourPos( new FGSD_MapFragment::Contour::iterator ) , _fetchDialogRequested( false ) , _fetchCancelled( false ) { _window = new FGSD_Window( w, h ); _markWindow = new FGSD_Window( 360, 290, "Coordinates" ); _markWindow->begin(); _syst = new Fl_Choice( 110, 10, 240, 30, "System :" ); _syst->add("WGS-84"); _syst->add("Lambert I"); _syst->add("Lambert II"); _syst->add("Lambert II extended"); _syst->add("Lambert III"); _syst->add("Lambert IV"); _syst->add("OSGB 36"); _syst->add("Universal Transverse Mercator"); _syst->value( 0 ); _syst->callback( &FGSD_InputWindow::system_cb, this ); _zone = new Fl_Choice( 110, 50, 100, 30, "Zone :" ); for ( size_t i = 1; i <= 60; i++ ) { std::ostringstream str; str << i << std::ends; _zone->add( str.str().c_str() ); } _zone->value( 0 ); _hemi = new Fl_Check_Button( 220, 50, 130, 30, "South" ); _lon = new Fl_Input( 110, 90, 240, 30, "Longitude :" ); _lat = new Fl_Input( 110, 130, 240, 30, "Latitude :" ); _hgt = new Fl_Input( 110, 170, 240, 30, "Altitude :\n( in meters )" ); _datum = new Fl_Choice( 110, 210, 240, 30, "Datum :" ); _datum->add("WGS-84"); _datum->add("NAD-27"); _datum->add("NAD-83"); _datum->add("S-42"); _datum->value( 0 ); _zone->deactivate(); _hemi->deactivate(); _datum->deactivate(); _markOk = new Fl_Button(10, 250, 100, 30, "Ok"); _markOk->callback( &FGSD_InputWindow::markok_cb, this ); _markCancel = new Fl_Button(130, 250, 100, 30, "Cancel"); _markCancel->callback( &FGSD_InputWindow::markcan_cb, this ); _markWindow->end(); _fetchWindow = new FGSD_Window( 360, 290, "Fetch terraserver-usa.com" ); _fetchWindow->begin(); _flon = new Fl_Input( 110, 10, 115, 30, "Location :" ); _flon->value( "-122.374926" ); _flon->when( FL_WHEN_CHANGED ); _flon->callback( &FGSD_InputWindow::checkFetch_cb, this ); _flat = new Fl_Input( 235, 10, 115, 30 ); _flat->value( "37.618763" ); _flat->when( FL_WHEN_CHANGED ); _flat->callback( &FGSD_InputWindow::checkFetch_cb, this ); _xradius = new Fl_Int_Input( 110, 50, 115, 30, "Radius :\n(in meters)" ); _xradius->when( FL_WHEN_CHANGED ); _xradius->callback( &FGSD_InputWindow::xradiusChange_cb, this ); _yradius = new Fl_Int_Input( 235, 50, 115, 30 ); _yradius->when( FL_WHEN_CHANGED ); _yradius->callback( &FGSD_InputWindow::yradiusChange_cb, this ); _resolution = new Fl_Choice( 110, 90, 115, 30, "Resolution :" ); for ( _terra_data *p = terra_resol; p->text != 0; p++ ) { _resolution->add( p->text, 0, 0, p ); } _resolution->value(0); _resolution->callback( &FGSD_InputWindow::checkFetch_cb, this ); _type = new Fl_Choice( 235, 90, 115, 30 ); for ( _terra_type *t = terra_types; t->text != 0; t++ ) { _type->add( t->text ); } _type->value(0); _xsize = new Fl_Output( 110, 130, 115, 30, "Image size :" ); _xsize->color( _fetchWindow->color() ); _ysize = new Fl_Output( 235, 130, 115, 30 ); _ysize->color( _fetchWindow->color() ); _weight = new Fl_Output( 110, 170, 115, 30, "Image weight :" ); _weight->color( _fetchWindow->color() ); Fl_Box *o = new Fl_Box( 10, 210, 340, 30, "Images courtesy of the USGS" ); o->box( FL_FLAT_BOX ); _fetchOk = new Fl_Button(10, 250, 100, 30, "Ok"); _fetchOk->callback( &FGSD_InputWindow::fetchok_cb, this ); _fetchCancel = new Fl_Button(130, 250, 100, 30, "Cancel"); _fetchCancel->callback( &FGSD_InputWindow::fetchcan_cb, this ); _fetchWindow->end(); _window->begin(); _popup = new Fl_Menu_Button( 0, 70, 0, 0 ); _popup->type( Fl_Menu_Button::POPUP3 ); _menubar = new Fl_Menu_Bar( 0, 0, w, 30 ); _menubar->box( FL_UP_BOX ); size_t nb = sizeof( inputMenu ) / sizeof( Fl_Menu_Item ); for ( size_t i = 0; i < nb; i++ ) { if ( !(inputMenu[i].flags & FL_SUBMENU ) && inputMenu[i].text != 0 ) { inputMenu[i].user_data_ = this; } } _menubar->menu( inputMenu ); _tools = new Fl_Group( 0, 30, w, 40 ); _tools->begin(); int posx = 5; _nbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _nbutton, New_i, true ); _nbutton->tooltip( "New fragment" ); _nbutton->callback( &FGSD_InputWindow::new_cb, this ); posx += 30; _ofbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _ofbutton, OpenF_i, true ); _ofbutton->tooltip( "Open fragment" ); _ofbutton->callback( &FGSD_InputWindow::openFragment_cb, this ); posx += 30; _oibutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _oibutton, OpenI_i, true ); _oibutton->tooltip( "Open image" ); _oibutton->callback( &FGSD_InputWindow::openImage_cb, this ); posx += 30; _vbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _vbutton, Save_i, true ); _vbutton->tooltip( "Save fragment" ); _vbutton->callback( &FGSD_InputWindow::save_cb, this ); posx += 40; _marker = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _marker, Marker_i, true ); _marker->tooltip( "Set markers" ); _marker->type( FL_TOGGLE_BUTTON ); posx += 30; _curve = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _curve, Contour_i, true ); _curve->tooltip( "Set contours" ); _curve->type( FL_TOGGLE_BUTTON ); posx += 30; _rotplus = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _rotplus, RotPlus_i, true ); _rotplus->tooltip( "Rotate +" ); _rotplus->callback( &FGSD_InputWindow::rot_plus_cb, (void *)this ); posx += 30; _rotminus = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _rotminus, RotMoins_i, true ); _rotminus->tooltip( "Rotate -" ); _rotminus->callback( &FGSD_InputWindow::rot_minus_cb, (void *)this ); posx += 30; // Spacing posx += 10; _zoom = new Fl_Value_Slider( posx, 35, 100, 30 ); _zoom->type( FL_HORIZONTAL ); _zoom->step( 1.0 ); _zoom->range( -5.0, 5.0 ); _zoom->callback( &FGSD_InputWindow::zoom_cb, (void *)this ); posx += 105; _tools->end(); _tools->resizable( 0 ); { Fl_Group *o = new Fl_Group( 0, h - 40, w, 40 ); o->box( FL_THIN_UP_BOX ); o->begin(); posx = 5; _xentry = new Fl_Output( posx, h - 35, 100, 30 ); _xentry->color( _window->color() ); posx += 105; _yentry = new Fl_Output( posx, h - 35, 100, 30 ); _yentry->color( _window->color() ); posx += 110; _progress = new Flu_Progress( posx, h - 35, 100, 30 ); _progress->box( FL_DOWN_BOX ); _progress->align( FL_ALIGN_BOTTOM ); _progress->selection_color(FL_BLUE); _progress->color(FL_WHITE); _progress->labelcolor(FL_WHITE); posx += 110; _fcancel = new Fl_Button( posx, h - 35, 80, 30, "Cancel" ); _fcancel->callback( &FGSD_InputWindow::cancelFetch_cb, (void *)this ); _fcancel->hide(); posx += 90; o->end(); o->resizable( 0 ); } _vscroll = new Fl_Scrollbar( w - 20, 70, 20, h - 130 ); _vscroll->deactivate(); _vscroll->callback( vscroll_cb, (void *)this ); _hscroll = new Fl_Scrollbar( 0, h - 60, w - 20, 20 ); _hscroll->deactivate(); _hscroll->type( FL_HORIZONTAL ); _hscroll->callback( hscroll_cb, (void *)this ); _input = new FGSD_InputGLWindow( 0, 70, w - 20, h - 130, this ); _window->resizable( _input ); _window->callback( close_cb, (void *)this ); _window->end(); setTitle(); } FGSD_InputWindow::~FGSD_InputWindow() { delete (MFCI *)_currentContourPos; delete _markWindow; delete _fetchWindow; delete _window; if ( _fragment ) delete _fragment; } void FGSD_InputWindow::loadImage() { std::string curdir = generalPreferences.currentInputDirectory(); const char *fileName = flu_file_chooser( "Select an image file ...", "*.jpg;*.png", curdir.c_str() ); if ( fileName ) { _window->cursor( FL_CURSOR_WAIT ); _input->make_current(); if ( _fragment ) delete _fragment; _fragment = new FGSD_MapFragment; _fragment->loadImage( fileName ); _fragment->initContour(); _fragment->refreshTesselation( false ); curdir = FGSD_Util::getDirectoryFromFile( fileName ); generalPreferences.currentInputDirectory( curdir ); _vscroll->activate(); _hscroll->activate(); layout_(); _window->cursor( FL_CURSOR_DEFAULT ); _modified = true; } } void FGSD_InputWindow::layout_() { if ( _fragment ) { double xcent = _posx + _visw / 2; if ( xcent < 0 ) xcent = 0; double ycent = _posy + _vish / 2; if ( ycent < 0 ) ycent = 0; if ( xcent > _fragment->realWidth() ) xcent = _fragment->realWidth(); if ( ycent > _fragment->realHeight() ) ycent = _fragment->realHeight(); _visw = _input->w() / _zLevel; _vish = _input->h() / _zLevel; centerPosition( xcent, ycent ); } } void FGSD_InputWindow::mouseMove( int x, int y, int e, int s ) { if ( _fragment ) { double mx = _posx + x / _zLevel; double my = _posy + ( _input->h() - y ) / _zLevel; double curx = -1, cury = -1; if ( _fragment->orientation() == 0 ) { int lv = (int)( _fragment->height() * _zLevel ); int v = _vscroll->value(); curx = ( x + _hscroll->value() ) / _zLevel; cury = ( lv - ( y + v + 1 ) ) / _zLevel; } else if ( _fragment->orientation() == 90 ) { int lv = (int)( _fragment->width() * _zLevel ); int v = _vscroll->value(); int lh = (int)( _fragment->height() * _zLevel ); int h = _hscroll->value(); curx = ( lv - ( y + v + 1 ) ) / _zLevel; cury = ( lh - ( x + h + 1 ) ) / _zLevel; } else if ( _fragment->orientation() == 180 ) { int lh = (int)( _fragment->width() * _zLevel ); int h = _hscroll->value(); curx = ( lh - ( x + h + 1 ) ) / _zLevel; cury = ( y + _vscroll->value() ) / _zLevel; } else if ( _fragment->orientation() == 270 ) { curx = ( y + _vscroll->value() ) / _zLevel; cury = ( x + _hscroll->value() ) / _zLevel; } std::ostringstream str; #ifdef HAVE_STD_FIXED int p = (int)_zoom->value(); if ( p < 0 ) p = 0; str << std::fixed << std::setprecision( p ) << curx << std::ends; #else str << std::setprecision( 20 ) << curx << std::ends; #endif _xentry->value( str.str().c_str() ); str.str(""); #ifdef HAVE_STD_FIXED str << std::fixed << std::setprecision( p ) << cury << std::ends; #else str << std::setprecision( 20 ) << cury << std::ends; #endif _yentry->value( str.str().c_str() ); FGSD_MapFragment::Contour::iterator posContour; bool edgeContour = false; bool onContour = false; if ( _curve->value() && ( onContour = _fragment->hitContour( curx, cury, _zLevel, posContour, edgeContour ) ) ) { if ( edgeContour ) _window->cursor( FL_CURSOR_HAND ); else _window->cursor( FL_CURSOR_MOVE ); } else _window->cursor( FL_CURSOR_DEFAULT ); if ( ( s & FL_BUTTON2 ) && e == FL_DRAG ) { if ( !_dragging ) { setCursor( FL_CURSOR_HAND ); _dragMove = true; _dragMoveX = (int)mx; _dragMoveY = (int)my; } if ( _visw > _fragment->realWidth() ) _dragMoveX = (int)mx; if ( _vish > _fragment->realHeight() ) _dragMoveY = (int)my; gotoPosition( _dragMoveX, _dragMoveY, x, y ); } else if ( ( s & FL_BUTTON1 ) && e == FL_DRAG && ( ( onContour && !edgeContour ) || _dragContour ) ) { if ( !_dragging ) { _dragContour = true; *(MFCI *)_currentContourPos = posContour; } _fragment->changeContourPointPosition( *(MFCI *)_currentContourPos, curx, cury ); _modified = true; _input->redraw(); } if ( e == FL_DRAG ) { _dragging = true; } else if ( _dragging ) { if ( _dragMove ) { setCursor( FL_CURSOR_DEFAULT ); _dragMove = false; } _dragContour = false; _dragging = false; } } } void FGSD_InputWindow::mouseClick( int x, int y, int b ) { if ( _fragment == 0 ) { return; } double mr = 16.0 / _zLevel; double curx = -1, cury = -1; if ( _fragment->orientation() == 0 ) { int lv = (int)( _fragment->height() * _zLevel ); int v = _vscroll->value(); curx = ( x + _hscroll->value() ) / _zLevel; cury = ( lv - ( y + v + 1 ) ) / _zLevel; } else if ( _fragment->orientation() == 90 ) { int lv = (int)( _fragment->width() * _zLevel ); int v = _vscroll->value(); int lh = (int)( _fragment->height() * _zLevel ); int h = _hscroll->value(); curx = ( lv - ( y + v + 1 ) ) / _zLevel; cury = ( lh - ( x + h + 1 ) ) / _zLevel; } else if ( _fragment->orientation() == 180 ) { int lh = (int)( _fragment->width() * _zLevel ); int h = _hscroll->value(); curx = ( lh - ( x + h + 1 ) ) / _zLevel; cury = ( y + _vscroll->value() ) / _zLevel; } else if ( _fragment->orientation() == 270 ) { curx = ( y + _vscroll->value() ) / _zLevel; cury = ( x + _hscroll->value() ) / _zLevel; } if ( b == 3 ) { int last = 0; int i = _fragment->markerHitTest( curx, cury, mr ); _popup->clear(); if ( i == -1 ) { last = _popup->add( "&Add..." ); } else { last = _popup->add( "&Remove" ); last = _popup->add( "&Edit..." ); } FGSD_MapFragment::Contour::iterator posContour; bool edgeContour = false; bool onContour = _fragment->hitContour( curx, cury, _zLevel, posContour, edgeContour ); if ( _curve->value() && onContour && !edgeContour ) { *(MFCI *)_currentContourPos = posContour; _popup->mode( last, FL_MENU_DIVIDER ); last = _popup->add( "&Remove point", 0, &FGSD_InputWindow::removePoint_cb, this ); } _popup->value(-1); // Should be : _popup->popup(); // but there is a problem with menu positionning so : const Fl_Menu_Item* m = _popup->menu()->popup(Fl::event_x(), Fl::event_y() + 70, _popup->label(), _popup->mvalue(), _popup ); _popup->picked(m); // } else if ( b == 1 && _marker->value() && _markWindow->exec() ) { bool error1, error2; double lon = FGSD_Util::parsePosition( _lon->value(), error1 ); double lat = FGSD_Util::parsePosition( _lat->value(), error2 ); int s = _syst->value(); FGSD_Marker::CoordSyst syst = (FGSD_Marker::CoordSyst)( s + 1 ); double h = 0; std::istringstream str( _hgt->value() ); str >> h; if ( !error1 && !error2 ) { size_t m = _fragment->nbMarkers(); if ( m < 3 ) { _fragment->addMarker( FGSD_Marker() ); } if ( syst == FGSD_Marker::UTM ) { int zone = _zone->value() + 1; if ( _hemi->value() ) zone = -zone; FGSD_Util::Datum datum = (FGSD_Util::Datum)( _datum->value() + 1 ); _fragment->setMarker( m, FGSD_Marker( curx, cury, syst, lon, lat, h, zone, datum ) ); } else { _fragment->setMarker( m, FGSD_Marker( curx, cury, syst, lon, lat, h ) ); } _modified = true; if ( _fragment->nbMarkers() == 3 ) { bool ok = _fragment->initMatrix(); if ( !ok ) { // Do something clever here ! } } _input->redraw(); } } else if ( b == 1 && _curve->value() ) { if ( Fl::event_state( FL_CTRL ) ) { if ( _fragment->insertPointToContour( curx, cury ) ) { _modified = true; } } else { FGSD_MapFragment::Contour::iterator posContour; bool edgeContour; bool onContour = _fragment->hitContour( curx, cury, _zLevel, posContour, edgeContour ); if ( onContour && edgeContour ) { _fragment->selectEdge( posContour ); } else { _fragment->unselectEdge(); } } _input->redraw(); } } void FGSD_InputWindow::close_cb(Fl_Widget *, void *v) { static_cast( v )->close_cb(); } void FGSD_InputWindow::close_cb() { bool close = checkModified(); if ( close ) { _window->hide(); } } void FGSD_InputWindow::new_cb(Fl_Widget *, void *v) { static_cast( v )->new_cb(); } void FGSD_InputWindow::new_cb() { if ( checkModified() ) { clearFragment( true ); _modified = false; _input->redraw(); } } void FGSD_InputWindow::openImage_cb(Fl_Widget *, void *v) { static_cast( v )->openImage_cb(); } void FGSD_InputWindow::openImage_cb() { loadImage(); } void FGSD_InputWindow::fetchTerraserverUsa_cb(Fl_Widget *, void *v) { static_cast( v )->fetchTerraserverUsa_cb(); } void FGSD_InputWindow::fetchTerraserverUsa_cb() { if ( _fetchDialogRequested ) { _fetchDialogRequested = false; _flon->value( FGSD_Util::positionToString( _lonRequested, true ).c_str() ); _flat->value( FGSD_Util::positionToString( _latRequested, false ).c_str() ); } _yradiusChanged = false; if ( _fetchWindow->exec() ) { int xstart, ystart, xrange, yrange, zone, scale; double size; bool error = computeFetchParameters( xstart, ystart, xrange, yrange, zone, scale, size ); if ( !error ) { _fetchCancelled = false; _fcancel->show(); _window->cursor( FL_CURSOR_WAIT ); _input->make_current(); _progress->labelcolor(FL_RED); _progress->value( 0 ); Fl::check(); _progress->maximum( xrange * yrange ); if ( _fragment ) delete _fragment; _fragment = new FGSD_MapFragment; _fragment->createDummyImage( xrange * 200, yrange * 200 ); _vscroll->activate(); _hscroll->activate(); layout_(); int t = terra_types[ _type->value() ].type; CURL *ceh = curl_easy_init(); if ( ceh != 0 ) { //curl_easy_setopt( ceh, CURLOPT_VERBOSE, 1 ); for ( int y = ystart; !_fetchCancelled && y < ystart + yrange; y++ ) { for ( int x = xstart; !_fetchCancelled && x < xstart + xrange; x++ ) { std::ostringstream ostr; ostr << "http://terraserver-usa.com/tile.ashx?t=" << t << "&s=" << scale << "&z=" << zone << "&x=" << x << "&y=" << y; std::string url = ostr.str(); curl_easy_setopt( ceh, CURLOPT_URL, url.c_str() ); curl_easy_setopt( ceh, CURLOPT_WRITEFUNCTION, writeFetchData ); curl_easy_setopt( ceh, CURLOPT_WRITEDATA, this ); file_size = 0; fetchStream.str(""); int success = curl_easy_perform( ceh ); if ( success == 0 ) { char *cType; curl_easy_getinfo( ceh, CURLINFO_CONTENT_TYPE, &cType ); if ( strcmp( cType, "image/jpeg" ) == 0 ) { FGSD_JPEGImage image; bool ok = image.loadFromBuffer( (unsigned char *)fetchStream.str().data(), file_size ); if ( ok ) { _fragment->putSubImage( &image, ( x - xstart ) * 200, ( y - ystart ) * 200 ); } } #ifdef HAVE_GIF_LIB_H else if ( strcmp( cType, "image/gif" ) == 0 ) { FGSD_GIFImage image; bool ok = image.loadFromBuffer( (unsigned char *)fetchStream.str().data(), file_size ); if ( ok ) { _fragment->putSubImage( &image, ( x - xstart ) * 200, ( y - ystart ) * 200 ); } } #endif } _progress->value( _progress->value() + 1 ); Fl::check(); } _input->redraw(); Fl::check(); } curl_easy_cleanup( ceh ); } if ( _fetchCancelled ) { delete _fragment; _fragment = 0; layout_(); _vscroll->deactivate(); _hscroll->deactivate(); } else { double utm_x = xstart * size; double utm_y = ystart * size; double utm_dx = xrange * size; double utm_dy = yrange * size; _fragment->addMarker( FGSD_Marker( 0, 0, FGSD_Marker::UTM, utm_x, utm_y, 0, zone, FGSD_Util::D_NAD83 ) ); _fragment->addMarker( FGSD_Marker( 0, yrange * 200, FGSD_Marker::UTM, utm_x, utm_y + utm_dy, 0, zone, FGSD_Util::D_NAD83 ) ); _fragment->addMarker( FGSD_Marker( xrange * 200, 0, FGSD_Marker::UTM, utm_x + utm_dx, utm_y, 0, zone, FGSD_Util::D_NAD83 ) ); _fragment->initMatrix(); _fragment->initContour(); _fragment->refreshTesselation( false ); _modified = true; _modifiedImage = true; } _progress->labelcolor(FL_WHITE); _progress->value( 0 ); _input->redraw(); _window->cursor( FL_CURSOR_DEFAULT ); _fcancel->hide(); } } } bool FGSD_InputWindow::checkModified() { bool go = true; if ( _modified ) { FGSD_MessageWindow mess( "Map fragment", "The current map fragment has been modified.\nDo you want to save it ?", FGSD_MessageWindow::Warning, FGSD_MessageWindow::Yes | FGSD_MessageWindow::No | FGSD_MessageWindow::Cancel ); FGSD_MessageWindow::Button b = mess.exec(); if ( b == FGSD_MessageWindow::Yes ) { go = saveFragment( false ); } else if ( b == FGSD_MessageWindow::Cancel ) { go = false; } } return go; } void FGSD_InputWindow::openFragment_cb(Fl_Widget *, void *v) { static_cast( v )->openFragment_cb(); } void FGSD_InputWindow::openFragment_cb() { if ( checkModified() ) { std::string curdir = generalPreferences.currentInputDirectory(); const char *fileName = flu_file_chooser( "Select a map fragment ...", "*.xml", curdir.c_str() ); if ( fileName ) { _window->cursor( FL_CURSOR_WAIT ); _input->make_current(); if ( _fragment ) delete _fragment; _fragment = new FGSD_MapFragment; _fragment->load( fileName ); curdir = FGSD_Util::getDirectoryFromFile( fileName ); generalPreferences.currentInputDirectory( curdir ); _vscroll->activate(); _hscroll->activate(); layout_(); _fragmentFileName = fileName; _modified = false; setTitle(); _window->cursor( FL_CURSOR_DEFAULT ); } } } void FGSD_InputWindow::save_cb(Fl_Widget *, void *v) { static_cast( v )->saveFragment( false ); } void FGSD_InputWindow::saveAs_cb(Fl_Widget *, void *v) { static_cast( v )->saveFragment( true ); } bool FGSD_InputWindow::saveFragment( bool __saveAs ) { bool ret = false; if ( _fragment ) { if ( _modifiedImage ) { const char *imageName = flu_file_chooser( "Save Imported Image", "*.jpg", _fragmentFileName.c_str() ); if ( imageName != 0 ) { _fragment->saveImage( imageName ); } } bool chosen = false; const char *fileName = 0; if ( __saveAs || _fragmentFileName.empty() ) { chosen = true; fileName = flu_file_chooser( "Save As", "*.xml", _fragmentFileName.c_str() ); } else { fileName = _fragmentFileName.c_str(); } if ( fileName ) { _fragment->save( fileName ); if ( chosen ) { _fragmentFileName = fileName; } _modified = false; setTitle(); ret = true; } } return ret; } void FGSD_InputWindow::removePoint_cb(Fl_Widget *, void *v) { static_cast( v )->removePoint_cb(); } void FGSD_InputWindow::removePoint_cb() { _fragment->removePointFromContour( *(MFCI *)_currentContourPos ); } void FGSD_InputWindow::hscroll_cb(Fl_Widget *, void *v) { static_cast( v )->hscroll_cb(); } void FGSD_InputWindow::hscroll_cb() { _posx = _hscroll->value() / _zLevel; _input->valid(0); _input->redraw(); } void FGSD_InputWindow::vscroll_cb(Fl_Widget *, void *v) { static_cast( v )->vscroll_cb(); } void FGSD_InputWindow::vscroll_cb() { double lv = _fragment->realHeight() * _zLevel; _posy = (int)( ( lv - _input->h() - _vscroll->value() ) / _zLevel ); _input->valid(0); _input->redraw(); } void FGSD_InputWindow::system_cb(Fl_Widget *o, void *v) { static_cast( v )->system_cb( o ); } void FGSD_InputWindow::system_cb( Fl_Widget *o ) { int v = ((Fl_Choice *)o)->value(); if ( v == 0 ) { _lon->label( "Longitude :" ); _lat->label( "Latitude :" ); } else { _lon->label( "Easting :\n( in meters )" ); _lat->label( "Northing :\n( in meters )" ); } if ( v == 7 ) { _zone->activate(); _hemi->activate(); _datum->activate(); } else { _zone->deactivate(); _hemi->deactivate(); _datum->deactivate(); } o->parent()->redraw(); } void FGSD_InputWindow::markok_cb(Fl_Widget *, void *v) { static_cast( v )->mark_cb( true ); } void FGSD_InputWindow::markcan_cb(Fl_Widget *, void *v) { static_cast( v )->mark_cb( false ); } void FGSD_InputWindow::mark_cb( bool ok ) { if ( ok ) { _markWindow->set_value(); } else { _markWindow->clear_value(); } _markWindow->hide(); } void FGSD_InputWindow::zoom_cb(Fl_Widget *, void *v) { static_cast( v )->zoom_cb(); } void FGSD_InputWindow::zoom_cb() { int visw = (int)( _visw * _zLevel ); int vish = (int)( _vish * _zLevel ); double xcent = _posx + _visw / 2; double ycent = _posy + _vish / 2; bool neg_ = false; int v = (int)_zoom->value(); if ( v < 0 ) { neg_ = true; v = -v; } _zLevel = 1 << v; if ( neg_ ) { _zLevel = 1 / _zLevel; } if ( _fragment ) { _visw = visw / _zLevel; _vish = vish / _zLevel; if ( _visw > _fragment->width() ) xcent = _fragment->width() / 2; if ( _vish > _fragment->height() ) ycent = _fragment->height() / 2; centerPosition( xcent, ycent ); } } void FGSD_InputWindow::rot_plus_cb(Fl_Widget *o, void *v) { static_cast( v )->rotation_cb( true ); } void FGSD_InputWindow::rot_minus_cb(Fl_Widget *o, void *v) { static_cast( v )->rotation_cb( false ); } void FGSD_InputWindow::rotation_cb( bool plus ) { if ( _fragment ) { _fragment->rotate( plus ); layout_(); _modified = true; } } void FGSD_InputWindow::centerPosition( double x, double y ) { double posx = x - _visw / 2; if ( _visw < _fragment->realWidth() ) { if ( posx + _visw > _fragment->realWidth() ) posx = _fragment->realWidth() - _visw; if ( posx < 0 ) posx = 0; } else { posx = ( _fragment->realWidth() - _visw ) / 2; } double posy = y - _vish / 2; if ( _vish < _fragment->realHeight() ) { if ( posy + _vish > _fragment->realHeight() ) posy = _fragment->realHeight() - _vish; if ( posy < 0 ) posy = 0; } else { posy = ( _fragment->realHeight() - _vish ) / 2; } _posx = posx; _posy = posy; double lv = _fragment->realHeight() * _zLevel; _vscroll->value( (int)( lv - _input->h() - _posy * _zLevel ), _input->h(), -5, (int)lv + 10 ); lv = _fragment->realWidth() * _zLevel; _hscroll->value( (int)( _posx * _zLevel ), _input->w(), -5, (int)lv + 10 ); _input->valid(0); _input->redraw(); } void FGSD_InputWindow::drawGL() { layout_(); glViewport( 0, 0, _input->w(), _input->h() ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); GLuint w_ = (GLuint)( _input->w() / zLevel() ); GLuint h_ = (GLuint)( _input->h() / zLevel() ); gluOrtho2D( _posx, _posx + _visw, _posy, _posy + _vish ); glClearColor( (GLfloat)0.3, (GLfloat)0.3, 0.0, 0.0 ); glClear( GL_COLOR_BUFFER_BIT ); if ( _fragment ) { _fragment->drawOrtho( zLevel() ); } } void FGSD_InputWindow::setTitle() { std::ostringstream str; str << "FlightGear Scenery Designer"; if ( _fragmentFileName.size() ) { std::string shortName = _fragmentFileName; size_t pos = _fragmentFileName.find_last_of( '/' ); if ( pos != std::string::npos ) shortName.erase( 0, pos + 1 ); std::string mod = ( _modified ? " *" : "" ); str << " - [" << shortName.c_str() << mod.c_str() << "]" << std::ends; } _windowTitle = str.str(); _window->label( _windowTitle.c_str() ); } void FGSD_InputWindow::setCursor( Fl_Cursor __cursor ) { _currentCursor = __cursor; _window->cursor( __cursor ); } void FGSD_InputWindow::gotoPosition( int px, int py, int x, int y ) { if ( px >= 0 && px < (int)_fragment->realWidth() && py >= 0 && py < (int)_fragment->realHeight() ) { double posx = px - ( _visw * x ) / _input->w(); if ( _visw < _fragment->realWidth() ) { if ( posx + _visw > _fragment->realWidth() ) posx = _fragment->realWidth() - _visw; if ( posx < 0 ) posx = 0; } else { posx = ( _fragment->realWidth() - _visw ) / 2; } double posy = py - ( _vish * ( _input->h() - y ) ) / _input->h(); if ( _vish < _fragment->realHeight() ) { if ( posy + _vish > _fragment->realHeight() ) posy = _fragment->realHeight() - _vish; if ( posy < 0 ) posy = 0; } else { posy = ( _fragment->realHeight() - _vish ) / 2; } _posx = posx; _posy = posy; double lv = _fragment->realHeight() * _zLevel; _vscroll->value( (int)( lv - _input->h() - _posy * _zLevel ), _input->h(), -5, (int)lv + 10 ); lv = _fragment->realWidth() * _zLevel; _hscroll->value( (int)( _posx * _zLevel ), _input->w(), -5, (int)lv + 10 ); _input->valid(0); _input->redraw(); } } void FGSD_InputWindow::clearFragment( bool __clear ) { if ( __clear && _fragment ) { delete _fragment; } _fragment = 0; _fragmentFileName = ""; setTitle(); _vscroll->deactivate(); _hscroll->deactivate(); } bool FGSD_InputWindow::computeFetchParameters( int &xstart, int &ystart, int &xrange, int &yrange, int &zone, int &scale, double &size ) { bool error = false; double lon = FGSD_Util::parsePosition( _flon->value(), error ), lat; if ( !error ) { lat = FGSD_Util::parsePosition( _flat->value(), error ); } if ( !error ) { double utm_x, utm_y; error = !FGSD_Util::getUTMPosition( FGSD_Util::D_NAD83, utm_x, utm_y, zone, lat, lon ); if ( !error ) { std::istringstream istr( _xradius->value() ); long xradius = 0; istr >> xradius; if ( xradius == 0 ) { error = true; } else { istr.clear(); istr.str( _yradius->value() ); long yradius = 0; istr >> yradius; if ( yradius == 0 ) { yradius = xradius; } const Fl_Menu_Item *l = _resolution->mvalue(); computeFetchParameters( l, utm_x, utm_y, xradius, yradius, xstart, ystart, xrange, yrange, scale, size ); } } } return error; } void FGSD_InputWindow::computeFetchParameters( const Fl_Menu_Item *l, double utm_x, double utm_y, int xradius, int yradius, int &xstart, int &ystart, int &xrange, int &yrange, int &scale, double &size ) { double rx = xradius; double ry = yradius; size = ((_terra_data *)l->user_data())->size; double minx = utm_x - rx, miny = utm_y - ry, maxx = utm_x + rx, maxy = utm_y + ry; xstart = (int)floor( minx / size ); ystart = (int)floor( miny / size ); int dxmax = (int)ceil( maxx / size ); int dymax = (int)ceil( maxy / size ); xrange = ( dxmax - xstart ); yrange = ( dymax - ystart ); scale = ((_terra_data *)l->user_data())->scale; } void FGSD_InputWindow::checkValid() { bool error = false; double lon = FGSD_Util::parsePosition( _flon->value(), error ), lat; if ( !error ) { lat = FGSD_Util::parsePosition( _flat->value(), error ); } if ( !error ) { double utm_x, utm_y; int zone; error = !FGSD_Util::getUTMPosition( FGSD_Util::D_NAD83, utm_x, utm_y, zone, lat, lon ); if ( !error ) { std::istringstream istr( _xradius->value() ); long xradius = 0; istr >> xradius; if ( xradius == 0 ) { error = true; } else { istr.clear(); istr.str( _yradius->value() ); long yradius = 0; istr >> yradius; if ( yradius == 0 ) { yradius = xradius; } const Fl_Menu_Item *l = _resolution->mvalue(); int xstart, ystart, xrange, yrange, scale; double size; computeFetchParameters( l, utm_x, utm_y, xradius, yradius, xstart, ystart, xrange, yrange, scale, size ); std::ostringstream ostr; ostr << ( xrange * 200 ); _xsize->value( ostr.str().c_str() ); ostr.str( "" ); ostr << ( yrange * 200 ); _ysize->value( ostr.str().c_str() ); ostr.str( "" ); double w = double( xrange ) * double( yrange ) * 40000.0; size_t i = 0; while ( w >= 1024.0 ) { w /= 1024.0; if ( units[i+1] == 0 ) { break; } i += 1; } if ( i > 1 ) { int dw = int( w * 100 ); w = double( dw ) / 100.0; ostr << w << " " << units[i]; } else { int dw = int( w ); ostr << dw << " " << units[i]; } _weight->value( ostr.str().c_str() ); } } } if ( !error ) { _fetchOk->activate(); } else { _fetchOk->deactivate(); } } void FGSD_InputWindow::xradiusChange_cb(Fl_Widget *o, void *v) { static_cast( v )->xradiusChange_cb(); } void FGSD_InputWindow::xradiusChange_cb() { const char *rx = _xradius->value(); const char *ry = _yradius->value(); if ( !_yradiusChanged ) { _yradius->value( rx ); } checkValid(); } void FGSD_InputWindow::yradiusChange_cb(Fl_Widget *o, void *v) { static_cast( v )->yradiusChange_cb(); } void FGSD_InputWindow::yradiusChange_cb() { const char *rx = _xradius->value(); const char *ry = _yradius->value(); if ( ry == 0 || ry[0] == '\0' || strcmp( rx, ry ) == 0 ) { _yradiusChanged = false; } else { _yradiusChanged = true; } checkValid(); } void FGSD_InputWindow::checkFetch_cb(Fl_Widget *o, void *v) { static_cast( v )->checkValid(); } void FGSD_InputWindow::fetchok_cb(Fl_Widget *o, void *v) { static_cast( v )->fetch_cb( true ); } void FGSD_InputWindow::fetchcan_cb(Fl_Widget *o, void *v) { static_cast( v )->fetch_cb( false ); } void FGSD_InputWindow::fetch_cb( bool ok ) { if ( ok ) { _fetchWindow->set_value(); } else { _fetchWindow->clear_value(); } _fetchDialogRequested = false; _fetchWindow->hide(); } size_t FGSD_InputWindow::writeFetchData( void *buffer, size_t size, size_t nmemb, void *userp ) { FGSD_InputWindow *w = static_cast( userp ); w->fetchStream.write( (char *)buffer, size * nmemb ); w->file_size += size * nmemb; return nmemb; } void FGSD_InputWindow::openFetchDialog( double lon, double lat ) { _fetchDialogRequested = true; _lonRequested = lon; _latRequested = lat; } void FGSD_InputWindow::differed_fetch( void* v ) { static_cast( v )->fetchTerraserverUsa_cb(); } void FGSD_InputWindow::show( /* int argc, char **argv */ ) { if ( _window ) { _window->show( /* argc, argv */ ); } if ( _fetchDialogRequested ) { Fl::add_timeout( 0.2, differed_fetch, this ); } } void FGSD_InputWindow::cancelFetch_cb(Fl_Widget *o, void *v) { static_cast( v )->cancelFetch_cb(); } void FGSD_InputWindow::cancelFetch_cb() { _fetchCancelled = true; }