// mapfragment.cpp -- map fragment // // 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: mapfragment.cpp,v 1.12 2005/05/09 07:02:08 fredb Exp $ #ifdef _MSC_VER #pragma warning( disable : 4786 4800 4503 4101 ) #define strcasecmp stricmp #endif #include #include #include #include #include "mapfragment.hpp" #include "sdutil.hpp" #include "jpgimage.hpp" #include "pngimage.hpp" #include "rgbimage.hpp" #include "fragtri.hpp" #include #include "mire.c" template T min3( T a, T b, T c ) { return a < b ? ( a < c ? a : c ) : ( b < c ? b : c ); } const size_t FGSD_MapFragment::TEX_SIZE = 256; GLuint FGSD_MapFragment::_markerName = 0; bool FGSD_MapFragment::_markerInit = false; FGSD_MapFragment::FGSD_MapFragment() : _imageFileName( "" ) , _textures( 0 ) , _orientation( 0 ) , _nx( 0 ) , _bx( 0 ) , _ny( 0 ) , _by( 0 ) , _nbMarkers( 0 ) , _tri( *new FGSD_MapTriangulation ) { unselectEdge(); } FGSD_MapFragment::~FGSD_MapFragment() { cleanTextures(); delete &_tri; } void FGSD_MapFragment::drawOrtho( double __zLevel ) const { glEnable( GL_TEXTURE_2D ); glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); if ( _orientation == 0 ) { drawOrthoMap_0( __zLevel ); } else if ( _orientation == 90 ) { drawOrthoMap_90( __zLevel ); } else if ( _orientation == 180 ) { drawOrthoMap_180( __zLevel ); } else if ( _orientation == 270 ) { drawOrthoMap_270( __zLevel ); } glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBegin( GL_TRIANGLES ); for ( CT::Finite_faces_iterator fi = _tri.finite_faces_begin(); fi != _tri.finite_faces_end(); ++fi ) { if ( fi->inside == 0 ) { glColor4d( 0, 0, 0, 0.5 ); } else if ( fi->inside == -2 ) { glColor4d( 1, 0, 0, 1 ); } if ( fi->inside == 0 || fi->inside == -2 ) { for ( size_t i = 0; i < 3; i++ ) { CT::Vertex_handle v = fi->vertex( i ); CT::Point p = v->point(); #if CGAL_VERSION_NR <= 1003000100 double px = p.x().to_double(); double py = p.y().to_double(); #else double px = p.x(); double py = p.y(); #endif glVertex2d( transformX( px, py ), transformY( px, py ) ); } } } glEnd(); #ifdef _DEBUG glColor4d( 0, 0, 0, 1 ); glLineWidth( 1.0 ); glBegin( GL_LINES ); for ( CT::Finite_edges_iterator ei = _tri.finite_edges_begin(); ei != _tri.finite_edges_end(); ++ei ) { CT::Point &p1 = ei->first->vertex( _tri.ccw( ei->second ) )->point(), &p2 = ei->first->vertex( _tri.cw( ei->second ) )->point(); glVertex2d( transformX( p1.x(), p1.y() ), transformY( p1.x(), p1.y() ) ); glVertex2d( transformX( p2.x(), p2.y() ), transformY( p2.x(), p2.y() ) ); } glEnd(); #endif if ( _nbMarkers ) { glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); glBindTexture( GL_TEXTURE_2D, _markerName ); double markerHalfSize = 16 / __zLevel; glColor4f( 0.0, 1.0, 0.0, 1.0 ); for ( size_t i = 0; i < _nbMarkers; i++ ) { double x1 = _markers[ i ].x() - markerHalfSize, y1 = _markers[ i ].y() - markerHalfSize, x2 = _markers[ i ].x() - markerHalfSize, y2 = _markers[ i ].y() + markerHalfSize, x3 = _markers[ i ].x() + markerHalfSize, y3 = _markers[ i ].y() + markerHalfSize, x4 = _markers[ i ].x() + markerHalfSize, y4 = _markers[ i ].y() - markerHalfSize; glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( transformX( x1, y1 ), transformY( x1, y1 ) ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( transformX( x2, y2 ), transformY( x2, y2 ) ); glTexCoord2d( 1.0, 1.0 ); glVertex2d( transformX( x3, y3 ), transformY( x3, y3 ) ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( transformX( x4, y4 ), transformY( x4, y4 ) ); glEnd(); } } glDisable( GL_BLEND ); glDisable( GL_TEXTURE_2D ); drawContour(); } void FGSD_MapFragment::drawOrthoMap_0( double __zLevel ) const { size_t nx = _nx; if ( _bx != TEX_SIZE ) nx -= 1; size_t ny = _ny; if ( _by != TEX_SIZE ) ny -= 1; double texSize = (double)TEX_SIZE; for ( size_t i = 0; i < nx; i++ ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( i * texSize, j * texSize ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( i * texSize, texSize + j * texSize ); glTexCoord2d( 1.0, 1.0 ); glVertex2d( texSize + i * texSize, texSize + j * texSize ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( texSize + i * texSize, j * texSize ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( i * texSize, ny * texSize ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( i * texSize, _by + ny * texSize ); glTexCoord2d( 1.0, _by / texSize ); glVertex2d( texSize + i * texSize, _by + ny * texSize ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( texSize + i * texSize, ny * texSize ); glEnd(); } } if ( _bx != TEX_SIZE ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( nx * texSize, j * texSize ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( nx * texSize, texSize + j * texSize ); glTexCoord2d( _bx / texSize, 1.0 ); glVertex2d( _bx + nx * texSize, texSize + j * texSize ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( _bx + nx * texSize, j * texSize ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( nx * texSize, ny * texSize ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( nx * texSize, _by + ny * texSize ); glTexCoord2d( _bx / texSize, _by / texSize ); glVertex2d( _bx + nx * texSize, _by + ny * texSize ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( _bx + nx * texSize, ny * texSize ); glEnd(); } } } void FGSD_MapFragment::drawOrthoMap_90( double __zLevel ) const { size_t h = height(); size_t nx = _nx; if ( _bx != TEX_SIZE ) nx -= 1; size_t ny = _ny; if ( _by != TEX_SIZE ) ny -= 1; double texSize = (double)TEX_SIZE; for ( size_t i = 0; i < nx; i++ ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( h - ( j * texSize ), i * texSize ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( h - ( texSize + j * texSize ), i * texSize ); glTexCoord2d( 1.0, 1.0 ); glVertex2d( h - ( texSize + j * texSize ), texSize + i * texSize ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( h - ( j * texSize ), texSize + i * texSize ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( h - ( ny * texSize ), i * texSize ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( h - ( _by + ny * texSize ), i * texSize ); glTexCoord2d( 1.0, _by / texSize ); glVertex2d( h - ( _by + ny * texSize ), texSize + i * texSize ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( h - ( ny * texSize ), texSize + i * texSize ); glEnd(); } } if ( _bx != TEX_SIZE ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( h - ( j * texSize ), nx * texSize ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( h - ( texSize + j * texSize ), nx * texSize ); glTexCoord2d( _bx / texSize, 1.0 ); glVertex2d( h - ( texSize + j * texSize ), _bx + nx * texSize ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( h - ( j * texSize ), _bx + nx * texSize ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( h - ( ny * texSize ), nx * texSize ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( h - ( _by + ny * texSize ), nx * texSize ); glTexCoord2d( _bx / texSize, _by / texSize ); glVertex2d( h - ( _by + ny * texSize ), _bx + nx * texSize ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( h - ( ny * texSize ), _bx + nx * texSize ); glEnd(); } } } void FGSD_MapFragment::drawOrthoMap_180( double __zLevel ) const { size_t w = width(), h = height(); size_t nx = _nx; if ( _bx != TEX_SIZE ) nx -= 1; size_t ny = _ny; if ( _by != TEX_SIZE ) ny -= 1; double texSize = (double)TEX_SIZE; for ( size_t i = 0; i < nx; i++ ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( w - ( i * texSize ), h - ( j * texSize ) ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( w - ( i * texSize ), h - ( texSize + j * texSize ) ); glTexCoord2d( 1.0, 1.0 ); glVertex2d( w - ( texSize + i * texSize ), h - ( texSize + j * texSize ) ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( w - ( texSize + i * texSize ), h - ( j * texSize ) ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( w - ( i * texSize ), h - ( ny * texSize ) ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( w - ( i * texSize ), h - ( _by + ny * texSize ) ); glTexCoord2d( 1.0, _by / texSize ); glVertex2d( w - ( texSize + i * texSize ), h - ( _by + ny * texSize ) ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( w - ( texSize + i * texSize ), h - ( ny * texSize ) ); glEnd(); } } if ( _bx != TEX_SIZE ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( w - ( nx * texSize ), h - ( j * texSize ) ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( w - ( nx * texSize ), h - ( texSize + j * texSize ) ); glTexCoord2d( _bx / texSize, 1.0 ); glVertex2d( w - ( _bx + nx * texSize ), h - ( texSize + j * texSize ) ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( w - ( _bx + nx * texSize ), h - ( j * texSize ) ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( w - ( nx * texSize ), h - ( ny * texSize ) ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( w - ( nx * texSize ), h - ( _by + ny * texSize ) ); glTexCoord2d( _bx / texSize, _by / texSize ); glVertex2d( w - ( _bx + nx * texSize ), h - ( _by + ny * texSize ) ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( w - ( _bx + nx * texSize ), h - ( ny * texSize ) ); glEnd(); } } } void FGSD_MapFragment::drawOrthoMap_270( double __zLevel ) const { size_t w = width(); size_t nx = _nx; if ( _bx != TEX_SIZE ) nx -= 1; size_t ny = _ny; if ( _by != TEX_SIZE ) ny -= 1; double texSize = (double)TEX_SIZE; for ( size_t i = 0; i < nx; i++ ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( j * texSize, w - ( i * texSize ) ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( texSize + j * texSize, w - ( i * texSize ) ); glTexCoord2d( 1.0, 1.0 ); glVertex2d( texSize + j * texSize, w - ( texSize + i * texSize ) ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( j * texSize, w - ( texSize + i * texSize ) ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + i ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( ny * texSize, w - ( i * texSize ) ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( _by + ny * texSize, w - ( i * texSize ) ); glTexCoord2d( 1.0, _by / texSize ); glVertex2d( _by + ny * texSize, w - ( texSize + i * texSize ) ); glTexCoord2d( 1.0, 0.0 ); glVertex2d( ny * texSize, w - ( texSize + i * texSize ) ); glEnd(); } } if ( _bx != TEX_SIZE ) { for ( size_t j = 0; j < ny; j++ ) { glBindTexture( GL_TEXTURE_2D, _textures[ j * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( j * texSize, w - ( nx * texSize ) ); glTexCoord2d( 0.0, 1.0 ); glVertex2d( texSize + j * texSize, w - ( nx * texSize ) ); glTexCoord2d( _bx / texSize, 1.0 ); glVertex2d( texSize + j * texSize, w - ( _bx + nx * texSize ) ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( j * texSize, w - ( _bx + nx * texSize ) ); glEnd(); } if ( _by != TEX_SIZE ) { glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + nx ]->texName() ); glBegin( GL_QUADS ); glTexCoord2d( 0.0, 0.0 ); glVertex2d( ny * texSize, w - ( nx * texSize ) ); glTexCoord2d( 0.0, _by / texSize ); glVertex2d( _by + ny * texSize, w - ( nx * texSize ) ); glTexCoord2d( _bx / texSize, _by / texSize ); glVertex2d( _by + ny * texSize, w - ( _bx + nx * texSize ) ); glTexCoord2d( _bx / texSize, 0.0 ); glVertex2d( ny * texSize, w - ( _bx + nx * texSize ) ); glEnd(); } } } void FGSD_MapFragment::drawTransformed( double xm, double ym, double xM, double yM ) const { glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); double texSize = (double)TEX_SIZE; double x_0 = _markers[ 0 ].x(); double y_0 = _markers[ 0 ].y(); for ( CT::Finite_faces_iterator fi = _tri.finite_faces_begin(); fi != _tri.finite_faces_end(); ++fi ) { if ( fi->inside == 1 ) { #if CGAL_VERSION_NR <= 1003000100 double x0 = fi->vertex( 0 )->point().x().to_double(); double y0 = fi->vertex( 0 )->point().y().to_double(); double x1 = fi->vertex( 1 )->point().x().to_double(); double y1 = fi->vertex( 1 )->point().y().to_double(); double x2 = fi->vertex( 2 )->point().x().to_double(); double y2 = fi->vertex( 2 )->point().y().to_double(); #else double x0 = fi->vertex( 0 )->point().x(); double y0 = fi->vertex( 0 )->point().y(); double x1 = fi->vertex( 1 )->point().x(); double y1 = fi->vertex( 1 )->point().y(); double x2 = fi->vertex( 2 )->point().x(); double y2 = fi->vertex( 2 )->point().y(); #endif double a0 = _ma * ( x0 - x_0 ) + _mc * ( y0 - y_0 ) + _tx; double minx = a0, maxx = a0; double b0 = _mb * ( x0 - x_0 ) + _md * ( y0 - y_0 ) + _ty; double miny = b0, maxy = b0; double a1 = _ma * ( x1 - x_0 ) + _mc * ( y1 - y_0 ) + _tx; if ( minx > a1 ) minx = a1; if ( maxx < a1 ) maxx = a1; double b1 = _mb * ( x1 - x_0 ) + _md * ( y1 - y_0 ) + _ty; if ( miny > b1 ) miny = b1; if ( maxy < b1 ) maxy = b1; double a2 = _ma * ( x2 - x_0 ) + _mc * ( y2 - y_0 ) + _tx; if ( minx > a2 ) minx = a2; if ( maxx < a2 ) maxx = a2; double b2 = _mb * ( x2 - x_0 ) + _md * ( y2 - y_0 ) + _ty; if ( miny > b2 ) miny = b2; if ( maxy < b2 ) maxy = b2; if ( xM > minx && xm < maxx && yM > miny && ym < maxy ) { int nx = int( x0 + x1 + x2 ) / 3, ny = int( y0 + y1 + y2 ) / 3; nx /= TEX_SIZE; ny /= TEX_SIZE; glBindTexture( GL_TEXTURE_2D, _textures[ ny * _nx + nx ]->texName() ); nx *= TEX_SIZE; ny *= TEX_SIZE; glBegin( GL_TRIANGLES ); glTexCoord2d( ( x0 - nx ) / texSize, ( y0 - ny ) / texSize ); glVertex2d( a0, b0 ); glTexCoord2d( ( x1 - nx ) / texSize, ( y1 - ny ) / texSize ); glVertex2d( a1, b1 ); glTexCoord2d( ( x2 - nx ) / texSize, ( y2 - ny ) / texSize ); glVertex2d( a2, b2 ); glEnd(); } } } } void FGSD_MapFragment::drawOutline() const { double x0 = _markers[ 0 ].x(); double y0 = _markers[ 0 ].y(); glBegin( GL_LINE_LOOP ); for ( Contour::const_iterator it = _contour.begin(); it != _contour.end(); ++it ) { double x = _ma * ( it->x - x0 ) + _mc * ( it->y - y0 ) + _tx, y = _mb * ( it->x - x0 ) + _md * ( it->y - y0 ) + _ty; glVertex2d( x, y ); } glEnd(); } double FGSD_MapFragment::transformX( double x, double y ) const { double ret; if ( _orientation == 0 ) { ret = x; } else if ( _orientation == 90 ) { ret = height() - y; } else if ( _orientation == 180 ) { ret = width() - x; } else { ret = y; } return ret; } double FGSD_MapFragment::transformY( double x, double y ) const { double ret; if ( _orientation == 0 ) { ret = y; } else if ( _orientation == 90 ) { ret = x; } else if ( _orientation == 180 ) { ret = height() - y; } else { ret = width() - x; } return ret; } void FGSD_MapFragment::drawContour() const { glColor4f( 1, 0, 1, 1 ); glLineWidth( 3.0 ); glBegin( GL_LINE_LOOP ); for ( Contour::const_iterator it = _contour.begin(); it != _contour.end(); ++it ) { glVertex2d( transformX( it->x, it->y ), transformY( it->x, it->y ) ); } glEnd(); glPointSize( 7.0 ); glBegin( GL_POINTS ); for ( Contour::const_iterator it = _contour.begin(); it != _contour.end(); ++it ) { glVertex2d( transformX( it->x, it->y ), transformY( it->x, it->y ) ); } glEnd(); if ( _edgeSelected != _contour.end() ) { Contour::const_iterator it = _edgeSelected; if ( _edgeSelected == _contour.begin() ) { it = --_contour.end(); } else { --it; } glColor4f( 0, 1, 1, 1 ); glBegin( GL_LINES ); glVertex2d( transformX( it->x, it->y ), transformY( it->x, it->y ) ); glVertex2d( transformX( _edgeSelected->x, _edgeSelected->y ), transformY( _edgeSelected->x, _edgeSelected->y ) ); glEnd(); } } void FGSD_MapFragment::boundingBox( double &x1, double &y1, double &x2, double &y2 ) const { double x0 = _markers[ 0 ].x(); double y0 = _markers[ 0 ].y(); double a1 = _ma * ( 0 - x0 ) + _mc * ( 0 - y0 ) + _tx; double b1 = _mb * ( 0 - x0 ) + _md * ( 0 - y0 ) + _ty; double a2 = _ma * ( 0 - x0 ) + _mc * ( height() - y0 ) + _tx; double b2 = _mb * ( 0 - x0 ) + _md * ( height() - y0 ) + _ty; double a3 = _ma * ( width() - x0 ) + _mc * ( 0 - y0 ) + _tx; double b3 = _mb * ( width() - x0 ) + _md * ( 0 - y0 ) + _ty; double a4 = _ma * ( width() - x0 ) + _mc * ( height() - y0 ) + _tx; double b4 = _mb * ( width() - x0 ) + _md * ( height() - y0 ) + _ty; x1 = a1; if ( a2 < x1 ) x1 = a2; if ( a3 < x1 ) x1 = a3; if ( a4 < x1 ) x1 = a4; y1 = b1; if ( b2 < y1 ) y1 = b2; if ( b3 < y1 ) y1 = b3; if ( b4 < y1 ) y1 = b4; x2 = a1; if ( a2 > x2 ) x2 = a2; if ( a3 > x2 ) x2 = a3; if ( a4 > x2 ) x2 = a4; y2 = b1; if ( b2 > y2 ) y2 = b2; if ( b3 > y2 ) y2 = b3; if ( b4 > y2 ) y2 = b4; } bool FGSD_MapFragment::isOver( double x, double y ) const { double x_0 = _markers[ 0 ].x(); double y_0 = _markers[ 0 ].y(); double det = _ma * _md - _mb * _mc; double a = -( _md * ( _tx - x ) - _mc * ( _ty - y ) - det * x_0 ) / det, b = ( _mb * ( _tx - x ) - _ma * ( _ty - y ) + det * y_0 ) / det; CT::Face_handle f = _tri.locate( CT::Point( a, b ) ); return f->inside == 1; } void FGSD_MapFragment::cleanTextures() { if ( _textures ) { FGSD_TexImage **tex = _textures; _textures = 0; for ( size_t i = 0; i < _nx; i++ ) for ( size_t j = 0; j < _ny; j++ ) delete tex[ j * _nx + i ]; delete[] tex; } } void FGSD_MapFragment::loadImage( const char *__fileName ) { initTextures(); cleanTextures(); if ( __fileName ) { _imageFileName = __fileName; } FGSD_Image *image = 0; size_t l = _imageFileName.size(); if ( l > 4 && strcasecmp( _imageFileName.substr( l - 4 ).c_str(), ".jpg" ) == 0 ) { image = new FGSD_JPEGImage( true ); } else if ( l > 4 && strcasecmp( _imageFileName.substr( l - 4 ).c_str(), ".png" ) == 0 ) { image = new FGSD_PNGImage( true ); } image->load( _imageFileName.c_str() ); _nx = ( image->width() - 1 ) / TEX_SIZE + 1; _bx = TEX_SIZE - (_nx * TEX_SIZE - image->width()); _ny = ( image->height() - 1 ) / TEX_SIZE + 1; _by = TEX_SIZE - (_ny * TEX_SIZE - image->height()); _textures = new FGSD_TexImage *[ _nx * _ny ]; for ( size_t i = 0; i < _nx; i++ ) { for ( size_t j = 0; j < _ny; j++ ) { _textures[ j * _nx + i ] = new FGSD_TexImage( image, 3, TEX_SIZE, i, j ); } } delete image; } void FGSD_MapFragment::addMarker( const FGSD_Marker &mark ) { if ( _nbMarkers < 4 ) { size_t n = _nbMarkers++; setMarker( n, mark ); } } void FGSD_MapFragment::setMarker( size_t n, const FGSD_Marker &mark ) { if ( n < _nbMarkers ) { _markers[ n ] = mark; } } int FGSD_MapFragment::markerHitTest( double x, double y, double r ) { int ret = -1; for ( size_t i = 0; i < _nbMarkers; i++ ) { if ( _markers[ i ].hittest( x, y, r ) ) { ret = i; break; } } return ret; } void FGSD_MapFragment::initTextures() { if ( !_markerInit ) { glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glGenTextures( 1, &_markerName ); glBindTexture( GL_TEXTURE_2D, _markerName ); GLenum error = glGetError(); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, gimp_image.width, gimp_image.height, 0, /*gimp_image.bytes_per_pixel == 3 ? GL_RGB :*/ GL_RGBA, GL_UNSIGNED_BYTE, gimp_image.pixel_data ); _markerInit = true; } } void FGSD_MapFragment::load( const char *__fileName ) { SGPropertyNode root; readProperties( __fileName, &root ); SGPropertyNode *pnode = root.getChild( "path" ); if ( pnode ) { loadImage( pnode->getStringValue() ); } else { pnode = root.getChild( "relpath" ); std::string path = FGSD_Util::buildAbsolutePath( __fileName, pnode->getStringValue() ); loadImage( path.c_str() ); } if ( pnode ) { int i = 0; std::vector marks = root.getChildren( "marker" ); for ( std::vector::iterator im = marks.begin(); im != marks.end(); ++im ) { SGPropertyNode_ptr mnode = *im; FGSD_Marker marker; marker.restoreFrom( mnode ); _markers[ i++ ] = marker; } _nbMarkers = i; if ( _nbMarkers == 3 ) { initMatrix(); } SGPropertyNode *pnode = root.getChild( "contour" ); if ( pnode ) { std::vector points = pnode->getChildren( "point" ); for ( std::vector::iterator ip = points.begin(); ip != points.end(); ++ip ) { SGPropertyNode_ptr mnode = *ip; _contour.push_back( Point( mnode->getDoubleValue( "x" ), mnode->getDoubleValue( "y" ) ) ); } } else { initContour(); } _orientation = root.getIntValue( "orientation", 0 ); _fileName = __fileName; } refreshTesselation( false ); } void FGSD_MapFragment::save( const char *__fileName ) { SGPropertyNode root; bool rel; std::string path = FGSD_Util::buildRelativePath( __fileName, _imageFileName.c_str(), rel ); SGPropertyNode *pnode = 0; if ( rel ) { pnode = root.getChild( "relpath", 0, true ); } else { pnode = root.getChild( "path", 0, true ); } pnode->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); pnode->setStringValue( path.c_str() ); pnode = root.getChild( "orientation", 0, true ); pnode->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); pnode->setIntValue( _orientation ); for ( size_t i = 0; i < _nbMarkers; i++ ) { SGPropertyNode *mnode = root.getChild( "marker", i, true ); _markers[ i ].saveAs( mnode ); } if ( _contour.size() ) { pnode = root.getChild( "contour", 0, true ); pnode->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); size_t i = 0; for ( Contour::const_iterator it = _contour.begin(); it != _contour.end(); ++it ) { SGPropertyNode *mnode = pnode->getChild( "point", i, true ); mnode->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); SGPropertyNode *node = mnode->getChild( "x", 0, true ); node->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); node->setDoubleValue( it->x ); node = mnode->getChild( "y", 0, true ); node->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); node->setDoubleValue( it->y ); i++; } } writeProperties( __fileName, &root ); _fileName = __fileName; } bool FGSD_MapFragment::initMatrix() { bool ret = false; if ( _nbMarkers == 3 ) { double w = _markers[ 1 ].x() - _markers[ 0 ].x(); double x = _markers[ 1 ].y() - _markers[ 0 ].y(); double y = _markers[ 2 ].x() - _markers[ 0 ].x(); double z = _markers[ 2 ].y() - _markers[ 0 ].y(); double denom = z * w - x * y; if ( fabs( denom ) > 0.000000001 ) { double lon0, lat0; _markers[ 0 ].getWGS84Position( lon0, lat0 ); double lon1, lat1; _markers[ 1 ].getWGS84Position( lon1, lat1 ); double lon2, lat2; _markers[ 2 ].getWGS84Position( lon2, lat2 ); double s = lon1 - lon0; double t = lat1 - lat0; double u = lon2 - lon0; double v = lat2 - lat0; _ma = ( s * z - u * x ) / denom; _mb = ( t * z - x * v ) / denom; _mc = ( u * w - s * y ) / denom; _md = ( w * v - t * y ) / denom; _tx = lon0; _ty = lat0; ret = true; } } return ret; } void FGSD_MapFragment::initContour() { _contour.push_back( Point( 0, 0 ) ); _contour.push_back( Point( width(), 0 ) ); _contour.push_back( Point( width(), height() ) ); _contour.push_back( Point( 0, height() ) ); } static bool insideContour( FGSD_MapTriangulation &_tri, CT::Face_handle f, int i, const std::list &cHandles ) { CT::Vertex_handle va = f->vertex( _tri.ccw( i ) ), vb = f->vertex( _tri.cw( i ) ); for ( CT::Context_iterator ci = _tri.contexts_begin( va, vb ); ci != _tri.contexts_end( va, vb ); ++ci ) { std::list::const_iterator it = std::find( cHandles.begin(), cHandles.end(), *ci->vertices_begin() ), it2; if ( it != cHandles.end() ) { it2 = it; ++it2; if ( it2 == cHandles.end() ) { it2 = cHandles.begin(); } CT::Vertex_handle v = *( --ci->vertices_end() ); if ( v == *it2 ) { return true; } else { it2 = it; if ( it2 == cHandles.begin() ) { it2 = --cHandles.end(); } else { --it2; } if ( v == *it2 ) { return true; } } } } return false; } void FGSD_MapFragment::refreshTesselation( bool grid ) { _tri.clear(); size_t i, w = width(), h = height(); _tri.insert( CT::Point( 0, 0 ) ); _tri.insert( CT::Point( w, 0 ) ); _tri.insert( CT::Point( w, h ) ); _tri.insert( CT::Point( 0, h ) ); std::list contourHandles; CT::Vertex_handle v0, v1; for ( Contour::const_iterator ci = _contour.begin(); ci != _contour.end(); ++ci ) { CT::Vertex_handle v = _tri.insert( CT::Point( ci->x, ci->y ) ); if ( v0 == CT::Vertex_handle() ) { v0 = v; } if ( v1 != CT::Vertex_handle() ) { _tri.insert( v1, v ); } v1 = v; contourHandles.push_back( v ); } _tri.insert( v1, v0 ); if ( grid ) { for ( i = 0; i < w; i += TEX_SIZE ) { CT::Vertex_handle v1 = _tri.insert( CT::Point( i, 0 ) ), v2 = _tri.insert( CT::Point( i, h ) ); _tri.insert( v1, v2 ); } if ( i != w ) { CT::Vertex_handle v1 = _tri.insert( CT::Point( w, 0 ) ), v2 = _tri.insert( CT::Point( w, h ) ); _tri.insert( v1, v2 ); } for ( i = 0; i < h; i += TEX_SIZE ) { CT::Vertex_handle v1 = _tri.insert( CT::Point( 0, i ) ), v2 = _tri.insert( CT::Point( w, i ) ); _tri.insert( v1, v2 ); } if ( i != h ) { CT::Vertex_handle v1 = _tri.insert( CT::Point( 0, h ) ), v2 = _tri.insert( CT::Point( w, h ) ); _tri.insert( v1, v2 ); } } std::list faceQ; CT::Face_circulator fc = _tri.incident_faces( _tri.infinite_vertex() ), done( fc ); if ( fc != 0 ) { do { fc->inside = 0; faceQ.push_back( fc ); } while ( ++fc != done ); } while ( !faceQ.empty() ) { CT::Face_handle f = faceQ.front(); faceQ.pop_front(); for ( size_t i = 0; i < 3; i++ ) { CT::Face_handle n = f->neighbor( i ); if ( n->inside == -2 ) { n->inside = -1; faceQ.push_back( n ); } else if ( f->inside == -1 && n->inside >= 0 ) { if ( f->is_constrained( i ) && insideContour( _tri, f, i, contourHandles ) ) { f->inside = 1 - n->inside; } else { f->inside = n->inside; } } } } } bool FGSD_MapFragment::hitContour( double x, double y, double zLevel, Contour::iterator &pos, bool &edge ) { double scale = 8.0 / zLevel; double minx = x - scale; double miny = y - scale; double maxx = x + scale; double maxy = y + scale; bool ret = false; pos = _contour.end(); Point p1( x, y ); Point p0 = _contour.back(); for ( Contour::iterator pi = _contour.begin(); pi != _contour.end(); ++pi ) { Point &p = *pi; if ( minx <= p.x && p.x < maxx && miny <= p.y && p.y < maxy ) { pos = pi; edge = false; ret = true; break; } else { K::Vector_2 v0( p.x - p0.x, p.y - p0.y ); #if CGAL_VERSION_NR <= 1003000100 double l0 = v0.squared_length().to_double(); K::Vector_2 v( p1.x - p0.x, p1.y - p0.y ); double a = ( v0.x().to_double() * v.x().to_double() + v0.y().to_double() * v.y().to_double() ) / l0; double b = ( v0.x().to_double() * v.y().to_double() - v0.y().to_double() * v.x().to_double() ) / l0; #else double l0 = v0.squared_length(); K::Vector_2 v( p1.x - p0.x, p1.y - p0.y ); double a = ( v0.x() * v.x() + v0.y() * v.y() ) / l0; double b = ( v0.x() * v.y() - v0.y() * v.x() ) / l0; #endif if ( a >= 0 && a < 1 && fabs( b ) < 0.002 ) { pos = pi; edge = true; ret = true; break; } } p0 = p; } return ret; } static bool checkForCrossingSegments( const FGSD_MapFragment::Point &A, const FGSD_MapFragment::Point &B, FGSD_MapFragment::Contour &_contour, FGSD_MapFragment::Contour::const_iterator moving ) { bool ret = true; FGSD_MapFragment::Point V = B - A; double AyVx = A.y * V.x; double AxVy = A.x * V.y; FGSD_MapFragment::Contour::const_iterator pi = _contour.begin(); FGSD_MapFragment::Contour::const_iterator opi = --_contour.end(); for ( ; ret && pi != _contour.end(); opi = pi++ ) { if ( pi != moving && opi != moving ) { FGSD_MapFragment::Point C = *opi; FGSD_MapFragment::Point W = *pi - 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; } void FGSD_MapFragment::changeContourPointPosition( Contour::iterator pos, double x, double y ) { if ( pos != _contour.end() ) { if ( x < 0 ) x = 0; if ( x > width() ) x = width(); if ( y < 0 ) y = 0; if ( y > height() ) y = height(); Point A( x, y ); Contour::const_iterator prev = pos; if ( prev == _contour.begin() ) { prev = --_contour.end(); } else { --prev; } Contour::const_iterator next = pos; ++next; if ( next == _contour.end() ) { next = _contour.begin(); } bool ok = checkForCrossingSegments( A, *prev, _contour, pos ) && checkForCrossingSegments( A, *next, _contour, pos ); if ( ok ) { *pos = A; refreshTesselation( false ); } } } bool FGSD_MapFragment::insertPointToContour( double x, double y ) { bool ret = false; if ( _edgeSelected != _contour.end() && x >= 0 && x < width() && y >= 0 && y < height() ) { Point A( x, y ); Contour::const_iterator prev = _edgeSelected; if ( _edgeSelected == _contour.begin() ) { prev = --_contour.end(); } else { --prev; } ret = checkForCrossingSegments( A, *prev, _contour, _contour.end() ) && checkForCrossingSegments( A, *_edgeSelected, _contour, _contour.end() ); if ( ret ) { _contour.insert( _edgeSelected, Point( x, y ) ); refreshTesselation( false ); } } return ret; } bool FGSD_MapFragment::removePointFromContour( Contour::iterator pos ) { bool ret; if ( _contour.size() > 3 ) { Contour::const_iterator prev = pos; if ( prev == _contour.begin() ) { prev = --_contour.end(); } else { --prev; } Contour::const_iterator next = pos; ++next; if ( next == _contour.end() ) { next = _contour.begin(); } if ( checkForCrossingSegments( *prev, *next, _contour, pos ) ) { _contour.erase( pos ); refreshTesselation( false ); ret = true; } } return ret; } void FGSD_MapFragment::rotate( bool plus ) { _orientation += ( plus ? 90 : -90 ); if ( _orientation < 0 ) { _orientation += 360; } if ( _orientation >= 360 ) { _orientation -= 360; } } void FGSD_MapFragment::createDummyImage( int width, int height ) { initTextures(); cleanTextures(); _imageFileName = ""; FGSD_Image *image = new FGSD_Image; image->allocImage( width, height, 3 ); unsigned char *buffer = image->buffer(); for ( int i = 0; i < width; i++ ) { int x = i / 16; for ( int j = 0; j < height; j++ ) { int y = j / 16; buffer[ ( j * width + i ) * 3 ] = 0xFF; if ( ( x + y ) & 1 ) { buffer[ ( j * width + i ) * 3 + 1 ] = 0xFF; buffer[ ( j * width + i ) * 3 + 2 ] = 0xFF; } else { buffer[ ( j * width + i ) * 3 + 1 ] = 0; buffer[ ( j * width + i ) * 3 + 2 ] = 0; } } } _nx = ( image->width() - 1 ) / TEX_SIZE + 1; _bx = TEX_SIZE - (_nx * TEX_SIZE - image->width()); _ny = ( image->height() - 1 ) / TEX_SIZE + 1; _by = TEX_SIZE - (_ny * TEX_SIZE - image->height()); _textures = new FGSD_TexImage *[ _nx * _ny ]; for ( size_t i = 0; i < _nx; i++ ) { for ( size_t j = 0; j < _ny; j++ ) { _textures[ j * _nx + i ] = new FGSD_TexImage( image, 3, TEX_SIZE, i, j ); } } delete image; } void FGSD_MapFragment::putSubImage( FGSD_Image *image, int x, int y ) { int w = image->width(); int h = image->height(); int d = image->depth(); unsigned char *b = image->buffer(); int i = x; while ( i < x + w ) { int ni = i / TEX_SIZE; int di = ( ni + 1 ) * TEX_SIZE; if ( di > x + w ) { di = x + w; } int j = y; while ( j < y + h ) { int nj = j / TEX_SIZE; int dj = ( nj + 1 ) * TEX_SIZE; if ( dj > y + h ) { dj = y + h; } unsigned char *buffer = new unsigned char[ ( di - i ) * ( dj - j ) * 3 ]; for ( int k = 0; k < ( di - i ); k++ ) { for ( int l = 0; l < ( dj - j ); l++ ) { int m = i - x + k; int n = h - ( j - y + l + 1 ); unsigned char red, green, blue; if ( d == 3 ) { red = b[ ( n * w + m ) * 3 + 0 ]; green = b[ ( n * w + m ) * 3 + 1 ]; blue = b[ ( n * w + m ) * 3 + 2 ]; } else if ( d == 1 ) { red = green = blue = b[ n * w + m ]; } else if ( d == 4 ) { red = b[ ( n * w + m ) * 4 + 0 ]; green = b[ ( n * w + m ) * 4 + 1 ]; blue = b[ ( n * w + m ) * 4 + 2 ]; } else if ( d == 2 ) { red = green = blue = b[ ( n * w + m ) * 2 ]; } buffer[ ( l * ( di - i ) + k ) * 3 + 0 ] = red; buffer[ ( l * ( di - i ) + k ) * 3 + 1 ] = green; buffer[ ( l * ( di - i ) + k ) * 3 + 2 ] = blue; } } FGSD_TexImage *tex = _textures[ nj * _nx + ni ]; glBindTexture( GL_TEXTURE_2D, tex->texName() ); glTexSubImage2D( GL_TEXTURE_2D, 0, i % TEX_SIZE, j % TEX_SIZE, di - i, dj - j, GL_RGB, GL_UNSIGNED_BYTE, buffer ); delete[] buffer; j = dj; } i = di; } } void FGSD_MapFragment::retrieveTexture( unsigned char *buffer, int w, unsigned char *tmp, size_t i, size_t j, size_t lines, size_t columns ) { FGSD_TexImage *tex = _textures[ j * _nx + i ]; glBindTexture( GL_TEXTURE_2D, tex->texName() ); glGetTexImage( GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp ); for ( size_t k = 0; k < lines; k++ ) { memcpy( &buffer[ ( ( j * TEX_SIZE + k ) * w + ( i * TEX_SIZE ) ) * 3 ], &tmp[ k * TEX_SIZE * 3 ], columns * 3 ); } } void FGSD_MapFragment::saveImage( const char *__fileName ) { int w = ( _nx * TEX_SIZE ) - ( TEX_SIZE - _bx ); int h = ( _ny * TEX_SIZE ) - ( TEX_SIZE - _by ); FGSD_JPEGImage image( true ); image.allocImage( w, h ); unsigned char *buffer = image.buffer(); unsigned char *tmp = new unsigned char[ TEX_SIZE * TEX_SIZE * 3 ]; size_t nx = _nx; if ( _bx != TEX_SIZE ) nx -= 1; size_t ny = _ny; if ( _by != TEX_SIZE ) ny -= 1; for ( size_t i = 0; i < nx; i++ ) { for ( size_t j = 0; j < ny; j++ ) { retrieveTexture( buffer, w, tmp, i, j, TEX_SIZE, TEX_SIZE ); } if ( _by != TEX_SIZE ) { retrieveTexture( buffer, w, tmp, i, ny, _by, TEX_SIZE ); } } if ( _bx != TEX_SIZE ) { for ( size_t j = 0; j < ny; j++ ) { retrieveTexture( buffer, w, tmp, nx, j, TEX_SIZE, _bx ); } if ( _by != TEX_SIZE ) { retrieveTexture( buffer, w, tmp, nx, ny, _by, _bx ); } } delete tmp; if ( __fileName ) { _imageFileName = __fileName; } image.save( __fileName ); }