afreechart/src/main/java/org/afree/chart/renderer/xy/XYSplineRenderer.java
/**
     * Draws the item (first pass). This method draws the lines
     * connecting the items. Instead of drawing separate lines,
     * a GeneralPath is constructed and drawn at the end of
     * the series painting.
     *
     * @param canvas  the graphics device.
     * @param state  the renderer state.
     * @param plot  the plot (can be used to obtain standard color information
     *              etc).
     * @param dataset  the dataset.
     * @param pass  the pass.
     * @param series  the series index (zero-based).
     * @param item  the item index (zero-based).
     * @param domainAxis  the domain axis.
     * @param rangeAxis  the range axis.
     * @param dataArea  the area within which the data is being drawn.
     */
Draws the item (first pass). This method draws the lines
connecting the items. Instead of drawing separate lines,
a GeneralPath is constructed and drawn at the end of
the series painting.

@param canvas  the graphics device.
@param state  the renderer state.
@param plot  the plot (can be used to obtain standard color information
etc).
@param dataset  the dataset.
@param pass  the pass.
@param series  the series index (zero-based).
@param item  the item index (zero-based).
@param domainAxis  the domain axis.
@param rangeAxis  the range axis.
@param dataArea  the area within which the data is being drawn.
Draws the item ( first pass ) . This method draws the lines connecting the items . Instead of drawing separate lines a GeneralPath is constructed and drawn at the end of the series painting . @param canvas the graphics device . @param state the renderer state . @param plot the plot ( can be used to obtain standard color information etc ) . @param dataset the dataset . @param pass the pass . @param series the series index ( zero - based ) . @param item the item index ( zero - based ) . @param domainAxis the domain axis . @param rangeAxis the range axis . @param dataArea the area within which the data is being drawn .
protected void drawPrimaryLineAsPath(XYItemRendererState state,
            Canvas canvas, XYPlot plot, XYDataset dataset, int pass,
            int series, int item, ValueAxis domainAxis, ValueAxis rangeAxis,
            RectShape dataArea) {
        RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
        RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
        double x1 = dataset.getXValue(series, item);
        double y1 = dataset.getYValue(series, item);
        double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
        double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
        if (!Double.isNaN(transX1) && !Double.isNaN(transY1)) {
            ControlPoint p = new ControlPoint(plot.getOrientation()
                                == PlotOrientation.HORIZONTAL ? (float) transY1
                                : (float) transX1, plot.getOrientation()
                                == PlotOrientation.HORIZONTAL ? (float) transX1
                                        : (float) transY1);
            if (!this.points.contains(p)) {
                this.points.add(p);
            }
        }
        if (item == dataset.getItemCount(series) - 1) {
            State s = (State) state;
            if (this.points.size() > 1) {
                ControlPoint cp0 = (ControlPoint) this.points.get(0);
                s.seriesPath.moveTo(cp0.x, cp0.y);
                if (this.points.size() == 2) {
                    ControlPoint cp1 = (ControlPoint) this.points.get(1);
                    s.seriesPath.lineTo(cp1.x, cp1.y);
                }
                else {
                    int np = this.points.size(); 
                    float[] d = new float[np]; 
                    float[] x = new float[np]; 
                    float y;
                    float t;
                    float oldy = 0;
                    float oldt = 0;
                    float[] a = new float[np];
                    float t1;
                    float t2;
                    float[] h = new float[np];
                    for (int i = 0; i < np; i++) {
                        ControlPoint cpi = (ControlPoint) this.points.get(i);
                        x[i] = cpi.x;
                        d[i] = cpi.y;
                    }
                    for (int i = 1; i <= np - 1; i++) {
                        h[i] = x[i] - x[i - 1];
                    }
                    float[] sub = new float[np - 1];
                    float[] diag = new float[np - 1];
                    float[] sup = new float[np - 1];
                    for (int i = 1; i <= np - 2; i++) {
                        diag[i] = (h[i] + h[i + 1]) / 3;
                        sup[i] = h[i + 1] / 6;
                        sub[i] = h[i] / 6;
                        a[i] = (d[i + 1] - d[i]) / h[i + 1]
                                   - (d[i] - d[i - 1]) / h[i];
                    }
                    solveTridiag(sub, diag, sup, a, np - 2);
                    oldt = x[0];
                    oldy = d[0];
                    s.seriesPath.moveTo(oldt, oldy);
                    for (int i = 1; i <= np - 1; i++) {
                        for (int j = 1; j <= this.precision; j++) {
                            t1 = (h[i] * j) / this.precision;
                            t2 = h[i] - t1;
                            y = ((-a[i - 1] / 6 * (t2 + h[i]) * t1 + d[i - 1])
                                    * t2 + (-a[i] / 6 * (t1 + h[i]) * t2
                                    + d[i]) * t1) / h[i];
                            t = x[i - 1] + t1;
                            s.seriesPath.lineTo(t, y);
                            oldt = t;
                            oldy = y;
                        }
                    }
                }
                 path
                drawFirstPassShape(canvas, pass, series, item, s.seriesPath);
            }
            this.points = new Vector();
        }
    }
protected void drawPrimaryLineAsPath ( XYItemRendererState state , Canvas canvas , XYPlot plot , XYDataset dataset , int pass , int series , int item , ValueAxis domainAxis , ValueAxis rangeAxis , RectShape dataArea ) { RectangleEdge xAxisLocation = plot . getDomainAxisEdge ( ) ; RectangleEdge yAxisLocation = plot . getRangeAxisEdge ( ) ; double x1 = dataset . getXValue ( series , item ) ; double y1 = dataset . getYValue ( series , item ) ; double transX1 = domainAxis . valueToJava2D ( x1 , dataArea , xAxisLocation ) ; double transY1 = rangeAxis . valueToJava2D ( y1 , dataArea , yAxisLocation ) ; if ( ! Double . isNaN ( transX1 ) && ! Double . isNaN ( transY1 ) ) { ControlPoint p = new ControlPoint ( plot . getOrientation ( ) == PlotOrientation . HORIZONTAL ? ( float ) transY1 : ( float ) transX1 , plot . getOrientation ( ) == PlotOrientation . HORIZONTAL ? ( float ) transX1 : ( float ) transY1 ) ; if ( ! this . points . contains ( p ) ) { this . points . add ( p ) ; } } if ( item == dataset . getItemCount ( series ) - 1 ) { State s = ( State ) state ; if ( this . points . size ( ) > 1 ) { ControlPoint cp0 = ( ControlPoint ) this . points . get ( 0 ) ; s . seriesPath . moveTo ( cp0 . x , cp0 . y ) ; if ( this . points . size ( ) == 2 ) { ControlPoint cp1 = ( ControlPoint ) this . points . get ( 1 ) ; s . seriesPath . lineTo ( cp1 . x , cp1 . y ) ; } else { int np = this . points . size ( ) ; float [ ] d = new float [ np ] ; float [ ] x = new float [ np ] ; float y ; float t ; float oldy = 0 ; float oldt = 0 ; float [ ] a = new float [ np ] ; float t1 ; float t2 ; float [ ] h = new float [ np ] ; for ( int i = 0 ; i < np ; i ++ ) { ControlPoint cpi = ( ControlPoint ) this . points . get ( i ) ; x [ i ] = cpi . x ; d [ i ] = cpi . y ; } for ( int i = 1 ; i <= np - 1 ; i ++ ) { h [ i ] = x [ i ] - x [ i - 1 ] ; } float [ ] sub = new float [ np - 1 ] ; float [ ] diag = new float [ np - 1 ] ; float [ ] sup = new float [ np - 1 ] ; for ( int i = 1 ; i <= np - 2 ; i ++ ) { diag [ i ] = ( h [ i ] + h [ i + 1 ] ) / 3 ; sup [ i ] = h [ i + 1 ] / 6 ; sub [ i ] = h [ i ] / 6 ; a [ i ] = ( d [ i + 1 ] - d [ i ] ) / h [ i + 1 ] - ( d [ i ] - d [ i - 1 ] ) / h [ i ] ; } solveTridiag ( sub , diag , sup , a , np - 2 ) ; oldt = x [ 0 ] ; oldy = d [ 0 ] ; s . seriesPath . moveTo ( oldt , oldy ) ; for ( int i = 1 ; i <= np - 1 ; i ++ ) { for ( int j = 1 ; j <= this . precision ; j ++ ) { t1 = ( h [ i ] * j ) / this . precision ; t2 = h [ i ] - t1 ; y = ( ( - a [ i - 1 ] / 6 * ( t2 + h [ i ] ) * t1 + d [ i - 1 ] ) * t2 + ( - a [ i ] / 6 * ( t1 + h [ i ] ) * t2 + d [ i ] ) * t1 ) / h [ i ] ; t = x [ i - 1 ] + t1 ; s . seriesPath . lineTo ( t , y ) ; oldt = t ; oldy = y ; } } } drawFirstPassShape ( canvas , pass , series , item , s . seriesPath ) ; } this . points = new Vector ( ) ; } }
Draws the item (first pass).
Draws the item ( first pass ) .
// get the data points // collect points // construct path // we need at least two points to draw something // we need at least 3 points to spline. Draw simple line // for two points // construct spline // number of points // Newton form coefficients // x-coordinates of nodes // note that a[0]=a[np-1]=0 // draw // loop over intervals between nodes // draw path // reset points vector