/*************************************************************************** qsdrv.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 "qsdrv.h" #include #include #include //-------------------------------------------------------------// QSCanvasDrv::QSCanvasDrv() { dpi = 72.0; } //-------------------------------------------------------------// QSCanvasDrv::~QSCanvasDrv() { stopDrawing(); } //-------------------------------------------------------------// void QSCanvasDrv::startDrawing() { } //-------------------------------------------------------------// void QSCanvasDrv::stopDrawing() { } //-------------------------------------------------------------// void QSCanvasDrv::drawPoint( const QSPt2f& pos, const QSGPoint& point ) { if ( point.style != QSGPoint::Invisible ) { double size = toPixels(point.size); QSPt2f p1( pos.x - size/2.0, pos.y - size/2.0 ); QSPt2f p2( p1.x + size, p1.y + size ); QSGLine cl = currentLine(); QSGFill cf = currentFill(); QSGLine l; l.color = point.color; l.width = int(floor(size/15.0+0.5)); QSGFill f; if ( point.fill == QSGPoint::Filled ) f.color = point.color; if ( point.fill == QSGPoint::Transparent ) f.style = QSGFill::Transparent; if ( cf != f ) setFill( f ); if ( cl != l ) setLine( l ); QSPt2f p[4]; switch( point.style ) { case QSGPoint::Circle: drawEllipse(p1,p2); break; case QSGPoint::Rect: drawRect( p1, p2 ); break; case QSGPoint::Triangle : p[0].set( pos.x, p1.y ); p[1].set( p2.x, p2.y ); p[2].set( p1.x, p2.y ); drawPoly( p, 3 ); break; case QSGPoint::Diamond: p[0].set( pos.x, p1.y ); p[1].set( p2.x, pos.y ); p[2].set( pos.x, p2.y ); p[3].set( p1.x, pos.y ); drawPoly( p, 4 ); break; case QSGPoint::Cross: drawLine( p1, p2 ); drawLine( p[0].set(p2.x,p1.y), p[1].set(p1.x,p2.y) ); break; case QSGPoint::Plus: drawLine( p[0].set(p1.x,pos.y), p[1].set(p2.x,pos.y) ); drawLine( p[0].set(pos.x,p1.y), p[1].set(pos.x,p2.y) ); break; case QSGPoint::HLine: drawLine( p[0].set(p1.x,pos.y), p[1].set(p2.x,pos.y) ); break; case QSGPoint::VLine: drawLine( p[0].set(pos.x,p1.y), p[1].set(pos.x,p2.y) ); break; default: break; } } } //-------------------------------------------------------------// /* { number_of_vertices, x1, y1, x2, y2, ... } */ // arrow static const double arrow_A[] = { 4, 0, 0, -2, -1, -1, 0, -2, 1 }; // filled arrow static const double arrow_FA[] = { 3, 0, 0, -2, -1, -2, 1 }; // narrow arrow static const double arrow_NA[] = { 3, 0, 0, -3, -1, -3, 1 }; // reversed arrow static const double arrow_RA[] = { 4, 0, 0, 2, -1, 1, 0, 2, 1 }; // reversed filled arrow static const double arrow_RFA[] = { 3, 0, 0, 2, -1, 2, 1 }; // reversed narrow arrow static const double arrow_RNA[] = { 3, 0, 0, 3, -1, 3, 1 }; // rectangle static const double arrow_R[] = { 4, -1, -1, 1, -1, 1, 1, -1, 1 }; // diamond static const double arrow_D[] = { 4, -1, 0, 0, -1, 1, 0, 0, 1 }; // line static const double arrow_L[] = { 2, 0, -1, 0, 1 }; // fdiag line static const double arrow_F[] = { 2, -1,-1, 1, 1 }; // bdiag line static const double arrow_B[] = { 2, -1, 1, 1, -1 }; static const double *arrows[] = { NULL, arrow_A, arrow_FA, arrow_NA, arrow_RA, arrow_RFA, arrow_RNA, arrow_R, arrow_D, NULL, arrow_L, arrow_F, arrow_B }; //-------------------------------------------------------------// void QSCanvasDrv::drawDart( const QSPt2f& pos, double angle, const QSGArrow& arrow ) { if ( arrow.style == QSGArrow::None ) return; double scale = toPixels( arrow.size ); QSGLine cl = currentLine(); QSGLine l; l.color = cl.color; setLine( l ); QSGFill f; f.color = cl.color; setFill( f ); if ( arrow.style == QSGArrow::Circle ) { double size = scale;; QSPt2f p1( pos.x - size, pos.y - size ); QSPt2f p2( pos.x + size, pos.y + size ); drawEllipse( p1, p2 ); return; } QSPt2f p[4]; QWMatrix m; m.translate( pos.x, pos.y ); m.rotate( angle ); m.scale( scale, scale ); for( int i=0; i 2 ) drawPoly( p, (int )arrows[arrow.style][0] ); else drawLine( p[0], p[1] ); } //-------------------------------------------------------------// void QSCanvasDrv::drawArrow( const QSPt2f& p1, const QSPt2f& p2, const QSGArrow& p1style, const QSGArrow& p2style ) { double angle = ( p1 == p2 ) ? 0.0 : atan2(p2.y-p1.y,p2.x-p1.x)*180.0/3.141592; drawLine( p1, p2 ); drawDart( p1, angle+180.0, p1style ); drawDart( p2, angle+ 0.0, p2style ); } //-------------------------------------------------------------// void QSCanvasDrv::drawRTextBox( const QSPt2f &pos, int angle, const QString& text, int align ) { QSPt2f text_size = rTextSize( angle, text ); QSPt2f text_pos = pos; if ( align & AlignLeft ) text_pos.x += text_size.x/2.0; if ( align & AlignRight ) text_pos.x -= text_size.x/2.0; if ( align & AlignTop ) text_pos.y += text_size.y/2.0; if ( align & AlignBottom ) text_pos.y -= text_size.y/2.0; drawRText( text_pos, angle, text, AlignVCenter | AlignHCenter ); } //-------------------------------------------------------------// QSPt2f QSCanvasDrv::rTextSize( int angle, const QString& text ) { QSPt2f pts[4]; getRTextBoundingPoly( pts, QSPt2f(0,0), angle, text ); QSPt2f min; QSPt2f max; min.x = QMIN(pts[0].x,pts[1].x); min.x = QMIN(min.x,pts[2].x); min.x = QMIN(min.x,pts[3].x); min.y = QMIN(pts[0].y,pts[1].y); min.y = QMIN(min.y,pts[2].y); min.y = QMIN(min.y,pts[3].y); max.x = QMAX(pts[0].x,pts[1].x); max.x = QMAX(max.x,pts[2].x); max.x = QMAX(max.x,pts[3].x); max.y = QMAX(pts[0].y,pts[1].y); max.y = QMAX(max.y,pts[2].y); max.y = QMAX(max.y,pts[3].y); return QSPt2f( max.x-min.x+1.0, max.y-min.y+1.0 ); } //-------------------------------------------------------------// /* void QSCanvasDrv::drawRText( const QSPt2f&, int, const QString&, int ) { } //-------------------------------------------------------------// void QSCanvasDrv::getRTextBoundingPoly( QSPt2f [4], const QSPt2f&, int, const QString&, int ) { } //-------------------------------------------------------------// void QSCanvasDrv::beginPolyline( const QSPt2f& ) { } //-------------------------------------------------------------// void QSCanvasDrv::drawPolylineTo( const QSPt2f& ) { } */ //-------------------------------------------------------------// void QSCanvasDrv::getPixmapBuffer( PixmapBuffer *buff, int, int ) { buff->ptr = NULL; } //-------------------------------------------------------------// void QSCanvasDrv::drawPixmap( const QSPt2f&, PixmapBuffer * ) { } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// QSDrv::QSDrv() :QSCanvasDrv() { m_t = NULL; m_clipping = false; m_pts = NULL; m_cpts2 = NULL; m_cpts3 = NULL; m_cedges = NULL; m_ncpts2 = 0; m_ncpts3 = 0; m_max_cedges = 0; m_max_pts = 0; m_max_cpts2 = 0; m_max_cpts3 = 0; m_top_bottom = false; m_category = -1; m_element = -1; } //-------------------------------------------------------------// QSDrv::~QSDrv() { } //-------------------------------------------------------------// void QSDrv::setProjection( const QSProjection *t ) { m_t = t; } //-------------------------------------------------------------// void QSDrv::setCurrentElement( int category, int element ) { m_category = category; m_element = element; } //-------------------------------------------------------------// void QSDrv::setClipping( bool enabled ) { m_clipping = enabled; } //-------------------------------------------------------------// void QSDrv::setTopBottom( bool enabled ) { m_top_bottom = enabled; } //-------------------------------------------------------------// void QSDrv::setBottomFill( const QSGFill& f ) { m_bottom_fill = f; } //-------------------------------------------------------------// void QSDrv::startDrawing() { QSCanvasDrv::startDrawing(); } //-------------------------------------------------------------// void QSDrv::stopDrawing() { delete[] m_pts; m_pts = NULL; m_max_pts = 0; delete[] m_cpts2; m_cpts2 = NULL; m_ncpts2 = 0; m_max_cpts2 = 0; delete[] m_cpts3; m_cpts3 = NULL; m_ncpts3 = 0; m_max_cpts3 = 0; m_category = -1; m_element = -1; QSCanvasDrv::stopDrawing(); } //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// void QSDrv::drawPoly3( const QSPt3f pts3[], int npoints, const QSPt3f *norm, const QSGFill *fills, const bool edges[], int edgeAutoColor ) // if driver uses something else except norm[0], colors[0] you must // reimplement this function to clipVertexColors and clipVertexNormals { const bool *in_edges = NULL; const QSPt3f *in_pts3 = NULL; int in_npts3 = 0; if ( m_clipping ) { QSProjection::ClipResult clip = clip_poly( pts3, npoints, edges ); if ( clip == QSProjection::Accepted ) { in_pts3 = pts3; in_npts3 = npoints; in_edges = edges; } else if ( clip == QSProjection::Clipped ) { in_pts3 = m_cpts3; in_npts3 = m_ncpts3; in_edges = m_cedges; } else if ( clip == QSProjection::Rejected ) return; } else { in_pts3 = pts3; in_npts3 = npoints; } map_to_screen( in_pts3, in_npts3 ); // if ( m_stage > 0 ) { QSGFill f = fills[0]; m_t->shade( f, norm[0], m_pts, in_npts3, (m_top_bottom?&m_bottom_fill:NULL) ); setFill( f ); drawPoly( m_pts, in_npts3, in_edges, edgeAutoColor ); } /* if ( cNormals() == VertexNormals || 1 ) { QSPt3f no_norm[2]; for( int i=0; iclipLine3(&p1,&p2) ) drawLine( m_t->world3DToCanvas(p1), m_t->world3DToCanvas(p2) ); } else { drawLine( m_t->world3DToCanvas(pos1), m_t->world3DToCanvas(pos2) ); } } //-------------------------------------------------------------// void QSDrv::drawText3( const QSPt3f& pos, const QString& text, int align ) { if ( !m_clipping || (m_clipping && m_t->clipPoint3(pos)) ) drawText( m_t->world3DToCanvas(pos), text, align ); } //-------------------------------------------------------------// void QSDrv::drawPoint3( const QSPt3f& pos, const QSGPoint& point ) { if ( !m_clipping || (m_clipping && m_t->clipPoint3(pos)) ) drawPoint( m_t->world3DToCanvas(pos), point ); } //-------------------------------------------------------------// void QSDrv::clearCanvas( const QSGFill&, const QSPt2f&, const QSPt2f& ) { } //-------------------------------------------------------------// void QSDrv::drawLine2( const QSPt2f &one, const QSPt2f &two ) { if ( m_clipping ) { QSPt2f p1 = one; QSPt2f p2 = two; if ( m_t->clipLine2(&p1,&p2) ) drawLine( m_t->world2DToCanvas(p1), m_t->world2DToCanvas(p2) ); } else { drawLine( m_t->world2DToCanvas(one), m_t->world2DToCanvas(two) ); } } //-------------------------------------------------------------// void QSDrv::drawRect2( const QSPt2f &p1, const QSPt2f &p2 ) { if ( !m_clipping || (m_clipping && (m_t->clipPoint2(p1) || m_t->clipPoint2(p2))) ) drawRect( m_t->world2DToCanvas(p1), m_t->world2DToCanvas(p2) ); } //-------------------------------------------------------------// void QSDrv::drawPoly2( const QSPt2f pts[], int npoints, const bool edges[], int edgeAutoColor ) { if ( m_clipping ) { QSProjection::ClipResult clip = clip_poly( pts, npoints, edges ); if ( clip == QSProjection::Accepted ) { map_to_screen( pts, npoints ); drawPoly( m_pts, npoints, edges, edgeAutoColor ); } else if ( clip == QSProjection::Clipped ) { map_to_screen( m_cpts2, m_ncpts2 ); drawPoly( m_pts, m_ncpts2, m_cedges, edgeAutoColor ); } } else { map_to_screen( pts, npoints ); drawPoly( m_pts, npoints, edges, edgeAutoColor ); } } //-------------------------------------------------------------// void QSDrv::drawEllipse2( const QSPt2f& p1, const QSPt2f& p2 ) { if ( !m_clipping || (m_clipping && (m_t->clipPoint2(p1) || m_t->clipPoint2(p2))) ) drawEllipse( m_t->world2DToCanvas(p1), m_t->world2DToCanvas(p2) ); } //-------------------------------------------------------------// void QSDrv::drawText2( const QSPt2f &pos, const QString& text, int align ) { if ( !m_clipping || (m_clipping && m_t->clipPoint2(pos)) ) drawText( m_t->world2DToCanvas(pos), text, align ); } //-------------------------------------------------------------// void QSDrv::drawRText2( const QSPt2f &pos, int angle, const QString& text, int align ) { if ( !m_clipping || (m_clipping && m_t->clipPoint2(pos)) ) drawRText( m_t->world2DToCanvas(pos), angle, text, align ); } //-------------------------------------------------------------// void QSDrv::drawRTextBox2( const QSPt2f &pos, int angle, const QString& text, int align ) { if ( !m_clipping || (m_clipping && m_t->clipPoint2(pos)) ) drawRTextBox( m_t->world2DToCanvas(pos), angle, text, align ); } //-------------------------------------------------------------// void QSDrv::drawPoint2( const QSPt2f& pos, const QSGPoint& style ) { if ( !m_clipping || (m_clipping && m_t->clipPoint2(pos)) ) drawPoint( m_t->world2DToCanvas(pos), style ); } //-------------------------------------------------------------// void QSDrv::drawDart2( const QSPt2f& pos, double angle, const QSGArrow& style ) { drawDart( m_t->world2DToCanvas(pos), angle, style ); } //-------------------------------------------------------------// void QSDrv::drawArrow2( const QSPt2f& pos1, const QSPt2f& pos2, const QSGArrow& p1style, const QSGArrow& p2style ) { if ( m_clipping ) { QSPt2f p1 = pos1; QSPt2f p2 = pos2; QSGArrow s1 = p1style; QSGArrow s2 = p2style; if (m_t->clipLine2(&p1,&p2)) { if ( p1 != pos1 ) s1.style = QSGArrow::None; if ( p2 != pos2 ) s2.style = QSGArrow::None; drawArrow( m_t->world2DToCanvas(p1), m_t->world2DToCanvas(p2), s1, s2 ); } } else { drawArrow( m_t->world2DToCanvas(pos1), m_t->world2DToCanvas(pos2), p1style, p2style ); } } //-------------------------------------------------------------// void QSDrv::beginPolyline2( const QSPt2f& pos ) { m_curr_polyline_pos = pos; beginPolyline( m_t->world2DToCanvas(pos) ); } //-------------------------------------------------------------// void QSDrv::drawPolylineTo2( const QSPt2f& pos ) { if ( m_clipping ) { QSPt2f p1 = m_curr_polyline_pos; QSPt2f p2 = pos; if (m_t->clipLine2(&p1,&p2)) { QSPt2f canvas_p1 = m_t->world2DToCanvas(p1); QSPt2f canvas_p2 = m_t->world2DToCanvas(p2); if (p1!=m_curr_polyline_pos) { endPolyline(); beginPolyline(canvas_p1); } // leave a place for a label QSPt2f label_p1 = canvas_p1; QSPt2f label_p2 = canvas_p2; QSProjection::ClipResult clip_result = m_t->clipLine( &label_p1, &label_p2, m_polyline_label_pos, m_polyline_label_size ); // skip if ( clip_result == QSProjection::Accepted ) { endPolyline(); beginPolyline( canvas_p2 ); } else // draw normal line if ( clip_result == QSProjection::Rejected ) { drawPolylineTo( canvas_p2 ); } else // draw clipped line if ( clip_result == QSProjection::Clipped ) { if ( canvas_p1 != label_p1 && canvas_p2 != label_p2 ) { drawPolylineTo( label_p1 ); endPolyline(); beginPolyline( label_p2 ); drawPolylineTo( canvas_p2 ); } else if ( canvas_p1 != label_p1 ) { drawPolylineTo( label_p1 ); } else if ( canvas_p2 != label_p2 ) { endPolyline(); beginPolyline( label_p2 ); drawPolylineTo( canvas_p2 ); } } } } else { drawPolylineTo( m_t->world2DToCanvas(pos) ); } m_curr_polyline_pos = pos; } //-------------------------------------------------------------// void QSDrv::endPolyline2() { endPolyline(); } //-------------------------------------------------------------// QSPt2f QSDrv::currPolylinePos2() { return m_curr_polyline_pos; } //-------------------------------------------------------------// void QSDrv::setPolylineLabelPlace2( const QString& label, const QSPt2f& label_place, int angle ) { if ( !label.isEmpty() ) { QSPt2f size = rTextSize( angle, label ); m_polyline_label_size = size; m_polyline_label_pos = m_t->world2DToCanvas( label_place ); m_polyline_label_pos.x -= size.x/2.0; m_polyline_label_pos.y -= size.y/2.0; } else { m_polyline_label_size = QSPt2f(); } } //-------------------------------------------------------------// QSProjection::ClipResult QSDrv::clip_poly( const QSPt2f *pts, int npoints, const bool edges[] ) { int clip_buff_size = npoints<<2; if ( clip_buff_size > m_max_cpts2 ) { delete[] m_cpts2; m_max_cpts2 = clip_buff_size; m_cpts2 = new QSPt2f[m_max_cpts2]; } if ( clip_buff_size > m_max_cedges ) { delete[] m_cedges; m_max_cedges = clip_buff_size; m_cedges = new bool[m_max_cedges]; } return m_t->clipPoly2( pts, npoints, m_cpts2, &m_ncpts2, m_max_cpts2, m_cedges, edges ); } //-------------------------------------------------------------// QSProjection::ClipResult QSDrv::clip_poly( const QSPt3f *pts, int npoints, const bool edges[] ) { int clip_buff_size = npoints<<2; if ( clip_buff_size > m_max_cpts3 ) { delete[] m_cpts3; m_max_cpts3 = clip_buff_size; m_cpts3 = new QSPt3f[m_max_cpts3]; } if ( clip_buff_size > m_max_cedges ) { delete[] m_cedges; m_max_cedges = clip_buff_size; m_cedges = new bool[m_max_cedges]; } QSPt3f bbox[2]; m_t->getPoly3Cube( pts, npoints, bbox ); return m_t->clipPoly3( pts, npoints, m_cpts3, &m_ncpts3, m_max_cpts3, bbox, m_cedges, edges ); } //-------------------------------------------------------------// void QSDrv::map_to_screen( const QSPt2f *pts, int npoints ) { if ( npoints > m_max_pts ) { delete[] m_pts; m_max_pts = npoints; m_pts = new QSPt2f[m_max_pts]; } for( int i=0; iworld2DToCanvas( pts[i] ); } //-------------------------------------------------------------// void QSDrv::map_to_screen( const QSPt3f *pts, int npoints ) { if ( npoints > m_max_pts ) { delete[] m_pts; m_max_pts = npoints; m_pts = new QSPt2f[m_max_pts]; } for( int i=0; iworld3DToCanvas( pts[i] ); } //-------------------------------------------------------------// void QSDrv::copySettingsFrom( const QSDrv *drv ) { setProjection( drv->projection() ); } /** * Converts points (1/72 inch) to pixels - "pixels = points*dpi/72". * All fixed sizes must be converted by this function. * There must not be fixed pixel-sizes ! * ( all legend sizes, spaces, shadows shifts etc must have its fixed size in points ) */ //inline int toPixels( int points ) { return int(QSCoord::pointsToPixels(points,dpi)+0.5); } /* //if ( cl != l ) setLine( cl ); //if ( cf != f ) setFill( cf ); //if ( cf != f ) setFill( cf ); //if ( cl != l ) setLine( cl ); //if ( cl != l ) setLine( l ); //if ( cf != f ) setFill( f ); // QSGFill cf = currentFill(); */