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.
511 lines
16 KiB
511 lines
16 KiB
// Copyright (C) 2002 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 "object_imp_factory.h"
|
|
|
|
#include "object_imp.h"
|
|
#include "bogus_imp.h"
|
|
#include "circle_imp.h"
|
|
#include "conic_imp.h"
|
|
#include "cubic_imp.h"
|
|
#include "line_imp.h"
|
|
#include "locus_imp.h"
|
|
#include "other_imp.h"
|
|
#include "point_imp.h"
|
|
#include "text_imp.h"
|
|
|
|
#include "../misc/coordinate.h"
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
const ObjectImpFactory* ObjectImpFactory::instance()
|
|
{
|
|
static const ObjectImpFactory t;
|
|
return &t;
|
|
}
|
|
|
|
ObjectImpFactory::ObjectImpFactory()
|
|
{
|
|
}
|
|
|
|
ObjectImpFactory::~ObjectImpFactory()
|
|
{
|
|
}
|
|
|
|
static void addXYElements( const Coordinate& c, TQDomElement& tqparent, TQDomDocument& doc )
|
|
{
|
|
TQDomElement xe = doc.createElement( "x" );
|
|
xe.appendChild(
|
|
doc.createTextNode(
|
|
TQString::number( c.x ) ) );
|
|
tqparent.appendChild( xe );
|
|
TQDomElement ye = doc.createElement( "y" );
|
|
ye.appendChild(
|
|
doc.createTextNode(
|
|
TQString::number( c.y ) ) );
|
|
tqparent.appendChild( ye );
|
|
}
|
|
|
|
static void addDoubleElement( const char* name, double d, TQDomElement& tqparent, TQDomDocument& doc )
|
|
{
|
|
TQDomElement e = doc.createElement( name );
|
|
e.appendChild( doc.createTextNode( TQString::number( d ) ) );
|
|
tqparent.appendChild( e );
|
|
}
|
|
|
|
static void addCoordinateElement( const char* name, const Coordinate& d, TQDomElement& p, TQDomDocument& doc )
|
|
{
|
|
TQDomElement e = doc.createElement( name );
|
|
addXYElements( d, e, doc );
|
|
p.appendChild( e );
|
|
}
|
|
|
|
TQString ObjectImpFactory::serialize( const ObjectImp& d, TQDomElement& tqparent,
|
|
TQDomDocument& doc ) const
|
|
{
|
|
if( d.inherits( IntImp::stype() ) )
|
|
{
|
|
tqparent.appendChild(
|
|
doc.createTextNode(
|
|
TQString::number( static_cast<const IntImp&>( d ).data() ) ) );
|
|
return TQString::tqfromLatin1( "int" );
|
|
}
|
|
else if ( d.inherits( DoubleImp::stype() ) )
|
|
{
|
|
tqparent.appendChild(
|
|
doc.createTextNode(
|
|
TQString::number( static_cast<const DoubleImp&>( d ).data() ) ) );
|
|
return TQString::tqfromLatin1( "double" );
|
|
}
|
|
else if( d.inherits( StringImp::stype() ) )
|
|
{
|
|
tqparent.appendChild(
|
|
doc.createTextNode(
|
|
static_cast<const StringImp&>( d ).data() ) );
|
|
return TQString::tqfromLatin1( "string" );
|
|
}
|
|
else if ( d.inherits( TestResultImp::stype() ) )
|
|
{
|
|
tqparent.appendChild(
|
|
doc.createTextNode(
|
|
static_cast<const TestResultImp&>( d ).data() ) );
|
|
return TQString::tqfromLatin1( "testresult" );
|
|
}
|
|
else if( d.inherits( HierarchyImp::stype() ) )
|
|
{
|
|
static_cast<const HierarchyImp&>( d ).data().serialize( tqparent, doc );
|
|
return TQString::tqfromLatin1( "hierarchy" );
|
|
}
|
|
else if ( d.inherits( TransformationImp::stype() ) )
|
|
{
|
|
const Transformation& trans = static_cast<const TransformationImp&>( d ).data();
|
|
|
|
TQDomElement matrixe = doc.createElement( "matrix" );
|
|
for ( int i = 0; i < 3; ++i )
|
|
{
|
|
for ( int j = 0; j < 3; ++j )
|
|
{
|
|
TQDomElement elel = doc.createElement( "element" );
|
|
elel.setAttribute( "row", TQString::number( i ) );
|
|
elel.setAttribute( "column", TQString::number( j ) );
|
|
elel.appendChild( doc.createTextNode( TQString::number( trans.data( i, j ) ) ) );
|
|
matrixe.appendChild( elel );
|
|
};
|
|
}
|
|
tqparent.appendChild( matrixe );
|
|
|
|
TQDomElement homothetye = doc.createElement( "homothetic" );
|
|
const char* ishomothety = trans.isHomothetic() ? "true" : "false";
|
|
homothetye.appendChild( doc.createTextNode( ishomothety ) );
|
|
tqparent.appendChild( homothetye );
|
|
|
|
return TQString::tqfromLatin1( "transformation" );
|
|
}
|
|
else if( d.inherits( AbstractLineImp::stype() ) )
|
|
{
|
|
LineData l = static_cast<const AbstractLineImp&>( d ).data();
|
|
addCoordinateElement( "a", l.a, tqparent, doc );
|
|
addCoordinateElement( "b", l.b, tqparent, doc );
|
|
if( d.inherits( SegmentImp::stype() ) )
|
|
return TQString::tqfromLatin1( "segment" );
|
|
else if( d.inherits( RayImp::stype() ) )
|
|
return TQString::tqfromLatin1( "ray" );
|
|
else return TQString::tqfromLatin1( "line" );
|
|
}
|
|
else if( d.inherits( PointImp::stype() ) )
|
|
{
|
|
addXYElements( static_cast<const PointImp&>( d ).coordinate(),
|
|
tqparent, doc );
|
|
return TQString::tqfromLatin1( "point" );
|
|
}
|
|
else if( d.inherits( TextImp::stype() ) )
|
|
{
|
|
TQString text = static_cast<const TextImp&>( d ).text();
|
|
tqparent.appendChild(
|
|
doc.createTextNode( text ) );
|
|
return TQString::tqfromLatin1( "text" );
|
|
}
|
|
else if( d.inherits( AngleImp::stype() ) )
|
|
{
|
|
addDoubleElement( "size", static_cast<const AngleImp&>( d ).size(), tqparent, doc );
|
|
return TQString::tqfromLatin1( "angle" );
|
|
}
|
|
else if ( d.inherits( ArcImp::stype() ) )
|
|
{
|
|
const ArcImp& a = static_cast<const ArcImp&>( d );
|
|
addCoordinateElement( "center", a.center(), tqparent, doc );
|
|
addDoubleElement( "radius", a.radius(), tqparent, doc );
|
|
addDoubleElement( "startangle", a.startAngle(), tqparent, doc );
|
|
addDoubleElement( "angle", a.angle(), tqparent, doc );
|
|
return TQString::tqfromLatin1( "arc" );
|
|
}
|
|
else if( d.inherits( VectorImp::stype() ) )
|
|
{
|
|
Coordinate dir = static_cast<const VectorImp&>( d ).dir();
|
|
addXYElements( dir, tqparent, doc );
|
|
return TQString::tqfromLatin1( "vector" );
|
|
}
|
|
else if( d.inherits( LocusImp::stype() ) )
|
|
{
|
|
const LocusImp& locus = static_cast<const LocusImp&>( d );
|
|
|
|
// serialize the curve..
|
|
TQDomElement curve = doc.createElement( "curve" );
|
|
const CurveImp& curveimp = *locus.curve();
|
|
TQString type = serialize( curveimp, curve, doc );
|
|
curve.setAttribute( "type", type );
|
|
tqparent.appendChild( curve );
|
|
|
|
// serialize the hierarchy..
|
|
TQDomElement hier = doc.createElement( "calculation" );
|
|
locus.hierarchy().serialize( hier, doc );
|
|
tqparent.appendChild( hier );
|
|
|
|
return TQString::tqfromLatin1( "locus" );
|
|
}
|
|
else if( d.inherits( CircleImp::stype() ) )
|
|
{
|
|
const CircleImp& c = static_cast<const CircleImp&>( d );
|
|
addCoordinateElement( "center", c.center(), tqparent, doc );
|
|
addDoubleElement( "radius", c.radius(), tqparent, doc );
|
|
return TQString::tqfromLatin1( "circle" );
|
|
}
|
|
else if( d.inherits( ConicImp::stype() ) )
|
|
{
|
|
const ConicPolarData data = static_cast<const ConicImp&>( d ).polarData();
|
|
addCoordinateElement( "focus1", data.focus1, tqparent, doc );
|
|
addDoubleElement( "pdimen", data.pdimen, tqparent, doc );
|
|
addDoubleElement( "ecostheta0", data.ecostheta0, tqparent, doc );
|
|
addDoubleElement( "esintheta0", data.esintheta0, tqparent, doc );
|
|
return TQString::tqfromLatin1( "conic" );
|
|
}
|
|
else if( d.inherits( CubicImp::stype() ) )
|
|
{
|
|
const CubicCartesianData data = static_cast<const CubicImp&>( d ).data();
|
|
TQDomElement coeffs = doc.createElement( "coefficients" );
|
|
addDoubleElement( "a000", data.coeffs[0], coeffs, doc );
|
|
addDoubleElement( "a001", data.coeffs[1], coeffs, doc );
|
|
addDoubleElement( "a002", data.coeffs[2], coeffs, doc );
|
|
addDoubleElement( "a011", data.coeffs[3], coeffs, doc );
|
|
addDoubleElement( "a012", data.coeffs[4], coeffs, doc );
|
|
addDoubleElement( "a022", data.coeffs[5], coeffs, doc );
|
|
addDoubleElement( "a111", data.coeffs[6], coeffs, doc );
|
|
addDoubleElement( "a112", data.coeffs[7], coeffs, doc );
|
|
addDoubleElement( "a122", data.coeffs[8], coeffs, doc );
|
|
addDoubleElement( "a222", data.coeffs[9], coeffs, doc );
|
|
tqparent.appendChild( coeffs );
|
|
return TQString::tqfromLatin1( "cubic" );
|
|
}
|
|
assert( false );
|
|
return TQString();
|
|
}
|
|
|
|
static Coordinate readXYElements( const TQDomElement& e, bool& ok )
|
|
{
|
|
double x, y;
|
|
ok = true;
|
|
TQDomElement xe = e.firstChild().toElement();
|
|
if ( xe.isNull() || xe.tagName() != "x" )
|
|
{
|
|
ok = false;
|
|
return Coordinate();
|
|
}
|
|
else x = xe.text().toDouble( &ok );
|
|
|
|
TQDomElement ye = xe.nextSibling().toElement();
|
|
if ( ye.isNull() || ye.tagName() != "y" )
|
|
{
|
|
ok = false;
|
|
return Coordinate();
|
|
}
|
|
else y = ye.text().toDouble( &ok );
|
|
|
|
return Coordinate( x, y );
|
|
}
|
|
|
|
static Coordinate readCoordinateElement( TQDomNode n, bool& ok,
|
|
const char* tagname )
|
|
{
|
|
TQDomElement e = n.toElement();
|
|
if ( e.isNull() || e.tagName() != tagname )
|
|
{
|
|
ok = false;
|
|
Coordinate ret;
|
|
return ret;
|
|
}
|
|
return readXYElements( e, ok );
|
|
}
|
|
|
|
static double readDoubleElement( TQDomNode n, bool& ok,
|
|
const char* tagname )
|
|
{
|
|
TQDomElement e = n.toElement();
|
|
if ( e.isNull() || e.tagName() != tagname )
|
|
{
|
|
ok = false;
|
|
return 0.;
|
|
};
|
|
return e.text().toDouble( &ok );
|
|
}
|
|
|
|
ObjectImp* ObjectImpFactory::deserialize( const TQString& type,
|
|
const TQDomElement& tqparent,
|
|
TQString& error ) const
|
|
{
|
|
#define KIG_GENERIC_PARSE_ERROR \
|
|
{ \
|
|
error = i18n( "An error was encountered at line %1 in file %2." ) \
|
|
.tqarg( __LINE__ ).tqarg( __FILE__ ); \
|
|
return 0; \
|
|
}
|
|
|
|
bool ok = true;
|
|
if ( type == "int" )
|
|
{
|
|
int ret = tqparent.text().toInt( &ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new IntImp( ret );
|
|
}
|
|
else if ( type == "double" )
|
|
{
|
|
double ret = tqparent.text().toDouble( &ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new DoubleImp( ret );
|
|
}
|
|
else if ( type == "string" )
|
|
{
|
|
return new StringImp( tqparent.text() );
|
|
}
|
|
else if ( type == "testresult" )
|
|
{
|
|
return new TestResultImp( tqparent.text() );
|
|
}
|
|
else if ( type == "hierarchy" )
|
|
{
|
|
ObjectHierarchy* hier = ObjectHierarchy::buildSafeObjectHierarchy( tqparent, error );
|
|
if ( ! hier ) return 0;
|
|
HierarchyImp* imp = new HierarchyImp( *hier );
|
|
delete hier;
|
|
return imp;
|
|
}
|
|
else if ( type == "transformation" )
|
|
{
|
|
double data[3][3];
|
|
bool homothetic = false;
|
|
for ( TQDomElement childe = tqparent.firstChild().toElement();
|
|
! childe.isNull(); childe = childe.nextSibling().toElement() )
|
|
{
|
|
if ( childe.tagName() == "matrix" )
|
|
{
|
|
for ( TQDomElement elel = childe.firstChild().toElement();
|
|
! elel.isNull(); elel = elel.nextSibling().toElement() )
|
|
{
|
|
if ( elel.tagName() != "element" ) KIG_GENERIC_PARSE_ERROR;
|
|
bool ok = true;
|
|
int row = elel.attribute( "row" ).toInt( &ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
int column = elel.attribute( "column" ).toInt( &ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
data[row][column] = elel.text().toDouble( &ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
};
|
|
}
|
|
else if ( childe.tagName() == "homothetic" )
|
|
{
|
|
homothetic = childe.text() == "true";
|
|
}
|
|
else continue;
|
|
};
|
|
Transformation trans( data, homothetic );
|
|
return new TransformationImp( trans );
|
|
}
|
|
else if ( type == "point" )
|
|
{
|
|
Coordinate ret = readXYElements( tqparent, ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new PointImp( ret );
|
|
}
|
|
else if ( type == "line" || type == "segment" || type == "ray" )
|
|
{
|
|
TQDomNode n = tqparent.firstChild();
|
|
Coordinate a = readCoordinateElement( n, ok, "a" );
|
|
if ( !ok ) KIG_GENERIC_PARSE_ERROR;
|
|
n = n.nextSibling();
|
|
Coordinate b = readCoordinateElement( n, ok, "b" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
if ( type == "line" ) return new LineImp( a, b );
|
|
else if ( type == "segment" ) return new SegmentImp( a, b );
|
|
else return new RayImp( a, b );
|
|
}
|
|
else if( type == "angle" )
|
|
{
|
|
double size = readDoubleElement( tqparent.firstChild(), ok, "size" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new AngleImp( Coordinate(), 0, size );
|
|
}
|
|
else if ( type == "arc" )
|
|
{
|
|
TQDomNode n = tqparent.firstChild();
|
|
Coordinate center = readCoordinateElement( n, ok, "center" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
n = n.nextSibling();
|
|
double radius = readDoubleElement( n, ok, "radius" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
n = n.nextSibling();
|
|
double startangle = readDoubleElement( n, ok, "startangle" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
n = n.nextSibling();
|
|
double angle = readDoubleElement( n, ok, "angle" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new ArcImp( center, radius, startangle, angle );
|
|
}
|
|
else if( type == "vector" )
|
|
{
|
|
Coordinate dir = readXYElements( tqparent, ok );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
return new VectorImp( Coordinate(), dir );
|
|
}
|
|
else if( type == "locus" )
|
|
{
|
|
TQDomElement curvee = tqparent.firstChild().toElement();
|
|
if ( curvee.isNull() || curvee.tagName() != "curve" ) KIG_GENERIC_PARSE_ERROR;
|
|
TQString type = curvee.attribute( "type" );
|
|
ObjectImp* oi = deserialize( type, curvee, error );
|
|
if ( ! oi || ! oi->inherits( CurveImp::stype() ) ) KIG_GENERIC_PARSE_ERROR;
|
|
//CurveImp* curvei = static_cast<CurveImp*>( oi );
|
|
|
|
TQDomElement hiere = curvee.nextSibling().toElement();
|
|
if ( hiere.isNull() || hiere.tagName() != "calculation" ) KIG_GENERIC_PARSE_ERROR;
|
|
assert( false ); // TODO
|
|
// return new LocusImp( curvei, hier );
|
|
}
|
|
else if( type == "circle" )
|
|
{
|
|
TQDomNode n = tqparent.firstChild();
|
|
Coordinate center = readCoordinateElement( n, ok, "center" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double radius = readDoubleElement( n, ok, "radius" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
return new CircleImp( center, radius );
|
|
}
|
|
else if( type == "conic" )
|
|
{
|
|
TQDomNode n = tqparent.firstChild();
|
|
Coordinate focus1 = readCoordinateElement( n, ok, "focus1" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double pdimen = readDoubleElement( n, ok, "pdimen" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double ecostheta0 = readDoubleElement( n, ok, "ecostheta0" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double esintheta0 = readDoubleElement( n, ok, "esintheta0" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
return new ConicImpPolar(
|
|
ConicPolarData( focus1, pdimen, ecostheta0, esintheta0 ) );
|
|
}
|
|
else if( type == "cubic" )
|
|
{
|
|
TQDomElement coeffse = tqparent.firstChild().toElement();
|
|
if ( coeffse.isNull() || coeffse.tagName() != "coefficients" )
|
|
KIG_GENERIC_PARSE_ERROR;
|
|
|
|
TQDomNode n = coeffse.firstChild();
|
|
double a000 = readDoubleElement( n, ok, "a000" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a001 = readDoubleElement( n, ok, "a001" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a002 = readDoubleElement( n, ok, "a002" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a011 = readDoubleElement( n, ok, "a011" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a012 = readDoubleElement( n, ok, "a012" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a022 = readDoubleElement( n, ok, "a022" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a111 = readDoubleElement( n, ok, "a111" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a112 = readDoubleElement( n, ok, "a112" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a122 = readDoubleElement( n, ok, "a112" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
n = n.nextSibling();
|
|
double a222 = readDoubleElement( n, ok, "a222" );
|
|
if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
|
|
|
|
return new CubicImp( CubicCartesianData( a000, a001, a002,
|
|
a011, a012, a022,
|
|
a111, a112, a122,
|
|
a222 ) );
|
|
}
|
|
|
|
error = i18n( "This Kig file uses an object of type \"%1\", "
|
|
"which this Kig version does not support."
|
|
"Perhaps you have compiled Kig without support "
|
|
"for this object type,"
|
|
"or perhaps you are using an older Kig version." ).tqarg( type );
|
|
return 0;
|
|
}
|
|
|