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

bestway.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  This program is free software; you can redistribute it and/or
00004  modify it under the terms of the GNU General Public License
00005  as published by the Free Software Foundation; either version 2
00006  of the License, or (at your option) any later version.
00007 
00008  This program is distributed in the hope that it will be useful,
00009  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  GNU General Public License for more details.
00012 
00013  You should have received a copy of the GNU General Public License
00014  along with this program; if not, write to the Free Software
00015  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00016  ***************************************************************************/
00017 
00018 // this is used by two classes
00019 $aHashCache = array();
00020 
00026 Class BestWay
00027 {
00028     var $aHashCache = array();      
00029     var $dblMinAufwand;             
00030     var $aTerrainPoints = array();  
00031 
00036     function BestWay ( &$aTerrainPoints )
00037     {
00038         global $aHashCache;
00039         $this->aTerrainPoints =& $aTerrainPoints;
00040         $this->aHashCache =& $aHashCache;
00041         $this->dblMinAufwand = 4 / 1.3;
00042     }
00043 
00060     function calcWay( $sx, $sy, $ex, $ey, $mapdata, $booDebug=false )
00061     {
00062         // hilfsarray zur einfachen nachbar bestimmung
00063         $nachbarn = array();
00064         for ( $i =- 1; $i < 2; $i++ )
00065         {
00066             for ( $j = -1; $j < 2; $j++ )
00067             {
00068                 if ( ( $i != 0 ) || ( $j != 0 ) )
00069                 {
00070                     $nachbarn[] = array( $i, $j );
00071                 }
00072             }
00073         }
00074         $result = array();
00075         // liste der offenen und geschlossenen knoten
00076         $aOpen   = array();
00077         $aClosed = array();
00078         // wurzel anlegen und in die open liste
00079         $actKey = $this->getHashKey ( $sx, $sy );
00080         $aOpen[$actKey] = new Node( $sx, $sy, 0, $this->getEST($sx, $sy, $ex, $ey), $sx, $sy );
00081         // solange nicht der zielknoten erreicht wurde
00082         while ( $aOpen[$actKey]->est > 0 )
00083         {
00084             // akt. knoten aus open loeschen und nach closed schieben
00085             $aClosed[$actKey] =& $aOpen[$actKey];
00086             unset( $aOpen[$actKey] );
00087             // alle nachbarn berechnen
00088             for ( $i = 0; $i < 8; $i++ )
00089             {
00090                 $tx = $aClosed[$actKey]->x + $nachbarn[$i][0];
00091                 $ty = $aClosed[$actKey]->y + $nachbarn[$i][1];
00092                 $nextKey = $this->getHashKey( $tx, $ty );
00093                 // akt. aufwand um an dieses feld zu gelangen
00094                 if ( isset ( $mapdata[$tx][$ty]['terrain'] ) )
00095                 {
00096                     $effort = $this->aTerrainPoints[$mapdata[$tx][$ty]['terrain']];
00097                     // falls eine strasse dabei ist, 30% weniger aufwand
00098                     if ( $mapdata[$tx][$ty]['street'] > 0 )
00099                     {
00100                         $effort /= 1.3;
00101                     }
00102                 }
00103                 else
00104                 {
00105                     // falls keine daten vorhanden, nehmen wir an es ist etwas besser
00106                     // als wasser
00107                     $effort = 90;
00108                 }
00109                 // vorherigen aufwand dazu addieren
00110                 $effort += $aClosed[$actKey]->effort;
00111                 if ( isset( $aOpen[$nextKey] ) )
00112                 {
00113                     // knoten existiert schon in der open list
00114                     // wenn aufwand besser, dann werte und vorgaenger anpassen
00115                     if ( $effort < $aOpen[$nextKey]->effort )
00116                     {
00117                         $aOpen[$nextKey]->effort= $effort;
00118                         $aOpen[$nextKey]->calc();
00119                         $aOpen[$nextKey]->prevKey= $actKey;
00120                     }
00121                 }
00122                 elseif ( isset ( $aClosed[$nextKey] ) )
00123                 {
00124                     // knoten ist bereits geschlossen
00125                     // wenn aufwand besser, dann werte und vorgaenger anpassen
00126                     // und zurueck nach open schieben
00127                     if ( $effort < $aClosed[$nextKey]->effort )
00128                     {
00129                         $aOpen[$nextKey] = $aClosed[$nextKey];
00130                         unset( $aClosed[$nextKey] );
00131                         $aOpen[$nextKey]->effort = $effort;
00132                         $aOpen[$nextKey]->calc();
00133                         $aOpen[$nextKey]->prevKey = $actKey;
00134                     }
00135                 }
00136                 else
00137                 {
00138                     // neuen Knoten anlegen
00139                     $aOpen[$nextKey] = new Node( $tx, $ty, $effort,
00140                                                 $this->getEST( $tx, $ty, $ex, $ey ) - ( ( $nachbarn[$i][0] == 0 || $nachbarn[$i][1] == 0 ) ? 0.001 : 0),
00141                                                 $aClosed[$actKey]->x, $aClosed[$actKey]->y );
00142                 }
00143                 if ( $booDebug )
00144                 {
00145                     echo $tx.'/'.$ty.'='.$effort.' est='.$this->getEST($tx,$ty,$ex,$ey).'<br />';
00146                 }
00147             }
00148             $minVal = 99999;
00149             // besten knoten aus open liste suchen
00150             foreach( $aOpen as $oNode )
00151             {
00152                 if ( $oNode->sum < $minVal )
00153                 {
00154                     $minVal = $oNode->sum;
00155                     $actKey = $oNode->hashKey;
00156                 }
00157             }
00158             if ( $booDebug )
00159             {
00160                 $aOpen[$actKey]->dump();
00161                 echo '<br />';
00162             }
00163         }
00164         // letzten key nach closed
00165         $aClosed[$actKey] = $aOpen[$actKey];
00166         $effort = $aClosed[$actKey]->effort;
00167         $text = $actKey;
00168         // vom endpunkt zurueck zum startpunk und ins result schreiben.
00169         while ( $aClosed[$actKey]->x != $sx || $aClosed[$actKey]->y != $sy )
00170         {
00171             //$aClosed[$actKey]->dump();
00172             $result[$aClosed[$actKey]->x][$aClosed[$actKey]->y] = 1;
00173             $actKey = $aClosed[$actKey]->prevKey;
00174             $text = $actKey.",".$text;
00175         }
00176         $text = $this->getWdsWayScript($text);
00177         return ( array($result,$effort,$text) );
00178     }
00179 
00186     function getHashKey( $x, $y )
00187     {
00188         if ( !isset($this->aHashCache[$x][$y] ) )
00189         {
00190             $this->aHashCache[$x][$y] = sprintf ( "%4d/%4d", $x, $y );
00191         }
00192         return( $this->aHashCache[$x][$y] );
00193     }
00194 
00202     function getEST( $intStartX, $intStartY, $intEndX, $intEndY )
00203     {
00204         // x und y abstand
00205         $intXDif = abs( $intStartX - $intEndX );
00206         $intYDif = abs( $intStartY - $intEndY );
00207         return ( $this->dblMinAufwand * max ( $intXDif, $intYDif ) );
00208     }
00209 
00214     function getWdsWayScript ( $strText )
00215     {
00216         //Mapping   (X)(Y) Change
00217         $aWaymapping [0][0]   = '';
00218         $aWaymapping [-1][1]  = 1;
00219         $aWaymapping [0][1]   = 2;
00220         $aWaymapping [1][1]   = 3;
00221         $aWaymapping [1][0]   = 6;
00222         $aWaymapping [1][-1]  = 9;
00223         $aWaymapping [0][-1]  = 8;
00224         $aWaymapping [-1][-1] = 7;
00225         $aWaymapping [-1][0]  = 4;
00226 
00227         $strWay = '';
00228         $aCoordlist = explode ( ',', $strText );
00229 
00230         //First Coordinate
00231         $aPrevCoord = explode ( '/', $aCoordlist[0] );
00232         $aPrevCoord[1] = trim ( $aPrevCoord[1] );
00233 
00234         //Begin with Second Coord for Way creation
00235         for ( $i = 1; $i < count($aCoordlist); $i++ )
00236         {
00237             //Load Coordinate
00238             $aCoord = explode ( '/', $aCoordlist[$i] );
00239             $aCoord[1] = trim ( $aCoord[1] );
00240 
00241             //Get Change of Coordinate
00242             $intXDiff = $aCoord[0] - $aPrevCoord[0];
00243             $intYDiff = $aCoord[1] - $aPrevCoord[1];
00244 
00245             //Add To Way
00246             $strWay .= $aWaymapping[$intXDiff][$intYDiff];
00247 
00248             //Set current Coordinate as Previous
00249             $aPrevCoord = $aCoord;
00250         }
00251 
00252         return $strWay;
00253     }
00254 }
00255 
00263 class Node
00264 {
00265     var $hashKey;   
00266     var $prevKey;   
00267     var $x, $y;
00268     var $effort;    
00269     var $est;       
00270     var $sum;       
00271     var $aHashCache;
00272 
00273     function Node( $x, $y, $effort, $est, $px, $py )
00274     {
00275         global $aHashCache;
00276         $this->aHashCache =& $aHashCache;
00277         $this->hashKey = $this->getHashKey( $x, $y);
00278         $this->prevKey = $this->getHashKey( $px, $py);
00279         $this->x = $x;
00280         $this->y = $y;
00281         $this->effort = $effort;
00282         $this->est = $est;
00283         $this->calc();
00284     }
00285 
00286     function calc()
00287     {
00288         $this->sum = $this->effort + $this->est;
00289     }
00290 
00294     function dump()
00295     {
00296         printf( " Node: '%s' Prev: '%s' effort=%4.4f EST=%4.4f sum= %4.4f<br /> ", $this->hashKey, $this->prevKey, $this->effort, $this->est, $this->sum );
00297     }
00298 
00305     function getHashKey( $x, $y )
00306     {
00307         if ( !isset($this->aHashCache[$x][$y] ) )
00308         {
00309             $this->aHashCache[$x][$y] = sprintf ( "%4d/%4d", $x, $y );
00310         }
00311         return( $this->aHashCache[$x][$y] );
00312     }
00313 }

Generated on Sun May 8 19:29:44 2005 for PhpMap by  doxygen 1.4.2