, source, loc, true );

					loc[0].set( midX, midY, z1 );
					loc[1].set( x1, midY, z1 );
					loc[2].set( x1, y1, z1 );
					return fill3DPlane( fillColor, source, loc, true );
				}
				else
				{
					loaPlane3d[0].set( x0, y0, z0 );
					loaPlane3d[1].set( x0, zeroLocation, z0 );
					loaPlane3d[2].set( x1, zeroLocation, z1 );
					loaPlane3d[3].set( x1, y1, z1 );
					return fill3DPlane( fillColor, source, false );
				}
			}
			else
			{
				if ( pValue!= null
						&& value!= null
						&& ( pValue.doubleValue( ) * value.doubleValue( ) ) < 0 )
				{
					double rate = ( 0 - pValue.doubleValue( ) )
							/ ( value.doubleValue( ) - pValue.doubleValue( ) );
					double midX = x0 + ( x1 - x0 ) * rate;
					double midY = y0 + ( y1 - y0 ) * rate;

					Location3D[] loc = createLocation3DArray( 3 );
					loc[0].set( x0, midY, z0 );
					loc[1].set( midX + 1, midY, z0 );
					loc[2].set( x0, y0, z0 );
					fill3DPlane( fillColor, source, loc, true );

					loc[0].set( midX, midY, z1 );
					loc[1].set( x1, y1, z1 );
					loc[2].set( x1, midY, z1 );
					return fill3DPlane( fillColor, source, loc, true );
				}
				else
				{
					loaPlane3d[0].set( x0, zeroLocation, z0 );
					loaPlane3d[1].set( x0, y0, z0 );
					loaPlane3d[2].set( x1, y1, z1 );
					loaPlane3d[3].set( x1, zeroLocation, z1 );
					return fill3DPlane( fillColor, source, false );
				}
			}
		}

		private void fillLeftSidePlane( int findex ) throws ChartException
		{
			double x = loa3d[findex].getX( );
			double y = shear( plotBaseLocation,
					plotHeight,
					loa3d[findex].getY( ) );
			double z = loa3d[findex].getZ( );

			if ( zeroLocation < loa3d[findex].getY( ) )
			{
				loaPlane3d[0].set( x, y, z );
				loaPlane3d[1].set( x, y, z - dTapeWidth );
				loaPlane3d[2].set( x, zeroLocation, z - dTapeWidth );
				loaPlane3d[3].set( x, zeroLocation, z );
			}
			else
			{
				loaPlane3d[0].set( x, y, z );
				loaPlane3d[1].set( x, zeroLocation, z );
				loaPlane3d[2].set( x, zeroLocation, z - dTapeWidth );
				loaPlane3d[3].set( x, y, z - dTapeWidth );
			}

			fill3DPlane( tapeColor, createSeriesSource( ), false );
		}

		private void fillRightSidePlane( int lindex ) throws ChartException
		{
			double x = loa3d[lindex].getX( );
			double y = shear( plotBaseLocation,
					plotHeight,
					loa3d[lindex].getY( ) );
			double z = loa3d[lindex].getZ( );

			if ( shear( plotBaseLocation, plotHeight, loa3d[lindex].getY( ) ) > zeroLocation )
			{
				loaPlane3d[0].set( x, y, z );
				loaPlane3d[1].set( x, zeroLocation, z );
				loaPlane3d[2].set( x, zeroLocation, z - dTapeWidth );
				loaPlane3d[3].set( x, y, z - dTapeWidth );
			}
			else
			{
				loaPlane3d[0].set( x, y, z );
				loaPlane3d[1].set( x, y, z - dTapeWidth );
				loaPlane3d[2].set( x, zeroLocation, z - dTapeWidth );
				loaPlane3d[3].set( x, zeroLocation, z );
			}

			fill3DPlane( sideColor, createDataPointSource( lindex ), false );

		}

		private void fillBottomPlane( int findex, int lindex, DataPointsSeeker seeker )
				throws ChartException
		{
			// Different polygons of chart might be crossing with each other, in order to avoid
			// polygon overlay, here must divide bottom polygon to multiple polygons
			// according to every data point on series.
			Double pValue = Methods.asDouble( seeker.getDataPointHints( findex ).getOrthogonalValue( ) );
			Double value = Methods.asDouble( seeker.getDataPointHints( lindex ).getOrthogonalValue( ) );
			
			if ( pValue!= null
					&& value!= null
					&& ( pValue.doubleValue( ) * value.doubleValue( ) ) < 0 )
			{
				double x0 = loa3d[findex].getX( );
				double y0 = shear( plotBaseLocation,
						plotHeight,
						loa3d[findex].getY( ) );
				double z0 = loa3d[findex].getZ( );

				double x1 = loa3d[lindex].getX( );
				double y1 = shear( plotBaseLocation,
						plotHeight,
						loa3d[lindex].getY( ) );
				double z1 = loa3d[lindex].getZ( );
				boolean up = ( y0 < y1 );
				double rate = ( 0 - pValue.doubleValue( ) ) / ( value.doubleValue( ) - pValue.doubleValue( ) );
				x1 = x0 + ( x1 - x0 ) * rate; 
				y1 = y0 + ( y1 - y0 ) * rate;

				fillBottomPlane( x0, z0, x1, z1, up );

				x0 = x1;
				y0 = y1;
				z0 = loa3d[findex].getZ( );

				x1 = loa3d[lindex].getX( );
				y1 = shear( plotBaseLocation,
						plotHeight,
						loa3d[lindex].getY( ) );
				z1 = loa3d[lindex].getZ( );

				fillBottomPlane( x0, z0, x1, z1,!up );
			}
			else
			{
				double x0 = loa3d[findex].getX( );
				double z0 = loa3d[findex].getZ( );

				double x1 = loa3d[lindex].getX( );
				double z1 = loa3d[lindex].getZ( );

				fillBottomPlane( x0, z0, x1, z1, true );
			}
		}

		private void fillBottomPlane( double x0, double z0, double x1, double z1, boolean bDoubleSided  )
				throws ChartException
		{
			loaPlane3d[0].set( x0, zeroLocation, z0 );
			loaPlane3d[1].set( x0, zeroLocation, z0 - dTapeWidth );
			loaPlane3d[2].set( x1, zeroLocation, z1 - dTapeWidth );
			loaPlane3d[3].set( x1, zeroLocation, z1 );

			fill3DPlane( fillColor, createSeriesSource( ), bDoubleSided );
		}

		private void fill