You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
7.5 KiB
286 lines
7.5 KiB
// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
|
|
|
|
// 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 "tangent_type.h"
|
|
|
|
#include "bogus_imp.h"
|
|
#include "conic_imp.h"
|
|
#include "cubic_imp.h"
|
|
#include "curve_imp.h"
|
|
#include "other_imp.h"
|
|
#include "point_imp.h"
|
|
#include "line_imp.h"
|
|
|
|
#include "../misc/common.h"
|
|
#include "../misc/conic-common.h"
|
|
//#include "../misc/calcpaths.h"
|
|
#include "../kig/kig_part.h"
|
|
#include "../kig/kig_view.h"
|
|
|
|
static const char constructlinetangentpoint[] = "SHOULDNOTBESEEN";
|
|
static const char selecttangent1[] =
|
|
I18N_NOOP( "Select the curve..." );
|
|
static const char selecttangent2[] =
|
|
I18N_NOOP( "Select the point for the tangent to go through..." );
|
|
|
|
static const ArgsParser::spec argsspecTangentConic[] =
|
|
{
|
|
{ ConicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
|
|
{ PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
|
|
};
|
|
|
|
KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentConicType )
|
|
|
|
TangentConicType::TangentConicType()
|
|
: ArgsParserObjectType( "TangentConic", argsspecTangentConic, 2 )
|
|
{
|
|
}
|
|
|
|
TangentConicType::~TangentConicType()
|
|
{
|
|
}
|
|
|
|
const TangentConicType* TangentConicType::instance()
|
|
{
|
|
static const TangentConicType t;
|
|
return &t;
|
|
}
|
|
|
|
ObjectImp* TangentConicType::calc( const Args& args, const KigDocument& doc ) const
|
|
{
|
|
if ( !margsparser.checkArgs( args ) )
|
|
return new InvalidImp;
|
|
|
|
const ConicImp* c = static_cast<const ConicImp*>( args[0] );
|
|
const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
|
|
|
|
if ( !c->containsPoint( p, doc ) )
|
|
return new InvalidImp;
|
|
|
|
bool ok;
|
|
const LineData tangent = calcConicPolarLine( c->cartesianData(), p, ok );
|
|
|
|
if ( !ok )
|
|
return new InvalidImp;
|
|
|
|
return new LineImp( tangent );
|
|
}
|
|
|
|
const ObjectImpType* TangentConicType::resultId() const
|
|
{
|
|
return LineImp::stype();
|
|
}
|
|
|
|
/*** Arc starts here ***/
|
|
|
|
static const ArgsParser::spec argsspecTangentArc[] =
|
|
{
|
|
{ ArcImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
|
|
{ PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
|
|
};
|
|
|
|
KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentArcType )
|
|
|
|
TangentArcType::TangentArcType()
|
|
: ArgsParserObjectType( "TangentArc", argsspecTangentArc, 2 )
|
|
{
|
|
}
|
|
|
|
TangentArcType::~TangentArcType()
|
|
{
|
|
}
|
|
|
|
const TangentArcType* TangentArcType::instance()
|
|
{
|
|
static const TangentArcType t;
|
|
return &t;
|
|
}
|
|
|
|
ObjectImp* TangentArcType::calc( const Args& args, const KigDocument& doc ) const
|
|
{
|
|
if ( !margsparser.checkArgs( args ) )
|
|
return new InvalidImp;
|
|
|
|
const ArcImp* arc = static_cast<const ArcImp*>( args[0] );
|
|
const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
|
|
|
|
if ( !arc->containsPoint( p, doc ) )
|
|
return new InvalidImp;
|
|
|
|
Coordinate c = arc->center();
|
|
double sqr = arc->radius();
|
|
sqr *= sqr;
|
|
ConicCartesianData data( 1.0, 1.0, 0.0, -2*c.x, -2*c.y, c.x*c.x + c.y*c.y - sqr );
|
|
|
|
bool ok;
|
|
const LineData tangent = calcConicPolarLine( data, p, ok );
|
|
|
|
if ( !ok )
|
|
return new InvalidImp;
|
|
|
|
return new LineImp( tangent );
|
|
}
|
|
|
|
const ObjectImpType* TangentArcType::resultId() const
|
|
{
|
|
return LineImp::stype();
|
|
}
|
|
|
|
/**** Cubic starts here ****/
|
|
|
|
static const ArgsParser::spec argsspecTangentCubic[] =
|
|
{
|
|
{ CubicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
|
|
{ PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
|
|
};
|
|
|
|
KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCubicType )
|
|
|
|
TangentCubicType::TangentCubicType()
|
|
: ArgsParserObjectType( "TangentCubic", argsspecTangentCubic, 2 )
|
|
{
|
|
}
|
|
|
|
TangentCubicType::~TangentCubicType()
|
|
{
|
|
}
|
|
|
|
const TangentCubicType* TangentCubicType::instance()
|
|
{
|
|
static const TangentCubicType t;
|
|
return &t;
|
|
}
|
|
|
|
ObjectImp* TangentCubicType::calc( const Args& args, const KigDocument& doc ) const
|
|
{
|
|
if ( !margsparser.checkArgs( args ) )
|
|
return new InvalidImp;
|
|
|
|
const CubicImp* cubic = static_cast<const CubicImp*>( args[0] );
|
|
const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
|
|
|
|
if ( !cubic->containsPoint( p, doc ) )
|
|
return new InvalidImp;
|
|
|
|
double x = p.x;
|
|
double y = p.y;
|
|
CubicCartesianData data = cubic->data();
|
|
// double aconst = data.coeffs[0];
|
|
double ax = data.coeffs[1];
|
|
double ay = data.coeffs[2];
|
|
double axx = data.coeffs[3];
|
|
double axy = data.coeffs[4];
|
|
double ayy = data.coeffs[5];
|
|
double axxx = data.coeffs[6];
|
|
double axxy = data.coeffs[7];
|
|
double axyy = data.coeffs[8];
|
|
double ayyy = data.coeffs[9];
|
|
|
|
/* mp: the tangent vector (-gy,gx) is orthogonal to the gradient (gx,gy)
|
|
* which is easy to compute from the CartesianData
|
|
*
|
|
* note: same thing could be done for conics, which would be
|
|
* much more efficient...
|
|
*/
|
|
|
|
Coordinate tangvec = Coordinate (
|
|
- axxy*x*x - 2*axyy*x*y - 3*ayyy*y*y - axy*x - 2*ayy*y - ay,
|
|
3*axxx*x*x + 2*axxy*x*y + axyy*y*y + 2*axx*x + axy*y + ax
|
|
);
|
|
const LineData tangent = LineData( p, p + tangvec );
|
|
|
|
return new LineImp( tangent );
|
|
}
|
|
|
|
const ObjectImpType* TangentCubicType::resultId() const
|
|
{
|
|
return LineImp::stype();
|
|
}
|
|
|
|
/**** Curve (locus) starts here ****/
|
|
|
|
static const ArgsParser::spec argsspecTangentCurve[] =
|
|
{
|
|
{ CurveImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
|
|
{ PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
|
|
};
|
|
|
|
KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCurveType )
|
|
|
|
TangentCurveType::TangentCurveType()
|
|
: ArgsParserObjectType( "TangentCurve", argsspecTangentCurve, 2 )
|
|
{
|
|
}
|
|
|
|
TangentCurveType::~TangentCurveType()
|
|
{
|
|
}
|
|
|
|
const TangentCurveType* TangentCurveType::instance()
|
|
{
|
|
static const TangentCurveType t;
|
|
return &t;
|
|
}
|
|
|
|
ObjectImp* TangentCurveType::calc( const Args& args, const KigDocument& doc ) const
|
|
{
|
|
if ( !margsparser.checkArgs( args ) )
|
|
return new InvalidImp;
|
|
|
|
const CurveImp* curve = static_cast<const CurveImp*>( args[0] );
|
|
const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
|
|
if ( !curve->containsPoint( p, doc ) )
|
|
return new InvalidImp;
|
|
|
|
const double t = curve->getParam( p, doc );
|
|
const double tau0 = 1e-3;
|
|
const double sigma = 1e-5;
|
|
const int maxiter = 20;
|
|
|
|
double tau = tau0;
|
|
Coordinate tang, err;
|
|
double tplus = t + tau;
|
|
double tminus = t - tau;
|
|
if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
|
|
if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
|
|
Coordinate tangold = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
|
|
|
|
for (int i = 0; i < maxiter; i++)
|
|
{
|
|
tau = tau/2;
|
|
tplus = t + tau;
|
|
tminus = t - tau;
|
|
if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
|
|
if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
|
|
tang = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
|
|
err = (tangold - tang)/3;
|
|
if (err.length() < sigma)
|
|
{
|
|
tang = (4*tang - tangold)/3;
|
|
const LineData tangent = LineData( p, p + tang );
|
|
return new LineImp( tangent );
|
|
}
|
|
tangold = tang;
|
|
}
|
|
return new InvalidImp;
|
|
}
|
|
|
|
const ObjectImpType* TangentCurveType::resultId() const
|
|
{
|
|
return LineImp::stype();
|
|
}
|