/*************************************************************************** qscurve.cpp ------------------- begin : 01-January-2000 copyright : (C) 2000 by Kamil Dobkowski email : kamildobk@poczta.onet.pl ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "qscurve.h" #include #define SET_PROPERTY( property, new_value ) if ((property)!=(new_value)) { parametersChanging(); (property)=(new_value); parametersChanged(); } struct curve_runtime_data { int stage; int pk; QSAxis *xaxis; QSAxis *yaxis; int cpass; int tpass; bool ipass; QSMatrix *sx; QSMatrix *sy; QSMatrix *dx; QSMatrix *dy; int xw; int yw; bool delete_po; bool shasx; bool shasdx; bool shasdy; QSSegment *po; QSPt2f zero; QSPt2f curr_pos; QSPt2f curr_delta; QSGFill curr_fill; QSGLine curr_line; QSGPoint curr_point; QSGLine curr_err_line; QSGArrow curr_arrow_1; QSGArrow curr_arrow_2; QSGLine curr_x_line; QSGLine curr_y_line; }; //-------------------------------------------------------------// QSCurve::QSCurve(QSAxes * parent, const char * name) :QSPlot2D(parent,name) { assert( parent ); d = NULL; m_title_str = tr("Untitled curve"); m_evalid = false; m_type = Lines; m_po = NULL; m_xmin = 0.0; m_xmax = 0.0; m_ymin = 0.0; m_ymax = 0.0; m_zero.set(0.0,0.0); m_pdelta.set(0.0,0.0); m_fdelta.set(0.0,0.0); #define CHANNELS_NUM 11 #define FILLS_NUM 1 #define FONTS_NUM 0 #define LINES_NUM 4 #define POINTS_NUM 1 initChannelTable( CHANNELS_NUM ); initAttributeTables( FONTS_NUM, FILLS_NUM, LINES_NUM, POINTS_NUM ); m_settings.lines[ErrorLine] = QSGLine::invisibleLine; m_settings.lines[XLine] = QSGLine::invisibleLine; m_settings.lines[YLine] = QSGLine::invisibleLine; m_settings.fills[BaseFill] = QSGFill::transparentFill; } //-------------------------------------------------------------// QSCurve::~QSCurve() { delete m_po; } //-------------------------------------------------------------// void QSCurve::dataChanged( int channel ) { m_evalid = false; QSPlot2D::dataChanged( channel ); } //-------------------------------------------------------------// void QSCurve::allocRuntimeData() { QSPlot2D::allocRuntimeData(); d = new curve_runtime_data(); d->po = NULL; d->stage = 0; d->delete_po = false; d->pk = 0; d->sx = matrix( XVector ); d->sy = matrix( YVector ); d->dx = matrix( DXVector ); d->dy = matrix( DYVector ); d->xw = matrixRows( XVector ); d->yw = matrixRows( YVector ); d->shasx = ( matrixRows(XVector) == d->yw ); d->shasdx = ( matrixRows(DXVector) == d->yw ); d->shasdy = ( matrixRows(DYVector) == d->yw ); d->xaxis = defaultAxis(QSAxis::XAxisType); d->yaxis = defaultAxis(QSAxis::YAxisType); } //-------------------------------------------------------------// void QSCurve::freeRuntimeData() { if ( d->delete_po ) delete d->po; delete d; d = NULL; QSPlot2D::freeRuntimeData(); } //-------------------------------------------------------------// void QSCurve::get_values( int index ) { d->curr_pos.x = d->shasx ? d->sx->value(index,0) : index; d->curr_pos.y = d->sy->value(index,0); d->curr_delta.x = m_fdelta.x + ( d->shasdx ? d->dx->value(index,0) : 0.0 ) + m_pdelta.x*d->curr_pos.x/100.0; d->curr_delta.y = m_fdelta.y + ( d->shasdy ? d->dy->value(index,0) : 0.0 ) + m_pdelta.y*d->curr_pos.y/100.0; } //-------------------------------------------------------------// void QSCurve::get_attributes( int index ) { d->curr_point = pointFromData( matrix(PointStyles), index, 0, m_settings.points[PointMark] ); d->curr_fill = fillFromData( matrix(FillStyles), index, 0, m_settings.fills[BaseFill] ); d->curr_line = lineFromData( matrix(LineStyles), index, 0, m_settings.lines[BaseLine] ); d->curr_arrow_1 = arrowFromData( matrix(ArrowStyles), index, 0, arrow1() ); d->curr_arrow_2 = arrowFromData( matrix(ArrowStyles), index, 2, arrow2() ); d->curr_err_line = lineFromData( matrix(ErrorLineStyles), index, 0, m_settings.lines[ErrorLine] ); d->curr_x_line = lineFromData( matrix(XLineStyles), index, 0, m_settings.lines[XLine] ); d->curr_y_line = lineFromData( matrix(YLineStyles), index, 0, m_settings.lines[YLine] ); } //-------------------------------------------------------------// bool QSCurve::getAxisRange( QSAxis *axis, double& min, double& max ) { allocRuntimeData(); if ( d->yw == 0 ) { freeRuntimeData(); return false; } if ( !m_evalid ) { d->pk = 0; // if we should care about +/-dx or only +dx bool dminus = (line(ErrorLine).style != QSGLine::Invisible || m_type == Ribbon); while ( d->pkyw ) { get_values( d->pk++ ); QSPt2f p1 = dminus ? d->curr_pos-d->curr_delta : d->curr_pos; QSPt2f p2 = d->curr_pos+d->curr_delta; if ( m_xmin > p1.x || d->pk == 1 ) m_xmin = p1.x; if ( m_xmax < p1.x || d->pk == 1 ) m_xmax = p1.x; if ( m_xmin > p2.x ) m_xmin = p2.x; if ( m_xmax < p2.x ) m_xmax = p2.x; if ( m_ymin > p1.y || d->pk == 1 ) m_ymin = p1.y; if ( m_ymax < p1.y || d->pk == 1 ) m_ymax = p1.y; if ( m_ymin > p2.y ) m_ymin = p2.y; if ( m_ymax < p2.y ) m_ymax = p2.y; } m_evalid = true; } if ( axis == d->xaxis ) { min = m_xmin; max = m_xmax; } else if ( axis == d->yaxis ) { min = m_ymin; max = m_ymax; } else { freeRuntimeData(); return false; } freeRuntimeData(); return true; } //-------------------------------------------------------------// bool QSCurve::start() { QSPlot2D::start(); d->stage = 0; d->pk = 0; d->zero = dataToWorld(m_zero); d->stage = StartDrawLines; return true; } //-------------------------------------------------------------// bool QSCurve::step() { switch( d->stage ) { case StartDrawLines: start_draw_lines(); break; case DrawLines: draw_lines(); break; case StartDrawSeries: start_draw_series(); break; case DrawSeries: draw_series(); break; case StartDrawErrorbars: start_draw_errorbars(); break; case DrawErrorbars: draw_errorbars(); break; case StartDrawPointMarks: start_draw_pointmarks(); break; case DrawPointMarks: draw_pointmarks(); break; default: return false; } return true; } //-------------------------------------------------------------// void QSCurve::end() { QSPlot2D::end(); } //-------------------------------------------------------------// void QSCurve::start_draw_lines() { d->pk=0; if ( line(XLine).style == QSGLine::Invisible && line(YLine).style == QSGLine::Invisible && !isChannel(XLineStyles) && !isChannel(YLineStyles) ) { d->stage = StartDrawSeries; } else { d->stage = DrawLines; } } //-------------------------------------------------------------// void QSCurve::draw_lines() { QSPt2f p1; QSPt2f p2; int curr_step = 0; while( d->pkyw ) { get_values( d->pk ); get_attributes( d->pk ); d->pk ++; QSPt2f pos = dataToWorld(d->curr_pos); // horizontal line p1.set( d->zero.x, pos.y ); p2.set( pos.x, pos.y ); m_drv->setLine( d->curr_x_line ); m_drv->drawLine2(p1,p2); // vertical line p1.set( pos.x, d->zero.y ); p2.set( pos.x, pos.y ); m_drv->setLine( d->curr_y_line ); m_drv->drawLine2(p1,p2); if ( ++curr_step > work_steps && m_bkg_handler ) return; } d->stage = StartDrawSeries; } //-------------------------------------------------------------// void QSCurve::create_po() { d->delete_po = true; switch( m_type ) { case Lines: d->po = new QSSLines(); break; case Area: d->po = new QSSPolys(QSSPolys::Area); break; case Ribbon: d->po = new QSSPolys(QSSPolys::Ribbon); break; case Bars: d->po = new QSSBars(); break; case Vectors: d->po = new QSSFigures(QSSFigures::Vectors); break; case Flux: d->po = new QSSFigures(QSSFigures::Flux); break; case Rectangles: d->po = new QSSFigures(QSSFigures::Rectangles); break; case Ellipses: d->po = new QSSFigures(QSSFigures::Ellipses); break; case LeftStairs: d->po = new QSSStairs(QSSStairs::Left ); break; case MiddleStairs:d->po = new QSSStairs(QSSStairs::Middle ); break; case RightStairs: d->po = new QSSStairs(QSSStairs::Right ); break; default: d->po = m_po; d->delete_po = false; break; } } //-------------------------------------------------------------// void QSCurve::start_draw_series() { create_po(); d->pk = 0; d->ipass = false; d->tpass = d->po->startDraw( this ); if ( d->tpass > 0 ) { d->cpass = 0; d->ipass = true; d->stage = DrawSeries; d->po->initPass( 0 ); } } //-------------------------------------------------------------// void QSCurve::draw_series() { int curr_step = 0; while( d->ipass && d->pkyw ) { get_values( d->pk ); get_attributes( d->pk ); d->po->drawSegment( d->pk, d->curr_pos, d->curr_delta, d->curr_line, d->curr_fill, d->curr_arrow_1, d->curr_arrow_2 ); d->pk++; if ( ++curr_step > work_steps && m_bkg_handler ) return; } d->po->endPass(); d->pk = 0; d->cpass = d->cpass ++; if ( d->cpass >= d->tpass ) { // stop drawing d->po->stopDraw(); if ( d->delete_po ) { delete d->po; d->po = NULL; } d->stage = StartDrawErrorbars; } else { // start new pass d->po->initPass(d->cpass); } } //-------------------------------------------------------------// void QSCurve::start_draw_errorbars() { d->pk = 0; if ( line(ErrorLine).style == QSGLine::Invisible && !isChannel(ErrorLineStyles) ) { d->stage = StartDrawPointMarks; } else { d->stage = DrawErrorbars; } } //-------------------------------------------------------------// void QSCurve::draw_errorbars() { int curr_step = 0; while( d->pkyw ) { get_values( d->pk ); get_attributes( d->pk ); d->pk++; // vertical ( y ) error bar m_drv->setLine( d->curr_err_line ); m_drv->drawArrow2( dataToWorld(QSPt2f(d->curr_pos.x,d->curr_pos.y-d->curr_delta.y)), dataToWorld(QSPt2f(d->curr_pos.x,d->curr_pos.y+d->curr_delta.y)), d->curr_arrow_2, d->curr_arrow_2 ); // horizontal ( x ) error bar m_drv->setLine( d->curr_err_line ); m_drv->drawArrow2( dataToWorld(QSPt2f(d->curr_pos.x-d->curr_delta.x,d->curr_pos.y)), dataToWorld(QSPt2f(d->curr_pos.x+d->curr_delta.x,d->curr_pos.y)), d->curr_arrow_1, d->curr_arrow_1 ); if ( ++curr_step > work_steps && m_bkg_handler ) return; } d->pk = 0; d->stage = StartDrawPointMarks; } //-------------------------------------------------------------// void QSCurve::start_draw_pointmarks() { d->pk = 0; if ( point(PointMark).style == QSGPoint::Invisible && !isChannel(PointStyles) ) { d->stage = Stop; } else { d->stage = DrawPointMarks; } } //-------------------------------------------------------------// void QSCurve::draw_pointmarks() { int curr_step = 0; while( d->pkyw ) { get_values( d->pk ); get_attributes( d->pk ); d->pk++; m_drv->drawPoint2( dataToWorld(d->curr_pos), d->curr_point ); if ( ++curr_step > work_steps && m_bkg_handler ) return; } d->pk = 0; d->stage = Stop; } //-------------------------------------------------------------// void QSCurve::setType( int type ) { if ( type >= Lines && type <= User ) if ( m_type != type ) { parametersChanging(); m_type = (SeriesType )type; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setPercentDelta( const QSPt2f& new_delta ) { if ( m_pdelta != new_delta ) { parametersChanging(); m_pdelta = new_delta; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setPercentDX( double value ) { if ( m_pdelta.x != value ) { parametersChanging(); m_pdelta.x = value; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setPercentDY( double value ) { if ( m_pdelta.y != value ) { parametersChanging(); m_pdelta.y = value; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setFixedDelta( const QSPt2f& new_delta ) { if ( m_fdelta != new_delta ) { parametersChanging(); m_fdelta = new_delta; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setFixedDX( double value ) { if ( m_fdelta.x != value ) { parametersChanging(); m_fdelta.x = value; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setFixedDY( double value ) { if ( m_fdelta.y != value ) { parametersChanging(); m_fdelta.y = value; m_evalid = false; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setZeroPoint( const QSPt2f& new_zero ) { SET_PROPERTY( m_zero, new_zero ); } //-------------------------------------------------------------// void QSCurve::setZeroLevelX( double x ) { SET_PROPERTY( m_zero.x, x ); } //-------------------------------------------------------------// void QSCurve::setZeroLevelY( double y ) { SET_PROPERTY( m_zero.y, y ); } //-------------------------------------------------------------// void QSCurve::setPObject( QSSegment *new_po ) { if ( m_po != new_po ) { parametersChanging(); delete m_po; m_po = new_po; parametersChanged(); } } //-------------------------------------------------------------// void QSCurve::setArrow1( const QSGArrow& astyle ) { SET_PROPERTY( m_arrow1, astyle ); } //-------------------------------------------------------------// void QSCurve::setArrow2( const QSGArrow& astyle ) { SET_PROPERTY( m_arrow2, astyle ); } //-------------------------------------------------------------// QString QSCurve::posInfo( QSPt2f& pos ) { if ( m_busy ) return QString::null; QSPt2f p; double dp = 100.0; QString result = QString::null; allocRuntimeData(); while( d->pkyw ) { get_values( d->pk ); QSPt2f p1 = m_axes->dataToCanvas(d->curr_pos,d->xaxis,d->yaxis); double d1 = (p1.x-pos.x)*(p1.x-pos.x)+(p1.y-pos.y)*(p1.y-pos.y); if ( d1 < 5.0*5.0 && d1 < dp ) { dp = d1; p = p1; result = QString(tr("Index ")) + QString::number(d->pk) + "\n"; result += QString(tr("X = ")) + QString::number(d->curr_pos.x) + "\n"; result += QString(tr("Y = ")) + QString::number(d->curr_pos.y) + "\n"; if ( d->shasdx ) result += QString(tr("DX = ")) + QString::number(d->dx->value(0,d->pk)) + "\n"; if ( d->shasdy ) result += QString(tr("DY = ")) + QString::number(d->dy->value(0,d->pk)) + "\n"; result += QString(tr("Delta DX = ")) + QString::number(d->curr_delta.x) + "\n"; result += QString(tr("Delta DY = ")) + QString::number(d->curr_delta.y) + "\n"; if ( d->curr_delta.x ) result += QString(tr("X-delta = ")) + QString::number(d->curr_pos.x-d->curr_delta.x) + "\n"; if ( d->curr_delta.x ) result += QString(tr("X+delta = ")) + QString::number(d->curr_pos.x+d->curr_delta.x) + "\n"; if ( d->curr_delta.y ) result += QString(tr("Y-delta = ")) + QString::number(d->curr_pos.y-d->curr_delta.y) + "\n"; if ( d->curr_delta.y ) result += QString(tr("Y+delta = ")) + QString::number(d->curr_pos.y+d->curr_delta.y) + "\n"; } d->pk++; } freeRuntimeData(); if ( result != QString::null ) pos.set( p.x, p.y ); return result; } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// #define BOX_SIZE 20 #define BOX_SPACE 5 //-------------------------------------------------------------// QSPt2f QSCurve::legendItemSize( QSDrv *drv ) { double boxSize = drv->toPixels(BOX_SIZE); double boxSpace = drv->toPixels(BOX_SPACE); QSPt2f tsize = drv->textSize( title() ); return QSPt2f(boxSize+boxSpace+tsize.x,QMAX(tsize.y,boxSize)); } //-------------------------------------------------------------// void QSCurve::drawLegendItem( const QSPt2f& pos, QSDrv *drv ) { double boxSize = drv->toPixels(BOX_SIZE); double boxSpace = drv->toPixels(BOX_SPACE); QSPt2f tsize = drv->textSize( title() ); double height = QMAX(tsize.y,boxSize); QSPt2f bpos( pos.x, pos.y+(height-boxSize)/2.0 ); QSPt2f tpos( pos.x+boxSpace+boxSize, pos.y+(height-tsize.y)/2.0 ); drv->drawText( tpos, title(), AlignLeft | AlignTop ); drv->setLine(line(BaseLine)); if ( fill(BaseFill).style != QSGFill::Transparent ) { drv->setFill( fill(BaseFill) ); drv->drawRect( bpos, QSPt2f(bpos.x+boxSize,bpos.y+boxSize) ); } else { drv->drawLine( QSPt2f(pos.x,pos.y+height/2.0), QSPt2f(pos.x+boxSize,pos.y+height/2.0) ); } if ( point(PointMark).style != QSGPoint::Invisible ) { drv->drawPoint( QSPt2f(pos.x+boxSize/2.0,pos.y+height/2.0), point(PointMark) ); } } //-------------------------------------------------------------// void QSCurve::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ) { QSPlot2D::loadStateFromStream( stream, factory ); } //-------------------------------------------------------------// void QSCurve::saveStateToStream( QDataStream& stream, QSObjectFactory *factory ) { QSPlot2D::saveStateToStream( stream, factory ); } //-------------------------------------------------------------// QString QSCurve::channelVariable( int channel ) const { switch( channel ) { case XVector: return "x"; case YVector: return "y"; case DXVector: return "dx"; case DYVector: return "dy"; case LineStyles: return "line"; case FillStyles: return "fill"; case PointStyles: return "point"; case ArrowStyles: return "arrow"; case ErrorLineStyles: return "eline"; case XLineStyles: return "xline"; case YLineStyles: return "yline"; } return QString::null; } //-------------------------------------------------------------// QSCurve::ColumnType QSCurve::columnType( int channel, int column ) const { } //-------------------------------------------------------------//