1 // Copyright (C) 2002 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
20 #include "bogus_imp.h"
21 #include "point_imp.h"
23 #include "../misc/rect.h"
24 #include "../misc/common.h"
25 #include "../misc/kigtransform.h"
26 #include "../misc/kigpainter.h"
27 #include "../kig/kig_view.h"
34 AbstractLineImp::AbstractLineImp( const Coordinate
& a
, const Coordinate
& b
)
39 AbstractLineImp::~AbstractLineImp()
43 bool AbstractLineImp::inRect( const Rect
& r
, int width
, const KigWidget
& w
) const
45 return lineInRect( r
, mdata
.a
, mdata
.b
, width
, this, w
);
48 const uint
AbstractLineImp::numberOfProperties() const
50 return Parent::numberOfProperties() + 2;
53 const ObjectImpType
* AbstractLineImp::impRequirementForProperty( uint which
) const
55 if ( which
< Parent::numberOfProperties() )
56 return Parent::impRequirementForProperty( which
);
57 else return AbstractLineImp::stype();
60 const char* AbstractLineImp::iconForProperty( uint which
) const
62 if ( which
< Parent::numberOfProperties() )
63 return Parent::iconForProperty( which
);
64 if ( which
== Parent::numberOfProperties() )
65 return "slope"; // slope
66 if ( which
== Parent::numberOfProperties() + 1 )
67 return "text"; // equation
72 ObjectImp
* AbstractLineImp::property( uint which
, const KigDocument
& w
) const
74 if ( which
< Parent::numberOfProperties() )
75 return Parent::property( which
, w
);
76 if ( which
== Parent::numberOfProperties() )
77 return new DoubleImp( slope() );
78 if ( which
== Parent::numberOfProperties() + 1 )
79 return new StringImp( equationString() );
81 return new InvalidImp
;
84 const QCStringList
AbstractLineImp::propertiesInternalNames() const
86 QCStringList l
= Parent::propertiesInternalNames();
89 assert( l
.size() == AbstractLineImp::numberOfProperties() );
93 const QCStringList
AbstractLineImp::properties() const
95 QCStringList l
= Parent::properties();
96 l
<< I18N_NOOP( "Slope" );
97 l
<< I18N_NOOP( "Equation" );
98 assert( l
.size() == AbstractLineImp::numberOfProperties() );
102 const uint
SegmentImp::numberOfProperties() const
104 return Parent::numberOfProperties() + 4;
107 const QCStringList
SegmentImp::propertiesInternalNames() const
109 QCStringList s
= Parent::propertiesInternalNames();
114 assert( s
.size() == SegmentImp::numberOfProperties() );
118 const QCStringList
SegmentImp::properties() const
120 QCStringList s
= Parent::properties();
121 s
<< I18N_NOOP( "Length" );
122 s
<< I18N_NOOP( "Mid Point" );
123 s
<< I18N_NOOP( "First End Point" );
124 s
<< I18N_NOOP( "Second End Point" );
125 assert( s
.size() == SegmentImp::numberOfProperties() );
129 const ObjectImpType
* SegmentImp::impRequirementForProperty( uint which
) const
131 if ( which
< Parent::numberOfProperties() )
132 return Parent::impRequirementForProperty( which
);
133 else return SegmentImp::stype();
136 const char* SegmentImp::iconForProperty( uint which
) const
139 if ( which
< Parent::numberOfProperties() )
140 return Parent::iconForProperty( which
);
141 else if ( which
== Parent::numberOfProperties() + pnum
++ )
142 return "distance"; // length
143 else if ( which
== Parent::numberOfProperties() + pnum
++ )
144 return "segment-midpoint"; // mid point
145 else if ( which
== Parent::numberOfProperties() + pnum
++ )
146 return "endpoint1"; // mid point
147 else if ( which
== Parent::numberOfProperties() + pnum
++ )
148 return "endpoint2"; // mid point
149 else assert( false );
153 ObjectImp
* SegmentImp::property( uint which
, const KigDocument
& w
) const
157 if ( which
< Parent::numberOfProperties() )
158 return Parent::property( which
, w
);
159 else if ( which
== Parent::numberOfProperties() + pnum
++ )
160 return new DoubleImp( mdata
.dir().length() );
161 else if ( which
== Parent::numberOfProperties() + pnum
++ )
162 return new PointImp( ( mdata
.a
+ mdata
.b
) / 2 );
163 else if ( which
== Parent::numberOfProperties() + pnum
++ )
164 return new PointImp( mdata
.a
);
165 else if ( which
== Parent::numberOfProperties() + pnum
++ )
166 return new PointImp( mdata
.b
);
167 else assert( false );
168 return new InvalidImp
;
171 double AbstractLineImp::slope() const
173 Coordinate diff
= mdata
.dir();
174 return diff
.y
/ diff
.x
;
177 const QString
AbstractLineImp::equationString() const
179 Coordinate p
= mdata
.a
;
180 Coordinate q
= mdata
.b
;
182 double m
= ( q
.y
- p
.y
) / ( q
.x
- p
.x
);
183 double r
= - ( q
.y
- p
.y
) * p
.x
/ ( q
.x
- p
.x
) + p
.y
;
185 QString ret
= QString::fromUtf8( "y = %1x " ) +
186 QString::fromUtf8( r
> 0 ? "+" : "-" ) +
187 QString::fromUtf8( " %2" );
189 ret
= ret
.arg( m
, 0, 'g', 3 );
190 ret
= ret
.arg( abs( r
), 0, 'g', 3 );
195 void SegmentImp::draw( KigPainter
& p
) const
197 p
.drawSegment( mdata
);
200 bool SegmentImp::contains( const Coordinate
& p
, int width
, const KigWidget
& w
) const
202 return internalContainsPoint( p
, w
.screenInfo().normalMiss( width
) );
205 void RayImp::draw( KigPainter
& p
) const
210 bool RayImp::contains( const Coordinate
& p
, int width
, const KigWidget
& w
) const
212 return internalContainsPoint( p
, w
.screenInfo().normalMiss( width
) );
215 void LineImp::draw( KigPainter
& p
) const
220 bool LineImp::contains( const Coordinate
& p
, int width
, const KigWidget
& w
) const
222 return internalContainsPoint( p
, w
.screenInfo().normalMiss( width
) );
225 SegmentImp::SegmentImp( const Coordinate
& a
, const Coordinate
& b
)
226 : AbstractLineImp( a
, b
)
230 RayImp::RayImp( const Coordinate
& a
, const Coordinate
& b
)
231 : AbstractLineImp( a
, b
)
235 LineImp::LineImp( const Coordinate
& a
, const Coordinate
& b
)
236 : AbstractLineImp( a
, b
)
240 SegmentImp
* SegmentImp::copy() const
242 return new SegmentImp( mdata
);
245 RayImp
* RayImp::copy() const
247 return new RayImp( mdata
);
250 LineImp
* LineImp::copy() const
252 return new LineImp( mdata
);
255 const Coordinate
SegmentImp::getPoint( double param
, const KigDocument
& ) const
257 return mdata
.a
+ mdata
.dir()*param
;
260 double SegmentImp::getParam( const Coordinate
& p
, const KigDocument
& ) const
262 Coordinate pt
= calcPointOnPerpend( data(), p
);
263 pt
= calcIntersectionPoint( data(), LineData( p
, pt
) );
264 // if pt is over the end of the segment ( i.e. it's on the line
265 // which the segment is a part of, but not of the segment itself..;
266 // ) we set it to one of the end points of the segment...
267 if ((pt
- mdata
.a
).length() > mdata
.dir().length() )
269 else if ( (pt
- mdata
.b
).length() > mdata
.dir().length() )
271 if (mdata
.b
== mdata
.a
) return 0;
272 return ((pt
- mdata
.a
).length())/(mdata
.dir().length());
275 LineData
AbstractLineImp::data() const
280 const Coordinate
RayImp::getPoint( double param
, const KigDocument
& ) const
282 param
= 1.0/param
- 1.0;
283 return mdata
.a
+ mdata
.dir()*param
;
286 double RayImp::getParam( const Coordinate
& p
, const KigDocument
& ) const
288 const LineData ld
= data();
289 Coordinate pt
= calcPointOnPerpend( ld
, p
);
290 pt
= calcIntersectionPoint( ld
, LineData( p
, pt
));
291 // if pt is over the end of the ray ( i.e. it's on the line
292 // which the ray is a part of, but not of the ray itself..;
293 // ) we set it to the start point of the ray...
294 Coordinate dir
= ld
.dir();
297 if ( dir
.x
!= 0 ) param
= pt
.x
/ dir
.x
;
298 else if ( dir
.y
!= 0 ) param
= pt
.y
/ dir
.y
;
300 if ( param
< 0. ) param
= 0.;
302 // mp: let's try with 1/(x+1), this reverses the mapping, but
303 // should allow to take advantage of the tightness of floating point
304 // numbers near zero, in order to get more possible positions near
307 param
= 1./( param
+ 1. );
309 assert( param
>= 0. && param
<= 1. );
313 const Coordinate
LineImp::getPoint( double p
, const KigDocument
& ) const
315 // inspired upon KSeg
317 // we need to spread the points over the line, it should also come near
318 // the (infinite) end of the line, but most points should be near
319 // the two points we contain...
320 if ( p
<= 0. ) p
= 1e-6;
321 if ( p
>= 1. ) p
= 1 - 1e-6;
323 if (p
> 0) p
= p
/(1 - p
);
325 // p *= 1024; // such multiplying factor could be useful in order to
326 // have more points near infinity, at the expense of
327 // points near ma and mb
328 return mdata
.a
+ p
*mdata
.dir();
331 double LineImp::getParam( const Coordinate
& point
, const KigDocument
& ) const
333 // somewhat the reverse of getPoint, although it also supports
334 // points not on the line...
336 Coordinate pa
= point
- mdata
.a
;
337 Coordinate ba
= mdata
.dir();
338 double balsq
= ba
.x
*ba
.x
+ ba
.y
*ba
.y
;
341 double p
= (pa
.x
*ba
.x
+ pa
.y
*ba
.y
)/balsq
;
343 if (p
> 0) p
= p
/(1+p
);
349 ObjectImp
* SegmentImp::transform( const Transformation
& t
) const
351 if ( ! t
.isAffine() ) /* we need to check the position of the two points */
353 if ( t
.getProjectiveIndicator( mdata
.a
) *
354 t
.getProjectiveIndicator( mdata
.b
) < 0 )
355 return new InvalidImp();
357 Coordinate na
= t
.apply( mdata
.a
);
358 Coordinate nb
= t
.apply( mdata
.b
);
359 if( na
.valid() && nb
.valid() ) return new SegmentImp( na
, nb
);
360 else return new InvalidImp();
363 ObjectImp
* LineImp::transform( const Transformation
& t
) const
365 Coordinate na
= t
.apply( mdata
.a
);
366 Coordinate nb
= t
.apply( mdata
.b
);
367 if ( na
.valid() && nb
.valid() ) return new LineImp( na
, nb
);
368 else return new InvalidImp();
371 ObjectImp
* RayImp::transform( const Transformation
& t
) const
373 if ( ! t
.isAffine() ) /* we need to check the position of the two points */
375 double pa
= t
.getProjectiveIndicator( mdata
.a
);
376 double pb
= t
.getProjectiveIndicator( mdata
.b
);
377 if ( pa
< 0 ) pb
= -pb
;
378 if ( pb
< fabs (pa
) ) return new InvalidImp();
379 Coordinate na
= t
.apply( mdata
.a
);
380 Coordinate nb
= t
.apply0( mdata
.b
- mdata
.a
);
381 if ( na
.valid() && nb
.valid() ) return new SegmentImp( na
, nb
);
382 else return new InvalidImp();
384 Coordinate na
= t
.apply( mdata
.a
);
385 Coordinate nb
= t
.apply( mdata
.b
);
386 if ( na
.valid() && nb
.valid() ) return new RayImp( na
, nb
);
387 else return new InvalidImp();
390 AbstractLineImp::AbstractLineImp( const LineData
& d
)
395 SegmentImp::SegmentImp( const LineData
& d
)
396 : AbstractLineImp( d
)
400 RayImp::RayImp( const LineData
& d
)
401 : AbstractLineImp( d
)
405 LineImp::LineImp( const LineData
& d
)
406 : AbstractLineImp( d
)
410 double SegmentImp::length() const
412 return mdata
.length();
415 void SegmentImp::visit( ObjectImpVisitor
* vtor
) const
420 void RayImp::visit( ObjectImpVisitor
* vtor
) const
425 void LineImp::visit( ObjectImpVisitor
* vtor
) const
430 bool AbstractLineImp::equals( const ObjectImp
& rhs
) const
432 return rhs
.type() == type() &&
433 static_cast<const AbstractLineImp
&>( rhs
).data() == data();
436 const ObjectImpType
* AbstractLineImp::stype()
438 static const ObjectImpType
t(
439 Parent::stype(), "line", I18N_NOOP( "line" ),
440 I18N_NOOP( "Select a Line" ), 0, 0, 0, 0, 0, 0, 0 );
444 const ObjectImpType
* LineImp::stype()
446 static const ObjectImpType
t(
447 Parent::stype(), "line",
449 I18N_NOOP( "Select this line" ),
450 I18N_NOOP( "Select line %1" ),
451 I18N_NOOP( "Remove a Line" ),
452 I18N_NOOP( "Add a Line" ),
453 I18N_NOOP( "Move a Line" ),
454 I18N_NOOP( "Attach to this line" ),
455 I18N_NOOP( "Show a Line" ),
456 I18N_NOOP( "Hide a Line" )
461 const ObjectImpType
* SegmentImp::stype()
463 static const ObjectImpType
t(
464 Parent::stype(), "segment",
465 I18N_NOOP( "segment" ),
466 I18N_NOOP( "Select this segment" ),
467 I18N_NOOP( "Select segment %1" ),
468 I18N_NOOP( "Remove a Segment" ),
469 I18N_NOOP( "Add a Segment" ),
470 I18N_NOOP( "Move a Segment" ),
471 I18N_NOOP( "Attach to this segment" ),
472 I18N_NOOP( "Show a Segment" ),
473 I18N_NOOP( "Hide a Segment" )
478 const ObjectImpType
* RayImp::stype()
480 static const ObjectImpType
t(
481 Parent::stype(), "ray",
482 I18N_NOOP( "half-line" ),
483 I18N_NOOP( "Select this half-line" ),
484 I18N_NOOP( "Select half-line %1" ),
485 I18N_NOOP( "Remove a Half-Line" ),
486 I18N_NOOP( "Add a Half-Line" ),
487 I18N_NOOP( "Move a Half-Line" ),
488 I18N_NOOP( "Attach to this half-line" ),
489 I18N_NOOP( "Show a Half-Line" ),
490 I18N_NOOP( "Hide a Half-Line" )
495 const ObjectImpType
* SegmentImp::type() const
497 return SegmentImp::stype();
500 const ObjectImpType
* RayImp::type() const
502 return RayImp::stype();
505 const ObjectImpType
* LineImp::type() const
507 return LineImp::stype();
510 bool SegmentImp::containsPoint( const Coordinate
& p
, const KigDocument
& ) const
512 return internalContainsPoint( p
, test_threshold
);
515 bool SegmentImp::internalContainsPoint( const Coordinate
& p
, double threshold
) const
517 return isOnSegment( p
, mdata
.a
, mdata
.b
, threshold
);
520 bool RayImp::containsPoint( const Coordinate
& p
, const KigDocument
& ) const
522 return internalContainsPoint( p
, test_threshold
);
525 bool RayImp::internalContainsPoint( const Coordinate
& p
, double threshold
) const
527 return isOnRay( p
, mdata
.a
, mdata
.b
, threshold
);
530 bool LineImp::containsPoint( const Coordinate
& p
, const KigDocument
& ) const
532 return internalContainsPoint( p
, test_threshold
);
535 bool LineImp::internalContainsPoint( const Coordinate
& p
, double threshold
) const
537 return isOnLine( p
, mdata
.a
, mdata
.b
, threshold
);
540 bool AbstractLineImp::isPropertyDefinedOnOrThroughThisImp( uint which
) const
544 if ( which
< Parent::numberOfProperties() )
545 return Parent::isPropertyDefinedOnOrThroughThisImp( which
);
546 else if ( which
== Parent::numberOfProperties() + pnum
++ )
548 else if ( which
== Parent::numberOfProperties() + pnum
++ )
550 else if ( which
== Parent::numberOfProperties() + pnum
++ )
552 else if ( which
== Parent::numberOfProperties() + pnum
++ )
554 else assert( false );
558 Rect
SegmentImp::surroundingRect() const
560 return Rect( mdata
.a
, mdata
.b
);
563 Rect
RayImp::surroundingRect() const
565 return Rect::invalidRect();
568 Rect
LineImp::surroundingRect() const
570 return Rect::invalidRect();