• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

kig

  • sources
  • kde-4.12
  • kdeedu
  • kig
  • misc
kigpainter.cpp
Go to the documentation of this file.
1 
21 #include "kigpainter.h"
22 
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"
30 #include "common.h"
31 #include "conic-common.h"
32 #include "cubic-common.h"
33 #include "coordinate_system.h"
34 
35 #include <qpen.h>
36 #include <qpolygon.h>
37 
38 #include <cmath>
39 #include <stack>
40 #include <functional>
41 #include <algorithm>
42 
43 using std::fabs;
44 using std::cos;
45 using std::sin;
46 
47 
48 KigPainter::KigPainter( const ScreenInfo& si, QPaintDevice* device,
49  const KigDocument& doc, bool no )
50  : mP ( device ),
51  color( Qt::blue ),
52  style( Qt::SolidLine ),
53  pointstyle( 0 ),
54  width( -1 ),
55  brushStyle( Qt::NoBrush ),
56  brushColor( Qt::blue ),
57  mdoc( doc ),
58  msi( si ),
59  mNeedOverlay( no ),
60  overlayenlarge( 0 ),
61  mSelected( false )
62 {
63  mP.setBackground( QBrush( Qt::white ) );
64 }
65 
66 KigPainter::~KigPainter()
67 {
68 }
69 
70 void KigPainter::drawRect( const Rect& r )
71 {
72  Rect rt = r.normalized();
73  QRect qr = toScreen(rt).normalized();
74  mP.drawRect(qr);
75  if( mNeedOverlay ) mOverlay.push_back( qr );
76 }
77 
78 void KigPainter::drawRect( const QRect& r )
79 {
80  mP.drawRect(r);
81  if( mNeedOverlay ) mOverlay.push_back( r );
82 }
83 
84 void KigPainter::drawCircle( const Coordinate& center, double radius )
85 {
86  Coordinate bottomLeft = center - Coordinate(radius, radius);
87  Coordinate topRight = center + Coordinate(radius, radius);
88  Rect r( bottomLeft, topRight );
89  QRect qr = toScreen( r );
90  mP.drawEllipse ( qr );
91  if( mNeedOverlay ) circleOverlay( center, radius );
92 }
93 
94 void KigPainter::drawSegment( const Coordinate& from, const Coordinate& to )
95 {
96  QPoint tF = toScreen(from), tT = toScreen(to);
97  mP.drawLine( tF, tT );
98  if( mNeedOverlay ) segmentOverlay( from, to );
99 }
100 
101 void KigPainter::drawFatPoint( const Coordinate& p )
102 {
103  int twidth = width == -1 ? 5 : width;
104  mP.setPen( QPen( color, 1, style ) );
105  switch ( pointstyle )
106  {
107  case 0:
108  {
109  double radius = twidth * pixelWidth();
110  setBrushStyle( Qt::SolidPattern );
111  Coordinate rad( radius, radius );
112  rad /= 2;
113  Coordinate tl = p - rad;
114  Coordinate br = p + rad;
115  Rect r( tl, br );
116  QRect qr = toScreen( r );
117  mP.drawEllipse( qr );
118  if( mNeedOverlay ) mOverlay.push_back( qr );
119  break;
120  }
121  case 1:
122  {
123  double radius = twidth * pixelWidth();
124  setBrushStyle( Qt::NoBrush );
125  Coordinate rad( radius, radius );
126  rad /= 2;
127  Coordinate tl = p - rad;
128  Coordinate br = p + rad;
129  Rect r( tl, br );
130  QRect qr = toScreen( r );
131  mP.drawEllipse( qr );
132  if( mNeedOverlay ) mOverlay.push_back( qr );
133  break;
134  }
135  case 2:
136  {
137  double radius = twidth * pixelWidth();
138  Coordinate rad( radius, radius );
139  rad /= 2;
140  Coordinate tl = p - rad;
141  Coordinate br = p + rad;
142  Rect r( tl, br );
143  QRect qr = toScreen( r );
144  mP.drawRect( qr );
145  mP.fillRect( qr, QBrush( color, Qt::SolidPattern ) );
146  if( mNeedOverlay ) mOverlay.push_back( qr );
147  break;
148  }
149  case 3:
150  {
151  double radius = twidth * pixelWidth();
152  Coordinate rad( radius, radius );
153  rad /= 2;
154  Coordinate tl = p - rad;
155  Coordinate br = p + rad;
156  Rect r( tl, br );
157  QRect qr = toScreen( r );
158  mP.drawRect( qr );
159  if( mNeedOverlay ) mOverlay.push_back( qr );
160  break;
161  }
162  case 4:
163  {
164  double radius = twidth * pixelWidth();
165  Coordinate rad( radius, radius );
166  rad /= 2;
167  Coordinate tl = p - rad;
168  Coordinate br = p + rad;
169  Rect r( tl, br );
170  QRect qr = toScreen( r );
171  mP.setPen( QPen( color, 2 ) );
172  mP.drawLine( qr.topLeft(), qr.bottomRight() );
173  mP.drawLine( qr.topRight(), qr.bottomLeft() );
174  if( mNeedOverlay ) mOverlay.push_back( qr );
175  break;
176  }
177  }
178  mP.setPen( QPen( color, twidth, style ) );
179 }
180 
181 void KigPainter::drawPoint( const Coordinate& p )
182 {
183  mP.drawPoint( toScreen(p) );
184  if( mNeedOverlay ) pointOverlay( p );
185 }
186 
187 void KigPainter::drawLine( const Coordinate& p1, const Coordinate& p2 )
188 {
189  drawLine( LineData( p1, p2 ) );
190 }
191 
192 void KigPainter::drawText( const Rect& p, const QString& s, int textFlags )
193 {
194  QRect t = toScreen(p);
195  int tf = textFlags;
196  t.translate( 2, 2 );
197  t.setWidth( t.width() - 4 );
198  t.setHeight( t.height() - 4 );
199  mP.drawText( t, tf, s );
200  if( mNeedOverlay ) textOverlay( t, s, tf );
201 }
202 
203 void KigPainter::textOverlay( const QRect& r, const QString& s, int textFlags )
204 {
205  // kDebug() << Rect::fromQRect( mP.boundingRect( r, textFlags, s, len ) );
206  QRect newr( mP.boundingRect( r, textFlags, s ) );
207  newr.setWidth( newr.width() + 4 );
208  newr.setHeight( newr.height() + 4 );
209  mOverlay.push_back( newr );
210 }
211 
212 const Rect KigPainter::boundingRect( const Rect& r, const QString& s, int f ) const
213 {
214  QRect qr = mP.boundingRect( toScreen( r ), f, s );
215  qr.setWidth( qr.width() + 4 );
216  qr.setHeight( qr.height() + 4 );
217  return fromScreen( qr );
218 }
219 
220 void KigPainter::setColor( const QColor& c )
221 {
222  color = c;
223  mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
224 }
225 
226 void KigPainter::setStyle( Qt::PenStyle c )
227 {
228  style = c;
229  mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
230 }
231 
232 void KigPainter::setWidth( int c )
233 {
234  width = c;
235  if (c > 0) overlayenlarge = c - 1;
236  mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
237 }
238 
239 void KigPainter::setPointStyle( int p )
240 {
241  pointstyle = p;
242 }
243 
244 void KigPainter::setPen( const QPen& p )
245 {
246  color = p.color();
247  width = p.width();
248  style = p.style();
249  mP.setPen(p);
250 }
251 
252 void KigPainter::setBrush( const QBrush& b )
253 {
254  brushStyle = b.style();
255  brushColor = b.color();
256  mP.setBrush( b );
257 }
258 
259 void KigPainter::setBrushStyle( Qt::BrushStyle c )
260 {
261  brushStyle = c;
262  mP.setBrush( QBrush( brushColor, brushStyle ) );
263 }
264 
265 void KigPainter::setBrushColor( const QColor& c )
266 {
267  brushColor = c;
268  mP.setBrush( QBrush( brushColor, brushStyle ) );
269 }
270 
271 void KigPainter::setFont( const QFont& f )
272 {
273  mP.setFont( f );
274 }
275 
276 bool KigPainter::getNightVision( ) const
277 {
278  return mdoc.getNightVision();
279 }
280 
281 QColor KigPainter::getColor() const
282 {
283  return color;
284 }
285 
286 void KigPainter::setSelected( bool selected )
287 {
288  mSelected = selected;
289 }
290 
291 /*
292 static void setContains( QRect& r, const QPoint& p )
293 {
294  if ( r.left() > p.x() ) r.setLeft( p.x() );
295  if ( r.right() < p.x() ) r.setRight( p.x() );
296  // this is correct, i think. In qt the bottom has the highest y
297  // coord...
298  if ( r.bottom() > p.y() ) r.setBottom( p.y() );
299  if ( r.top() < p.y() ) r.setTop( p.y() );
300 }
301 */
302 
303 void KigPainter::drawPolygon( const std::vector<QPoint>& pts, Qt::FillRule fillRule )
304 {
305  QPen oldpen = mP.pen();
306  QBrush oldbrush = mP.brush();
307  QColor alphacolor = color;
308  if ( !mSelected )
309  alphacolor.setAlpha( 100 );
310  setBrush( QBrush( alphacolor, Qt::SolidPattern ) );
311  setPen( Qt::NoPen );
312  // i know this isn't really fast, but i blame it all on Qt with its
313  // stupid container classes... what's wrong with the STL ?
314  QPolygon t( pts.size() );
315  int c = 0;
316  for( std::vector<QPoint>::const_iterator i = pts.begin(); i != pts.end(); ++i )
317  {
318  t.putPoints( c++, 1, i->x(), i->y() );
319  };
320  mP.drawPolygon( t, fillRule );
321  setPen( oldpen );
322  setBrush( oldbrush );
323  unsetSelected();
324  if( mNeedOverlay ) mOverlay.push_back( t.boundingRect() );
325 }
326 
327 void KigPainter::drawArea( const std::vector<Coordinate>& pts, bool border )
328 {
329  QPen oldpen = mP.pen();
330  QBrush oldbrush = mP.brush();
331  setBrush( QBrush( color, Qt::SolidPattern ) );
332  if ( border )
333  setPen( QPen( color, width == -1 ? 1 : width ) );
334  else
335  setPen( Qt::NoPen );
336  QPolygon t( pts.size() );
337  int c = 0;
338  for( std::vector<Coordinate>::const_iterator i = pts.begin(); i != pts.end(); ++i )
339  {
340  QPoint p = toScreen( *i );
341  t.putPoints( c++, 1, p.x(), p.y() );
342  }
343  mP.drawPolygon( t );
344  setPen( oldpen );
345  setBrush( oldbrush );
346  if( mNeedOverlay ) mOverlay.push_back( t.boundingRect() );
347 }
348 
349 Rect KigPainter::window()
350 {
351  return msi.shownRect();
352 }
353 
354 void KigPainter::circleOverlayRecurse( const Coordinate& centre,
355  double radiussq,
356  const Rect& cr )
357 {
358  Rect currentRect = cr.normalized();
359 
360  if( !currentRect.intersects( window() ) ) return;
361 
362  // this code is an adaptation of Marc Bartsch's code, from KGeo
363  Coordinate tl = currentRect.topLeft();
364  Coordinate br = currentRect.bottomRight();
365  Coordinate tr = currentRect.topRight();
366  Coordinate bl = currentRect.bottomLeft();
367  Coordinate c = currentRect.center();
368 
369  // mp: we compute the minimum and maximum distance from the center
370  // of the circle and this rect
371  double distxmin = 0, distxmax = 0, distymin = 0, distymax = 0;
372  if ( centre.x >= tr.x ) distxmin = centre.x - tr.x;
373  if ( centre.x <= bl.x ) distxmin = bl.x - centre.x;
374  if ( centre.y >= tr.y ) distymin = centre.y - tr.y;
375  if ( centre.y <= bl.y ) distymin = bl.y - centre.y;
376  distxmax = fabs(centre.x - c.x) + currentRect.width()/2;
377  distymax = fabs(centre.y - c.y) + currentRect.height()/2;
378  // this should take into account the thickness of the line...
379  distxmin -= pixelWidth();
380  if (distxmin < 0) distxmin = 0;
381  distxmax += pixelWidth();
382  distymin -= pixelWidth();
383  if (distymin < 0) distymin = 0;
384  distymax += pixelWidth();
385  double distminsq = distxmin*distxmin + distymin*distymin;
386  double distmaxsq = distxmax*distxmax + distymax*distymax;
387 
388  // if the circle doesn't touch this rect, we return
389  // too far from the centre
390  if (distminsq > radiussq) return;
391 
392  // too near to the centre
393  if (distmaxsq < radiussq) return;
394 
395  // the rect contains some of the circle
396  // -> if it's small enough, we keep it
397  if( currentRect.width() < overlayRectSize() ) {
398  mOverlay.push_back( toScreenEnlarge( currentRect) );
399  } else {
400  // this func works recursive: we subdivide the current rect, and if
401  // it is of a good size, we keep it, otherwise we handle it again
402  double width = currentRect.width() / 2;
403  double height = currentRect.height() / 2;
404  Rect r1 ( c, -width, -height);
405  r1.normalize();
406  circleOverlayRecurse(centre, radiussq, r1);
407  Rect r2 ( c, width, -height);
408  r2.normalize();
409  circleOverlayRecurse(centre, radiussq, r2);
410  Rect r3 ( c, -width, height);
411  r3.normalize();
412  circleOverlayRecurse(centre, radiussq, r3);
413  Rect r4 ( c, width, height);
414  r4.normalize();
415  circleOverlayRecurse(centre, radiussq, r4);
416  };
417 }
418 
419 void KigPainter::circleOverlay( const Coordinate& centre, double radius )
420 {
421  double t = radius + pixelWidth();
422  Coordinate r( t, t );
423  Coordinate bottomLeft = centre - r;
424  Coordinate topRight = centre + r;
425  Rect rect( bottomLeft, topRight );
426  circleOverlayRecurse ( centre , radius*radius, rect );
427 }
428 
429 void KigPainter::segmentOverlay( const Coordinate& p1, const Coordinate& p2 )
430 {
431  // this code is based upon what Marc Bartsch wrote for KGeo
432 
433  // some stuff we may need:
434  Coordinate p3 = p2 - p1;
435  Rect border = window();
436 // double length = p3.length();
437  // mp: using the l-infinity distance is more natural here
438  double length = fabs(p3.x);
439  if ( fabs( p3.y ) > length ) length = fabs( p3.y );
440  if ( length < pixelWidth() )
441  {
442  // hopefully prevent SIGZERO's
443  mOverlay.push_back( toScreen( Rect( p1, p2 ) ) );
444  return;
445  };
446  p3 *= overlayRectSize();
447  p3 /= length;
448 
449  int counter = 0;
450 
451  Rect r(p1, p2);
452  r.normalize();
453 
454  for (;;) {
455  Rect tR( Coordinate( 0, 0 ), overlayRectSize(), overlayRectSize() );
456  Coordinate tP = p1+p3*counter;
457  tR.setCenter(tP);
458  if (!tR.intersects(r))
459  {
460  //kDebug()<< "stopped after "<< counter << " passes.";
461  break;
462  }
463  if (tR.intersects(border)) mOverlay.push_back( toScreenEnlarge( tR ) );
464  if (++counter > 100)
465  {
466  kDebug()<< "counter got too big :( ";
467  break;
468  }
469  }
470 }
471 
472 double KigPainter::overlayRectSize()
473 {
474  return 20 * pixelWidth();
475 }
476 
477 void KigPainter::unsetSelected()
478 {
479  mSelected = false;
480 }
481 
482 void KigPainter::pointOverlay( const Coordinate& p1 )
483 {
484  Rect r( p1, 3*pixelWidth(), 3*pixelWidth());
485  r.setCenter( p1 );
486  mOverlay.push_back( toScreen( r) );
487 }
488 
489 double KigPainter::pixelWidth()
490 {
491  return msi.pixelWidth();
492 }
493 
494 void KigPainter::setWholeWinOverlay()
495 {
496  mOverlay.clear();
497  mOverlay.push_back( mP.viewport() );
498  // don't accept any more overlay's...
499  mNeedOverlay = false;
500 }
501 
502 QPoint KigPainter::toScreen( const Coordinate& p ) const
503 {
504  return msi.toScreen( p );
505 }
506 
507 void KigPainter::drawGrid( const CoordinateSystem& c, bool showGrid, bool showAxes )
508 {
509  c.drawGrid( *this, showGrid, showAxes );
510  setWholeWinOverlay();
511 }
512 
513 void KigPainter::drawObject( const ObjectHolder* o, bool ss )
514 {
515  o->draw( *this, ss );
516 }
517 
518 void KigPainter::drawObjects( const std::vector<ObjectHolder*>& os, bool sel )
519 {
520  drawObjects( os.begin(), os.end(), sel );
521 }
522 
523 void KigPainter::drawFilledRect( const QRect& r )
524 {
525  QPen pen( Qt::black, 1, Qt::DotLine );
526  setPen( pen );
527  setBrush( QBrush( Qt::cyan, Qt::Dense6Pattern ) );
528  drawRect( r.normalized() );
529 }
530 
531 void KigPainter::drawTextStd( const QPoint& p, const QString& s )
532 {
533  if ( s.isNull() ) return;
534  // tf = text formatting flags
535  int tf = Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap;
536  // we need the rect where we're going to paint text
537  setPen(QPen(Qt::blue, 1, Qt::SolidLine));
538  setBrush(Qt::NoBrush);
539  drawText( Rect(
540  msi.fromScreen(p), window().bottomRight()
541  ).normalized(), s, tf );
542 
543 }
544 
545 QRect KigPainter::toScreen( const Rect& r ) const
546 {
547  return msi.toScreen( r );
548 }
549 
550 QRect KigPainter::toScreenEnlarge( const Rect& r ) const
551 {
552  if ( overlayenlarge == 0 ) return msi.toScreen( r );
553 
554  QRect qr = msi.toScreen( r );
555  qr.translate( -overlayenlarge, -overlayenlarge );
556  int w = qr.width();
557  int h = qr.height();
558  qr.setWidth (w + 2*overlayenlarge);
559  qr.setHeight (h + 2*overlayenlarge);
560  return qr;
561 }
562 
563 void KigPainter::drawSimpleText( const Coordinate& c, const QString& s )
564 {
565  int tf = Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap;
566  drawText( c, s, tf );
567 }
568 
569 void KigPainter::drawText( const Coordinate& p, const QString& s, int textFlags )
570 {
571  drawText( Rect( p, mP.window().right(), mP.window().top() ), s, textFlags );
572 }
573 const Rect KigPainter::simpleBoundingRect( const Coordinate& c, const QString& s )
574 {
575  int tf = Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip | Qt::TextWordWrap;
576  return boundingRect( c, s, tf );
577 }
578 
579 const Rect KigPainter::boundingRect( const Coordinate& c, const QString& s, int f ) const
580 {
581  return boundingRect( Rect( c, mP.window().right(), mP.window().top() ), s, f );
582 }
583 
584 Coordinate KigPainter::fromScreen( const QPoint& p ) const
585 {
586  return msi.fromScreen( p );
587 }
588 
589 Rect KigPainter::fromScreen( const QRect& r ) const
590 {
591  return msi.fromScreen( r );
592 }
593 
594 void KigPainter::drawRay( const Coordinate& a, const Coordinate& b )
595 {
596  Coordinate tb = b;
597  calcRayBorderPoints( a, tb, window() );
598  drawSegment( a, tb );
599 }
600 
601 typedef std::pair<double,Coordinate> coordparampair;
602 
603 struct workitem
604 {
605  workitem( coordparampair f, coordparampair s, Rect *o) :
606  first(f), second(s), overlay(o) {}
607  coordparampair first;
608  coordparampair second;
609  Rect *overlay;
610 };
611 
612 void KigPainter::drawLine( const LineData& d )
613 {
614  if ( d.a != d.b )
615  {
616  LineData l = calcBorderPoints( d, window() );
617  drawSegment( l.a, l.b );
618  }
619 }
620 
621 void KigPainter::drawSegment( const LineData& d )
622 {
623  drawSegment( d.a, d.b );
624 }
625 
626 void KigPainter::drawRay( const LineData& d )
627 {
628  drawRay( d.a, d.b );
629 }
630 
631 void KigPainter::drawAngle( const Coordinate& point, double startangle, double angle, int radius )
632 {
633  const int startangleDegrees = static_cast<int>( Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg ) );
634  const int angleDegrees = static_cast<int>( Goniometry::convert( angle, Goniometry::Rad, Goniometry::Deg ) );
635 
636  QPoint screenPoint = toScreen( point );
637  QRect surroundingRect( 0, 0, radius*2, radius*2 );
638  surroundingRect.moveCenter( screenPoint );
639 
640  mP.drawArc( surroundingRect, 16 * startangleDegrees, 16 * angleDegrees );
641 
642  // now for the arrow...
643  QPoint end( static_cast<int>( screenPoint.x() + radius * cos( startangle + angle ) ),
644  static_cast<int>( screenPoint.y() - radius * sin( startangle + angle ) ) );
645  QPoint vect = (end - screenPoint);
646  double vectlen = std::sqrt( float( vect.x() * vect.x() + vect.y() * vect.y() ) );
647  QPoint orthvect( -vect.y(), vect.x() );
648  vect = vect * 6 / vectlen;
649  orthvect = orthvect * 6 / vectlen;
650 
651  QPolygon arrow( 3 );
652  arrow.setPoint( 0, end );
653  arrow.setPoint( 1, end + orthvect + vect );
654  arrow.setPoint( 2, end + orthvect - vect );
655 
656  setBrushStyle( Qt::SolidPattern );
657  mP.drawPolygon( arrow );
658 
659 // if ( mNeedOverlay ) mOverlay.push_back( toScreen( r ) );
660  setWholeWinOverlay(); //mp: ugly! why not compute a correct overlay?
661  // mOverlay.push_back( arrow.boundingRect() );
662 }
663 
664 void KigPainter::drawRightAngle( const Coordinate& point, double startangle, int diagonal )
665 {
666  const int startangleDegrees = static_cast<int>( Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg ) );
667  QPolygon rightAnglePolygon;
668  QMatrix rotationMatrix;
669  int halfSide = diagonal * sin( M_PI / 4 );
670  const QPoint screenPoint = toScreen( point );
671 
672  rightAnglePolygon << QPoint( halfSide, 0 ) << QPoint( halfSide, -halfSide ) << QPoint( 0, -halfSide );
673 
674  rotationMatrix.rotate( -startangleDegrees );
675  rightAnglePolygon = rotationMatrix.map( rightAnglePolygon );
676  rightAnglePolygon.translate( screenPoint );
677 
678  mP.drawPolyline( rightAnglePolygon );
679 
680  setWholeWinOverlay();
681 }
682 
683 void KigPainter::drawPolygon( const std::vector<Coordinate>& pts, Qt::FillRule fillRule )
684 {
685  using namespace std;
686  vector<QPoint> points;
687  for ( uint i = 0; i < pts.size(); ++i )
688  points.push_back( toScreen( pts[i] ) );
689  drawPolygon( points, fillRule );
690 }
691 
692 void KigPainter::drawVector( const Coordinate& a, const Coordinate& b )
693 {
694  // bugfix...
695  if ( a == b ) return;
696  // the segment
697  drawSegment( a, b );
698  // the arrows...
699  Coordinate dir = b - a;
700  Coordinate perp( dir.y, -dir.x );
701  double length = perp.length();
702  perp *= 10* pixelWidth();
703  perp /= length;
704  dir *= 10 * pixelWidth();
705  dir /= length;
706  Coordinate c = b - dir + perp;
707  Coordinate d = b - dir - perp;
708  // draw the arrow lines with a normal style
709  mP.setPen( QPen( color, width == -1 ? 1 : width, Qt::SolidLine ) );
710  drawSegment( b, c );
711  drawSegment( b, d );
712  // setting again the original style
713  mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
714 }
715 
716 /* *** this function is commented out ***
717 inline Coordinate locusGetCoord( double p, const CurveImp* curve, const ObjectHierarchy& h,
718  bool& valid, const KigDocument& doc )
719 {
720  Coordinate pt = curve->getPoint( p, valid, doc );
721  if ( ! valid ) return Coordinate();
722  PointImp pimp( pt );
723  Args args;
724  args.push_back( &pimp );
725  std::vector<ObjectImp*> calced = h.calc( args, doc );
726  assert( calced.size() == 1 );
727  ObjectImp* o = calced.front();
728  Coordinate ret;
729  if ( o->inherits( ObjectImp::ID_PointImp ) )
730  {
731  valid = true;
732  ret = static_cast<PointImp*>( o )->coordinate();
733  }
734  else
735  valid = false;
736  delete o;
737  return ret;
738 };
739 */
740 
741 class CurveImpPointCalcer
742 {
743  const CurveImp* curve;
744 public:
745  CurveImpPointCalcer( const CurveImp* c )
746  : curve( c )
747  {
748  }
749  static const double endinterval;
750  inline const Coordinate getPoint( double param, const KigDocument& d ) const {
751  return curve->getPoint( param, d );
752  }
753 };
754 
755 const double CurveImpPointCalcer::endinterval = 1.;
756 
757 void KigPainter::drawCurve( const CurveImp* curve )
758 {
759  // we manage our own overlay
760  bool tNeedOverlay = mNeedOverlay;
761  mNeedOverlay = false;
762 
763  QPen pen = mP.pen();
764 
765  // this stack contains pairs of Coordinates ( parameter intervals )
766  // that we still need to process:
767  std::stack<workitem> workstack;
768  // mp: this stack contains all the generated overlays:
769  // the strategy for generating the overlay structure is the same
770  // recursive-like used to draw the segments: a new rectangle is
771  // generated whenever the length of a segment becomes lower than
772  // overlayRectSize(), or if the segment would be drawn anyway
773  // to avoid strange things from happening we impose that the distance
774  // in parameter space be less than a threshold before generating
775  // any overlay.
776  //
777  // The third parameter in workitem is a pointer into a stack of
778  // all generated rectangles (in real coordinate space); if 0
779  // there is no rectangles associated to that segment yet.
780  //
781  // Using the final mOverlay stack would be much more efficient, but
782  // 1. needs transformations into window space
783  // 2. would be more difficult to drop rectangles not intersecting
784  // the window.
785  std::stack<Rect> overlaystack;
786 
787  // mp: the original version in which an initial set of 20 intervals
788  // were pushed onto the stack is replaced by a single interval and
789  // by forcing subdivision till h < hmax (with more or less the same
790  // final result).
791  // First push the [0,1] interval into the stack:
792 
793  Coordinate coo1 = curve->getPoint( 0., mdoc );
794  Coordinate coo2 = curve->getPoint( 1., mdoc );
795  workstack.push( workitem(
796  coordparampair( 0., coo1 ),
797  coordparampair( 1., coo2 ),
798  0 ) );
799 
800  // maxlength is the square of the maximum size that we allow
801  // between two points..
802  double maxlength = 1.5 * pixelWidth();
803  maxlength *= maxlength;
804  // error squared is required to be less that sigma (half pixel)
805  double sigma = maxlength/4;
806  // distance between two parameter values cannot be too small
807  double hmin = 3e-5;
808  // distance between two parameter values cannot be too large
809  double hmax = 1./40;
810  double hmaxoverlay = 1./8;
811 
812  int count = 1; // the number of segments we've already
813  // visited...
814  static const int maxnumberofpoints = 1000;
815 
816  const Rect& sr = window();
817 
818  // what this algorithm does is approximating the curve with a set of
819  // segments. we don't draw the individual segments, but use
820  // QPainter::drawPolyline() so that the line styles work properly.
821  // Possibly there are performance advantages as well ? this array
822  // is a buffer of the polyline approximation of the part of the
823  // curve that we are currently processing.
824  QPolygon curpolyline( 1000 );
825  int curpolylinenextfree = 0;
826 
827  // we don't use recursion, but a stack based approach for efficiency
828  // concerns...
829  while ( ! workstack.empty() && count < maxnumberofpoints )
830  {
831  workitem curitem = workstack.top();
832  workstack.pop();
833  bool curitemok = true;
834  while ( curitemok && count++ < maxnumberofpoints )
835  {
836  double t0 = curitem.first.first;
837  double t1 = curitem.second.first;
838  Coordinate p0 = curitem.first.second;
839  bool valid0 = p0.valid();
840  Coordinate p1 = curitem.second.second;
841  bool valid1 = p1.valid();
842 
843  // we take the middle parameter of the two previous points...
844  double t2 = ( t0 + t1 ) / 2;
845  double h = fabs( t1 - t0 ) /2;
846 
847  // if exactly one of the two endpoints is invalid, then
848  // we prefer to find an internal value of the parameter
849  // separating valid points from invalid points. We use
850  // a bisection strategy (this is not implemented yet!)
851 // if ( ( valid0 && ! valid1 ) || ( valid1 && ! valid0 ) )
852 // {
853 // while ( h >= hmin )
854 // {
855 // .......................................
856 // }
857 // }
858 
859  Rect *overlaypt = curitem.overlay;
860  Coordinate p2 = curve->getPoint( t2, mdoc );
861  bool allvalid = p2.valid() && valid0 && valid1;
862  bool dooverlay = ! overlaypt && h < hmaxoverlay && valid0 && valid1
863  && fabs( p0.x - p1.x ) <= overlayRectSize()
864  && fabs( p0.y - p1.y ) <= overlayRectSize();
865  bool addn = sr.contains( p2 ) || h >= hmax;
866  // estimated error between the curve and the segments
867  double errsq = 1e21;
868  if ( allvalid ) errsq = (0.5*p0 + 0.5*p1 - p2).squareLength();
869  errsq /= 4;
870  curitemok = false;
871 // bool dodraw = allvalid && h < hmax && ( errsq < sigma || h < hmin );
872  bool dodraw = allvalid && h < hmax && errsq < sigma;
873  if ( tNeedOverlay && ( dooverlay || dodraw ) )
874  {
875  Rect newoverlay( p0, p1 );
876  overlaystack.push( newoverlay );
877  overlaypt = &overlaystack.top();
878  }
879  if ( overlaypt ) overlaypt->setContains( p2 );
880  if ( dodraw )
881  {
882  // draw the two segments
883  QPoint tp0 = toScreen(p0);
884  QPoint tp1 = toScreen(p1);
885  QPoint tp2 = toScreen(p2);
886  if ( curpolylinenextfree > 0 && curpolyline[curpolylinenextfree - 1] != tp1 )
887  {
888  // flush the current part of the curve
889  mP.drawPolyline( curpolyline.constData(), curpolylinenextfree );
890  curpolylinenextfree = 0;
891  }
892  if ( curpolylinenextfree == 0 )
893  curpolyline[curpolylinenextfree++] = tp1;
894  curpolyline[curpolylinenextfree++] = tp2;
895  curpolyline[curpolylinenextfree++] = tp0;
896  }
897  else if ( h >= hmin ) // we do not continue to subdivide indefinitely!
898  {
899  // push into stack in order to process both subintervals
900  if ( addn || ( valid0 && sr.contains( p0 ) ) )
901  workstack.push( workitem( curitem.first, coordparampair( t2, p2 ),
902  overlaypt ) );
903  if ( addn || ( valid1 && sr.contains( p1 ) ) )
904  {
905  curitem = workitem( coordparampair( t2, p2 ), curitem.second ,
906  overlaypt );
907  curitemok = true;
908  }
909  }
910  }
911  }
912  // flush the rest of the curve
913  mP.drawPolyline( curpolyline.constData(), curpolylinenextfree );
914  curpolylinenextfree = 0;
915 
916  if ( ! workstack.empty () )
917  kDebug() << "Stack not empty in KigPainter::drawCurve!\n";
918  assert ( tNeedOverlay || overlaystack.empty() );
919  if ( tNeedOverlay )
920  {
921  Rect border = window();
922  while ( ! overlaystack.empty() )
923  {
924  Rect overlay = overlaystack.top();
925  overlaystack.pop();
926  if (overlay.intersects( border ))
927  mOverlay.push_back( toScreenEnlarge( overlay ) );
928  }
929  }
930  mNeedOverlay = tNeedOverlay;
931 }
932 
933 void KigPainter::drawTextFrame( const Rect& frame,
934  const QString& s, bool needframe )
935 {
936  QPen oldpen = mP.pen();
937  QBrush oldbrush = mP.brush();
938  if ( needframe )
939  {
940  // inspired upon kgeo, thanks to Marc Bartsch, i've taken some of
941  // his code too..
942  setPen( QPen( Qt::black, 1 ) );
943  setBrush( QBrush( QColor( 255, 255, 222 ) ) );
944  drawRect( frame );
945  setPen( QPen( QColor( 197, 194, 197 ), 1, Qt::SolidLine ) );
946 
947  QRect qr = toScreen( frame );
948 
949  mP.drawLine( qr.topLeft(), qr.topRight() );
950  mP.drawLine( qr.topLeft(), qr.bottomLeft() );
951  };
952  setPen( oldpen );
953  setBrush( oldbrush );
954  drawText( frame, s, Qt::AlignVCenter | Qt::AlignLeft );
955 }
956 
957 void KigPainter::drawArc( const Coordinate& center, double radius,
958  double dstartangle, double dangle )
959 {
960  // convert to 16th of degrees...
961  const int startangle = static_cast<int>( Goniometry::convert( 16 * dstartangle, Goniometry::Rad, Goniometry::Deg ) );
962  const int angle = static_cast<int>( Goniometry::convert( 16 * dangle, Goniometry::Rad, Goniometry::Deg ) );
963 
964  if ( angle <= 16 ) // in this case just draw a segment
965  {
966  Coordinate a = center + radius * Coordinate( cos( dstartangle ), sin( dstartangle ));
967  Coordinate b = center + radius * Coordinate( cos( dstartangle + dangle ), sin( dstartangle + dangle ));
968  drawSegment ( a , b );
969  }
970  else
971  {
972  Rect krect( 0, 0, 2*radius, 2*radius );
973  krect.setCenter( center );
974  QRect rect = toScreen( krect );
975 
976  mP.drawArc( rect, startangle, angle );
977  setWholeWinOverlay();
978  }
979 }
980 
calcRayBorderPoints
void calcRayBorderPoints(const Coordinate &a, Coordinate &b, const Rect &r)
this does the same as the above function, but only for b.
Definition: common.cpp:131
KigPainter::setPointStyle
void setPointStyle(int p)
Definition: kigpainter.cpp:239
KigPainter::pixelWidth
double pixelWidth()
Definition: kigpainter.cpp:489
Rect::normalize
void normalize()
this makes sure width and height are > 0 ...
Definition: rect.cc:130
CoordinateSystem
a CoordinateSystem is what the user sees: it is kept by KigPart to show the user a grid...
Definition: coordinate_system.h:60
KigPainter::setWholeWinOverlay
void setWholeWinOverlay()
this is called by some drawing functions that modify the 'entire' screen, i.e.
Definition: kigpainter.cpp:494
KigPainter::drawCircle
void drawCircle(const Coordinate &center, double radius)
draw a circle...
Definition: kigpainter.cpp:84
KigPainter::drawText
void drawText(const Rect &r, const QString &s, int textFlags=0)
draw text...
Definition: kigpainter.cpp:192
KigPainter::setBrushColor
void setBrushColor(const QColor &c)
Definition: kigpainter.cpp:265
Rect::width
double width() const
Definition: rect.cc:204
KigPainter::drawCurve
void drawCurve(const CurveImp *curve)
draw a generic curve...
Definition: kigpainter.cpp:757
LineData
Simple class representing a line.
Definition: misc/common.h:49
LineData::b
Coordinate b
Another point on the line.
Definition: misc/common.h:68
Goniometry::Deg
Definition: goniometry.h:31
KigPainter::brushColor
QColor brushColor
Definition: kigpainter.h:64
Rect::bottomLeft
Coordinate bottomLeft() const
Definition: rect.cc:161
Rect
This file is part of Kig, a KDE program for Interactive Geometry...
Definition: rect.h:34
KigPainter::drawFatPoint
void drawFatPoint(const Coordinate &p)
draw a thick point.
Definition: kigpainter.cpp:101
KigPainter::circleOverlayRecurse
void circleOverlayRecurse(const Coordinate &centre, double radius, const Rect &currentRect)
Definition: kigpainter.cpp:354
KigPainter::pointOverlay
void pointOverlay(const Coordinate &p1)
...
Definition: kigpainter.cpp:482
KigPainter::unsetSelected
void unsetSelected()
Definition: kigpainter.cpp:477
KigDocument::getNightVision
bool getNightVision() const
Definition: kig_document.cc:211
KigPainter::boundingRect
const Rect boundingRect(const Rect &r, const QString &s, int f=0) const
Definition: kigpainter.cpp:212
kigpainter.h
KigPainter::drawVector
void drawVector(const Coordinate &a, const Coordinate &b)
draw a vector ( with an arrow etc.
Definition: kigpainter.cpp:692
coordinate_system.h
KigPainter::setBrush
void setBrush(const QBrush &b)
Definition: kigpainter.cpp:252
KigPainter::drawRect
void drawRect(const Rect &r)
draw a rect.
Definition: kigpainter.cpp:70
Rect::intersects
bool intersects(const Rect &p) const
Definition: rect.cc:230
KigPainter::drawRay
void drawRay(const Coordinate &a, const Coordinate &b)
draw a ray...
Definition: kigpainter.cpp:594
KigPainter::~KigPainter
~KigPainter()
Definition: kigpainter.cpp:66
KigPainter::drawPolygon
void drawPolygon(const std::vector< QPoint > &pts, Qt::FillRule fillRule=Qt::OddEvenFill)
draw a polygon defined by the points in pts...
Definition: kigpainter.cpp:303
ScreenInfo
ScreenInfo is a simple utility class that maps a region of the document onto a region of the screen...
Definition: screeninfo.h:31
Coordinate
The Coordinate class is the basic class representing a 2D location by its x and y components...
Definition: coordinate.h:33
coordparampair
std::pair< double, Coordinate > coordparampair
Definition: kigpainter.cpp:601
KigPainter::getNightVision
bool getNightVision() const
Definition: kigpainter.cpp:276
Coordinate::length
double length() const
Length.
Definition: coordinate.cpp:144
CurveImp::getPoint
virtual const Coordinate getPoint(double param, const KigDocument &) const =0
KigPainter::drawLine
void drawLine(const Coordinate &p1, const Coordinate &p2)
draw a line...
Definition: kigpainter.cpp:187
cubic-common.h
KigPainter::mNeedOverlay
bool mNeedOverlay
Definition: kigpainter.h:69
KigPainter::brushStyle
Qt::BrushStyle brushStyle
Definition: kigpainter.h:63
Rect::contains
bool contains(const Coordinate &p) const
Definition: rect.cc:222
KigPainter::drawFilledRect
void drawFilledRect(const QRect &)
draws a rect filled up with a pattern of cyan lines...
Definition: kigpainter.cpp:523
conic-common.h
KigPainter::toScreen
QPoint toScreen(const Coordinate &p) const
Definition: kigpainter.cpp:502
KigPainter::setWidth
void setWidth(int c)
setting this to -1 means to use the default width for the object being drawn.
Definition: kigpainter.cpp:232
ObjectHolder
An ObjectHolder represents an object as it is known to the document.
Definition: object_holder.h:40
KigPainter::overlayRectSize
double overlayRectSize()
the size we want the overlay rects to be...
Definition: kigpainter.cpp:472
KigPainter::setSelected
void setSelected(bool selected)
Definition: kigpainter.cpp:286
Rect::topLeft
Coordinate topLeft() const
Definition: rect.cc:171
KigPainter::mP
QPainter mP
Definition: kigpainter.h:57
ScreenInfo::toScreen
QPoint toScreen(const Coordinate &p) const
Definition: screeninfo.cc:44
KigPainter::window
Rect window()
what rect are we drawing on ?
Definition: kigpainter.cpp:349
KigPainter::fromScreen
Coordinate fromScreen(const QPoint &p) const
Definition: kigpainter.cpp:584
Rect::setCenter
void setCenter(const Coordinate p)
Definition: rect.cc:91
KigPainter::drawArc
void drawArc(const Coordinate &center, double radius, double startangle, double angle)
draw the arc ( a part of a circle ), of the circle with center center, radius radius, with size angle, starting at the angle startAngle.
Definition: kigpainter.cpp:957
KigPainter::mOverlay
std::vector< QRect > mOverlay
Definition: kigpainter.h:294
LineData::a
Coordinate a
One point on the line.
Definition: misc/common.h:64
KigPainter::setBrushStyle
void setBrushStyle(Qt::BrushStyle c)
Definition: kigpainter.cpp:259
KigPainter::drawTextFrame
void drawTextFrame(const Rect &frame, const QString &s, bool needframe)
Definition: kigpainter.cpp:933
KigPainter::textOverlay
void textOverlay(const QRect &r, const QString &s, int textFlags)
...
Definition: kigpainter.cpp:203
Rect::center
Coordinate center() const
Definition: rect.cc:181
KigPainter::msi
ScreenInfo msi
Definition: kigpainter.h:67
Rect::top
double top() const
Definition: rect.cc:199
KigPainter::getColor
QColor getColor() const
Definition: kigpainter.cpp:281
KigPainter::drawPoint
void drawPoint(const Coordinate &p)
draw a point...
Definition: kigpainter.cpp:181
Rect::setContains
void setContains(Coordinate p)
this makes sure p is in the rect, extending it if necessary...
Definition: rect.cc:240
KigPainter::drawGrid
void drawGrid(const CoordinateSystem &c, bool showGrid=true, bool showAxes=true)
Definition: kigpainter.cpp:507
Goniometry::convert
static double convert(const double angle, const Goniometry::System from, const Goniometry::System to)
The most useful method of this class: convert the specified angle from the system from to the system ...
Definition: goniometry.cc:87
CoordinateSystem::drawGrid
virtual void drawGrid(KigPainter &p, bool showgrid=true, bool showaxes=true) const =0
KigPainter::pointstyle
int pointstyle
Definition: kigpainter.h:61
KigPainter::overlayenlarge
int overlayenlarge
Definition: kigpainter.h:70
KigPainter::simpleBoundingRect
const Rect simpleBoundingRect(const Coordinate &c, const QString &s)
Definition: kigpainter.cpp:573
KigPainter::drawObject
void drawObject(const ObjectHolder *o, bool sel)
draw an object ( by calling its draw function.
Definition: kigpainter.cpp:513
common.h
Rect::topRight
Coordinate topRight() const
Definition: rect.cc:176
KigPainter::drawSimpleText
void drawSimpleText(const Coordinate &c, const QString &s)
Definition: kigpainter.cpp:563
Rect::normalized
Rect normalized() const
Definition: rect.cc:249
Goniometry::Rad
Definition: goniometry.h:31
KigPainter::setStyle
void setStyle(Qt::PenStyle c)
Definition: kigpainter.cpp:226
ObjectHolder::draw
void draw(KigPainter &p, bool selected) const
Draw this object on the given KigPainter.
Definition: object_holder.cc:78
KigPainter::color
QColor color
Definition: kigpainter.h:59
KigPainter::width
int width
Definition: kigpainter.h:62
calcBorderPoints
void calcBorderPoints(Coordinate &p1, Coordinate &p2, const Rect &r)
this sets p1 and p2 to p1' and p2' so that p1'p2' is the same line as p1p2, and so that p1' and p2' a...
Definition: common.cpp:82
Rect::height
double height() const
Definition: rect.cc:209
KigPainter::setPen
void setPen(const QPen &p)
Definition: kigpainter.cpp:244
KigPainter::circleOverlay
void circleOverlay(const Coordinate &centre, double radius)
adds a number of rects to mOverlay so that the rects entirely contain the circle...
Definition: kigpainter.cpp:419
KigDocument
KigDocument is the class holding the real data in a Kig document.
Definition: kig_document.h:36
KigPainter::segmentOverlay
void segmentOverlay(const Coordinate &p1, const Coordinate &p2)
adds some rects to mOverlay, so that they cover the segment p1p2 completely...
Definition: kigpainter.cpp:429
KigPainter::toScreenEnlarge
QRect toScreenEnlarge(const Rect &r) const
Definition: kigpainter.cpp:550
KigPainter::overlay
const std::vector< QRect > & overlay()
Definition: kigpainter.h:257
Coordinate::x
double x
X Component.
Definition: coordinate.h:126
ScreenInfo::pixelWidth
double pixelWidth() const
Definition: screeninfo.cc:61
Coordinate::y
double y
Y Component.
Definition: coordinate.h:129
KigPainter::setColor
void setColor(const QColor &c)
Definition: kigpainter.cpp:220
KigPainter::mSelected
bool mSelected
Definition: kigpainter.h:71
ScreenInfo::shownRect
const Rect & shownRect() const
Definition: screeninfo.cc:68
Rect::bottomRight
Coordinate bottomRight() const
Definition: rect.cc:166
KigPainter::drawAngle
void drawAngle(const Coordinate &point, double startangle, double angle, int radius)
draw the angle with center point, with size angle, starting at the angle startAngle.
Definition: kigpainter.cpp:631
object_hierarchy.h
KigPainter::drawRightAngle
void drawRightAngle(const Coordinate &point, double startangle, int diagonal)
draw the angle with center point, with size angle, starting at the angle startAngle.
Definition: kigpainter.cpp:664
ScreenInfo::fromScreen
Coordinate fromScreen(const QPoint &p) const
Definition: screeninfo.cc:35
KigPainter::drawObjects
void drawObjects(const std::vector< ObjectHolder * > &os, bool sel)
Definition: kigpainter.cpp:518
KigPainter::setFont
void setFont(const QFont &f)
Definition: kigpainter.cpp:271
KigPainter::style
Qt::PenStyle style
Definition: kigpainter.h:60
KigPainter::mdoc
const KigDocument & mdoc
Definition: kigpainter.h:66
KigPainter::drawSegment
void drawSegment(const Coordinate &from, const Coordinate &to)
draw a segment...
Definition: kigpainter.cpp:94
uint
unsigned int uint
Definition: object_imp.h:87
KigPainter::KigPainter
KigPainter(const ScreenInfo &r, QPaintDevice *device, const KigDocument &doc, bool needOverlay=true)
construct a new KigPainter: the ScreenInfo is used to map the document coordinates to the widget coor...
Definition: kigpainter.cpp:48
Coordinate::valid
bool valid() const
Return whether this is a valid Coordinate.
Definition: coordinate.cpp:176
KigPainter::drawArea
void drawArea(const std::vector< Coordinate > &pts, bool border=true)
draw an area defined by the points in pts filled with the set color...
Definition: kigpainter.cpp:327
CurveImp
This class represents a curve: something which is composed of points, like a line, a circle, a locus.
Definition: curve_imp.h:27
KigPainter::drawTextStd
void drawTextStd(const QPoint &p, const QString &s)
draws text in a standard manner, convenience function...
Definition: kigpainter.cpp:531
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:35:39 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal