summaryrefslogtreecommitdiffstats
path: root/kig/objects/other_imp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'kig/objects/other_imp.cc')
-rw-r--r--kig/objects/other_imp.cc710
1 files changed, 710 insertions, 0 deletions
diff --git a/kig/objects/other_imp.cc b/kig/objects/other_imp.cc
new file mode 100644
index 00000000..137a3e93
--- /dev/null
+++ b/kig/objects/other_imp.cc
@@ -0,0 +1,710 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "other_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../misc/screeninfo.h"
+#include "../misc/common.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+#include <utility>
+using namespace std;
+
+AngleImp::~AngleImp()
+{
+}
+
+ObjectImp* AngleImp::transform( const Transformation& ) const
+{
+ // TODO ?
+ return new InvalidImp;
+}
+
+void AngleImp::draw( KigPainter& p ) const
+{
+ p.drawAngle( mpoint, mstartangle, mangle );
+}
+
+AngleImp::AngleImp( const Coordinate& pt, double start_angle_in_radials,
+ double angle_in_radials )
+ : mpoint( pt ), mstartangle( start_angle_in_radials ),
+ mangle( angle_in_radials )
+{
+}
+
+bool AngleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ double radius = 50*w.screenInfo().pixelWidth();
+
+ if ( fabs( (p-mpoint).length() - radius ) > w.screenInfo().normalMiss( width ) )
+ return false;
+
+ // and next we check if the angle is appropriate...
+ Coordinate vect = p - mpoint;
+ double angle = atan2( vect.y, vect.x );
+ while ( angle < mstartangle ) angle += 2*M_PI;
+ return angle <= mstartangle + mangle;
+}
+
+bool AngleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ // TODO ?
+ return r.contains( mpoint, w.screenInfo().normalMiss( width ) );
+}
+
+Coordinate AngleImp::attachPoint() const
+{
+ return mpoint;
+}
+
+const uint AngleImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 3;
+}
+
+const QCStringList AngleImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "angle-radian";
+ l << "angle-degrees";
+ l << "angle-bisector";
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList AngleImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Angle in Radians" );
+ l << I18N_NOOP( "Angle in Degrees" );
+ l << I18N_NOOP( "Angle Bisector" );
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* AngleImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return AngleImp::stype();
+}
+
+const char* AngleImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in radians
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in degrees
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_bisector"; // angle bisector..
+ else assert( false );
+ return "";
+}
+
+ObjectImp* AngleImp::property( uint which, const KigDocument& w ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( size() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( Goniometry::convert( size(), Goniometry::Rad, Goniometry::Deg ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ {
+ const double angle = mstartangle + mangle / 2;
+ Coordinate p2 = mpoint + Coordinate( cos( angle ), sin( angle ) ) * 10;
+ return new RayImp( mpoint, p2 );
+ }
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double AngleImp::size() const
+{
+ return mangle;
+}
+
+ObjectImp* AngleImp::copy() const
+{
+ return new AngleImp( mpoint, mstartangle, mangle );
+}
+
+VectorImp::VectorImp( const Coordinate& a, const Coordinate& b )
+ : mdata( a, b )
+{
+}
+
+VectorImp::~VectorImp()
+{
+}
+
+ObjectImp* VectorImp::transform( const Transformation& t ) const
+{
+ Coordinate ta = t.apply( mdata.a );
+ Coordinate tb = t.apply( mdata.b );
+ if ( ta.valid() && tb.valid() ) return new VectorImp( ta, tb );
+ else return new InvalidImp;
+}
+
+void VectorImp::draw( KigPainter& p ) const
+{
+ p.drawVector( mdata.a, mdata.b );
+}
+
+bool VectorImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool VectorImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ return lineInRect( r, mdata.a, mdata.b, width, this, w );
+}
+
+const uint VectorImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList VectorImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "length";
+ ret << "vect-mid-point";
+ ret << "length-x";
+ ret << "length-y";
+ ret << "vector-opposite";
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList VectorImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Length" );
+ ret << I18N_NOOP( "Midpoint" );
+ ret << I18N_NOOP( "X length" );
+ ret << I18N_NOOP( "Y length" );
+ ret << I18N_NOOP( "Opposite Vector" );
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const ObjectImpType* VectorImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return VectorImp::stype();
+}
+
+const char* VectorImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "distance"; // length
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return "bisection"; // mid point
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return "distance"; // length-x
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return "distance"; // length-y
+ else if ( which == Parent::numberOfProperties() + 4 )
+ return "opposite-vector"; // opposite vector
+ else assert( false );
+ return "";
+}
+
+ObjectImp* VectorImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ return new DoubleImp( length() );
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return new PointImp( ( mdata.a + mdata.b ) / 2 );
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return new DoubleImp( fabs( mdata.a.x - mdata.b.x ) );
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return new DoubleImp( fabs( mdata.a.y - mdata.b.y ) );
+ else if ( which == Parent::numberOfProperties() + 4 ) // opposite
+ return new VectorImp( mdata.a, 2*mdata.a-mdata.b );
+ else assert( false );
+ return new InvalidImp;
+}
+
+VectorImp* VectorImp::copy() const
+{
+ return new VectorImp( mdata.a, mdata.b );
+}
+
+const Coordinate VectorImp::dir() const
+{
+ return mdata.dir();
+}
+
+void AngleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void VectorImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+const double VectorImp::length() const
+{
+ return ( mdata.a - mdata.b ).length();
+}
+
+ArcImp::ArcImp( const Coordinate& center, const double radius,
+ const double startangle, const double angle )
+ : CurveImp(), mcenter( center ), mradius( radius ),
+ msa( startangle ), ma( angle )
+{
+ if ( ma < 0 )
+ {
+ // we want a positive angle..
+ msa = msa + ma;
+ ma = -ma;
+ };
+}
+
+ArcImp::~ArcImp()
+{
+}
+
+ArcImp* ArcImp::copy() const
+{
+ return new ArcImp( mcenter, mradius, msa, ma );
+}
+
+ObjectImp* ArcImp::transform( const Transformation& t ) const
+{
+ //
+ // we don't have conic arcs! So it is invalid to transform an arc
+ // with a nonhomothetic transformation
+ //
+ if ( ! t.isHomothetic() ) return new InvalidImp();
+
+ Coordinate nc = t.apply( mcenter );
+ double nr = t.apply( mradius );
+ // transform msa...
+ double nmsa = msa;
+ if ( t.getAffineDeterminant() > 0 )
+ {
+ nmsa = msa - t.getRotationAngle();
+ } else
+ {
+ Coordinate ar = t.apply2by2only( Coordinate( cos(msa), sin(msa) ) );
+ nmsa = atan2( ar.y, ar.x );
+ nmsa -= ma;
+ }
+ while ( nmsa < -M_PI ) nmsa += 2*M_PI;
+ while ( nmsa > M_PI ) nmsa -= 2*M_PI;
+ if ( nc.valid() ) return new ArcImp( nc, nr, nmsa, ma );
+ else return new InvalidImp;
+}
+
+void ArcImp::draw( KigPainter& p ) const
+{
+ p.drawArc( mcenter, mradius, msa, ma );
+}
+
+bool ArcImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+bool ArcImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO
+ return false;
+}
+
+bool ArcImp::valid() const
+{
+ return true;
+}
+
+const uint ArcImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 9;
+}
+
+const QCStringList ArcImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Center" );
+ ret << I18N_NOOP( "Radius" );
+ ret << I18N_NOOP( "Angle" );
+ ret << I18N_NOOP( "Angle in Degrees" );
+ ret << I18N_NOOP( "Angle in Radians" );
+ ret << I18N_NOOP( "Sector Surface" );
+ ret << I18N_NOOP( "Arc Length" );
+ ret << I18N_NOOP( "First End Point" );
+ ret << I18N_NOOP( "Second End Point" );
+ assert( ret.size() == ArcImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList ArcImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "center";
+ ret << "radius";
+ ret << "angle";
+ ret << "angle-degrees";
+ ret << "angle-radians";
+ ret << "sector-surface";
+ ret << "arc-length";
+ ret << "end-point-A";
+ ret << "end-point-B";
+ return ret;
+}
+
+const char* ArcImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "arc_center"; // center
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else assert( false );
+ return "";
+}
+
+ObjectImp* ArcImp::property( uint which, const KigDocument& d ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( mcenter );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new AngleImp( mcenter, msa, ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new IntImp( static_cast<int>( Goniometry::convert( ma, Goniometry::Rad, Goniometry::Deg ) ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( sectorSurface() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius * ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( firstEndPoint() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( secondEndPoint() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double ArcImp::sectorSurface() const
+{
+ return mradius * mradius * ma / 2;
+}
+
+const ObjectImpType* ArcImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else
+ return ArcImp::stype();
+}
+
+void ArcImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+double ArcImp::getParam( const Coordinate& c, const KigDocument& ) const
+{
+ Coordinate d = (c - mcenter).normalize();
+ double angle = atan2( d.y, d.x );
+ angle -= msa;
+// mp: problems with large arcs
+ while ( angle > ma/2 + M_PI ) angle -= 2*M_PI;
+ while ( angle < ma/2 - M_PI ) angle += 2*M_PI;
+//
+ angle = max( 0., min( angle, ma ) );
+ angle /= ma;
+ return angle;
+}
+
+const Coordinate ArcImp::getPoint( double p, const KigDocument& ) const
+{
+ double angle = msa + p * ma;
+ Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ return mcenter + d;
+}
+
+const Coordinate ArcImp::center() const
+{
+ return mcenter;
+}
+
+double ArcImp::radius() const
+{
+ return mradius;
+}
+
+double ArcImp::startAngle() const
+{
+ return msa;
+}
+
+double ArcImp::angle() const
+{
+ return ma;
+}
+
+Coordinate ArcImp::firstEndPoint() const
+{
+ double angle = msa;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+Coordinate ArcImp::secondEndPoint() const
+{
+ double angle = msa + ma;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+const Coordinate VectorImp::a() const
+{
+ return mdata.a;
+}
+
+const Coordinate VectorImp::b() const
+{
+ return mdata.b;
+}
+
+bool ArcImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( ArcImp::stype() ) &&
+ static_cast<const ArcImp&>( rhs ).radius() == radius() &&
+ static_cast<const ArcImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const ArcImp&>( rhs ).angle() == angle();
+}
+
+bool AngleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( AngleImp::stype() ) &&
+ static_cast<const AngleImp&>( rhs ).point() == point() &&
+ static_cast<const AngleImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const AngleImp&>( rhs ).angle() == angle();
+}
+
+bool VectorImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( VectorImp::stype() ) &&
+ static_cast<const VectorImp&>( rhs ).a() == a() &&
+ static_cast<const VectorImp&>( rhs ).b() == b();
+}
+
+const ObjectImpType* AngleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "angle",
+ I18N_NOOP( "angle" ),
+ I18N_NOOP( "Select this angle" ),
+ I18N_NOOP( "Select angle %1" ),
+ I18N_NOOP( "Remove an Angle" ),
+ I18N_NOOP( "Add an Angle" ),
+ I18N_NOOP( "Move an Angle" ),
+ I18N_NOOP( "Attach to this angle" ),
+ I18N_NOOP( "Show an Angle" ),
+ I18N_NOOP( "Hide an Angle" )
+ );
+ return &t;
+}
+const ObjectImpType* VectorImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "vector",
+ I18N_NOOP( "vector" ),
+ I18N_NOOP( "Select this vector" ),
+ I18N_NOOP( "Select vector %1" ),
+ I18N_NOOP( "Remove a Vector" ),
+ I18N_NOOP( "Add a Vector" ),
+ I18N_NOOP( "Move a Vector" ),
+ I18N_NOOP( "Attach to this vector" ),
+ I18N_NOOP( "Show a Vector" ),
+ I18N_NOOP( "Hide a Vector" )
+ );
+ return &t;
+}
+const ObjectImpType* ArcImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "arc",
+ I18N_NOOP( "arc" ),
+ I18N_NOOP( "Select this arc" ),
+ I18N_NOOP( "Select arc %1" ),
+ I18N_NOOP( "Remove an Arc" ),
+ I18N_NOOP( "Add an Arc" ),
+ I18N_NOOP( "Move an Arc" ),
+ I18N_NOOP( "Attach to this arc" ),
+ I18N_NOOP( "Show an Arc" ),
+ I18N_NOOP( "Hide an Arc" )
+ );
+ return &t;
+}
+
+const ObjectImpType* AngleImp::type() const
+{
+ return AngleImp::stype();
+}
+
+const ObjectImpType* VectorImp::type() const
+{
+ return VectorImp::stype();
+}
+
+const ObjectImpType* ArcImp::type() const
+{
+ return ArcImp::stype();
+}
+
+bool ArcImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool ArcImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnArc( p, mcenter, mradius, msa, ma, threshold );
+}
+
+bool AngleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+bool VectorImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+bool ArcImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ else if ( which == Parent::numberOfProperties() )
+ return true;
+ else
+ return false;
+}
+
+Rect AngleImp::surroundingRect() const
+{
+ return Rect( mpoint, 0, 0 );
+}
+
+Rect VectorImp::surroundingRect() const
+{
+ return Rect( mdata.a, mdata.b );
+}
+
+Rect ArcImp::surroundingRect() const
+{
+ // the returned rect should contain the center point(?), the two end
+ // points, and all extreme x and y positions in between.
+ //Rect ret( mcenter, 0, 0 );
+ double a = msa;
+ //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ Rect ret ( mcenter + mradius*Coordinate( cos( a ), sin( a ) ), 0, 0 );
+ a = msa + ma;
+ ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ for ( a = -2*M_PI; a <= 2*M_PI; a+=M_PI/2 )
+ {
+ Coordinate d = mcenter + mradius*Coordinate( cos( a ), sin( a ) );
+ if ( msa <= a && a <= msa + ma )
+ ret.setContains( d );
+ }
+ return ret;
+}
+
+const Coordinate VectorImp::getPoint( double param, const KigDocument& ) const
+{
+ return mdata.a + mdata.dir() * param;
+}
+
+double VectorImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ Coordinate pt = calcPointOnPerpend( mdata, p );
+ pt = calcIntersectionPoint( mdata, LineData( p, pt ) );
+ // if pt is over the end of the vector we set it to one of the end
+ // points of the vector...
+ if ( ( pt - mdata.a ).length() > dir().length() )
+ pt = mdata.b;
+ else if ( ( pt - mdata.b ).length() > dir().length() )
+ pt = mdata.a;
+ if ( mdata.b == mdata.a ) return 0;
+ return ( ( pt - mdata.a ).length() ) / ( dir().length() );
+}
+
+bool VectorImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool VectorImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnSegment( p, mdata.a, mdata.b, threshold );
+}
+
+LineData VectorImp::data() const
+{
+ return mdata;
+}