2 This file is part of Kig, a KDE program for Interactive Geometry...
3 Copyright (C) 2002-2003 Dominique Devriese <devriese@kde.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 #include "kigpainter.h"
23 #include "../kig/kig_view.h"
24 #include "../kig/kig_document.h"
25 #include "../misc/goniometry.h"
26 #include "../objects/object_holder.h"
27 #include "../objects/curve_imp.h"
28 #include "../objects/point_imp.h"
29 #include "object_hierarchy.h"
31 #include "conic-common.h"
32 #include "cubic-common.h"
33 #include "coordinate_system.h"
42 KigPainter::KigPainter( const ScreenInfo
& si
, QPaintDevice
* device
,
43 const KigDocument
& doc
, bool no
)
46 style( Qt::SolidLine
),
49 brushStyle( Qt::NoBrush
),
50 brushColor( Qt::blue
),
56 mP
.setBackgroundColor( Qt::white
);
59 KigPainter::~KigPainter()
63 void KigPainter::drawRect( const Rect
& r
)
65 Rect rt
= r
.normalized();
66 QRect qr
= toScreen(rt
);
69 if( mNeedOverlay
) mOverlay
.push_back( qr
);
72 void KigPainter::drawRect( const QRect
& r
)
75 if( mNeedOverlay
) mOverlay
.push_back( r
);
78 void KigPainter::drawCircle( const Coordinate
& center
, const double radius
)
80 Coordinate bottomLeft
= center
- Coordinate(radius
, radius
);
81 Coordinate topRight
= center
+ Coordinate(radius
, radius
);
82 Rect
r( bottomLeft
, topRight
);
83 QRect qr
= toScreen( r
);
84 mP
.drawEllipse ( qr
);
85 if( mNeedOverlay
) circleOverlay( center
, radius
);
88 void KigPainter::drawSegment( const Coordinate
& from
, const Coordinate
& to
)
90 QPoint tF
= toScreen(from
), tT
= toScreen(to
);
91 mP
.drawLine( tF
, tT
);
92 if( mNeedOverlay
) segmentOverlay( from
, to
);
95 void KigPainter::drawFatPoint( const Coordinate
& p
)
97 int twidth
= width
== -1 ? 5 : width
;
98 mP
.setPen( QPen( color
, 1, style
) );
103 double radius
= twidth
* pixelWidth();
104 setBrushStyle( Qt::SolidPattern
);
105 Coordinate
rad( radius
, radius
);
107 Coordinate tl
= p
- rad
;
108 Coordinate br
= p
+ rad
;
110 QRect qr
= toScreen( r
);
111 mP
.drawEllipse( qr
);
112 if( mNeedOverlay
) mOverlay
.push_back( qr
);
117 double radius
= twidth
* pixelWidth();
118 setBrushStyle( Qt::NoBrush
);
119 Coordinate
rad( radius
, radius
);
121 Coordinate tl
= p
- rad
;
122 Coordinate br
= p
+ rad
;
124 QRect qr
= toScreen( r
);
125 mP
.drawEllipse( qr
);
126 if( mNeedOverlay
) mOverlay
.push_back( qr
);
131 double radius
= twidth
* pixelWidth();
132 Coordinate
rad( radius
, radius
);
134 Coordinate tl
= p
- rad
;
135 Coordinate br
= p
+ rad
;
137 QRect qr
= toScreen( r
);
139 mP
.fillRect( qr
, QBrush( color
, Qt::SolidPattern
) );
140 if( mNeedOverlay
) mOverlay
.push_back( qr
);
145 double radius
= twidth
* pixelWidth();
146 Coordinate
rad( radius
, radius
);
148 Coordinate tl
= p
- rad
;
149 Coordinate br
= p
+ rad
;
151 QRect qr
= toScreen( r
);
153 if( mNeedOverlay
) mOverlay
.push_back( qr
);
158 double radius
= twidth
* pixelWidth();
159 Coordinate
rad( radius
, radius
);
161 Coordinate tl
= p
- rad
;
162 Coordinate br
= p
+ rad
;
164 QRect qr
= toScreen( r
);
165 mP
.setPen( QPen( color
, 2 ) );
166 mP
.drawLine( qr
.topLeft(), qr
.bottomRight() );
167 mP
.drawLine( qr
.topRight(), qr
.bottomLeft() );
168 if( mNeedOverlay
) mOverlay
.push_back( qr
);
172 mP
.setPen( QPen( color
, twidth
, style
) );
175 void KigPainter::drawPoint( const Coordinate
& p
)
177 mP
.drawPoint( toScreen(p
) );
178 if( mNeedOverlay
) pointOverlay( p
);
181 void KigPainter::drawLine( const Coordinate
& p1
, const Coordinate
& p2
)
183 drawLine( LineData( p1
, p2
) );
186 void KigPainter::drawText( const Rect p
, const QString s
, int textFlags
, int len
)
188 QRect t
= toScreen(p
);
191 t
.setWidth( t
.width() - 4 );
192 t
.setHeight( t
.height() - 4 );
193 mP
.drawText( t
, tf
, s
, len
);
194 if( mNeedOverlay
) textOverlay( t
, s
, tf
, len
);
197 void KigPainter::textOverlay( const QRect
& r
, const QString s
, int textFlags
, int len
)
199 // kdDebug() << Rect::fromQRect( mP.boundingRect( r, textFlags, s, len ) ) << endl;
200 QRect
newr( mP
.boundingRect( r
, textFlags
, s
, len
) );
201 newr
.moveBy( -2, -2 );
202 newr
.setWidth( newr
.width() + 4 );
203 newr
.setHeight( newr
.height() + 4 );
204 mOverlay
.push_back( newr
);
207 const Rect
KigPainter::boundingRect( const Rect
& r
, const QString s
,
210 QRect qr
= mP
.boundingRect( toScreen( r
), f
, s
, l
);
212 qr
.setWidth( qr
.width() + 4 );
213 qr
.setHeight( qr
.height() + 4 );
214 return fromScreen( qr
);
217 void KigPainter::setColor( const QColor
& c
)
220 mP
.setPen( QPen( color
, width
== -1 ? 1 : width
, style
) );
223 void KigPainter::setStyle( const PenStyle c
)
226 mP
.setPen( QPen( color
, width
== -1 ? 1 : width
, style
) );
229 void KigPainter::setWidth( const int c
)
232 if (c
> 0) overlayenlarge
= c
- 1;
233 mP
.setPen( QPen( color
, width
== -1 ? 1 : width
, style
) );
236 void KigPainter::setPointStyle( const int p
)
241 void KigPainter::setPen( const QPen
& p
)
249 void KigPainter::setBrush( const QBrush
& b
)
251 brushStyle
= b
.style();
252 brushColor
= b
.color();
256 void KigPainter::setBrushStyle( const BrushStyle c
)
259 mP
.setBrush( QBrush( brushColor
, brushStyle
) );
262 void KigPainter::setBrushColor( const QColor
& c
)
265 mP
.setBrush( QBrush( brushColor
, brushStyle
) );
268 bool KigPainter::getNightVision( ) const
270 return mdoc
.getNightVision();
273 QColor
KigPainter::getColor() const
279 static void setContains( QRect& r, const QPoint& p )
281 if ( r.left() > p.x() ) r.setLeft( p.x() );
282 if ( r.right() < p.x() ) r.setRight( p.x() );
283 // this is correct, i think. In qt the bottom has the highest y
285 if ( r.bottom() > p.y() ) r.setBottom( p.y() );
286 if ( r.top() < p.y() ) r.setTop( p.y() );
290 void KigPainter::drawPolygon( const std::vector
<QPoint
>& pts
,
291 bool winding
, int index
, int npoints
)
293 QPen oldpen
= mP
.pen();
294 QBrush oldbrush
= mP
.brush();
295 setBrush( QBrush( color
, Dense4Pattern
) );
297 // i know this isn't really fast, but i blame it all on Qt with its
298 // stupid container classes... what's wrong with the STL ?
299 QPointArray
t( pts
.size() );
301 for( std::vector
<QPoint
>::const_iterator i
= pts
.begin(); i
!= pts
.end(); ++i
)
303 t
.putPoints( c
++, 1, i
->x(), i
->y() );
305 mP
.drawPolygon( t
, winding
, index
, npoints
);
307 setBrush( oldbrush
);
308 if( mNeedOverlay
) mOverlay
.push_back( t
.boundingRect() );
311 void KigPainter::drawArea( const std::vector
<Coordinate
>& pts
, bool border
)
313 QPen oldpen
= mP
.pen();
314 QBrush oldbrush
= mP
.brush();
315 setBrush( QBrush( color
, SolidPattern
) );
317 setPen( QPen( color
, width
== -1 ? 1 : width
) );
320 QPointArray
t( pts
.size() );
322 for( std::vector
<Coordinate
>::const_iterator i
= pts
.begin(); i
!= pts
.end(); ++i
)
324 QPoint p
= toScreen( *i
);
325 t
.putPoints( c
++, 1, p
.x(), p
.y() );
329 setBrush( oldbrush
);
330 if( mNeedOverlay
) mOverlay
.push_back( t
.boundingRect() );
333 Rect
KigPainter::window()
335 return msi
.shownRect();
338 void KigPainter::circleOverlayRecurse( const Coordinate
& centre
,
342 Rect currentRect
= cr
.normalized();
344 if( !currentRect
.intersects( window() ) ) return;
346 // this code is an adaptation of Marc Bartsch's code, from KGeo
347 Coordinate tl
= currentRect
.topLeft();
348 Coordinate br
= currentRect
.bottomRight();
349 Coordinate tr
= currentRect
.topRight();
350 Coordinate bl
= currentRect
.bottomLeft();
351 Coordinate c
= currentRect
.center();
353 // mp: we compute the minimum and maximum distance from the center
354 // of the circle and this rect
355 double distxmin
= 0, distxmax
= 0, distymin
= 0, distymax
= 0;
356 if ( centre
.x
>= tr
.x
) distxmin
= centre
.x
- tr
.x
;
357 if ( centre
.x
<= bl
.x
) distxmin
= bl
.x
- centre
.x
;
358 if ( centre
.y
>= tr
.y
) distymin
= centre
.y
- tr
.y
;
359 if ( centre
.y
<= bl
.y
) distymin
= bl
.y
- centre
.y
;
360 distxmax
= fabs(centre
.x
- c
.x
) + currentRect
.width()/2;
361 distymax
= fabs(centre
.y
- c
.y
) + currentRect
.height()/2;
362 // this should take into account the thickness of the line...
363 distxmin
-= pixelWidth();
364 if (distxmin
< 0) distxmin
= 0;
365 distxmax
+= pixelWidth();
366 distymin
-= pixelWidth();
367 if (distymin
< 0) distymin
= 0;
368 distymax
+= pixelWidth();
369 double distminsq
= distxmin
*distxmin
+ distymin
*distymin
;
370 double distmaxsq
= distxmax
*distxmax
+ distymax
*distymax
;
372 // if the circle doesn't touch this rect, we return
373 // too far from the centre
374 if (distminsq
> radiussq
) return;
376 // too near to the centre
377 if (distmaxsq
< radiussq
) return;
379 // the rect contains some of the circle
380 // -> if it's small enough, we keep it
381 if( currentRect
.width() < overlayRectSize() ) {
382 mOverlay
.push_back( toScreenEnlarge( currentRect
) );
384 // this func works recursive: we subdivide the current rect, and if
385 // it is of a good size, we keep it, otherwise we handle it again
386 double width
= currentRect
.width() / 2;
387 double height
= currentRect
.height() / 2;
388 Rect
r1 ( c
, -width
, -height
);
390 circleOverlayRecurse(centre
, radiussq
, r1
);
391 Rect
r2 ( c
, width
, -height
);
393 circleOverlayRecurse(centre
, radiussq
, r2
);
394 Rect
r3 ( c
, -width
, height
);
396 circleOverlayRecurse(centre
, radiussq
, r3
);
397 Rect
r4 ( c
, width
, height
);
399 circleOverlayRecurse(centre
, radiussq
, r4
);
403 void KigPainter::circleOverlay( const Coordinate
& centre
, double radius
)
405 double t
= radius
+ pixelWidth();
406 Coordinate
r( t
, t
);
407 Coordinate bottomLeft
= centre
- r
;
408 Coordinate topRight
= centre
+ r
;
409 Rect
rect( bottomLeft
, topRight
);
410 circleOverlayRecurse ( centre
, radius
*radius
, rect
);
413 void KigPainter::segmentOverlay( const Coordinate
& p1
, const Coordinate
& p2
)
415 // this code is based upon what Marc Bartsch wrote for KGeo
417 // some stuff we may need:
418 Coordinate p3
= p2
- p1
;
419 Rect border
= window();
420 // double length = p3.length();
421 // mp: using the l-infinity distance is more natural here
422 double length
= fabs(p3
.x
);
423 if ( fabs( p3
.y
) > length
) length
= fabs( p3
.y
);
424 if ( length
< pixelWidth() )
426 // hopefully prevent SIGZERO's
427 mOverlay
.push_back( toScreen( Rect( p1
, p2
) ) );
430 p3
*= overlayRectSize();
439 Rect
tR( Coordinate( 0, 0 ), overlayRectSize(), overlayRectSize() );
440 Coordinate tP
= p1
+p3
*counter
;
442 if (!tR
.intersects(r
))
444 //kdDebug()<< "stopped after "<< counter << " passes." << endl;
447 if (tR
.intersects(border
)) mOverlay
.push_back( toScreenEnlarge( tR
) );
450 kdDebug()<< k_funcinfo
<< "counter got too big :( " << endl
;
456 double KigPainter::overlayRectSize()
458 return 20 * pixelWidth();
461 void KigPainter::pointOverlay( const Coordinate
& p1
)
463 Rect
r( p1
, 3*pixelWidth(), 3*pixelWidth());
465 mOverlay
.push_back( toScreen( r
) );
468 double KigPainter::pixelWidth()
470 return msi
.pixelWidth();
473 void KigPainter::setWholeWinOverlay()
476 mOverlay
.push_back( mP
.viewport() );
477 // don't accept any more overlay's...
478 mNeedOverlay
= false;
481 QPoint
KigPainter::toScreen( const Coordinate p
) const
483 return msi
.toScreen( p
);
486 void KigPainter::drawGrid( const CoordinateSystem
& c
, bool showGrid
, bool showAxes
)
488 c
.drawGrid( *this, showGrid
, showAxes
);
489 setWholeWinOverlay();
492 void KigPainter::drawObject( const ObjectHolder
* o
, bool ss
)
494 o
->draw( *this, ss
);
497 void KigPainter::drawObjects( const std::vector
<ObjectHolder
*>& os
, bool sel
)
499 drawObjects( os
.begin(), os
.end(), sel
);
502 void KigPainter::drawFilledRect( const QRect
& r
)
504 QPen
pen( Qt::black
, 1, Qt::DotLine
);
506 setBrush( QBrush( Qt::cyan
, Dense6Pattern
) );
507 drawRect( r
.normalize() );
510 void KigPainter::drawTextStd( const QPoint
& p
, const QString
& s
)
513 // tf = text formatting flags
514 int tf
= AlignLeft
| AlignTop
| DontClip
| WordBreak
;
515 // we need the rect where we're going to paint text
516 setPen(QPen(Qt::blue
, 1, SolidLine
));
517 setBrush(Qt::NoBrush
);
519 msi
.fromScreen(p
), window().bottomRight()
520 ).normalized(), s
, tf
);
524 QRect
KigPainter::toScreen( const Rect r
) const
526 return msi
.toScreen( r
);
529 QRect
KigPainter::toScreenEnlarge( const Rect r
) const
531 if ( overlayenlarge
== 0 ) return msi
.toScreen( r
);
533 QRect qr
= msi
.toScreen( r
);
534 qr
.moveBy ( -overlayenlarge
, -overlayenlarge
);
537 qr
.setWidth (w
+ 2*overlayenlarge
);
538 qr
.setHeight (h
+ 2*overlayenlarge
);
542 void KigPainter::drawSimpleText( const Coordinate
& c
, const QString s
)
544 int tf
= AlignLeft
| AlignTop
| DontClip
| WordBreak
;
548 void KigPainter::drawText( const Coordinate p
, const QString s
,
549 int textFlags
, int len
)
551 drawText( Rect( p
, mP
.window().right(), mP
.window().top() ),
554 const Rect
KigPainter::simpleBoundingRect( const Coordinate
& c
, const QString s
)
556 int tf
= AlignLeft
| AlignTop
| DontClip
| WordBreak
;
557 return boundingRect( c
, s
, tf
);
560 const Rect
KigPainter::boundingRect( const Coordinate
& c
, const QString s
,
563 return boundingRect( Rect( c
, mP
.window().right(), mP
.window().top() ),
567 Coordinate
KigPainter::fromScreen( const QPoint
& p
) const
569 return msi
.fromScreen( p
);
572 Rect
KigPainter::fromScreen( const QRect
& r
) const
574 return msi
.fromScreen( r
);
577 void KigPainter::drawRay( const Coordinate
& a
, const Coordinate
& b
)
580 calcRayBorderPoints( a
, tb
, window() );
581 drawSegment( a
, tb
);
584 typedef std::pair
<double,Coordinate
> coordparampair
;
588 workitem( coordparampair f
, coordparampair s
, Rect
*o
) :
589 first(f
), second(s
), overlay(o
) {};
590 coordparampair first
;
591 coordparampair second
;
595 void KigPainter::drawLine( const LineData
& d
)
599 LineData l
= calcBorderPoints( d
, window() );
600 drawSegment( l
.a
, l
.b
);
604 void KigPainter::drawSegment( const LineData
& d
)
606 drawSegment( d
.a
, d
.b
);
609 void KigPainter::drawRay( const LineData
& d
)
614 void KigPainter::drawAngle( const Coordinate
& cpoint
, const double dstartangle
,
615 const double dangle
)
617 // convert to 16th of degrees...
618 const int startangle
= static_cast<int>( Goniometry::convert( 16 * dstartangle
, Goniometry::Rad
, Goniometry::Deg
) );
619 const int angle
= static_cast<int>( Goniometry::convert( 16 * dangle
, Goniometry::Rad
, Goniometry::Deg
) );
621 QPoint point
= toScreen( cpoint
);
623 // int radius = mP.window().width() / 5;
625 QRect
surroundingRect( 0, 0, radius
*2, radius
*2 );
626 surroundingRect
.moveCenter( point
);
628 mP
.drawArc( surroundingRect
, startangle
, angle
);
630 // now for the arrow...
631 QPoint
end( static_cast<int>( point
.x() + radius
* cos( dstartangle
+ dangle
) ),
632 static_cast<int>( point
.y() - radius
* sin( dstartangle
+ dangle
) ) );
633 QPoint vect
= (end
- point
);
634 double vectlen
= sqrt( float( vect
.x() * vect
.x() + vect
.y() * vect
.y() ) );
635 QPoint
orthvect( -vect
.y(), vect
.x() );
636 vect
= vect
* 6 / vectlen
;
637 orthvect
= orthvect
* 6 / vectlen
;
639 QPointArray
arrow( 3 );
640 arrow
.setPoint( 0, end
);
641 arrow
.setPoint( 1, end
+ orthvect
+ vect
);
642 arrow
.setPoint( 2, end
+ orthvect
- vect
);
643 // std::vector<QPoint> arrow;
644 // arrow.push_back( end );
645 // arrow.push_back( end + orthvect + vect );
646 // arrow.push_back( end + orthvect - vect );
648 setBrushStyle( Qt::SolidPattern
);
649 // drawPolygon( arrow );
650 mP
.drawPolygon( arrow
, false, 0, -1 );
652 // if ( mNeedOverlay ) mOverlay.push_back( toScreen( r ) );
653 setWholeWinOverlay(); //mp: ugly! why not compute a correct overlay?
654 // mOverlay.push_back( arrow.boundingRect() );
657 void KigPainter::drawPolygon( const std::vector
<Coordinate
>& pts
,
658 bool winding
, int index
, int npoints
)
661 vector
<QPoint
> points
;
662 for ( uint i
= 0; i
< pts
.size(); ++i
)
663 points
.push_back( toScreen( pts
[i
] ) );
664 drawPolygon( points
, winding
, index
, npoints
);
667 void KigPainter::drawVector( const Coordinate
& a
, const Coordinate
& b
)
670 if ( a
== b
) return;
674 Coordinate dir
= b
- a
;
675 Coordinate
perp( dir
.y
, -dir
.x
);
676 double length
= perp
.length();
677 perp
*= 10* pixelWidth();
679 dir
*= 10 * pixelWidth();
681 Coordinate c
= b
- dir
+ perp
;
682 Coordinate d
= b
- dir
- perp
;
687 /* *** this function is commented out ***
688 inline Coordinate locusGetCoord( double p, const CurveImp* curve, const ObjectHierarchy& h,
689 bool& valid, const KigDocument& doc )
691 Coordinate pt = curve->getPoint( p, valid, doc );
692 if ( ! valid ) return Coordinate();
695 args.push_back( &pimp );
696 std::vector<ObjectImp*> calced = h.calc( args, doc );
697 assert( calced.size() == 1 );
698 ObjectImp* o = calced.front();
700 if ( o->inherits( ObjectImp::ID_PointImp ) )
703 ret = static_cast<PointImp*>( o )->coordinate();
712 class CurveImpPointCalcer
714 const CurveImp
* curve
;
716 CurveImpPointCalcer( const CurveImp
* c
)
720 static const double endinterval
;
721 inline const Coordinate
getPoint( double param
, const KigDocument
& d
) const {
722 return curve
->getPoint( param
, d
);
726 const double CurveImpPointCalcer::endinterval
= 1.;
728 void KigPainter::drawCurve( const CurveImp
* curve
)
730 // we manage our own overlay
731 bool tNeedOverlay
= mNeedOverlay
;
732 mNeedOverlay
= false;
736 // this stack contains pairs of Coordinates ( parameter intervals )
737 // that we still need to process:
738 std::stack
<workitem
> workstack
;
739 // mp: this stack contains all the generated overlays:
740 // the strategy for generating the overlay structure is the same
741 // recursive-like used to draw the segments: a new rectangle is
742 // generated whenever the length of a segment becomes lower than
743 // overlayRectSize(), or if the segment would be drawn anyway
744 // to avoid strange things from happening we impose that the distance
745 // in parameter space be less than a threshold before generating
748 // The third parameter in workitem is a pointer into a stack of
749 // all generated rectangles (in real coordinate space); if 0
750 // there is no rectangles associated to that segment yet.
752 // Using the final mOverlay stack would be much more efficient, but
753 // 1. needs transformations into window space
754 // 2. would be more difficult to drop rectangles not intersecting
756 std::stack
<Rect
> overlaystack
;
758 // mp: the original version in which an initial set of 20 intervals
759 // were pushed onto the stack is replaced by a single interval and
760 // by forcing subdivision till h < hmax (with more or less the same
762 // First push the [0,1] interval into the stack:
764 Coordinate coo1
= curve
->getPoint( 0., mdoc
);
765 Coordinate coo2
= curve
->getPoint( 1., mdoc
);
766 workstack
.push( workitem(
767 coordparampair( 0., coo1
),
768 coordparampair( 1., coo2
),
771 // maxlength is the square of the maximum size that we allow
772 // between two points..
773 double maxlength
= 1.5 * pixelWidth();
774 maxlength
*= maxlength
;
775 // error squared is required to be less that sigma (half pixel)
776 double sigma
= maxlength
/4;
777 // distance between two parameter values cannot be too small
779 // distance between two parameter values cannot be too large
781 double hmaxoverlay
= 1./8;
783 int count
= 1; // the number of segments we've already
785 static const int maxnumberofpoints
= 1000;
787 const Rect
& sr
= window();
789 // what this algorithm does is approximating the curve with a set of
790 // segments. we don't draw the individual segments, but use
791 // QPainter::drawPolyline() so that the line styles work properly.
792 // Possibly there are performance advantages as well ? this array
793 // is a buffer of the polyline approximation of the part of the
794 // curve that we are currently processing.
795 QPointArray
curpolyline( 1000 );
796 int curpolylinenextfree
= 0;
798 // we don't use recursion, but a stack based approach for efficiency
800 while ( ! workstack
.empty() && count
< maxnumberofpoints
)
802 workitem curitem
= workstack
.top();
804 bool curitemok
= true;
805 while ( curitemok
&& count
++ < maxnumberofpoints
)
807 double t0
= curitem
.first
.first
;
808 double t1
= curitem
.second
.first
;
809 Coordinate p0
= curitem
.first
.second
;
810 bool valid0
= p0
.valid();
811 Coordinate p1
= curitem
.second
.second
;
812 bool valid1
= p1
.valid();
814 // we take the middle parameter of the two previous points...
815 double t2
= ( t0
+ t1
) / 2;
816 double h
= fabs( t1
- t0
) /2;
818 // if exactly one of the two endpoints is invalid, then
819 // we prefer to find an internal value of the parameter
820 // separating valid points from invalid points. We use
821 // a bisection strategy (this is not implemented yet!)
822 // if ( ( valid0 && ! valid1 ) || ( valid1 && ! valid0 ) )
824 // while ( h >= hmin )
826 // .......................................
830 Rect
*overlaypt
= curitem
.overlay
;
831 Coordinate p2
= curve
->getPoint( t2
, mdoc
);
832 bool allvalid
= p2
.valid() && valid0
&& valid1
;
833 bool dooverlay
= ! overlaypt
&& h
< hmaxoverlay
&& valid0
&& valid1
834 && fabs( p0
.x
- p1
.x
) <= overlayRectSize()
835 && fabs( p0
.y
- p1
.y
) <= overlayRectSize();
836 bool addn
= sr
.contains( p2
) || h
>= hmax
;
837 // estimated error between the curve and the segments
839 if ( allvalid
) errsq
= (0.5*p0
+ 0.5*p1
- p2
).squareLength();
842 // bool dodraw = allvalid && h < hmax && ( errsq < sigma || h < hmin );
843 bool dodraw
= allvalid
&& h
< hmax
&& errsq
< sigma
;
844 if ( tNeedOverlay
&& ( dooverlay
|| dodraw
) )
846 Rect
newoverlay( p0
, p1
);
847 overlaystack
.push( newoverlay
);
848 overlaypt
= &overlaystack
.top();
850 if ( overlaypt
) overlaypt
->setContains( p2
);
853 // draw the two segments
854 QPoint tp0
= toScreen(p0
);
855 QPoint tp1
= toScreen(p1
);
856 QPoint tp2
= toScreen(p2
);
857 if ( curpolylinenextfree
> 0 && curpolyline
[curpolylinenextfree
- 1] != tp1
)
859 // flush the current part of the curve
860 mP
.drawPolyline( curpolyline
, 0, curpolylinenextfree
);
861 curpolylinenextfree
= 0;
863 if ( curpolylinenextfree
== 0 )
864 curpolyline
[curpolylinenextfree
++] = tp1
;
865 curpolyline
[curpolylinenextfree
++] = tp2
;
866 curpolyline
[curpolylinenextfree
++] = tp0
;
868 else if ( h
>= hmin
) // we do not continue to subdivide indefinitely!
870 // push into stack in order to process both subintervals
871 if ( addn
|| ( valid0
&& sr
.contains( p0
) ) )
872 workstack
.push( workitem( curitem
.first
, coordparampair( t2
, p2
),
874 if ( addn
|| ( valid1
&& sr
.contains( p1
) ) )
876 curitem
= workitem( coordparampair( t2
, p2
), curitem
.second
,
883 // flush the rest of the curve
884 mP
.drawPolyline( curpolyline
, 0, curpolylinenextfree
);
885 curpolylinenextfree
= 0;
887 if ( ! workstack
.empty () )
888 kdDebug() << "Stack not empty in KigPainter::drawCurve!\n" << endl
;
889 assert ( tNeedOverlay
|| overlaystack
.empty() );
892 Rect border
= window();
893 while ( ! overlaystack
.empty() )
895 Rect overlay
= overlaystack
.top();
897 if (overlay
.intersects( border
))
898 mOverlay
.push_back( toScreenEnlarge( overlay
) );
901 mNeedOverlay
= tNeedOverlay
;
904 void KigPainter::drawTextFrame( const Rect
& frame
,
905 const QString
& s
, bool needframe
)
907 QPen oldpen
= mP
.pen();
908 QBrush oldbrush
= mP
.brush();
911 // inspired upon kgeo, thanks to Marc Bartsch, i've taken some of
913 setPen( QPen( Qt::black
, 1 ) );
914 setBrush( QBrush( QColor( 255, 255, 222 ) ) );
916 setPen( QPen( QColor( 197, 194, 197 ), 1, Qt::SolidLine
) );
918 QRect qr
= toScreen( frame
);
920 mP
.drawLine( qr
.topLeft(), qr
.topRight() );
921 mP
.drawLine( qr
.topLeft(), qr
.bottomLeft() );
924 setBrush( oldbrush
);
925 drawText( frame
, s
, Qt::AlignVCenter
| Qt::AlignLeft
);
928 void KigPainter::drawArc( const Coordinate
& center
, const double radius
,
929 const double dstartangle
, const double dangle
)
931 // convert to 16th of degrees...
932 const int startangle
= static_cast<int>( Goniometry::convert( 16 * dstartangle
, Goniometry::Rad
, Goniometry::Deg
) );
933 const int angle
= static_cast<int>( Goniometry::convert( 16 * dangle
, Goniometry::Rad
, Goniometry::Deg
) );
935 Rect
krect( 0, 0, 2*radius
, 2*radius
);
936 krect
.setCenter( center
);
937 QRect rect
= toScreen( krect
);
939 mP
.drawArc( rect
, startangle
, angle
);
940 setWholeWinOverlay();