Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

mapalgorithms.cpp

Go to the documentation of this file.
00001 
00005 /***************************************************************************
00006                           mapalgorithms.cpp  -  description
00007                              -------------------
00008     begin                : Thu Oct 5 2000
00009     copyright            : (C) 2000 by Martin Bickel
00010     email                : bickel@asc-hq.org
00011  ***************************************************************************/
00012 
00013 /***************************************************************************
00014  *                                                                         *
00015  *   This program is free software; you can redistribute it and/or modify  *
00016  *   it under the terms of the GNU General Public License as published by  *
00017  *   the Free Software Foundation; either version 2 of the License, or     *
00018  *   (at your option) any later version.                                   *
00019  *                                                                         *
00020  ***************************************************************************/
00021 
00022 #include <math.h>
00023 #include "mapalgorithms.h"
00024 #include "typen.h"
00025 #include "vehicletype.h"
00026 #include "errors.h"
00027 #include "gamemap.h"
00028 
00029 
00030 tdrawgettempline :: tdrawgettempline ( int _freefields, GameMap* _gamemap )
00031 {
00032    gamemap = _gamemap;
00033    tempsum = 0;
00034    freefields = _freefields;
00035    num = 0;
00036 }
00037 
00038 void tdrawgettempline :: putpix8 ( int x, int y )
00039 {
00040    if ( !gamemap->getField ( x, y ) )
00041       return;
00042    
00043    if ( num >= freefields )
00044       tempsum += gamemap->getField ( x, y )->getjamming();
00045    num++;
00046    /*
00047                            getfield( x,y )->temp = 100;
00048                            displaymap();
00049                            cursor.gotoxy ( x , y );
00050                                                    */
00051 }
00052 
00053 int tdrawgettempline :: winkelcomp ( double w1, double w2 )
00054 {
00055    double pi = 3.141592654;
00056    double delta = w2 - w1;
00057    if ( delta > -0.0001 && delta < 0.0001 )
00058       return 0;
00059 
00060    if ( delta > 0 ) {
00061       if ( delta <= pi )
00062          return 1;
00063       else
00064          return -1;
00065    }
00066 
00067    if ( delta < 0 ) {
00068       if ( delta < -pi )
00069          return 1;
00070       else
00071          return -1;
00072    }
00073 
00074    return 0;
00075 }
00076 
00077 
00078 int tdrawgettempline :: initialized = 0;
00079 double tdrawgettempline :: dirs[ sidenum ];
00080 double tdrawgettempline :: offset;
00081 
00082 void tdrawgettempline :: init ( void )
00083 {
00084    if ( !initialized ) {
00085       offset = 0;
00086       sx = 10;
00087       sy = 10;
00088       int i;
00089 
00090       for ( i = 0; i < sidenum; i++ ) {
00091          sx = 10;
00092          sy = 10;
00093          getnextfield ( sx, sy, i );
00094          dirs[i] = winkel ( 10, 10 );
00095       }
00096       offset = dirs[0];
00097 
00098       for ( i = 0; i < sidenum; i++ ) {
00099          sx = 10;
00100          sy = 10;
00101          getnextfield ( sx, sy, i );
00102          dirs[i] = winkel ( 10, 10 );
00103       }
00104 
00105       initialized = 1;
00106    }
00107 }
00108 
00109 
00110 double tdrawgettempline :: winkel ( int x, int y )
00111 {
00112    int xp2 = sx * fielddistx + (sy & 1) * fielddisthalfx;
00113    int yp2 = sy * fielddisty;
00114 
00115    int xp1 = x * fielddistx + (y & 1) * fielddisthalfx;
00116    int yp1 = y * fielddisty;
00117 
00118    int dx = xp2-xp1;
00119    int dy = yp2-yp1;
00120    double at = atan2 ( double(dy), double(dx) );
00121    // printf("%d / %d / %f \n", dx, dy, at);
00122    at -= offset;
00123    while ( at < 0 )
00124       at += 2 * 3.14159265;
00125 
00126    // printf("%f \n", at);
00127    return at;
00128 }
00129 
00130 #define checkvisibility
00131 
00132 void tdrawgettempline :: start ( int x1, int y1, int x2, int y2 )
00133 {
00134    init();
00135 
00136    sx = x2;
00137    sy = y2;
00138 
00139    if ( y1 == y2  && x1 == x2 )
00140       return;
00141 
00142    int x = x1;
00143    int y = y1;
00144 
00145    double w = winkel ( x1, y1 );
00146 
00147    int dir = -1;
00148    double mindiff = 10000;
00149    for ( int i = 0; i < sidenum; i++ ) {
00150       double nd = fabs ( dirs[i] - w );
00151       if ( nd < mindiff ) {
00152          dir = i;
00153          mindiff = nd;
00154       }
00155    }
00156 
00157 #ifdef checkvisibility
00158    int ldist = beeline ( x1, y1, x2, y2 );
00159 #endif
00160 
00161    int lastdir = winkelcomp ( w, dirs[dir] );
00162    /*
00163       if ( x1 == 18 && y1 == 24 && x2 == 18 && y2 == 9 ) {
00164          printf("blurb");
00165       }
00166    */
00167 
00168    getnextfield( x, y, dir );
00169    while ( x != x2 || y != y2 ) {
00170 #ifdef checkvisibility
00171       int ldist2 = beeline ( x, y, x2, y2 );
00172       if ( ldist2 > ldist ) {
00173          fatalError ( "inconsistency in tdrawgettempline :: start ; parameters are %d/%d ; %d/%d ", 1, x1, y1, x2, y2 );
00174          return;
00175       }
00176 #endif
00177 
00178       putpix8 ( x, y );
00179       double w2 = winkel ( x, y );
00180       // printf("%f \n", w2);
00181       if ( lastdir > 0 ) {
00182          if ( winkelcomp ( w2,  w ) == 1 ) {
00183             dir--;
00184             lastdir = -1;
00185          }
00186       } else {
00187          if ( winkelcomp ( w2 , w ) == -1 ) {
00188             dir++;
00189             lastdir = 1;
00190          }
00191       }
00192       if ( dir < 0 )
00193          dir += sidenum;
00194 
00195       if ( dir >= sidenum )
00196          dir = dir % sidenum;
00197 
00198       getnextfield ( x, y, dir );
00199    }
00200    putpix8 ( x, y );
00201 }
00202 
00203 
00204 
00205 
00206 
00207 
00208 SearchFields :: SearchFields ( GameMap* _gamemap )
00209 {
00210    gamemap = _gamemap;
00211    cancelSearch = false;
00212 }
00213 
00214 void         SearchFields::initsearch( const MapCoordinate& startPosition, int _firstDistance, int _lastDistance )
00215 {
00216    cancelSearch = false;
00217    startPos = startPosition;
00218    firstDistance = _firstDistance;
00219    lastDistance = _lastDistance;
00220 }
00221 
00222 
00223 
00224 void         SearchFields::startsearch(void)
00225 {
00226    if ( cancelSearch )
00227       return;
00228 
00229    int   step;
00230 
00231    if (firstDistance > lastDistance)
00232       step = -1;
00233    else
00234       step = 1;
00235 
00236    dist = firstDistance;
00237 
00238    do {
00239       MapCoordinate mc ( startPos.x, startPos.y - 2 * dist );
00240       if ( dist == 0 ) {
00241          if ((mc.x >= 0) && (mc.y >= 0) && (mc.x < gamemap->xsize) && (mc.y < gamemap->ysize))
00242             testfield( mc );
00243 
00244          if ( cancelSearch )
00245             return;
00246 
00247       } else {
00248          for ( int e = 0; e < 6; e++ ) {
00249             int dir = (e + 2) % sidenum;
00250             for ( int c = 0; c < dist; c++) {
00251                if ((mc.x >= 0) && (mc.y >= 0) && (mc.x < gamemap->xsize) && (mc.y < gamemap->ysize)) {
00252                   testfield( mc );
00253                   if ( cancelSearch )
00254                      return;
00255                }
00256                getnextfield ( mc.x, mc.y, dir );
00257             }
00258 
00259          }
00260       }
00261 
00262       dist += step;
00263 
00264    }  while (!((dist - step == lastDistance) || cancelSearch));
00265 }
00266 
00267 
00268 class SearchFieldsIterator : public SearchFields {
00269    public:
00270       typedef FieldIterationFunctor MyFunctor;
00271    private:   
00272       MyFunctor& myFunctor;
00273    protected:
00274       void testfield ( const MapCoordinate& pos ) {
00275          myFunctor(pos);
00276       };      
00277    public: 
00278       SearchFieldsIterator ( GameMap* _gamemap, MyFunctor& functor ) : SearchFields( _gamemap ), myFunctor( functor ) {};
00279            
00280 };
00281 
00282 void circularFieldIterator( GameMap* gamemap, const MapCoordinate& center, int startDist, int stopDist, FieldIterationFunctor functor )
00283 {
00284    SearchFieldsIterator searchFields( gamemap, functor );
00285    searchFields.initsearch( center, startDist, stopDist );
00286    searchFields.startsearch();      
00287 }
00288 
00289 
00290 int         ccmpheighchangemovedir[6]  = {0, 1, 5, 2, 4, 3 };
00291 
00292 
00293 MapCoordinate3D getNeighbouringFieldCoordinate( const MapCoordinate3D& pos, int direc)
00294 {
00295   MapCoordinate3D mc = pos;
00296   getnextfield ( mc.x, mc.y, direc );
00297   return mc;
00298 }
00299 
00300 MapCoordinate getNeighbouringFieldCoordinate( const MapCoordinate& pos, int direc)
00301 {
00302   MapCoordinate mc = pos;
00303   getnextfield ( mc.x, mc.y, direc );
00304   return mc;
00305 }
00306 
00307 
00308 void         getnextfield(int&       x,
00309                           int&       y,
00310                           int       direc)
00311 {
00312    switch (direc) {
00313 
00314       case 0:
00315          y-=2   ;                      /*  oben  */
00316          break;
00317 
00318       case 1:
00319          if ((y & 1) == 1) x+=1;        /*  rechts oben  */
00320          y-=1;
00321          break;
00322 
00323       case 2:
00324          if ((y & 1) == 1) x+=1;        /*  rechts unten  */
00325          y+=1;
00326          break;
00327 
00328       case 3:
00329          y+=2;                          /*  unten  */
00330          break;
00331 
00332       case 4:
00333          if ((y & 1) == 0) x-=1;        /*  links unten  */
00334          y+=1;
00335          break;
00336 
00337       case 5:
00338          if ((y & 1) == 0) x-=1;        /*  links oben  */
00339          y-=1;
00340          break;
00341 
00342    }
00343 }
00344 
00345 
00346 int getdirection( const MapCoordinate& start, const MapCoordinate& dest )
00347 {
00348    return getdirection(start.x, start.y, dest.x, dest.y );
00349 }
00350 
00351 int          getdirection(    int      x1,
00352                               int      y1,
00353                               int      x2,
00354                               int      y2)
00355 {
00356    int a;
00357    int dx = (2 * x2 + (y2 & 1)) - (2 * x1 + (y1 & 1));
00358    int dy = y2 - y1;
00359 
00360    if (dx < 0)
00361       if (dy < 0)
00362          a = 5;
00363       else
00364          a = 4;
00365    else
00366       if (dx > 0)
00367          if (dy < 0)
00368             a = 1;
00369          else
00370             a = 2;
00371       else  // dx is 0
00372          if (dy < 0)
00373             a = 0;
00374          else
00375             if ( dy > 0 )
00376                a = 3;
00377             else
00378                a = -1;
00379    return a;
00380 }
00381 
00382 
00383 int beeline ( const Vehicle* a, const Vehicle* b )
00384 {
00385    return beeline ( a->xpos, a->ypos, b->xpos, b->ypos );
00386 }
00387 
00388 int beeline ( const MapCoordinate& a, const MapCoordinate& b )
00389 {
00390    return beeline ( a.x, a.y, b.x, b.y );
00391 }
00392 
00393 
00394 int beeline ( int x1, int y1, int x2, int y2 )
00395 {
00396    int xdist = abs ( (x1 * 2 + (y1 & 1 )) - ( x2 * 2 + ( y2 & 1)) );
00397    int ydist = abs ( y2 - y1 );
00398    int num2;
00399    if ( ydist > xdist )
00400       num2 = (ydist - xdist) / 2 + xdist;
00401    else
00402       num2 = max ( xdist, ydist );
00403 /*
00404    int num = 0;
00405    while ( x1 != x2  || y1 != y2 ) {
00406       num++;
00407       getnextfield ( x1, y1, getdirection ( x1, y1, x2, y2 ));
00408    }
00409 
00410    if ( num != num2 )
00411       printf("beeline inconsistent\n" );
00412 */
00413    return minmalq*num2;
00414 }
00415 
00416 
00417 int square ( int i )
00418 {
00419    return i*i;
00420 }
00421 
00422 inline float square ( float i )
00423 {
00424    return i*i;
00425 }
00426 
00427 
00428 WindMovement::WindMovement ( const Vehicle* vehicle )
00429 {
00430    for ( int i = 0; i < sidenum; i++ )
00431       wm[i] = 0;
00432 
00433    int movement = 0;
00434    for ( int height = 4; height <= 6; height++ ){
00435       if ( vehicle->typ->movement[height] )
00436          if ( vehicle->typ->movement[height] > movement )
00437             movement = vehicle->typ->movement[height];
00438    }
00439 
00440    if ( movement ) {
00441       int wmn[7];
00442       
00443       int lastDir = 0;
00444       
00445       float abswindspeed = float( vehicle->getMap()->weather.windSpeed) * maxwindspeed / 255;
00446       
00447       for ( float direc = 0; direc < 360; direc++) {
00448          static const float pi = 3.14159265;
00449          float unitspeedx = movement * sin(direc/180*pi);
00450          float unitspeedy = movement * cos(direc/180*pi);
00451 
00452          float angle = atan2( unitspeedx, unitspeedy + abswindspeed );
00453          if ( angle < 0 )
00454             angle += 2 * pi;
00455 
00456          if ( angle >= 60 * float(lastDir) * (2*pi) / 360 ) {
00457             float absspeed = sqrt ( square ( unitspeedy + abswindspeed)+ square ( unitspeedx) );
00458             wmn[lastDir] = int( 10 - 10*movement/absspeed );
00459             ++lastDir;
00460          }
00461       }
00462             
00463       
00464       for ( int i = 0; i <= 3; i++ ) {
00465          wm[(i+vehicle->getMap()->weather.windDirection)%6] = wmn[i];
00466          if ( i > 0 )
00467             wm[(6-i+vehicle->getMap()->weather.windDirection)%6] = wmn[i];
00468       }
00469    }
00470 }
00471 
00472 
00473 
00474 int WindMovement::getDist ( int dir )
00475 {
00476    assert( dir >= 0 && dir <= 5 );
00477    return wm[dir];
00478 }
00479 
00480 
00481 /*
00482 Wenn Du Wind aus Westen hast und willst nach norden fliegen, dann darf der Flieger nicht Kurs auf Norden nehmen, denn dann wrde er abgetrieben. Er muss stattdessen etwas gegen den Wind fliegen. 
00483 
00484 Diesen Winkel ermittel' ich durch plumpes ausprobieren, in WindMovement::WindMovement
00485 
00486 Solange die Sollrichtung der Einheitenbewegung und die WindRichtungen bereinstimmen, brauche ich nur den Fall fr 1 Windrichtung berechnen. Ich ermittel' dann fr die 6 Einheitenrichtungen den Malus. Fr andere Windrichtungen verschiebe ich einfach nur die Werte in die Tabelle (die letzten beiden Anweisungen in WindMovement), da das entscheidende ja nur der Winkelunterschied zwischen Wind- und Sollbewegungsrichtung ist.
00487 */
00488 

Generated on Tue Jun 24 01:27:44 2008 for Advanced Strategic Command by  doxygen 1.4.2