Skip to content
Snippets Groups Projects
plot.cpp 17.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • //**************************************************************************//
    //* FRIDA: fast reliable interactive data analysis                         *//
    //* plot.cpp: plot on-line files                                           *//
    //* (C) Joachim Wuttke 1990-, v2(C++) 2001-                                *//
    //* http://frida.sourceforge.net                                           *//
    //**************************************************************************//
    
    #include <stdlib.h>
    #include <math.h>
    #include <iostream>
    #include <algorithm>
    
    #include "mystd.h"
    #include "olm.h"
    
    #include "expr.h"
    
    #include <ask_simple_value.h>
    #include "dualplot.h"
    #include "plot.h"
    
    #include <boost/format.hpp>
    using boost::format;
    
    namespace NPlot {
    /* auxiliary routines */
        double FindAngleCos( double x0,double y0,  
                             double x1,double y1,  
                             double x2,double y2 );
        void FindNextPoint( const COlc *fc,
                            double xtm, double ytm, double dx,
                            double* xt, double* yt, uint k, uint j );
        void InterY( double xtm,double ytm,double xt,double yt,
                     double* xtt,double *ytt,double border);
    };
    
    double NPlot::FindAngleCos(double x1,double y1, //point 1
                               double x2,double y2, //point 2
                               double x3,double y3 )//point 3
    // Li Huang mar10
    {   
        /*
        (1) ________(2)  
                  \)cos
                   \
                    \(3)
                 
        (x1,y1), (x2,y2)     
        (x2,y2) and (x3,y3)
        a = x2 - x1, b = y2 - y1
        c = x3 - x2, d = y3 - y2.
        The so called dot product yields the equation
        Cosine( Theta ) = ( (a x c) + (b x d) )/(Sqrt(a^2 + b^2) x Sqrt(c^2 + d^2) ) = Z.
        */
        double a,b,c,d,cos;
        a = x2 - x1;
        b = y2 - y1;
        c = x3 - x2;
        d = y3 - y2;
        cos = ( (a * c) + (b * d) )/(sqrt(a*a + b*b) * sqrt(c*c + d*d) );
        return cos;
    }
    
    //! The next point to be plotted is returned as *xt, *yt.
    
    void NPlot::FindNextPoint( const COlc *fc,
                               double xtm, double ytm, double dx,
                               double* xt, double* yt, uint k, uint j )
    // Li Huang mar10
    {
        uint i = 0;
        double cos123 = 0;
        double cos234 = 0;
        double x1 = xtm;
        double y1 = ytm;
        double x2 = *xt;
        double y2 = *yt;
        double x3,y3;
        double x4,y4;
        /*
                           /)o1__   (3)
                       (2)_____________
                         /          \)o2
                        /            \
                    (1)/              \(4)
        
                   (xt,yt)__________(xt+dx,yt+dx)
                         /          \
                        /            \
              (xtm,ytm)/              \(xt+2*dx,yt+2*dx)
        
            o1 < 1/4 degree   &&  o2 < 1/4 degree
            cos(1/4 degree) = 0.99999
        */
        do{ 
            x3 = x2 + dx;
            y3 = fc->T->tree_curve_val_sca( x3, k, j );
            x4 = x3 + dx;
            y4 = fc->T->tree_curve_val_sca( x4, k, j );
            cos123 = FindAngleCos(x1,y1,x2,y2,x3,y3);
            cos234 = FindAngleCos(x2,y2,x3,y3,x4,y4);
            dx = dx/2;
            i++;
        }while ( ( cos123 < 0.99999 || cos234 < 0.99999 ) && i <= 7);
        *xt = x3;
        *yt = y3;
    }
    
    void NPlot::InterY(double xtm,double ytm,double xt,double yt,
                        double* xtt,double *ytt,double border)
    {
        *ytt = border;
        *xtt = (*ytt-ytm)*(xt-xtm)/(yt-ytm)+xtm;
    }
    
    
    //! Plot spectrum.
    
    void NPlot::Plot( class CPlot *plot, bool add )
    {
        static CList JSel;
        CEle *e;
        uint k, j;
        const COld *fd;
        const COlc *fc;
    
        vector<double> novec;
        static int pstyle = 0, cstyle = 0;
        static string jSel = "";
        NOlm::JSelAsk( "Plot which spectra", &jSel, &JSel );
    
        if (!add) {
    
            pstyle = 0;
            cstyle = 0;
    
            // determine x-range ?
    		
            double inf, sup;
            if (!plot->X.finite()) {
                NOlm::IterateD fiter;
                const vector<double> *vx;
                bool first = true;
                while((fd=fiter())) {
    
                    for( uint iv=0; iv<JSel.size(); ++iv ) {
    
                        for( uint i=0; i<vx->size(); ++i ){
                            if( plot->X.logflag && (*vx)[i]<=0 )
                                continue;
                            if( first ){
                                inf = (*vx)[i];
                                sup = (*vx)[i];
                                first = false;
                            } else {
                                if( (*vx)[i]<inf ) inf = (*vx)[i];
                                if( (*vx)[i]>sup ) sup = (*vx)[i];
                            }
                        }
                    }
                }
                if( first )
                    throw string( "x range is empty" );
                plot->X.setRoundedLimits( "x", inf, sup );
            }
    
            // determine y-range ?
            if (!plot->Y.finite()) {
                bool first=true;
                NOlm::IterateEle eiter;
                int npts = 100;
    
                while( (e=eiter()) ){
                    k = eiter.SelNo();
                    fc = e->C();
                    if( fc && fc->kconv!=-1 )
                        continue;
                    fd = e->D();
                    JSel.evaluate( 0, e->nSpec()-1 );
                    for( uint iv=0; iv<JSel.size(); ++iv ){ 
                        uint j = JSel.V[iv];
                        if( fd ){
    
                                S->x[i] = plot->X.plotcoord2value( i/(npts-1.0) );
                            fc->T->tree_curve_val_vec( &(S->y), S->x, k, j );
                            s = S;
    
                        }
                        for (uint i=0; i<s->size(); i++) {
                            if( !plot->X.contains( s->x[i] ) )
                                continue;
                            if( plot->Y.logflag && s->y[i]<=0 )
                                continue;
                            if (first) {
                                inf=s->y[i], sup=s->y[i];
                                first = false;
                            } else {
                                if (s->y[i]<inf) inf=s->y[i];
                                if (s->y[i]>sup) sup=s->y[i];
                            }
                        }
                    }
                }
                if( first )
                    throw string( "y range is empty" );
                plot->Y.setRoundedLimits( "y", inf, sup );
            }
    
            // build label: (zur Zeit nur vom ersten File; definiere +=)
            CCoord xCo = NOlm::MOM[*(NOlm::FSel.V.begin())].P()->xco;
            CCoord yCo = NOlm::MOM[*(NOlm::FSel.V.begin())].P()->yco;
    
            // draw new frame:
            plot->clearFrame();
            plot->plotFrame( xCo.ps_str(), yCo.ps_str() );
        }
    
        // plot data:
        NOlm::IterateEle eiter;
        while( (e=eiter()) ){
            k = eiter.SelNo();
            fc = e->C();
            fd = e->D();
            JSel.evaluate( 0, e->nSpec()-1 );
            for ( uint iv=0; iv<JSel.size(); ++iv){
                j = JSel.V[iv];
                // cout << "DEBUG edif plot k="<<k<<", j="<<j<<"\n";
                if ( fd ) {
                    // plot data
    
                    uint n=s->x.size();
                    if ( n!=s->y.size() )
                        throw string( "BUG: plot: x.size<>y.size" );
                    // Filter: x,y -> xp,yp if inside frame
                    uint np=0, nxl=0, nxh=0, nyl=0, nyh=0;
                    vector<double> xp, yp, dyp;
                    for ( uint i=0; i<n; i++ ) {
                        double x = s->x[i];
                        if( !plot->X.contains(x) ) {
                            if ( x<=plot->X.inf ){
                                x = plot->X.inf;
                                nxl++;
                            }
                            if ( x>=plot->X.sup ){
                                x = plot->X.sup;
                                nxh++;
                            }
                            if ( !plot->X.force )
                                continue;
                        }
                        double y = s->y[i];
                        if( !plot->Y.contains(y) ) {
                            if ( y<=plot->Y.inf ){
                                y = plot->Y.inf;
                                nyl++;
                            }
                            if ( y>=plot->Y.sup ){
                                y = plot->Y.sup;
                                nyh++;
                            }
                            if ( !plot->Y.force )
                                continue;
                        }
                        if( np==plot->maxpoints && np<n ) {
    
                            cout << "reached maxpoints at " << s->x[i] << "\n";
    
                        }
                        xp.push_back( x );
                        yp.push_back( y );
                        if( s->dy.size() )
                            dyp.push_back( s->dy[i] );
                        np = xp.size();
                        if( np > plot->maxpoints ) // continue in large steps
                            i += plot->maxpoints;
                    }
                    if ( np==0 ) {
    
                        cout << "file " << k << " spec " << j << " all " << n <<
                            " points outside plot range:\n";
    
                            cout << "  " << nxl << " points < xmin\n";
    
                            cout << "  " << nxh << " points < xmax\n";
    
                            cout << "  " << nyl << " points < ymin\n";
    
                            cout << "  " << nyh << " points > ymax\n";
    
                        continue;
                    } else {
                        plot->addSpec( false, pstyle++,
                                       xp, yp, dyp, *(e->Z(j)),
                                       e->P()->xco.str(), e->P()->yco.str(),
                                       "data file " + strg(k) +
                                       " spectrum "+strg(j) );
                    }
                } else if ( fc && fc->kconv!=-1 ) {
                    // plot curve, but only at x points of convolutand
                    uint kconv = fc->kconv;
                    uint jconv = CTree::setConvJ( k, j, kconv );
                    COld *fconv = NOlm::MOM[kconv].D();
                    if ( !fconv )
                        throw string( "convolutand is not a data file" );
                    vector<double> xp, yp;
    
                    for( uint i=0; i<fconv->VS(jconv)->size(); ++i ){
                        double x = fconv->VS(jconv)->x[i];
    
                        if( plot->X.contains( x ) )
                            xp.push_back( x );
                    }
                    fc->T->tree_curve_val_vec( &yp, xp, k, j );
                    vector<double> xo, yo;
                    for( uint i=0; i<xp.size(); ++i ){
                        if( !( plot->X.contains( xp[i] ) &&
                               plot->Y.contains( yp[i] )   ) )
                            continue;
                        xo.push_back( xp[i] );
                        yo.push_back( yp[i] );
                    }
                    if( xo.size()==0 ){
                        cout << "curve k="<<strg(k)<<", j="<<strg(j)<<" is empty\n";
                        return;
                    }
                    plot->addSpec( true, cstyle++, xo, yo, novec, *(e->Z(j)),
                                    e->P()->xco.str(), e->P()->yco.str(),
                                    "curve file "+strg(k)+" spectrum "+strg(j) );
                } else if ( fc && false ) {
                    // PRESENTLY UNUSED
                    // plot ordinary curve
                    // straight vectorial version, for rapid plotting
                    int npts = 297;
                    vector<double> xc(npts), yc, xp, yp;
                    for( uint i=0; i<npts; ++i )
                        xc[i] = plot->X.plotcoord2value( i/(npts-1.0) );
                    fc->T->tree_curve_val_vec( &yc, xc, k, j );
                    for( uint i=0; i<npts; ++i ) {
                        if( plot->X.contains(xc[i]) && plot->Y.contains(yc[i]) ) {
                            xp.push_back( xc[i] );
                            yp.push_back( yc[i] );
                        }
                    }
                    plot->addSpec( true, cstyle++, xp, yp, novec, *(e->Z(j)),
                                   e->P()->xco.str(), e->P()->yco.str(),
                                   "curve file "+strg(k)+" spectrum "+strg(j) );
                } else if ( fc ) {
                    // plot ordinary curve, taking care:
                    // - stop/start line when leaving/reentering the frame (done)
                    // - interpolate when crossing the horizontal border (done)
                    // - interpolate at discontinuities (done)               
                    //iamhere
                    uint npts = 97;
                    double dx = plot->X.plotcoord2value( 1/(npts-1.0) ) -
                        plot->X.plotcoord2value( 0/(npts-1.0) );
                    vector< vector<double> > xpv, ypv;
                    vector<double> xp, yp;
                    bool plotfirst = true;
                    bool plotlast = false;
                    bool plotend = false;
                    bool started = false;
                    bool ended = false;
                    double xt, yt; //current point (i)
                    double xtm,ytm;//        point (i - 1)
                    double xtmo,ytmo;// back up of (i - 1)
                    while ( (!plotend) ) {
                        if( xpv.size()>180 )
                            throw string( "curve oscillates too fast for "
                                          "interpolating plot mode" );
                        if ( !plotlast ) {
                            if ( plotfirst ){
                                xt = plot->X.plotcoord2value( 0.0 );
                                yt = fc->T->tree_curve_val_sca( xt, k, j );
                            } else {
                                FindNextPoint( fc, xtmo, ytmo, dx,
                                               &xt, &yt, k, j ); 
                            }
                        }
                        if ( plot->X.contains(xt)  ){// if xt <= X.sup
                            if ( plot->Y.contains(yt) ) { //if in
                                if ( plotfirst ) { //a new curve starts 
                                    //with the first point as the starting point 
                                    xp.push_back( xt );
                                    yp.push_back( yt );
                                    plotfirst = false;
                                    started = true;
                                }
                                else if ( !started ) { //a new curve starts
                                    //i.e. the case: out -> in
                                    double xtt,ytt;
                                    double border = ytm > plot->Y.sup ?
                                                          plot->Y.sup : plot->Y.inf;
                                    //using the previous point and current point to 
                                    //interpolate the intersection point 
                                    InterY(xtm,ytm,xt,yt,&xtt,&ytt,border);
                                    xp.push_back( xtt );
                                    yp.push_back( ytt );
                                    xp.push_back( xt );
                                    yp.push_back( yt );
                                    started = true;
                                }
                                else if ( started ) { //continues a started curve
                                    //i.e. the case in -> in
                                    xp.push_back( xt );
                                    yp.push_back( yt );
                                }
                            }
                            else if ( started ) {
                                // a curve ends
                                //i.e. the case: in -> in -> out
                                double xtt,ytt;
                                double border = yt > plot->Y.sup ?
                                    plot->Y.sup : plot->Y.inf;
                                //using the previous point and current point to 
                                //interpolate the intersection point 
                                InterY(xtm,ytm,xt,yt,&xtt,&ytt,border);
                                xp.push_back( xtt );
                                yp.push_back( ytt );
                                started = false;
                                ended = true;
                            }
                            else if ( plotfirst ) { //a new curve starts 
                                //with the first point is not inside the plotting
                                plotfirst = false;
                            }
                            if ( xt == plot->X.sup ) { 
                                ended = true;
                                plotlast = true;
                                plotend = true;
                            }
                        } else if ( ( xt > plot->X.sup ) && !plotlast ){
                            xt = plot->X.sup;
                            plotlast = true;
                        } else
                            throw string( "PROGRAM ERROR plot in fc: no ending" );
                            
                        xtmo = xtm;
                        ytmo = ytm;
                        xtm = xt;
                        ytm = yt;
                        if ( ended ){
                            xpv.push_back(xp);
                            ypv.push_back(yp);
                            xp.clear();
                            yp.clear();
                            ended = false;
                        }
                    } // end loop over points
                    
                    for ( uint ipv=0; ipv<xpv.size();++ipv) {
                        if(!xpv[ipv].empty()){
                            plot->addSpec( true, cstyle, xpv[ipv], ypv[ipv],
                                           novec, *(e->Z(j)),
                                           e->P()->xco.str(), e->P()->yco.str(),
                                           "curve file "+strg(k)+
                                           " spectrum "+strg(j) );
                        }
                    }
                    cstyle++;
                } else
                    throw string( "PROGRAM ERROR plot invalid *e" );
            }
            plot->plotDoclines( e->P()->lDoc );
            if( fc )
                plot->plotDoclines( fc->pInfo() );
        }
        plot->showSpecs();
    }