moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / objects / other_imp.cc
blob3e7861f29d3dca8c948a6a71f4eff18fba52397f
1 // Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16 // 02111-1307, USA.
18 #include "other_imp.h"
20 #include "bogus_imp.h"
21 #include "point_imp.h"
22 #include "line_imp.h"
24 #include "../misc/screeninfo.h"
25 #include "../misc/common.h"
26 #include "../misc/kigtransform.h"
27 #include "../misc/kigpainter.h"
28 #include "../misc/goniometry.h"
29 #include "../kig/kig_view.h"
31 #include <klocale.h>
33 #include <cmath>
34 #include <utility>
35 using namespace std;
37 AngleImp::~AngleImp()
41 ObjectImp* AngleImp::transform( const Transformation& ) const
43 // TODO ?
44 return new InvalidImp;
47 void AngleImp::draw( KigPainter& p ) const
49 p.drawAngle( mpoint, mstartangle, mangle );
52 AngleImp::AngleImp( const Coordinate& pt, double start_angle_in_radials,
53 double angle_in_radials )
54 : mpoint( pt ), mstartangle( start_angle_in_radials ),
55 mangle( angle_in_radials )
59 bool AngleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
61 double radius = 50*w.screenInfo().pixelWidth();
63 if ( fabs( (p-mpoint).length() - radius ) > w.screenInfo().normalMiss( width ) )
64 return false;
66 // and next we check if the angle is appropriate...
67 Coordinate vect = p - mpoint;
68 double angle = atan2( vect.y, vect.x );
69 while ( angle < mstartangle ) angle += 2*M_PI;
70 return angle <= mstartangle + mangle;
73 bool AngleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
75 // TODO ?
76 return r.contains( mpoint, w.screenInfo().normalMiss( width ) );
79 Coordinate AngleImp::attachPoint() const
81 return mpoint;
84 const uint AngleImp::numberOfProperties() const
86 return Parent::numberOfProperties() + 3;
89 const QCStringList AngleImp::propertiesInternalNames() const
91 QCStringList l = Parent::propertiesInternalNames();
92 l << "angle-radian";
93 l << "angle-degrees";
94 l << "angle-bisector";
95 assert( l.size() == AngleImp::numberOfProperties() );
96 return l;
99 const QCStringList AngleImp::properties() const
101 QCStringList l = Parent::properties();
102 l << I18N_NOOP( "Angle in Radians" );
103 l << I18N_NOOP( "Angle in Degrees" );
104 l << I18N_NOOP( "Angle Bisector" );
105 assert( l.size() == AngleImp::numberOfProperties() );
106 return l;
109 const ObjectImpType* AngleImp::impRequirementForProperty( uint which ) const
111 if ( which < Parent::numberOfProperties() )
112 return Parent::impRequirementForProperty( which );
113 else return AngleImp::stype();
116 const char* AngleImp::iconForProperty( uint which ) const
118 int numprop = 0;
119 if ( which < Parent::numberOfProperties() )
120 return Parent::iconForProperty( which );
121 if ( which == Parent::numberOfProperties() + numprop++ )
122 return "angle-size"; // size in radians
123 else if ( which == Parent::numberOfProperties() + numprop++ )
124 return "angle-size"; // size in degrees
125 else if ( which == Parent::numberOfProperties() + numprop++ )
126 return "angle-bisector"; // angle bisector..
127 else assert( false );
128 return "";
131 ObjectImp* AngleImp::property( uint which, const KigDocument& w ) const
133 int numprop = 0;
134 if ( which < Parent::numberOfProperties() )
135 return Parent::property( which, w );
136 if ( which == Parent::numberOfProperties() + numprop++ )
137 return new DoubleImp( size() );
138 else if ( which == Parent::numberOfProperties() + numprop++ )
139 return new DoubleImp( Goniometry::convert( size(), Goniometry::Rad, Goniometry::Deg ) );
140 else if ( which == Parent::numberOfProperties() + numprop++ )
142 const double angle = mstartangle + mangle / 2;
143 Coordinate p2 = mpoint + Coordinate( cos( angle ), sin( angle ) ) * 10;
144 return new RayImp( mpoint, p2 );
146 else assert( false );
147 return new InvalidImp;
150 const double AngleImp::size() const
152 return mangle;
155 ObjectImp* AngleImp::copy() const
157 return new AngleImp( mpoint, mstartangle, mangle );
160 VectorImp::VectorImp( const Coordinate& a, const Coordinate& b )
161 : mdata( a, b )
165 VectorImp::~VectorImp()
169 ObjectImp* VectorImp::transform( const Transformation& t ) const
171 Coordinate ta = t.apply( mdata.a );
172 Coordinate tb = t.apply( mdata.b );
173 if ( ta.valid() && tb.valid() ) return new VectorImp( ta, tb );
174 else return new InvalidImp;
177 void VectorImp::draw( KigPainter& p ) const
179 p.drawVector( mdata.a, mdata.b );
182 bool VectorImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
184 return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
187 bool VectorImp::inRect( const Rect& r, int width, const KigWidget& w ) const
189 return lineInRect( r, mdata.a, mdata.b, width, this, w );
192 const uint VectorImp::numberOfProperties() const
194 return Parent::numberOfProperties() + 5;
197 const QCStringList VectorImp::propertiesInternalNames() const
199 QCStringList ret = Parent::propertiesInternalNames();
200 ret << "length";
201 ret << "vect-mid-point";
202 ret << "length-x";
203 ret << "length-y";
204 ret << "vector-opposite";
205 assert( ret.size() == VectorImp::numberOfProperties() );
206 return ret;
209 const QCStringList VectorImp::properties() const
211 QCStringList ret = Parent::properties();
212 ret << I18N_NOOP( "Length" );
213 ret << I18N_NOOP( "Midpoint" );
214 ret << I18N_NOOP( "X length" );
215 ret << I18N_NOOP( "Y length" );
216 ret << I18N_NOOP( "Opposite Vector" );
217 assert( ret.size() == VectorImp::numberOfProperties() );
218 return ret;
221 const ObjectImpType* VectorImp::impRequirementForProperty( uint which ) const
223 if ( which < Parent::numberOfProperties() )
224 return Parent::impRequirementForProperty( which );
225 else return VectorImp::stype();
228 const char* VectorImp::iconForProperty( uint which ) const
230 if ( which < Parent::numberOfProperties() )
231 return Parent::iconForProperty( which );
232 else if ( which == Parent::numberOfProperties() )
233 return "distance"; // length
234 else if ( which == Parent::numberOfProperties() + 1 )
235 return "bisection"; // mid point
236 else if ( which == Parent::numberOfProperties() + 2 )
237 return "distance"; // length-x
238 else if ( which == Parent::numberOfProperties() + 3 )
239 return "distance"; // length-y
240 else if ( which == Parent::numberOfProperties() + 4 )
241 return "opposite-vector"; // opposite vector
242 else assert( false );
243 return "";
246 ObjectImp* VectorImp::property( uint which, const KigDocument& w ) const
248 if ( which < Parent::numberOfProperties() )
249 return Parent::property( which, w );
250 else if ( which == Parent::numberOfProperties() )
251 return new DoubleImp( length() );
252 else if ( which == Parent::numberOfProperties() + 1 )
253 return new PointImp( ( mdata.a + mdata.b ) / 2 );
254 else if ( which == Parent::numberOfProperties() + 2 )
255 return new DoubleImp( fabs( mdata.a.x - mdata.b.x ) );
256 else if ( which == Parent::numberOfProperties() + 3 )
257 return new DoubleImp( fabs( mdata.a.y - mdata.b.y ) );
258 else if ( which == Parent::numberOfProperties() + 4 ) // opposite
259 return new VectorImp( mdata.a, 2*mdata.a-mdata.b );
260 else assert( false );
261 return new InvalidImp;
264 VectorImp* VectorImp::copy() const
266 return new VectorImp( mdata.a, mdata.b );
269 const Coordinate VectorImp::dir() const
271 return mdata.dir();
274 void AngleImp::visit( ObjectImpVisitor* vtor ) const
276 vtor->visit( this );
279 void VectorImp::visit( ObjectImpVisitor* vtor ) const
281 vtor->visit( this );
284 const double VectorImp::length() const
286 return ( mdata.a - mdata.b ).length();
289 ArcImp::ArcImp( const Coordinate& center, const double radius,
290 const double startangle, const double angle )
291 : CurveImp(), mcenter( center ), mradius( radius ),
292 msa( startangle ), ma( angle )
294 if ( ma < 0 )
296 // we want a positive angle..
297 msa = msa + ma;
298 ma = -ma;
302 ArcImp::~ArcImp()
306 ArcImp* ArcImp::copy() const
308 return new ArcImp( mcenter, mradius, msa, ma );
311 ObjectImp* ArcImp::transform( const Transformation& t ) const
314 // we don't have conic arcs! So it is invalid to transform an arc
315 // with a nonhomothetic transformation
317 if ( ! t.isHomothetic() ) return new InvalidImp();
319 Coordinate nc = t.apply( mcenter );
320 double nr = t.apply( mradius );
321 // transform msa...
322 double nmsa = msa;
323 if ( t.getAffineDeterminant() > 0 )
325 nmsa = msa - t.getRotationAngle();
326 } else
328 Coordinate ar = t.apply2by2only( Coordinate( cos(msa), sin(msa) ) );
329 nmsa = atan2( ar.y, ar.x );
330 nmsa -= ma;
332 while ( nmsa < -M_PI ) nmsa += 2*M_PI;
333 while ( nmsa > M_PI ) nmsa -= 2*M_PI;
334 if ( nc.valid() ) return new ArcImp( nc, nr, nmsa, ma );
335 else return new InvalidImp;
338 void ArcImp::draw( KigPainter& p ) const
340 p.drawArc( mcenter, mradius, msa, ma );
343 bool ArcImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
345 return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
348 bool ArcImp::inRect( const Rect&, int, const KigWidget& ) const
350 // TODO
351 return false;
354 bool ArcImp::valid() const
356 return true;
359 const uint ArcImp::numberOfProperties() const
361 return Parent::numberOfProperties() + 9;
364 const QCStringList ArcImp::properties() const
366 QCStringList ret = Parent::properties();
367 ret << I18N_NOOP( "Center" );
368 ret << I18N_NOOP( "Radius" );
369 ret << I18N_NOOP( "Angle" );
370 ret << I18N_NOOP( "Angle in Degrees" );
371 ret << I18N_NOOP( "Angle in Radians" );
372 ret << I18N_NOOP( "Sector Surface" );
373 ret << I18N_NOOP( "Arc Length" );
374 ret << I18N_NOOP( "First End Point" );
375 ret << I18N_NOOP( "Second End Point" );
376 assert( ret.size() == ArcImp::numberOfProperties() );
377 return ret;
380 const QCStringList ArcImp::propertiesInternalNames() const
382 QCStringList ret = Parent::propertiesInternalNames();
383 ret << "center";
384 ret << "radius";
385 ret << "angle";
386 ret << "angle-degrees";
387 ret << "angle-radians";
388 ret << "sector-surface";
389 ret << "arc-length";
390 ret << "end-point-A";
391 ret << "end-point-B";
392 return ret;
395 const char* ArcImp::iconForProperty( uint which ) const
397 int numprop = 0;
398 if ( which < Parent::numberOfProperties() )
399 return Parent::iconForProperty( which );
400 else if ( which == Parent::numberOfProperties() + numprop++ )
401 return "arc-center"; // center
402 else if ( which == Parent::numberOfProperties() + numprop++ )
403 return "";
404 else if ( which == Parent::numberOfProperties() + numprop++ )
405 return "angle";
406 else if ( which == Parent::numberOfProperties() + numprop++ )
407 return "angle-size";
408 else if ( which == Parent::numberOfProperties() + numprop++ )
409 return "angle-size";
410 else if ( which == Parent::numberOfProperties() + numprop++ )
411 return "";
412 else if ( which == Parent::numberOfProperties() + numprop++ )
413 return "";
414 else if ( which == Parent::numberOfProperties() + numprop++ )
415 return "";
416 else if ( which == Parent::numberOfProperties() + numprop++ )
417 return "";
418 else assert( false );
419 return "";
422 ObjectImp* ArcImp::property( uint which, const KigDocument& d ) const
424 int numprop = 0;
425 if ( which < Parent::numberOfProperties() )
426 return Parent::property( which, d );
427 else if ( which == Parent::numberOfProperties() + numprop++ )
428 return new PointImp( mcenter );
429 else if ( which == Parent::numberOfProperties() + numprop++ )
430 return new DoubleImp( mradius );
431 else if ( which == Parent::numberOfProperties() + numprop++ )
432 return new AngleImp( mcenter, msa, ma );
433 else if ( which == Parent::numberOfProperties() + numprop++ )
434 return new IntImp( static_cast<int>( Goniometry::convert( ma, Goniometry::Rad, Goniometry::Deg ) ) );
435 else if ( which == Parent::numberOfProperties() + numprop++ )
436 return new DoubleImp( ma );
437 else if ( which == Parent::numberOfProperties() + numprop++ )
438 return new DoubleImp( sectorSurface() );
439 else if ( which == Parent::numberOfProperties() + numprop++ )
440 return new DoubleImp( mradius * ma );
441 else if ( which == Parent::numberOfProperties() + numprop++ )
442 return new PointImp( firstEndPoint() );
443 else if ( which == Parent::numberOfProperties() + numprop++ )
444 return new PointImp( secondEndPoint() );
445 else assert( false );
446 return new InvalidImp;
449 const double ArcImp::sectorSurface() const
451 return mradius * mradius * ma / 2;
454 const ObjectImpType* ArcImp::impRequirementForProperty( uint which ) const
456 if ( which < Parent::numberOfProperties() )
457 return Parent::impRequirementForProperty( which );
458 else
459 return ArcImp::stype();
462 void ArcImp::visit( ObjectImpVisitor* vtor ) const
464 vtor->visit( this );
467 double ArcImp::getParam( const Coordinate& c, const KigDocument& ) const
469 Coordinate d = (c - mcenter).normalize();
470 double angle = atan2( d.y, d.x );
471 angle -= msa;
472 // mp: problems with large arcs
473 while ( angle > ma/2 + M_PI ) angle -= 2*M_PI;
474 while ( angle < ma/2 - M_PI ) angle += 2*M_PI;
476 angle = max( 0., min( angle, ma ) );
477 angle /= ma;
478 return angle;
481 const Coordinate ArcImp::getPoint( double p, const KigDocument& ) const
483 double angle = msa + p * ma;
484 Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * mradius;
485 return mcenter + d;
488 const Coordinate ArcImp::center() const
490 return mcenter;
493 double ArcImp::radius() const
495 return mradius;
498 double ArcImp::startAngle() const
500 return msa;
503 double ArcImp::angle() const
505 return ma;
508 Coordinate ArcImp::firstEndPoint() const
510 double angle = msa;
511 return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
514 Coordinate ArcImp::secondEndPoint() const
516 double angle = msa + ma;
517 return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
520 const Coordinate VectorImp::a() const
522 return mdata.a;
525 const Coordinate VectorImp::b() const
527 return mdata.b;
530 bool ArcImp::equals( const ObjectImp& rhs ) const
532 return rhs.inherits( ArcImp::stype() ) &&
533 static_cast<const ArcImp&>( rhs ).radius() == radius() &&
534 static_cast<const ArcImp&>( rhs ).startAngle() == startAngle() &&
535 static_cast<const ArcImp&>( rhs ).angle() == angle();
538 bool AngleImp::equals( const ObjectImp& rhs ) const
540 return rhs.inherits( AngleImp::stype() ) &&
541 static_cast<const AngleImp&>( rhs ).point() == point() &&
542 static_cast<const AngleImp&>( rhs ).startAngle() == startAngle() &&
543 static_cast<const AngleImp&>( rhs ).angle() == angle();
546 bool VectorImp::equals( const ObjectImp& rhs ) const
548 return rhs.inherits( VectorImp::stype() ) &&
549 static_cast<const VectorImp&>( rhs ).a() == a() &&
550 static_cast<const VectorImp&>( rhs ).b() == b();
553 const ObjectImpType* AngleImp::stype()
555 static const ObjectImpType t(
556 Parent::stype(), "angle",
557 I18N_NOOP( "angle" ),
558 I18N_NOOP( "Select this angle" ),
559 I18N_NOOP( "Select angle %1" ),
560 I18N_NOOP( "Remove an Angle" ),
561 I18N_NOOP( "Add an Angle" ),
562 I18N_NOOP( "Move an Angle" ),
563 I18N_NOOP( "Attach to this angle" ),
564 I18N_NOOP( "Show an Angle" ),
565 I18N_NOOP( "Hide an Angle" )
567 return &t;
569 const ObjectImpType* VectorImp::stype()
571 static const ObjectImpType t(
572 Parent::stype(), "vector",
573 I18N_NOOP( "vector" ),
574 I18N_NOOP( "Select this vector" ),
575 I18N_NOOP( "Select vector %1" ),
576 I18N_NOOP( "Remove a Vector" ),
577 I18N_NOOP( "Add a Vector" ),
578 I18N_NOOP( "Move a Vector" ),
579 I18N_NOOP( "Attach to this vector" ),
580 I18N_NOOP( "Show a Vector" ),
581 I18N_NOOP( "Hide a Vector" )
583 return &t;
585 const ObjectImpType* ArcImp::stype()
587 static const ObjectImpType t(
588 Parent::stype(), "arc",
589 I18N_NOOP( "arc" ),
590 I18N_NOOP( "Select this arc" ),
591 I18N_NOOP( "Select arc %1" ),
592 I18N_NOOP( "Remove an Arc" ),
593 I18N_NOOP( "Add an Arc" ),
594 I18N_NOOP( "Move an Arc" ),
595 I18N_NOOP( "Attach to this arc" ),
596 I18N_NOOP( "Show an Arc" ),
597 I18N_NOOP( "Hide an Arc" )
599 return &t;
602 const ObjectImpType* AngleImp::type() const
604 return AngleImp::stype();
607 const ObjectImpType* VectorImp::type() const
609 return VectorImp::stype();
612 const ObjectImpType* ArcImp::type() const
614 return ArcImp::stype();
617 bool ArcImp::containsPoint( const Coordinate& p, const KigDocument& ) const
619 return internalContainsPoint( p, test_threshold );
622 bool ArcImp::internalContainsPoint( const Coordinate& p, double threshold ) const
624 return isOnArc( p, mcenter, mradius, msa, ma, threshold );
627 bool AngleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
629 if ( which < Parent::numberOfProperties() )
630 return Parent::isPropertyDefinedOnOrThroughThisImp( which );
631 return false;
634 bool VectorImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
636 return Parent::isPropertyDefinedOnOrThroughThisImp( which );
639 bool ArcImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
641 if ( which < Parent::numberOfProperties() )
642 return Parent::isPropertyDefinedOnOrThroughThisImp( which );
643 else if ( which == Parent::numberOfProperties() )
644 return true;
645 else
646 return false;
649 Rect AngleImp::surroundingRect() const
651 return Rect( mpoint, 0, 0 );
654 Rect VectorImp::surroundingRect() const
656 return Rect( mdata.a, mdata.b );
659 Rect ArcImp::surroundingRect() const
661 // the returned rect should contain the center point(?), the two end
662 // points, and all extreme x and y positions in between.
663 //Rect ret( mcenter, 0, 0 );
664 double a = msa;
665 //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
666 Rect ret ( mcenter + mradius*Coordinate( cos( a ), sin( a ) ), 0, 0 );
667 a = msa + ma;
668 ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
669 for ( a = -2*M_PI; a <= 2*M_PI; a+=M_PI/2 )
671 Coordinate d = mcenter + mradius*Coordinate( cos( a ), sin( a ) );
672 if ( msa <= a && a <= msa + ma )
673 ret.setContains( d );
675 return ret;
678 const Coordinate VectorImp::getPoint( double param, const KigDocument& ) const
680 return mdata.a + mdata.dir() * param;
683 double VectorImp::getParam( const Coordinate& p, const KigDocument& ) const
685 Coordinate pt = calcPointOnPerpend( mdata, p );
686 pt = calcIntersectionPoint( mdata, LineData( p, pt ) );
687 // if pt is over the end of the vector we set it to one of the end
688 // points of the vector...
689 if ( ( pt - mdata.a ).length() > dir().length() )
690 pt = mdata.b;
691 else if ( ( pt - mdata.b ).length() > dir().length() )
692 pt = mdata.a;
693 if ( mdata.b == mdata.a ) return 0;
694 return ( ( pt - mdata.a ).length() ) / ( dir().length() );
697 bool VectorImp::containsPoint( const Coordinate& p, const KigDocument& ) const
699 return internalContainsPoint( p, test_threshold );
702 bool VectorImp::internalContainsPoint( const Coordinate& p, double threshold ) const
704 return isOnSegment( p, mdata.a, mdata.b, threshold );
707 LineData VectorImp::data() const
709 return mdata;