|
|
|
// 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 "circle_imp.h"
|
|
|
|
|
|
|
|
#include "bogus_imp.h"
|
|
|
|
#include "point_imp.h"
|
|
|
|
|
|
|
|
#include "../misc/kigtransform.h"
|
|
|
|
#include "../misc/kigpainter.h"
|
|
|
|
#include "../misc/coordinate_system.h"
|
|
|
|
|
|
|
|
#include "../kig/kig_document.h"
|
|
|
|
#include "../kig/kig_view.h"
|
|
|
|
|
|
|
|
#include <tdelocale.h>
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
CircleImp::CircleImp( const Coordinate& center, double radius )
|
|
|
|
: mcenter( center ), mradius( radius )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CircleImp::~CircleImp()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectImp* CircleImp::transform( const Transformation& t ) const
|
|
|
|
{
|
|
|
|
if ( t.isHomothetic() )
|
|
|
|
{
|
|
|
|
Coordinate nc = t.apply( mcenter );
|
|
|
|
double nr = t.apply( mradius );
|
|
|
|
if ( nc.valid() )
|
|
|
|
return new CircleImp( nc, nr );
|
|
|
|
else return new InvalidImp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// domi: i should return a ConicImp here, but i don't know how to
|
|
|
|
// calculate it..
|
|
|
|
return Parent::transform( t );
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void CircleImp::draw( KigPainter& p ) const
|
|
|
|
{
|
|
|
|
p.drawCircle( mcenter, mradius );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CircleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
|
|
|
|
{
|
|
|
|
return fabs((mcenter - p).length() - mradius) <= w.screenInfo().normalMiss( width );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CircleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
|
|
|
|
{
|
|
|
|
// first we check if the rect contains at least one of the
|
|
|
|
// north/south/east/west points of the circle
|
|
|
|
if ( r.contains( mcenter + Coordinate( 0, -mradius ) ) ) return true;
|
|
|
|
if ( r.contains( mcenter + Coordinate( mradius, 0 ) ) ) return true;
|
|
|
|
if ( r.contains( mcenter + Coordinate( 0, mradius ) ) ) return true;
|
|
|
|
if ( r.contains( mcenter + Coordinate( -mradius, 0 ) ) ) return true;
|
|
|
|
|
|
|
|
// we allow a miss of some pixels ..
|
|
|
|
double miss = w.screenInfo().normalMiss( width );
|
|
|
|
double bigradius = mradius + miss;
|
|
|
|
bigradius *= bigradius;
|
|
|
|
double smallradius = mradius - miss;
|
|
|
|
smallradius *= smallradius;
|
|
|
|
|
|
|
|
const int in = -1;
|
|
|
|
const int undecided = 0;
|
|
|
|
const int out = 1;
|
|
|
|
|
|
|
|
int inorout = undecided;
|
|
|
|
|
|
|
|
Coordinate coords[4];
|
|
|
|
coords[0] = r.topLeft();
|
|
|
|
coords[1] = r.topRight();
|
|
|
|
coords[2] = r.bottomRight();
|
|
|
|
coords[3] = r.bottomLeft();
|
|
|
|
|
|
|
|
// we check if the corners of the rect are either
|
|
|
|
for ( Coordinate* i = coords; i < coords + 4; ++i )
|
|
|
|
{
|
|
|
|
double t = ( *i - mcenter ).squareLength();
|
|
|
|
if ( t >= bigradius )
|
|
|
|
{
|
|
|
|
if ( inorout == in ) return true;
|
|
|
|
inorout = out;
|
|
|
|
}
|
|
|
|
else if ( t <= smallradius )
|
|
|
|
{
|
|
|
|
if ( inorout == out ) return true;
|
|
|
|
inorout = in;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return inorout == undecided;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CircleImp::valid() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint CircleImp::numberOfProperties() const
|
|
|
|
{
|
|
|
|
// We _intentionally_ do not use the Conic properties..
|
|
|
|
return CurveImp::numberOfProperties() + 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QCStringList CircleImp::propertiesInternalNames() const
|
|
|
|
{
|
|
|
|
QCStringList l = CurveImp::propertiesInternalNames();
|
|
|
|
l << "surface";
|
|
|
|
l << "circumference";
|
|
|
|
l << "radius";
|
|
|
|
l << "center";
|
|
|
|
l << "cartesian-equation";
|
|
|
|
l << "simply-cartesian-equation";
|
|
|
|
l << "polar-equation";
|
|
|
|
assert( l.size() == CircleImp::numberOfProperties() );
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QCStringList CircleImp::properties() const
|
|
|
|
{
|
|
|
|
QCStringList l = CurveImp::properties();
|
|
|
|
l << I18N_NOOP( "Surface" );
|
|
|
|
l << I18N_NOOP( "Circumference" );
|
|
|
|
l << I18N_NOOP( "Radius" );
|
|
|
|
l << I18N_NOOP( "Center" );
|
|
|
|
l << I18N_NOOP( "Expanded Cartesian Equation" );
|
|
|
|
l << I18N_NOOP( "Cartesian Equation" );
|
|
|
|
l << I18N_NOOP( "Polar Equation" );
|
|
|
|
assert( l.size() == CircleImp::numberOfProperties() );
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectImpType* CircleImp::impRequirementForProperty( uint which ) const
|
|
|
|
{
|
|
|
|
if ( which < CurveImp::numberOfProperties() )
|
|
|
|
return CurveImp::impRequirementForProperty( which );
|
|
|
|
else return CircleImp::stype();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* CircleImp::iconForProperty( uint which ) const
|
|
|
|
{
|
|
|
|
assert( which < CircleImp::numberOfProperties() );
|
|
|
|
if ( which < CurveImp::numberOfProperties() )
|
|
|
|
return CurveImp::iconForProperty( which );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() )
|
|
|
|
return "areaCircle"; // surface
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 1 )
|
|
|
|
return "circumference"; // circumference
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 2 )
|
|
|
|
return ""; //radius
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 3 )
|
|
|
|
return "baseCircle"; // circle center
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 4 )
|
|
|
|
return "kig_text"; // cartesian equation
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 5 )
|
|
|
|
return "kig_text"; // simply cartesian equation
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 6 )
|
|
|
|
return "kig_text"; // polar equation
|
|
|
|
else assert( false );
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectImp* CircleImp::property( uint which, const KigDocument& w ) const
|
|
|
|
{
|
|
|
|
assert( which < CircleImp::numberOfProperties() );
|
|
|
|
if ( which < CurveImp::numberOfProperties() )
|
|
|
|
return CurveImp::property( which, w );
|
|
|
|
if ( which == CurveImp::numberOfProperties() )
|
|
|
|
return new DoubleImp( surface() );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 1 )
|
|
|
|
return new DoubleImp( circumference() );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 2 )
|
|
|
|
return new DoubleImp( radius() );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 3 )
|
|
|
|
return new PointImp( center() );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 4 )
|
|
|
|
return new StringImp( cartesianEquationString( w ) );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 5 )
|
|
|
|
return new StringImp( simplyCartesianEquationString( w ) );
|
|
|
|
else if ( which == CurveImp::numberOfProperties() + 6 )
|
|
|
|
return new StringImp( polarEquationString( w ) );
|
|
|
|
else assert( false );
|
|
|
|
return new InvalidImp;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Coordinate CircleImp::center() const
|
|
|
|
{
|
|
|
|
return mcenter;
|
|
|
|
}
|
|
|
|
|
|
|
|
double CircleImp::radius() const
|
|
|
|
{
|
|
|
|
return mradius;
|
|
|
|
}
|
|
|
|
|
|
|
|
double CircleImp::surface() const
|
|
|
|
{
|
|
|
|
return M_PI * squareRadius();
|
|
|
|
}
|
|
|
|
|
|
|
|
double CircleImp::squareRadius() const
|
|
|
|
{
|
|
|
|
return mradius * mradius;
|
|
|
|
}
|
|
|
|
|
|
|
|
double CircleImp::circumference() const
|
|
|
|
{
|
|
|
|
return 2 * M_PI * radius();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString CircleImp::polarEquationString( const KigDocument& w ) const
|
|
|
|
{
|
|
|
|
TQString ret = i18n( "rho = %1 [centered at %2]" );
|
|
|
|
ConicPolarData data = polarData();
|
|
|
|
ret = ret.arg( data.pdimen, 0, 'g', 3 );
|
|
|
|
ret = ret.arg( w.coordinateSystem().fromScreen( data.focus1, w ) );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString CircleImp::cartesianEquationString( const KigDocument& ) const
|
|
|
|
{
|
|
|
|
TQString ret = i18n( "x² + y² + %1 x + %2 y + %3 = 0" );
|
|
|
|
ConicCartesianData data = cartesianData();
|
|
|
|
ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
|
|
|
|
ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
|
|
|
|
ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString CircleImp::simplyCartesianEquationString( const KigDocument& ) const
|
|
|
|
{
|
|
|
|
TQString ret = i18n( "( x - %1 )² + ( y - %2 )² = %3" );
|
|
|
|
ret = ret.arg( mcenter.x, 0, 'g', 3 );
|
|
|
|
ret = ret.arg( mcenter.y, 0, 'g', 3 );
|
|
|
|
ret = ret.arg( mradius * mradius, 0, 'g', 3 );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Coordinate CircleImp::focus1() const
|
|
|
|
{
|
|
|
|
return center();
|
|
|
|
}
|
|
|
|
|
|
|
|
Coordinate CircleImp::focus2() const
|
|
|
|
{
|
|
|
|
return center();
|
|
|
|
}
|
|
|
|
|
|
|
|
int CircleImp::conicType() const
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ConicCartesianData CircleImp::cartesianData() const
|
|
|
|
{
|
|
|
|
Coordinate c = center();
|
|
|
|
double sqr = squareRadius();
|
|
|
|
ConicCartesianData data(
|
|
|
|
1.0, 1.0, 0.0, -2*c.x, -2*c.y,
|
|
|
|
c.x*c.x + c.y*c.y - sqr );
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ConicPolarData CircleImp::polarData() const
|
|
|
|
{
|
|
|
|
return ConicPolarData( center(), radius(), 0, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
CircleImp* CircleImp::copy() const
|
|
|
|
{
|
|
|
|
return new CircleImp( mcenter, mradius );
|
|
|
|
}
|
|
|
|
|
|
|
|
double CircleImp::getParam( const Coordinate& point, const KigDocument& ) const
|
|
|
|
{
|
|
|
|
Coordinate tmp = point - mcenter;
|
|
|
|
double ret = atan2(tmp.y, tmp.x) / ( 2 * M_PI );
|
|
|
|
if ( ret > 0 ) return ret;
|
|
|
|
else return ret + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Coordinate CircleImp::getPoint( double p, const KigDocument& ) const
|
|
|
|
{
|
|
|
|
return mcenter + Coordinate (cos(p * 2 * M_PI), sin(p * 2 * M_PI)) * mradius;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CircleImp::visit( ObjectImpVisitor* vtor ) const
|
|
|
|
{
|
|
|
|
vtor->visit( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CircleImp::equals( const ObjectImp& rhs ) const
|
|
|
|
{
|
|
|
|
return rhs.inherits( CircleImp::stype() ) &&
|
|
|
|
static_cast<const CircleImp&>( rhs ).center() == center() &&
|
|
|
|
static_cast<const CircleImp&>( rhs ).radius() == radius();
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectImpType* CircleImp::stype()
|
|
|
|
{
|
|
|
|
static const ObjectImpType t(
|
|
|
|
Parent::stype(), "circle",
|
|
|
|
I18N_NOOP( "circle" ),
|
|
|
|
I18N_NOOP( "Select this circle" ),
|
|
|
|
I18N_NOOP( "Select circle %1" ),
|
|
|
|
I18N_NOOP( "Remove a Circle" ),
|
|
|
|
I18N_NOOP( "Add a Circle" ),
|
|
|
|
I18N_NOOP( "Move a Circle" ),
|
|
|
|
I18N_NOOP( "Attach to this circle" ),
|
|
|
|
I18N_NOOP( "Show a Circle" ),
|
|
|
|
I18N_NOOP( "Hide a Circle" )
|
|
|
|
);
|
|
|
|
return &t;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectImpType* CircleImp::type() const
|
|
|
|
{
|
|
|
|
return CircleImp::stype();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CircleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
|
|
|
|
{
|
|
|
|
assert( which < CircleImp::numberOfProperties() );
|
|
|
|
if ( which < CurveImp::numberOfProperties() )
|
|
|
|
return CurveImp::isPropertyDefinedOnOrThroughThisImp( which );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Rect CircleImp::surroundingRect() const
|
|
|
|
{
|
|
|
|
Coordinate d( mradius, mradius );
|
|
|
|
return Rect( mcenter - d, mcenter + d );
|
|
|
|
}
|