scOrthogonal.getEnd( ) - scOrthogonal.getStart( ),
	public ISeriesRenderingHints getSeriesRenderingHints(			SeriesDefinition sdOrthogonal, Series seOrthogonal )			throws ChartException, IllegalArgumentException	{		if ( seOrthogonal == null				|| seOrthogonal.getClass( ) == SeriesImpl.class ) // EMPTY		// PLOT		// RENDERING		// TECHNIQUE		{			return null;		}		OneAxis oaxOrthogonal = findOrthogonalAxis( seOrthogonal );		if ( oaxOrthogonal == null )		{			throw new ChartException( ChartEnginePlugin.ID,					ChartException.NOT_FOUND,					"exception.axis.series.link.broken", //$NON-NLS-1$					new Object[]{						seOrthogonal					},					ResourceBundle.getBundle( Messages.ENGINE, rtc.getLocale( ) ) );		}		final OneAxis oaxBase = aax.getPrimaryBase( );		final SeriesDefinition sdBase = (SeriesDefinition) oaxBase.getModelAxis( )				.getSeriesDefinitions( )				.get( 0 );		final OneAxis oaxAncillaryBase = aax.getAncillaryBase( );		final AutoScale scBase = oaxBase.getScale( );		final AutoScale scOrthogonal = oaxOrthogonal.getScale( );		final AutoScale scAncillary = oaxAncillaryBase.getScale( );		final int iXTickCount = scBase.getTickCount( );		final int iZTickCount = scAncillary.getTickCount( );		final double dXUnitSize = scBase.getUnitSize( );		final double dZUnitSize = scAncillary.getUnitSize( );		final boolean bZCategoryTextStyle = scAncillary.isCategoryScale( )				|| scAncillary.getType( ) == IConstants.TEXT;		double[] daXTickCoordinates = scBase.getNormalizedTickCoordinates( );		double[] daZTickCoordinates = scAncillary.getNormalizedTickCoordinates( );		Object oDataBase = null;		DataSetIterator dsiDataBase = scBase.getData( );		Object oDataOrthogonal;		DataSetIterator dsiDataOrthogonal = getTypedDataSet( seOrthogonal,				oaxOrthogonal.getScale( ).getType( ) );		DataSetIterator dsiDataAncillary = scAncillary.getData( );		double dOrthogonalZero = 0;		if ( ( scOrthogonal.getType( ) & NUMERICAL ) == NUMERICAL )		{			dOrthogonalZero = getNormalizedLocation( scOrthogonal, 0 );		}		else		{			dOrthogonalZero = scOrthogonal.getNormalizedStart( );		}		double dAncillaryZero = 0;		if ( ( scAncillary.getType( ) & NUMERICAL ) == NUMERICAL )		{			dAncillaryZero = getNormalizedLocation( scAncillary, 0 );		}		else		{			dAncillaryZero = scAncillary.getNormalizedStart( );		}		double dX = 0, dY = 0, dZ = 0, dXLength = 0, dZLength = 0;		Location3D lo3d;		final int iBaseCount = dsiDataBase.size( );		final int iOrthogonalCount = dsiDataOrthogonal.size( );		DataPointHints[] dpa = null;		int seriesIndex = 0;		Series[] rss = oaxOrthogonal.getModelAxis( ).getRuntimeSeries( );		for ( int i = 0; i < rss.length; i++ )		{			if ( rss[i] == seOrthogonal )			{				seriesIndex = i;				break;			}		}		Object oDataAncillary = null;		for ( int i = 0; i < seriesIndex; i++ )		{			if ( dsiDataAncillary.hasNext( ) )			{				dsiDataAncillary.next( );			}		}		if ( dsiDataAncillary.hasNext( ) )		{			oDataAncillary = dsiDataAncillary.next( );		}		if ( iBaseCount != iOrthogonalCount ) // DO NOT COMPUTE DATA POINT		// HINTS		// FOR OUT-OF-SYNC DATA		{			logger.log( ILogger.INFORMATION,					Messages.getString( "exception.base.orthogonal.inconsistent.count", //$NON-NLS-1$							new Object[]{									new Integer( iBaseCount ),									new Integer( iOrthogonalCount )							},							rtc.getLocale( ) ) );		}		else		{			dpa = new DataPointHints[iBaseCount];			final boolean bScatter = ( oaxBase.getScale( ).getType( ) != IConstants.TEXT && !oaxBase.isCategoryScale( ) );			FormatSpecifier fsSDAncillary = null;			if ( oaxAncillaryBase.getModelAxis( )					.getSeriesDefinitions( )					.size( ) > 0 )			{				fsSDAncillary = ( (SeriesDefinition) oaxAncillaryBase.getModelAxis( )						.getSeriesDefinitions( )						.get( 0 ) ).getFormatSpecifier( );			}			// OPTIMIZED PRE-FETCH FORMAT SPECIFIERS FOR ALL DATA POINTS			final DataPoint dp = seOrthogonal.getDataPoint( );			final EList el = dp.getComponents( );			DataPointComponent dpc;			DataPointComponentType dpct;			FormatSpecifier fsBase = null, fsOrthogonal = null, fsSeries = null, fsPercentile = null;			for ( int i = 0; i < el.size( ); i++ )			{				dpc = (DataPointComponent) el.get( i );				dpct = dpc.getType( );				if ( dpct == DataPointComponentType.BASE_VALUE_LITERAL )				{					fsBase = dpc.getFormatSpecifier( );					if ( fsBase == null ) // BACKUP					{						fsBase = sdBase.getFormatSpecifier( );					}				}				else if ( dpct == DataPointComponentType.ORTHOGONAL_VALUE_LITERAL )				{					fsOrthogonal = dpc.getFormatSpecifier( );					if ( fsOrthogonal == null							&& seOrthogonal.eContainer( ) instanceof SeriesDefinition )					{						fsOrthogonal = ( (SeriesDefinition) seOrthogonal.eContainer( ) ).getFormatSpecifier( );					}				}				else if ( dpct == DataPointComponentType.SERIES_VALUE_LITERAL )				{					fsSeries = dpc.getFormatSpecifier( );					if ( fsSeries == null )					{						fsSeries = fsSDAncillary;					}				}				else if ( dpct == DataPointComponentType.PERCENTILE_ORTHOGONAL_VALUE_LITERAL )				{					fsPercentile = dpc.getFormatSpecifier( );				}			}			dsiDataBase.reset( );			dsiDataOrthogonal.reset( );			UserDataSetHints udsh = new UserDataSetHints( seOrthogonal.getDataSets( ) );			udsh.reset( );			double total = 0;			// get total orthogonal value.			for ( int i = 0; i < iOrthogonalCount; i++ )			{				Object v = dsiDataOrthogonal.next( );				if ( v instanceof Number )				{					total += ( (Number) v ).doubleValue( );				}				else if ( v instanceof NumberDataElement )				{					total += ( (NumberDataElement) v ).getValue( );				}			}			dsiDataOrthogonal.reset( );			for ( int i = 0; i < iBaseCount; i++ )			{				oDataBase = dsiDataBase.next( );				oDataOrthogonal = dsiDataOrthogonal.next( );				if ( !bScatter )				{					if ( aax.areAxesSwapped( ) )					{						dY = daXTickCoordinates[0] + dXUnitSize * i;						if ( bZCategoryTextStyle )						{							dZ = daZTickCoordinates[0]									+ dZUnitSize									* seriesIndex;						}						else						{							try							{								dZ = getNormalizedLocation( scAncillary,										oDataAncillary );							}							catch ( IllegalArgumentException e )							{								dZ = dAncillaryZero;							}							catch ( ChartException e )							{								dZ = dAncillaryZero;							}						}						try						{							dX = getNormalizedLocation( scOrthogonal,									oDataOrthogonal );						}						catch ( IllegalArgumentException nvex )						{							// dX = dOrthogonalZero;							dX = Double.NaN;						}						catch ( ChartException dfex )						{							dX = dOrthogonalZero; // FOR CUSTOM DATA ELEMENTS						}					}					else					{						dX = daXTickCoordinates[0] + dXUnitSize * i;						if ( bZCategoryTextStyle )						{							dZ = daZTickCoordinates[0]									+ dZUnitSize									* seriesIndex;						}						else						{							try							{								dZ = getNormalizedLocation( scAncillary,										oDataAncillary );							}							catch ( IllegalArgumentException e )							{								dZ = dAncillaryZero;							}							catch ( ChartException e )							{								dZ = dAncillaryZero;							}						}						try						{							dY = getNormalizedLocation( scOrthogonal,									oDataOrthogonal );						}						catch ( IllegalArgumentException nvex )						{							// dY = dOrthogonalZero;							dX = Double.NaN;						}						catch ( ChartException dfex )						{							dY = dOrthogonalZero; // FOR CUSTOM DATA ELEMENTS						}					}				}				else				{					// Do not support scatter for 3D chart.					throw new ChartException( ChartEnginePlugin.ID,							ChartException.COMPUTATION,							"exception.scatter.3D.not.supported", //$NON-NLS-1$ 							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}				lo3d = Location3DImpl.create( dX, dY, dZ );				dXLength = ( i < iXTickCount - 1 ) ? daXTickCoordinates[i + 1]						- daXTickCoordinates[i] : 0;				dZLength = ( seriesIndex < iZTickCount - 1 ) ? daZTickCoordinates[seriesIndex + 1]						- daZTickCoordinates[seriesIndex]						: 0;				Object percentileValue = null;				if ( total != 0 )				{					if ( oDataOrthogonal instanceof Number )					{						percentileValue = new Double( ( (Number) oDataOrthogonal ).doubleValue( )								/ total );					}					else if ( oDataOrthogonal instanceof NumberDataElement )					{						percentileValue = new Double( ( (NumberDataElement) oDataOrthogonal ).getValue( )								/ total );					}				}				dpa[i] = new DataPointHints( oDataBase,						oDataOrthogonal,						oDataAncillary,						percentileValue,						seOrthogonal.getDataPoint( ),						fsBase,						fsOrthogonal,						fsSeries,						fsPercentile,						lo3d,						new double[]{								dXLength, dZLength						},						rtc );				udsh.next( dpa[i] );			}		}		return new SeriesRenderingHints3D( this,				oaxBase.getAxisCoordinate( ) - scBase.getStart( ),				oaxAncillaryBase.getAxisCoordinate( ) - scAncillary.getStart( ),				scOrthogonal.getNormalizedStart( ),				dOrthogonalZero,				daXTickCoordinates,				daZTickCoordinates,				dpa,				scBase,				scOrthogonal,				scAncillary,				dsiDataBase,				dsiDataOrthogonal,				dsiDataAncillary );	}