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
18 #include "other_imp.h"
20 #include "bogus_imp.h"
21 #include "point_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"
41 ObjectImp
* AngleImp::transform( const Transformation
& ) const
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
) )
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
76 return r
.contains( mpoint
, w
.screenInfo().normalMiss( width
) );
79 Coordinate
AngleImp::attachPoint() const
84 const uint
AngleImp::numberOfProperties() const
86 return Parent::numberOfProperties() + 3;
89 const QCStringList
AngleImp::propertiesInternalNames() const
91 QCStringList l
= Parent::propertiesInternalNames();
94 l
<< "angle-bisector";
95 assert( l
.size() == AngleImp::numberOfProperties() );
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() );
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
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 );
131 ObjectImp
* AngleImp::property( uint which
, const KigDocument
& w
) const
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
155 ObjectImp
* AngleImp::copy() const
157 return new AngleImp( mpoint
, mstartangle
, mangle
);
160 VectorImp::VectorImp( const Coordinate
& a
, const Coordinate
& 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();
201 ret
<< "vect-mid-point";
204 ret
<< "vector-opposite";
205 assert( ret
.size() == VectorImp::numberOfProperties() );
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() );
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 );
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
274 void AngleImp::visit( ObjectImpVisitor
* vtor
) const
279 void VectorImp::visit( ObjectImpVisitor
* vtor
) const
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
)
296 // we want a positive angle..
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
);
323 if ( t
.getAffineDeterminant() > 0 )
325 nmsa
= msa
- t
.getRotationAngle();
328 Coordinate ar
= t
.apply2by2only( Coordinate( cos(msa
), sin(msa
) ) );
329 nmsa
= atan2( ar
.y
, ar
.x
);
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
354 bool ArcImp::valid() const
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() );
380 const QCStringList
ArcImp::propertiesInternalNames() const
382 QCStringList ret
= Parent::propertiesInternalNames();
386 ret
<< "angle-degrees";
387 ret
<< "angle-radians";
388 ret
<< "sector-surface";
390 ret
<< "end-point-A";
391 ret
<< "end-point-B";
395 const char* ArcImp::iconForProperty( uint which
) const
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
++ )
404 else if ( which
== Parent::numberOfProperties() + numprop
++ )
406 else if ( which
== Parent::numberOfProperties() + numprop
++ )
408 else if ( which
== Parent::numberOfProperties() + numprop
++ )
410 else if ( which
== Parent::numberOfProperties() + numprop
++ )
412 else if ( which
== Parent::numberOfProperties() + numprop
++ )
414 else if ( which
== Parent::numberOfProperties() + numprop
++ )
416 else if ( which
== Parent::numberOfProperties() + numprop
++ )
418 else assert( false );
422 ObjectImp
* ArcImp::property( uint which
, const KigDocument
& d
) const
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
);
459 return ArcImp::stype();
462 void ArcImp::visit( ObjectImpVisitor
* vtor
) const
467 double ArcImp::getParam( const Coordinate
& c
, const KigDocument
& ) const
469 Coordinate d
= (c
- mcenter
).normalize();
470 double angle
= atan2( d
.y
, d
.x
);
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
) );
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
;
488 const Coordinate
ArcImp::center() const
493 double ArcImp::radius() const
498 double ArcImp::startAngle() const
503 double ArcImp::angle() const
508 Coordinate
ArcImp::firstEndPoint() const
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
525 const Coordinate
VectorImp::b() const
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" )
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" )
585 const ObjectImpType
* ArcImp::stype()
587 static const ObjectImpType
t(
588 Parent::stype(), "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" )
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
);
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() )
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 );
665 //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
666 Rect
ret ( mcenter
+ mradius
*Coordinate( cos( a
), sin( a
) ), 0, 0 );
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
);
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() )
691 else if ( ( pt
- mdata
.b
).length() > dir().length() )
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