moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / filters / kgeo-filter.cc
blob3bb2daabdd24cddae3f755441581db5e62d75721
1 /**
2 This file is part of Kig, a KDE program for Interactive Geometry...
3 Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 USA
19 **/
21 #include "kgeo-filter.h"
23 #include "kgeo-resource.h"
24 #include "filters-common.h"
26 #include "../kig/kig_part.h"
27 #include "../kig/kig_document.h"
28 #include "../objects/angle_type.h"
29 #include "../objects/bogus_imp.h"
30 #include "../objects/circle_imp.h"
31 #include "../objects/circle_type.h"
32 #include "../objects/intersection_types.h"
33 #include "../objects/line_type.h"
34 #include "../objects/object_calcer.h"
35 #include "../objects/object_drawer.h"
36 #include "../objects/object_factory.h"
37 #include "../objects/object_holder.h"
38 #include "../objects/other_type.h"
39 #include "../objects/point_imp.h"
40 #include "../objects/point_type.h"
41 #include "../objects/text_type.h"
42 #include "../objects/transform_types.h"
43 #include "../objects/vector_type.h"
45 #include <ksimpleconfig.h>
47 #include <algorithm>
48 #include <functional>
50 bool KigFilterKGeo::supportMime( const QString& mime )
52 return mime == "application/x-kgeo";
55 KigDocument* KigFilterKGeo::load( const QString& sFrom )
57 // kgeo uses a KSimpleConfig to save its contents...
58 KSimpleConfig config ( sFrom );
60 loadMetrics ( &config );
61 return loadObjects ( sFrom, &config );
64 void KigFilterKGeo::loadMetrics(KSimpleConfig* c )
66 c->setGroup("Main");
67 xMax = c->readNumEntry("XMax", 16);
68 yMax = c->readNumEntry("YMax", 11);
69 grid = c->readBoolEntry( "Grid", true );
70 axes = c->readBoolEntry( "Axes", true );
71 // the rest is not relevant to us (yet ?)...
74 struct KGeoHierarchyElement
76 int id;
77 std::vector<int> parents;
80 static void visitElem( std::vector<KGeoHierarchyElement>& ret,
81 const std::vector<KGeoHierarchyElement>& elems,
82 std::vector<bool>& seen,
83 int i )
85 if ( !seen[i] )
87 for ( uint j = 0; j < elems[i].parents.size(); ++j )
88 visitElem( ret, elems, seen, elems[i].parents[j] );
89 ret.push_back( elems[i] );
90 seen[i] = true;
94 static std::vector<KGeoHierarchyElement> sortElems( const std::vector<KGeoHierarchyElement> elems )
96 std::vector<KGeoHierarchyElement> ret;
97 std::vector<bool> seenElems( elems.size(), false );
98 for ( uint i = 0; i < elems.size(); ++i )
99 visitElem( ret, elems, seenElems, i );
100 return ret;
103 KigDocument* KigFilterKGeo::loadObjects( const QString& file, KSimpleConfig* c )
105 KigDocument* ret = new KigDocument();
107 using namespace std;
109 QString group;
110 bool ok = true;
111 c->setGroup("Main");
112 int number = c->readNumEntry ("Number");
114 // first we determine the parent relationships, and sort the
115 // elements in an order that we can be sure all of an object's
116 // parents will have been handled before it is handled itself..
117 // ( aka topological sort of the parent relations graph..
118 std::vector<KGeoHierarchyElement> elems;
119 elems.reserve( number );
121 for ( int i = 0; i < number; ++i )
123 KGeoHierarchyElement elem;
124 elem.id = i;
125 group.setNum( i + 1 );
126 group.prepend( "Object " );
127 c->setGroup( group );
128 QStrList parents;
129 c->readListEntry( "Parents", parents );
130 elems.push_back( elem );
131 for ( const char* parent = parents.first(); parent; parent = parents.next() )
133 int parentIndex = QString::fromLatin1( parent ).toInt( &ok );
134 if ( ! ok ) KIG_FILTER_PARSE_ERROR;
135 if ( parentIndex != 0 )
136 elems[i].parents.push_back( parentIndex - 1 );
140 std::vector<KGeoHierarchyElement> sortedElems = sortElems( elems );
141 std::vector<ObjectHolder*> os;
142 os.resize( number, 0 );
143 const ObjectFactory* factory = ObjectFactory::instance();
145 // now we iterate over the elems again in the newly determined
146 // order..
147 for ( uint i = 0; i < sortedElems.size(); ++i )
149 const KGeoHierarchyElement& e = sortedElems[i];
150 int id = e.id;
151 group.setNum( id + 1 );
152 group.prepend( "Object " );
153 c->setGroup( group );
154 int objID = c->readNumEntry( "Geo" );
156 std::vector<ObjectCalcer*> parents;
157 for ( uint j = 0; j < e.parents.size(); ++j )
159 int parentid = e.parents[j];
160 parents.push_back( os[parentid]->calcer() );
163 ObjectCalcer* o = 0;
164 switch (objID)
166 case ID_point:
168 // fetch the coordinates...
169 QString strX = c->readEntry("QPointX");
170 QString strY = c->readEntry("QPointY");
171 double x = strX.toDouble(&ok);
172 if (!ok) KIG_FILTER_PARSE_ERROR;
173 double y = strY.toDouble(&ok);
174 if (!ok) KIG_FILTER_PARSE_ERROR;
175 Coordinate m( x, y );
176 uint nparents = parents.size();
177 if ( nparents == 0 )
178 o = factory->fixedPointCalcer( m );
179 else if ( nparents == 1 )
180 o = factory->constrainedPointCalcer( parents[0], m, *ret );
181 else
182 KIG_FILTER_PARSE_ERROR;
183 break;
185 case ID_segment:
187 o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
188 break;
190 case ID_circle:
192 o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
193 break;
195 case ID_line:
197 o = new ObjectTypeCalcer( LineABType::instance(), parents );
198 break;
200 case ID_bisection:
202 // if this is the bisection of two points, first build a segment
203 // between them..
204 if ( parents.size() == 2 )
206 ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), parents );
207 parents.clear();
208 parents.push_back( seg );
210 if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
211 o = factory->propertyObjectCalcer( parents[0], "mid-point" );
212 break;
214 case ID_perpendicular:
216 o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
217 break;
219 case ID_parallel:
221 o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
222 break;
224 case ID_vector:
226 o = new ObjectTypeCalcer( VectorType::instance(), parents );
227 break;
229 case ID_ray:
231 o = new ObjectTypeCalcer( RayABType::instance(), parents );
232 break;
234 case ID_move:
236 o = new ObjectTypeCalcer( TranslatedType::instance(), parents );
237 break;
239 case ID_mirrorPoint:
241 o = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
242 break;
244 case ID_pointOfConc:
246 o = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents );
247 break;
249 case ID_text:
251 bool frame = c->readBoolEntry( "Frame" );
252 double x = c->readDoubleNumEntry( "TextRectCenterX" );
253 double y = c->readDoubleNumEntry( "TextRectCenterY" );
254 QString text = c->readEntry( "TextRectEntry" );
255 double height = c->readNumEntry( "TextRectHeight" );
256 double width = c->readNumEntry( "TextRectWidth" );
257 // we don't want the center, but the top left..
258 x -= width / 80;
259 y -= height / 80;
260 o = factory->labelCalcer(
261 text, Coordinate( x, y ), frame, std::vector<ObjectCalcer*>(), *ret );
262 break;
264 case ID_fixedCircle:
266 double r = c->readDoubleNumEntry( "Radius" );
267 parents.push_back( new ObjectConstCalcer( new DoubleImp( r ) ) );
268 o = new ObjectTypeCalcer( CircleBPRType::instance(), parents );
269 break;
271 case ID_angle:
273 if ( parents.size() == 3 )
275 ObjectTypeCalcer* ao = new ObjectTypeCalcer( AngleType::instance(), parents );
276 ao->calc( *ret );
277 parents.clear();
278 parents.push_back( ao );
280 if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
281 ObjectCalcer* angle = parents[0];
282 parents.clear();
283 const Coordinate c =
284 static_cast<const PointImp*>( angle->parents()[1]->imp() )->coordinate();
285 o = filtersConstructTextObject( c, angle, "angle-degrees", *ret, true );
286 break;
288 case ID_distance:
290 if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
291 ObjectTypeCalcer* segment = new ObjectTypeCalcer( SegmentABType::instance(), parents );
292 segment->calc( *ret );
293 Coordinate m = ( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
294 static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
295 o = filtersConstructTextObject( m, segment, "length", *ret, true );
296 break;
298 case ID_arc:
300 o = new ObjectTypeCalcer( AngleType::instance(), parents );
301 break;
303 case ID_area:
305 if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
306 const CircleImp* circle = static_cast<const CircleImp*>( parents[0]->imp() );
307 const Coordinate c = circle->center() + Coordinate( circle->radius(), 0 );
308 o = filtersConstructTextObject( c, parents[0], "surface", *ret, true );
309 break;
311 case ID_slope:
313 // if parents contains a segment, line, vector or whatever, we
314 // take its parents cause we want points..
315 if ( parents.size() == 1 ) parents = parents[0]->parents();
316 if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
317 const Coordinate c = (
318 static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
319 static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
320 ObjectTypeCalcer* line = new ObjectTypeCalcer( LineABType::instance(), parents );
321 line->calc( *ret );
322 o = filtersConstructTextObject( c, line, "slope", *ret, true );
323 break;
325 case ID_circumference:
327 if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
328 const CircleImp* c = static_cast<const CircleImp*>( parents[0]->imp() );
329 const Coordinate m = c->center() + Coordinate( c->radius(), 0 );
330 o = filtersConstructTextObject( m, parents[0], "circumference", *ret, true );
331 break;
333 case ID_rotation:
335 // in kig, the rotated object should be last..
336 ObjectCalcer* t = parents[2];
337 parents[2] = parents[0];
338 parents[0] = t;
339 o = new ObjectTypeCalcer( RotationType::instance(), parents );
340 break;
342 default:
343 KIG_FILTER_PARSE_ERROR;
346 // set the color...
347 QColor co = c->readColorEntry( "Color" );
348 if( !co.isValid() )
349 co = Qt::blue;
350 ObjectDrawer* d = new ObjectDrawer( co );
352 os[i] = new ObjectHolder( o, d );
353 os[i]->calc( *ret );
354 }; // for loop (creating KGeoHierarchyElements..
356 ret->addObjects( os );
357 ret->setGrid( grid );
358 ret->setAxes( axes );
359 return ret;
362 KigFilterKGeo::KigFilterKGeo()
366 KigFilterKGeo::~KigFilterKGeo()
370 KigFilterKGeo* KigFilterKGeo::instance()
372 static KigFilterKGeo f;
373 return &f;