/**
* Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP).
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package net.ctdp.rfdynhud.util;
import java.util.Arrays;
import java.util.Comparator;
import net.ctdp.rfdynhud.gamedata.ScoringInfo;
import net.ctdp.rfdynhud.gamedata.VehicleScoringInfo;
public class MapTools
{
private static final class LapDistanceComparator implements Comparator<VehicleScoringInfo>
{
private VehicleScoringInfo viewedVSI = null;
private float trackLength = 0f;
@Override
public int compare( VehicleScoringInfo vsi1, VehicleScoringInfo vsi2 )
{
float ld0 = viewedVSI.getLapDistance();
float ld1 = vsi1.getLapDistance();
float ld2 = vsi2.getLapDistance();
float d1, d2;
if ( ld1 > ld0 )
d1 = Math.min( ld1 - ld0, trackLength - ld1 + ld0 );
else
d1 = Math.min( ld0 - ld1, trackLength - ld0 + ld1 );
if ( ld2 > ld0 )
d2 = Math.min( ld2 - ld0, trackLength - ld2 + ld0 );
else
d2 = Math.min( ld0 - ld2, trackLength - ld0 + ld2 );
if ( d1 < d2 )
return ( -1 );
if ( d1 > d2 )
return ( +1 );
return ( 0 );
}
}
private static final LapDistanceComparator LAP_DISTANCE_COMPARATOR = new LapDistanceComparator();
private static final boolean vsiConsumed( VehicleScoringInfo vsi, VehicleScoringInfo viewedVSI, boolean useClassScoring, boolean forceLeaderDisplayed )
{
if ( vsi.equals( viewedVSI ) )
{
// already consumed above
}
else if ( vsi.equals( viewedVSI.getNextInFront( useClassScoring ) ) )
{
// already consumed above
}
else if ( vsi.equals( viewedVSI.getNextBehind( useClassScoring ) ) )
{
// already consumed above
}
else if ( forceLeaderDisplayed && ( vsi.getPlace( useClassScoring ) == 1 ) && ( !useClassScoring || ( vsi.getVehicleClassId() == viewedVSI.getVehicleClassId() ) ) )
{
// already consumed above
}
else// if ( /*!vsi.isInPits() &&*/ ( vsi.getFinishStatus().isNone() || vsi.getFinishStatus().isFinished() ) )
{
return ( false );
}
return ( true );
}
private static final boolean finishStatusOk( final VehicleScoringInfo vsi )
{
return ( vsi.getFinishStatus().isNone() || vsi.getFinishStatus().isFinished() );
}
/*
private static int getDisplayedVSIsForMap_all( ScoringInfo scoringInfo, VehicleScoringInfo viewedVSI, boolean forceLeaderDisplayed, VehicleScoringInfo[] target )
{
final short ownPlace = viewedVSI.getPlace( false );
int n = Math.min( scoringInfo.getNumVehicles(), target.length );
int result = n;
int i0 = Math.max( 0, ownPlace - (int)Math.ceil( ( n + 1 ) / 2f ) );
//int i1 = Math.min( i0 + n - 1, n - 1 );
int i1 = i0 + n - 1;
target[--n] = viewedVSI;
VehicleScoringInfo nif = viewedVSI.getNextInFront( false );
if ( nif != null )
{
target[--n] = nif;
}
VehicleScoringInfo nb = viewedVSI.getNextBehind( false );
if ( nb != null )
{
target[--n] = nb;
}
if ( ( ownPlace > 1 ) && ( ( i0 == 0 ) || forceLeaderDisplayed ) )
{
target[--n] = scoringInfo.getLeadersVehicleScoringInfo();
if ( i0 == 0 )
i0++;
}
int n2 = Math.max( ( ownPlace - 1 ) - i0, i1 - ( ownPlace - 1 ) );
for ( int i = 0; i < n2; i++ )
{
int j = ownPlace - 1 - i - 1;
if ( ( n > 0 ) && ( j >= i0 ) )
{
VehicleScoringInfo vsi = scoringInfo.getVehicleScoringInfo( j );
if ( !vsiConsumed( vsi, viewedVSI, false ) )
{
target[--n] = vsi;
}
}
j = ownPlace - 1 + i + 1;
if ( ( n > 0 ) && ( j <= i1 ) )
{
VehicleScoringInfo vsi = scoringInfo.getVehicleScoringInfo( j );
if ( !vsiConsumed( vsi, viewedVSI, false ) )
{
target[--n] = vsi;
}
}
}
// Should never do anything. But just in case...
for ( int i = i1 + 1; i < n; i++ )
{
target[i] = null;
}
return ( result );
}
*/
private static VehicleScoringInfo[] vsis = new VehicleScoringInfo[ 32 ];
public static int getDisplayedVSIsForMap( ScoringInfo scoringInfo, VehicleScoringInfo viewedVSI, boolean useClassScoring, boolean forceLeaderDisplayed, VehicleScoringInfo[] target )
{
if ( target == null )
throw new NullPointerException( "target array must not be null." );
if ( !forceLeaderDisplayed && ( target.length < 3 ) )
throw new ArrayIndexOutOfBoundsException( "target array must be at least of size 3." );
if ( forceLeaderDisplayed && ( target.length < 4 ) )
throw new ArrayIndexOutOfBoundsException( "target array must be at least of size 4." );
int n = Math.min( scoringInfo.getNumVehicles(), target.length );
int result = n;
if ( n > 0 )
{
target[--n] = viewedVSI;
}
VehicleScoringInfo nif = viewedVSI.getNextInFront( useClassScoring );
if ( ( n > 0 ) && ( nif != null ) && finishStatusOk( nif ) )
{
target[--n] = nif;
}
VehicleScoringInfo nb = viewedVSI.getNextBehind( useClassScoring );
if ( ( n > 0 ) && ( nb != null ) && finishStatusOk( nb ) )
{
target[--n] = nb;
}
int leaderIndex = n - 1;
if ( forceLeaderDisplayed )
{
VehicleScoringInfo leader = useClassScoring ? viewedVSI.getLeaderByClass() : scoringInfo.getLeadersVehicleScoringInfo();
if ( ( n > 0 ) && ( leader != null ) && finishStatusOk( leader ) )
{
target[--n] = leader;
}
}
if ( ( vsis == null ) || ( vsis.length != scoringInfo.getNumVehicles() ) )
{
vsis = new VehicleScoringInfo[ scoringInfo.getNumVehicles() ];
}
scoringInfo.getVehicleScoringInfos( vsis );
LAP_DISTANCE_COMPARATOR.trackLength = scoringInfo.getTrackLength();
LAP_DISTANCE_COMPARATOR.viewedVSI = viewedVSI;
Arrays.sort( vsis, LAP_DISTANCE_COMPARATOR );
for ( int i = 0; ( i < vsis.length ) && ( n > 0 ); i++ )
{
VehicleScoringInfo vsi = vsis[i];
if ( !vsiConsumed( vsi, viewedVSI, useClassScoring, forceLeaderDisplayed ) && finishStatusOk( vsi ) )
{
if ( vsi.getPlace( useClassScoring ) == 1 )
{
System.arraycopy( target, n, target, n - 1, leaderIndex - n + 1 );
target[leaderIndex] = vsi;
n--;
}
else
{
target[--n] = vsi;
}
}
}
// Should never do anything. But just in case...
for ( int i = 0; i < n; i++ )
{
target[i] = null;
}
return ( result );
}
}