00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "KPrPieObject.h"
00022 #include "KPrGradient.h"
00023 #include "KPrUtils.h"
00024 #include "KPrPieObjectIface.h"
00025
00026 #include <KoTextZoomHandler.h>
00027 #include <KoOasisContext.h>
00028 #include <KoStyleStack.h>
00029 #include <KoXmlNS.h>
00030
00031 #include <kdebug.h>
00032
00033 #include <qregion.h>
00034 #include <qpicture.h>
00035 #include <qdom.h>
00036 #include <qpainter.h>
00037 #include <qbitmap.h>
00038 using namespace std;
00039
00040 KPrPieObject::KPrPieObject()
00041 : KPr2DObject()
00042 , KPrStartEndLine( L_NORMAL, L_NORMAL )
00043 {
00044 pieType = PT_PIE;
00045 p_angle = 45 * 16;
00046 p_len = 270 * 16;
00047 }
00048
00049 KPrPieObject::KPrPieObject( const KoPen &_pen, const QBrush &_brush, FillType _fillType,
00050 const QColor &_gColor1, const QColor &_gColor2, BCType _gType,
00051 PieType _pieType, int _p_angle, int _p_len,
00052 LineEnd _lineBegin, LineEnd _lineEnd,
00053 bool _unbalanced, int _xfactor, int _yfactor )
00054 : KPr2DObject( _pen, _brush, _fillType, _gColor1, _gColor2, _gType, _unbalanced, _xfactor, _yfactor )
00055 , KPrStartEndLine( _lineBegin, _lineEnd )
00056 {
00057 pieType = _pieType;
00058 p_angle = _p_angle;
00059 p_len = _p_len;
00060 }
00061
00062 DCOPObject* KPrPieObject::dcopObject()
00063 {
00064 if ( !dcop )
00065 dcop = new KPrPieObjectIface( this );
00066 return dcop;
00067 }
00068
00069 KPrPieObject &KPrPieObject::operator=( const KPrPieObject & )
00070 {
00071 return *this;
00072 }
00073
00074 QDomDocumentFragment KPrPieObject::save( QDomDocument& doc, double offset )
00075 {
00076 QDomDocumentFragment fragment=KPr2DObject::save(doc, offset);
00077 KPrStartEndLine::save( fragment, doc );
00078 if (p_angle!=720)
00079 fragment.appendChild(KPrObject::createValueElement("PIEANGLE", p_angle, doc));
00080 if (p_len!=1440)
00081 fragment.appendChild(KPrObject::createValueElement("PIELENGTH", p_len, doc));
00082 if (pieType!=PT_PIE)
00083 fragment.appendChild(KPrObject::createValueElement("PIETYPE", static_cast<int>(pieType), doc));
00084 return fragment;
00085 }
00086
00087 bool KPrPieObject::saveOasisObjectAttributes( KPOasisSaveContext &sc ) const
00088 {
00089 switch( pieType )
00090 {
00091 case PT_PIE:
00092 sc.xmlWriter.addAttribute( "draw:kind", "section" );
00093 break;
00094 case PT_CHORD:
00095 sc.xmlWriter.addAttribute( "draw:kind", "cut" );
00096 break;
00097 case PT_ARC:
00098 sc.xmlWriter.addAttribute( "draw:kind", "arc" );
00099 break;
00100 default:
00101 kdDebug() << " type of pie not supported" << endl;
00102 }
00103
00104 int startangle = ( (int)p_angle / 16 );
00105 sc.xmlWriter.addAttribute( "draw:start-angle", startangle );
00106
00107 int endangle = ( (int) p_len / 16 ) + startangle;
00108 sc.xmlWriter.addAttribute( "draw:end-angle", endangle );
00109
00110 return true;
00111 }
00112
00113 void KPrPieObject::fillStyle( KoGenStyle& styleObjectAuto, KoGenStyles& mainStyles ) const
00114 {
00115 KPrShadowObject::fillStyle( styleObjectAuto, mainStyles );
00116 if ( pieType == PT_ARC )
00117 {
00118 saveOasisMarkerElement( mainStyles, styleObjectAuto );
00119 }
00120 else
00121 {
00122 m_brush.saveOasisFillStyle( styleObjectAuto, mainStyles );
00123 }
00124 }
00125
00126 const char * KPrPieObject::getOasisElementName() const
00127 {
00128 return ext.width() == ext.height() ? "draw:circle" : "draw:ellipse";
00129 }
00130
00131
00132 void KPrPieObject::loadOasis(const QDomElement &element, KoOasisContext & context, KPrLoadingInfo *info)
00133 {
00134 kdDebug()<<"void KPrPieObject::loadOasis(const QDomElement &element) ***************\n";
00135 KPr2DObject::loadOasis(element, context, info);
00136 QString kind = element.attributeNS( KoXmlNS::draw, "kind", QString::null );
00137 if ( kind == "section" )
00138 pieType = PT_PIE;
00139 else if ( kind == "cut" )
00140 pieType = PT_CHORD;
00141 else if ( kind == "arc" )
00142 pieType =PT_ARC;
00143 else
00144 {
00145 kdDebug()<<" KPrPieObject::loadOasis(const QDomElement &element) type indefined :"<<kind<<endl;
00146 pieType = PT_PIE;
00147 }
00148 kdDebug()<<" type of pie object :"<<( ( pieType == PT_PIE ) ? "pie" : ( pieType == PT_CHORD )?"cut" : "arc" )<<endl;
00149
00150 int start = (int) ( element.attributeNS( KoXmlNS::draw, "start-angle", QString::null ).toDouble() );
00151 p_angle=start*16;
00152
00153 int end = (int) ( element.attributeNS( KoXmlNS::draw, "end-angle", QString::null ).toDouble() );
00154 if ( end < start )
00155 p_len = ( ( 360 - start + end ) * 16 );
00156 else
00157 p_len = ( ( end - start ) * 16 );
00158
00159 kdDebug()<<"KPrPieObject::loadOasis(const QDomElement &element) : p_angle :"<<p_angle<<" p_len :"<<p_len<<endl;
00160 if ( pieType == PT_ARC )
00161 {
00162 loadOasisMarkerElement( context, "marker-start", lineBegin );
00163 loadOasisMarkerElement( context, "marker-end", lineEnd );
00164 }
00165 }
00166
00167 double KPrPieObject::load(const QDomElement &element)
00168 {
00169 double offset=KPr2DObject::load(element);
00170 KPrStartEndLine::load( element );
00171 QDomElement e=element.namedItem("PIEANGLE").toElement();
00172 if(!e.isNull()) {
00173 int tmp=0;
00174 if(e.hasAttribute("value"))
00175 tmp=e.attribute("value").toInt();
00176 p_angle=tmp;
00177 }
00178 e=element.namedItem("PIELENGTH").toElement();
00179 if(!e.isNull()) {
00180 int tmp=0;
00181 if(e.hasAttribute("value"))
00182 tmp=e.attribute("value").toInt();
00183 p_len=tmp;
00184 }
00185 else
00186 p_len=1440;
00187
00188 e=element.namedItem("PIETYPE").toElement();
00189 if(!e.isNull()) {
00190 int tmp=0;
00191 if(e.hasAttribute("value"))
00192 tmp=e.attribute("value").toInt();
00193 pieType=static_cast<PieType>(tmp);
00194 }
00195 return offset;
00196 }
00197
00198 void KPrPieObject::paint( QPainter* _painter, KoTextZoomHandler*_zoomHandler,
00199 int , bool drawingShadow, bool drawContour )
00200 {
00201 double ow = ext.width();
00202 double oh = ext.height();
00203 double pw = ( ( pen.style() == Qt::NoPen ) ? 1 : pen.pointWidth() ) / 2.0;
00204
00205 if ( drawContour ) {
00206 QPen pen3( Qt::black, 1, Qt::DotLine );
00207 _painter->setPen( pen3 );
00208 _painter->setRasterOp( Qt::NotXorROP );
00209 }
00210 else {
00211 QPen pen2 = pen.zoomedPen( _zoomHandler );
00212 _painter->setPen( pen2 );
00213 if ( drawingShadow || getFillType() == FT_BRUSH || !gradient )
00214 {
00215 _painter->setBrush( getBrush() );
00216 }
00217 else
00218 {
00219 if ( pieType != PT_ARC )
00220 {
00221 QSize size( _zoomHandler->zoomSize( ext ) );
00222
00223 if ( m_redrawGradientPix || gradient->size() != size )
00224 {
00225 m_redrawGradientPix = false;
00226 gradient->setSize( size );
00227
00228 m_gradientPix.resize ( size );
00229 m_gradientPix.fill( Qt::white );
00230 QPainter p;
00231 p.begin( &m_gradientPix );
00232 p.drawPixmap( 0, 0, gradient->pixmap() );
00233 p.end();
00234
00235 QBitmap mask( size, true );
00236 p.begin( &mask );
00237 p.setPen( QPen( Qt::color1 ) );
00238 p.setBrush( QBrush( Qt::color1 ) );
00239 if ( pieType == PT_CHORD )
00240 {
00241 p.drawChord( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw),
00242 _zoomHandler->zoomItX(ow - 2 * pw),
00243 _zoomHandler->zoomItY(oh - 2 * pw), p_angle, p_len );
00244 }
00245 else
00246 {
00247 p.drawPie( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw),
00248 _zoomHandler->zoomItX( ow - 2 * pw),
00249 _zoomHandler->zoomItY( oh - 2 * pw), p_angle, p_len );
00250 }
00251 p.end();
00252 m_gradientPix.setMask( mask );
00253 }
00254 _painter->drawPixmap( 0, 0, m_gradientPix, 0, 0, size.width(), size.height() );
00255 _painter->setBrush( Qt::NoBrush );
00256 }
00257 }
00258 if ( pieType == PT_ARC )
00259 {
00260 KoPointArray points( 2 );
00261 setEndPoints( points );
00262 KoPoint start( points.point( 0 ) );
00263 KoPoint end( points.point( 1 ) );
00264
00265 double ys = ( ( 1 - start.x() / ( ext.width() * ext.width() / 4 ) ) * ext.height() * ext.height() / 4 ) / start.y();
00266 double s_angle = 90 + ( atan( ( start.x() - 1 ) / ( start.y() - ys ) ) * 180 / M_PI );
00267 if ( p_angle / 16 >= 90 && p_angle / 16 <= 270 )
00268 {
00269 s_angle += 180.0;
00270 }
00271 double ye = ( ( 1 - end.x() / ( ext.width() * ext.width() / 4 ) ) * ext.height() * ext.height() / 4 ) / end.y();
00272 double e_angle = 270 + ( atan( ( end.x() - 1 ) / ( end.y() - ye ) ) * 180 / M_PI );
00273 if ( ( ( p_angle + p_len ) / 16 ) % 360 >= 90 && ( ( p_angle + p_len ) / 16 ) % 360 <= 270 )
00274 {
00275 e_angle -= 180.0;
00276 }
00277
00278 start = KoPoint( ext.width() / 2.0 + start.x(), ext.height() / 2.0 - start.y() );
00279 end = KoPoint( ext.width() / 2.0 + end.x(), ext.height() / 2.0 - end.y() );
00280
00281
00282
00283 if ( lineBegin != L_NORMAL )
00284 drawFigureWithOffset( lineBegin, _painter, start,
00285 pen2.color(), int( pen.pointWidth() ), s_angle, _zoomHandler, true );
00286
00287 if ( lineEnd != L_NORMAL )
00288 drawFigureWithOffset( lineEnd, _painter, end,
00289 pen2.color(), int( pen.pointWidth() ), e_angle, _zoomHandler, false );
00290 }
00291 }
00292 switch ( pieType )
00293 {
00294 case PT_PIE:
00295 _painter->drawPie( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY( pw),
00296 _zoomHandler->zoomItX( ow - 2 * pw),
00297 _zoomHandler->zoomItY( oh - 2 * pw), p_angle, p_len );
00298 break;
00299 case PT_ARC:
00300 _painter->drawArc( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw),
00301 _zoomHandler->zoomItX(ow - 2 * pw),
00302 _zoomHandler->zoomItY(oh - 2 * pw), p_angle, p_len );
00303 break;
00304 case PT_CHORD:
00305 _painter->drawChord( _zoomHandler->zoomItX(pw), _zoomHandler->zoomItY(pw),
00306 _zoomHandler->zoomItX(ow - 2 * pw),
00307 _zoomHandler->zoomItY(oh - 2 * pw), p_angle, p_len );
00308 break;
00309 default: break;
00310 }
00311 }
00312
00313 void KPrPieObject::flip( bool horizontal )
00314 {
00315 KPr2DObject::flip( horizontal );
00316 if ( ! horizontal )
00317 {
00318 p_angle = 360*16 - p_angle -p_len;
00319 }
00320 else
00321 {
00322 p_angle = 180*16 - p_angle - p_len;
00323 }
00324
00325 while ( p_angle < 0 ) {
00326 p_angle += 360*16;
00327 }
00328
00329 }
00330
00331
00332 void KPrPieObject::setMinMax( double &min_x, double &min_y,
00333 double &max_x, double &max_y, KoPoint point ) const
00334 {
00335 double tmp_x = point.x();
00336 double tmp_y = point.y();
00337
00338 if ( tmp_x < min_x ) {
00339 min_x = tmp_x;
00340 }
00341 else if ( tmp_x > max_x ) {
00342 max_x = tmp_x;
00343 }
00344
00345 if ( tmp_y < min_y ) {
00346 min_y = tmp_y;
00347 }
00348 else if ( tmp_y > max_y ) {
00349 max_y = tmp_y;
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 void KPrPieObject::getRealSizeAndOrig( KoSize &size, KoPoint &realOrig ) const {
00366 double radius1 = size.width() / 2.0;
00367 double radius2 = size.height() / 2.0;
00368
00369
00370 double angInRad = angle * M_PI / 180;
00371
00372
00373 KoPointArray points(2);
00374 setEndPoints( points );
00375
00376
00377 for ( int i = 0; i < 2; i++ ) {
00378 if ( angle != 0 ) {
00379 double sinus = sin( angInRad );
00380 double cosinus = cos( angInRad );
00381
00382 double tmp_x = points.point( i ).x();
00383 double tmp_y = points.point( i ).y();
00384
00385 double x = tmp_x * cosinus + tmp_y * sinus;
00386 double y = - tmp_x * sinus + tmp_y * cosinus;
00387 points.setPoint( i, x, y );
00388 }
00389 }
00390
00391 KoPoint firstPoint( points.point(0) );
00392 KoPoint secondPoint( points.point(1) );
00393
00394
00395 KoPointArray maxPoints(4);
00396 if ( angle == 0 ) {
00397 maxPoints.setPoint( 0, 0, radius2 );
00398 maxPoints.setPoint( 1, radius1, 0 );
00399 maxPoints.setPoint( 2, 0, -radius2 );
00400 maxPoints.setPoint( 3, -radius1, 0 );
00401 }
00402 else {
00403 double sinus = sin( angInRad );
00404 double cosinus = cos( angInRad );
00405
00406 double x = sqrt( pow( radius1 * cosinus , 2 ) + pow(radius2 * sinus, 2));
00407 double y = ( pow( radius2, 2 ) - pow( radius1, 2) ) * sinus * cosinus / x;
00408 maxPoints.setPoint( 0, x, y );
00409 maxPoints.setPoint( 1, -x, -y );
00410
00411 y = sqrt( pow( radius1 * sinus , 2 ) + pow(radius2 * cosinus, 2));
00412 x = ( pow( radius1, 2 ) - pow( radius2, 2) ) * sinus * cosinus / y;
00413 maxPoints.setPoint( 2, x, y);
00414 maxPoints.setPoint( 3, -x, -y );
00415 }
00416
00417
00418 double min_x = firstPoint.x();
00419 double min_y = firstPoint.y();
00420 double max_x = firstPoint.x();
00421 double max_y = firstPoint.y();
00422
00423 if ( pieType == PT_PIE ) {
00424 KoPoint zero(0,0);
00425 setMinMax( min_x, min_y, max_x, max_y, zero );
00426 }
00427 setMinMax( min_x, min_y, max_x, max_y, secondPoint );
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 if ( firstPoint.y() >= 0 ) {
00448 if ( secondPoint.y() >= 0 ) {
00449 if ( firstPoint.x() > secondPoint.x() || p_len == 0 ) {
00450
00451
00452 KoPointArray::ConstIterator it( maxPoints.begin() );
00453 for ( ; it != maxPoints.end(); ++it ) {
00454 if ( (*it).y() >= 0 &&
00455 (*it).x() <= firstPoint.x() && (*it).x() >= secondPoint.x() )
00456 {
00457 setMinMax( min_x, min_y, max_x, max_y, *it );
00458 }
00459 }
00460 }
00461 else {
00462
00463
00464
00465
00466 KoPointArray::ConstIterator it( maxPoints.begin() );
00467 for ( ; it != maxPoints.end(); ++it ) {
00468 if ( (*it).y() >= 0 ) {
00469 if ( (*it).x() <= firstPoint.x() || (*it).x() >= secondPoint.x() ) {
00470 setMinMax( min_x, min_y, max_x, max_y, *it );
00471 }
00472 }
00473 else {
00474 setMinMax( min_x, min_y, max_x, max_y, *it );
00475 }
00476 }
00477 }
00478 }
00479 else {
00480
00481
00482
00483 KoPointArray::ConstIterator it( maxPoints.begin() );
00484 for ( ; it != maxPoints.end(); ++it ) {
00485 if ( (*it).y() >= 0 ) {
00486 if ( (*it).x() <= firstPoint.x() ) {
00487 setMinMax( min_x, min_y, max_x, max_y, *it );
00488 }
00489 }
00490 else {
00491 if ( (*it).x() <= secondPoint.x() ) {
00492 setMinMax( min_x, min_y, max_x, max_y, *it );
00493 }
00494 }
00495 }
00496 }
00497 }
00498 else {
00499 if ( secondPoint.y() >= 0 ) {
00500
00501
00502
00503 KoPointArray::ConstIterator it( maxPoints.begin() );
00504 for ( ; it != maxPoints.end(); ++it ) {
00505 if ( (*it).y() < 0 ) {
00506 if ( (*it).x() >= firstPoint.x() ) {
00507 setMinMax( min_x, min_y, max_x, max_y, *it );
00508 }
00509 }
00510 else {
00511 if ( (*it).x() >= secondPoint.x() ) {
00512 setMinMax( min_x, min_y, max_x, max_y, *it );
00513 }
00514 }
00515 }
00516 }
00517 else {
00518 if ( firstPoint.x() < secondPoint.x() || p_len == 0 ) {
00519
00520
00521 KoPointArray::ConstIterator it( maxPoints.begin() );
00522 for ( ; it != maxPoints.end(); ++it ) {
00523 if ( (*it).y() < 0 &&
00524 (*it).x() >= firstPoint.x() && (*it).x() <= secondPoint.x() )
00525 {
00526 setMinMax( min_x, min_y, max_x, max_y, *it );
00527 }
00528 }
00529 }
00530 else {
00531
00532
00533
00534
00535 KoPointArray::ConstIterator it( maxPoints.begin() );
00536 for ( ; it != maxPoints.end(); ++it ) {
00537 if ( (*it).y() < 0 ) {
00538 if ( (*it).x() >= firstPoint.x() || (*it).x() <= secondPoint.x() ) {
00539 setMinMax( min_x, min_y, max_x, max_y, *it );
00540 }
00541 }
00542 else {
00543 setMinMax( min_x, min_y, max_x, max_y, *it );
00544 }
00545 }
00546 }
00547 }
00548 }
00549
00550 double mid_x = size.width() / 2;
00551 double mid_y = size.height() / 2;
00552
00553 size.setWidth( max_x - min_x );
00554 size.setHeight( max_y - min_y );
00555
00556 realOrig.setX( realOrig.x() + mid_x + min_x );
00557 realOrig.setY( realOrig.y() + mid_y - max_y );
00558 }
00559
00560 void KPrPieObject::setEndPoints( KoPointArray &points ) const
00561 {
00562 int angles[] = { p_angle, ( p_angle + p_len ) % ( 16 * 360 ) };
00563 double anglesInRad[] = { p_angle / 16.0 * M_PI / 180, ( angles[1] ) / 16.0 * M_PI / 180 };
00564
00565 double radius1 = ext.width() / 2.0;
00566 double radius2 = ext.height() / 2.0;
00567
00568 double prop = radius2 / radius1;
00569
00570 for ( int i = 0; i < 2; i++ ) {
00571 double x = 0;
00572 double y = 0;
00573
00574
00575 if ( angles[i] == 90 * 16 ) {
00576 y = radius2;
00577 }
00578 else if ( angles[i] == 270 * 16 ) {
00579 y = -radius2;
00580 }
00581 else {
00582
00583
00584 double tanalpha = tan( anglesInRad[i] ) * prop;
00585 x = sqrt( 1 / ( pow ( 1 / radius1, 2 ) + pow( tanalpha / radius2, 2 ) ) );
00586 if ( angles[i] > 90 * 16 && angles[i] < 270 * 16 )
00587 x = -x;
00588 y = tanalpha * x;
00589 }
00590 points.setPoint( i, x, y );
00591 }
00592 }
00593
00594 KoSize KPrPieObject::getRealSize() const {
00595 KoSize size( ext );
00596 KoPoint realOrig( orig );
00597 getRealSizeAndOrig( size, realOrig );
00598 return size;
00599 }
00600
00601
00602 KoPoint KPrPieObject::getRealOrig() const {
00603 KoSize size( ext );
00604 KoPoint realOrig( orig );
00605 getRealSizeAndOrig( size, realOrig );
00606 return realOrig;
00607 }