moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / filters / kseg-filter.cc
blob165cd8baf5ed202841e0fa1e7bdf87cac9e0c0b8
1 // Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16 // 02111-1307, USA.
18 #include "kseg-filter.h"
20 #include "kseg-defs.h"
22 #include "../kig/kig_document.h"
23 #include "../kig/kig_part.h"
24 #include "../misc/coordinate.h"
25 #include "../objects/angle_type.h"
26 #include "../objects/arc_type.h"
27 #include "../objects/bogus_imp.h"
28 #include "../objects/circle_type.h"
29 #include "../objects/conic_imp.h"
30 #include "../objects/conic_types.h"
31 #include "../objects/intersection_types.h"
32 #include "../objects/line_imp.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_imp.h"
39 #include "../objects/other_type.h"
40 #include "../objects/point_imp.h"
41 #include "../objects/point_type.h"
42 #include "../objects/polygon_type.h"
43 #include "../objects/transform_types.h"
44 #include "../objects/vector_type.h"
46 #include <qfont.h>
47 #include <qpen.h>
48 #include <qbrush.h>
49 #include <qfile.h>
50 #include <qdatastream.h>
51 #include <qbuffer.h>
53 #include <klocale.h>
55 KigFilterKSeg::KigFilterKSeg()
59 KigFilterKSeg::~KigFilterKSeg()
63 bool KigFilterKSeg::supportMime( const QString& mime )
65 return mime == "application/x-kseg";
68 struct drawstyle
70 Q_INT8 pointstyle;
71 QFont font;
72 QPen pen;
73 QBrush brush;
76 static Coordinate readKSegCoordinate( QDataStream& stream )
78 // read the coord..
79 float inx, iny;
80 stream >> inx >> iny;
81 // KSeg uses a coordinate system, where the topleft is (0,0), and
82 // the bottom right is the widget coordinate in the window: if the
83 // KSeg window had a width of 600 pixels and a height of 600, then
84 // the bottom right will be at (600,600). We assume a window of
85 // such a height here, and transform it into Kig Coordinates. This
86 // function is quite similar to ScreenInfo::fromScreen, and it's
87 // basically a simple modification of that code to floats..
89 // invert the y-axis: 0 is at the bottom !
90 Coordinate t( inx, 600 - iny );
91 t *= 14;
92 t /= 600;
93 return t + Coordinate( -7, -7 );
96 static ObjectTypeCalcer* intersectionPoint( const std::vector<ObjectCalcer*>& parents, int which )
98 if ( parents.size() != 2 ) return 0;
99 int nlines = 0;
100 int nconics = 0;
101 int narcs = 0;
102 for ( int i = 0; i < 2; ++i )
104 if ( parents[i]->imp()->inherits( AbstractLineImp::stype() ) ) ++nlines;
105 else if ( parents[i]->imp()->inherits( ConicImp::stype() ) ) ++nconics;
106 else if ( parents[i]->imp()->inherits( ArcImp::stype() ) ) ++narcs;
107 else return 0;
109 if ( nlines == 2 )
110 return which == -1 ? new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ) : 0;
111 else if ( nlines == 1 && nconics == 1 )
113 std::vector<ObjectCalcer*> intparents( parents );
114 intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
115 return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents );
117 else if ( nlines == 0 && nconics == 2 )
119 std::vector<ObjectCalcer*> rparents( parents );
120 rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
121 rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
122 rparents.push_back( new ObjectTypeCalcer( ConicRadicalType::instance(), rparents ) );
123 std::vector<ObjectCalcer*> iparents;
124 iparents.push_back( parents[0] );
125 iparents.push_back( rparents.back() );
126 iparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
127 return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), iparents );
129 else if ( nlines == 1 && narcs == 1 )
131 std::vector<ObjectCalcer*> intparents( parents );
132 intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
133 return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents );
135 else return 0;
138 ObjectCalcer* KigFilterKSeg::transformObject( const QString& file, KigDocument& kigdoc,
139 std::vector<ObjectCalcer*>& parents,
140 int subtype, bool& ok )
142 ok = true;
143 ObjectCalcer* retobj = 0;
144 switch( subtype )
146 case G_TRANSLATED:
148 std::vector<ObjectCalcer*> vectorparents( parents.begin() + 1, parents.end() );
149 ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents );
150 vector->calc( kigdoc );
152 std::vector<ObjectCalcer*> transparents;
153 transparents.push_back( parents[0] );
154 transparents.push_back( vector );
155 retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents );
156 break;
158 case G_ROTATED:
160 std::vector<ObjectCalcer*> angleparents( parents.begin() + 2, parents.end() );
161 ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents );
162 angle->calc( kigdoc );
164 std::vector<ObjectCalcer*> rotparents;
165 rotparents.push_back( parents[0] );
166 rotparents.push_back( parents[1] );
167 rotparents.push_back( angle );
168 retobj = new ObjectTypeCalcer( RotationType::instance(), rotparents );
169 break;
171 case G_SCALED:
173 if ( parents.size() == 4 )
175 retobj = new ObjectTypeCalcer( ScalingOverCenter2Type::instance(), parents );
177 else
179 // TODO
180 notSupported( file, i18n( "This KSeg document uses a scaling "
181 "transformation, which Kig currently "
182 "cannot import." ) );
183 ok = false;
184 return 0;
186 break;
188 case G_REFLECTED:
190 std::vector<ObjectCalcer*> mirparents( parents.begin(), parents.end() );
191 retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents );
192 break;
196 return retobj;
199 KigDocument* KigFilterKSeg::load( const QString& file )
201 QFile ffile( file );
202 if ( ! ffile.open( IO_ReadOnly ) )
204 fileNotFound( file );
205 return false;
208 KigDocument* retdoc = new KigDocument();
210 QDataStream fstream( &ffile );
212 QString versionstring;
213 fstream >> versionstring;
214 if ( !versionstring.startsWith( "KSeg Document Version " ) )
215 KIG_FILTER_PARSE_ERROR;
217 QByteArray array;
218 fstream >> array;
219 QBuffer buf( array );
220 buf.open( IO_ReadOnly );
221 QDataStream stream( &buf );
223 stream.setVersion( 3 );
225 // G_drawstyles:
226 short numstyles;
227 stream >> numstyles;
228 std::vector<drawstyle> drawstyles( numstyles );
229 for ( short i = 0; i < numstyles; ++i )
231 stream >> drawstyles[i].pointstyle;
232 stream >> drawstyles[i].font;
233 stream >> drawstyles[i].pen;
234 stream >> drawstyles[i].brush;
237 std::vector<ObjectHolder*> ret;
238 std::vector<ObjectHolder*> ret2;
240 // G_refs
241 unsigned int count;
242 stream >> count;
244 ret.resize( count, 0 );
245 const ObjectFactory* fact = ObjectFactory::instance();
247 // KSeg topologically sorts the objects before saving, that means we
248 // can read the entire file in one iteration..
249 for ( uint i = 0; i < count; ++i )
251 short styleid;
252 stream >> styleid;
253 short nparents;
254 stream >> nparents;
255 std::vector<ObjectCalcer*> parents( nparents, 0 );
256 for ( short j = 0; j < nparents; ++j )
258 int parent;
259 stream >> parent;
260 parents[j] = ret[parent]->calcer();
263 // read the object..
264 short info;
265 stream >> info;
266 int type = 1 << (info & 31);
267 info >>= 5;
268 int descendtype = (info & 15);
269 info >>= 4;
270 bool visible = info & 1;
271 bool labelVisible = info & 2;
272 bool given = info & 4;
273 bool final = info & 8;
275 // avoid g++ warnings about unused vars..
276 // this doesn't really do anything..
277 (void) given;
278 (void) final;
280 drawstyle style = drawstyles[styleid];
282 if ( type == G_LOOP ) continue;
283 // read the label..
284 QString labeltext;
285 stream >> labeltext;
286 Coordinate relcoord = readKSegCoordinate( stream );
287 // shut up gcc
288 (void) relcoord;
289 if ( type & G_CURVE )
291 Coordinate relcurvecoord = readKSegCoordinate( stream );
292 // shut up gcc
293 (void) relcurvecoord;
296 // now load the object data..
297 ObjectHolder* object = 0;
298 ObjectCalcer* o = 0;
299 bool ok = true;
301 QColor color = style.pen.color();
302 int width = style.pen.width();
305 kdDebug() << "type: " << type << endl
306 << "descendtype: " << descendtype << endl
307 << "label: " << labeltext << endl;
308 //*/
310 switch ( type )
312 case G_POINT:
314 switch( descendtype )
316 case G_TRANSLATED:
317 case G_ROTATED:
318 case G_SCALED:
319 case G_REFLECTED:
321 o = transformObject( file, *retdoc, parents, descendtype, ok );
322 break;
324 case G_FREE_POINT:
326 // fixed point
327 if ( nparents != 0 ) KIG_FILTER_PARSE_ERROR;
328 Coordinate c = readKSegCoordinate( stream );
329 o = fact->fixedPointCalcer( c );
330 break;
332 case G_CONSTRAINED_POINT:
334 // constrained point
335 double p;
336 stream >> p;
337 if ( nparents != 1 ) KIG_FILTER_PARSE_ERROR;
338 ObjectCalcer* parent = parents[0];
339 assert( parent );
340 o = fact->constrainedPointCalcer( parent, p );
341 break;
343 case G_INTERSECTION_POINT:
345 // KSeg has somewhat weird intersection objects..
346 // for all objects G_INTERSECTION_POINT gets the
347 // first intersection of its parents, G_INTERSECTION2_POINT
348 // represents the second, if present.
349 o = intersectionPoint( parents, -1 );
350 if ( ! o ) KIG_FILTER_PARSE_ERROR;
351 break;
353 case G_INTERSECTION2_POINT:
355 o = intersectionPoint( parents, 1 );
356 if ( ! o ) KIG_FILTER_PARSE_ERROR;
357 break;
359 case G_MID_POINT:
361 // midpoint of a segment..
362 if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
363 if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) )
364 KIG_FILTER_PARSE_ERROR;
365 int index = parents[0]->imp()->propertiesInternalNames().findIndex( "mid-point" );
366 assert( index != -1 );
367 o = new ObjectPropertyCalcer( parents[0], index );
368 break;
370 default:
371 KIG_FILTER_PARSE_ERROR;
373 width = style.pointstyle == SMALL_CIRCLE ? 2 : style.pointstyle == MEDIUM_CIRCLE ? 3 : 5;
374 color = style.brush.color();
375 break;
377 case G_SEGMENT:
379 switch( descendtype )
381 case G_TRANSLATED:
382 case G_ROTATED:
383 case G_SCALED:
384 case G_REFLECTED:
386 o = transformObject( file, *retdoc, parents, descendtype, ok );
387 break;
389 case G_ENDPOINTS_SEGMENT:
391 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
392 o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
393 break;
395 default:
396 KIG_FILTER_PARSE_ERROR;
398 break;
400 case G_RAY:
402 switch( descendtype )
404 case G_TRANSLATED:
405 case G_ROTATED:
406 case G_SCALED:
407 case G_REFLECTED:
409 o = transformObject( file, *retdoc, parents, descendtype, ok );
410 break;
412 case G_TWOPOINTS_RAY:
414 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
415 o = new ObjectTypeCalcer( RayABType::instance(), parents );
416 break;
418 case G_BISECTOR_RAY:
420 ObjectTypeCalcer* angle = new ObjectTypeCalcer( HalfAngleType::instance(), parents );
421 angle->calc( *retdoc );
422 o = fact->propertyObjectCalcer( angle, "angle-bisector" );
423 break;
425 default:
426 KIG_FILTER_PARSE_ERROR;
428 break;
430 case G_LINE:
432 switch( descendtype )
434 case G_TRANSLATED:
435 case G_ROTATED:
436 case G_SCALED:
437 case G_REFLECTED:
439 o = transformObject( file, *retdoc, parents, descendtype, ok );
440 break;
442 case G_TWOPOINTS_LINE:
444 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
445 o = new ObjectTypeCalcer( LineABType::instance(), parents );
446 break;
448 case G_PARALLEL_LINE:
450 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
451 o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
452 break;
454 case G_PERPENDICULAR_LINE:
456 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
457 o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
458 break;
460 default:
461 KIG_FILTER_PARSE_ERROR;
463 break;
465 case G_CIRCLE:
467 switch( descendtype )
469 case G_TRANSLATED:
470 case G_ROTATED:
471 case G_SCALED:
472 case G_REFLECTED:
474 o = transformObject( file, *retdoc, parents, descendtype, ok );
475 break;
477 case G_CENTERPOINT_CIRCLE:
479 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
480 o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
481 break;
483 case G_CENTERRADIUS_CIRCLE:
485 ObjectCalcer* point;
486 ObjectCalcer* segment;
487 if ( parents[0]->imp()->inherits( PointImp::stype() ) )
489 point = parents[0];
490 segment = parents[1];
492 else
494 point = parents[1];
495 segment = parents[0];
497 int index = segment->imp()->propertiesInternalNames().findIndex( "length" );
498 if ( index == -1 ) KIG_FILTER_PARSE_ERROR;
499 ObjectPropertyCalcer* length = new ObjectPropertyCalcer( segment, index );
500 length->calc( *retdoc );
501 std::vector<ObjectCalcer*> cparents;
502 cparents.push_back( point );
503 cparents.push_back( length );
504 o = new ObjectTypeCalcer( CircleBPRType::instance(), cparents );
505 break;
507 default:
508 KIG_FILTER_PARSE_ERROR;
510 break;
512 case G_ARC:
514 switch( descendtype )
516 case G_TRANSLATED:
517 case G_ROTATED:
518 case G_SCALED:
519 case G_REFLECTED:
521 o = transformObject( file, *retdoc, parents, descendtype, ok );
522 break;
524 case G_THREEPOINTS_ARC:
526 if ( nparents != 3 ) KIG_FILTER_PARSE_ERROR;
527 o = new ObjectTypeCalcer( ArcBTPType::instance(), parents );
528 break;
530 default:
531 KIG_FILTER_PARSE_ERROR;
533 break;
535 case G_POLYGON:
537 switch( descendtype )
539 case G_TRANSLATED:
540 case G_ROTATED:
541 case G_SCALED:
542 case G_REFLECTED:
544 o = transformObject( file, *retdoc, parents, descendtype, ok );
545 break;
547 default:
549 if ( nparents < 3 ) KIG_FILTER_PARSE_ERROR;
550 o = new ObjectTypeCalcer( PolygonBNPType::instance(), parents );
553 // default:
554 // KIG_FILTER_PARSE_ERROR;
555 break;
557 case G_CIRCLEINTERIOR:
559 notSupported( file, i18n( "This KSeg file contains a filled circle, "
560 "which Kig does not currently support." ) );
561 return false;
563 case G_ARCSECTOR:
565 notSupported( file, i18n( "This KSeg file contains an arc sector, "
566 "which Kig does not currently support." ) );
567 return false;
569 case G_ARCSEGMENT:
571 notSupported( file, i18n( "This KSeg file contains an arc segment, "
572 "which Kig does not currently support." ) );
573 return false;
575 case G_LOCUS:
577 switch( descendtype )
579 case G_TRANSLATED:
580 case G_ROTATED:
581 case G_SCALED:
582 case G_REFLECTED:
584 o = transformObject( file, *retdoc, parents, descendtype, ok );
585 break;
587 case G_OBJECT_LOCUS:
589 if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
590 o = fact->locusCalcer( parents[0], parents[1] );
591 break;
593 default:
594 KIG_FILTER_PARSE_ERROR;
596 break;
598 case G_MEASURE:
599 KIG_FILTER_PARSE_ERROR;
600 case G_CALCULATE:
601 KIG_FILTER_PARSE_ERROR;
602 case G_ANNOTATION:
603 KIG_FILTER_PARSE_ERROR;
604 case G_LOOP:
605 KIG_FILTER_PARSE_ERROR;
606 default:
607 KIG_FILTER_PARSE_ERROR;
611 // checking if the object was correctly created
612 if ( ! o )
614 if ( ok )
615 KIG_FILTER_PARSE_ERROR
616 else
617 return 0;
620 ObjectDrawer* d = new ObjectDrawer( color, width, visible, style.pen.style() );
621 if ( !labeltext.isEmpty() )
623 ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( labeltext ) );
624 object = new ObjectHolder( o, d, name );
626 else
628 object = new ObjectHolder( o, d );
631 assert( object );
632 ret[i] = object;
633 object->calc( *retdoc );
634 if ( !labeltext.isEmpty() && labelVisible )
636 std::vector<ObjectCalcer*> args2;
637 args2.push_back( object->nameCalcer() );
638 ObjectCalcer* oc2 = fact->attachedLabelCalcer(
639 QString::fromLatin1( "%1" ), object->calcer(),
640 static_cast<const PointImp*>( object->imp() )->coordinate(),
641 false, args2, *retdoc );
642 oc2->calc( *retdoc );
643 ObjectDrawer* d2 = new ObjectDrawer( style.pen.color() );
644 ObjectHolder* o2 = new ObjectHolder( oc2, d2 );
645 ret2.push_back( o2 );
649 // selection groups ( we ignore them, but we pretend to read them
650 // out anyway, so we can find what comes after them.. )
651 int selgroupcount;
652 stream >> selgroupcount;
653 for ( int i = 0; i < selgroupcount; ++i )
655 QString name;
656 stream >> name;
657 int size;
658 stream >> size;
659 for ( int i = 0; i < size; ++i )
661 short object;
662 stream >> object;
663 (void) object;
667 // no more data in the file..
668 retdoc->addObjects( ret );
669 retdoc->addObjects( ret2 );
670 retdoc->setAxes( false );
671 retdoc->setGrid( false );
672 return retdoc;
675 KigFilterKSeg* KigFilterKSeg::instance()
677 static KigFilterKSeg f;
678 return &f;