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
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"
50 #include <qdatastream.h>
55 KigFilterKSeg::KigFilterKSeg()
59 KigFilterKSeg::~KigFilterKSeg()
63 bool KigFilterKSeg::supportMime( const QString
& mime
)
65 return mime
== "application/x-kseg";
76 static Coordinate
readKSegCoordinate( QDataStream
& stream
)
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
);
93 return t
+ Coordinate( -7, -7 );
96 static ObjectTypeCalcer
* intersectionPoint( const std::vector
<ObjectCalcer
*>& parents
, int which
)
98 if ( parents
.size() != 2 ) return 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
;
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
);
138 ObjectCalcer
* KigFilterKSeg::transformObject( const QString
& file
, KigDocument
& kigdoc
,
139 std::vector
<ObjectCalcer
*>& parents
,
140 int subtype
, bool& ok
)
143 ObjectCalcer
* retobj
= 0;
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
);
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
);
173 if ( parents
.size() == 4 )
175 retobj
= new ObjectTypeCalcer( ScalingOverCenter2Type::instance(), parents
);
180 notSupported( file
, i18n( "This KSeg document uses a scaling "
181 "transformation, which Kig currently "
182 "cannot import." ) );
190 std::vector
<ObjectCalcer
*> mirparents( parents
.begin(), parents
.end() );
191 retobj
= new ObjectTypeCalcer( LineReflectionType::instance(), mirparents
);
199 KigDocument
* KigFilterKSeg::load( const QString
& file
)
202 if ( ! ffile
.open( IO_ReadOnly
) )
204 fileNotFound( file
);
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
;
219 QBuffer
buf( array
);
220 buf
.open( IO_ReadOnly
);
221 QDataStream
stream( &buf
);
223 stream
.setVersion( 3 );
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
;
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
)
255 std::vector
<ObjectCalcer
*> parents( nparents
, 0 );
256 for ( short j
= 0; j
< nparents
; ++j
)
260 parents
[j
] = ret
[parent
]->calcer();
266 int type
= 1 << (info
& 31);
268 int descendtype
= (info
& 15);
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..
280 drawstyle style
= drawstyles
[styleid
];
282 if ( type
== G_LOOP
) continue;
286 Coordinate relcoord
= readKSegCoordinate( stream
);
289 if ( type
& G_CURVE
)
291 Coordinate relcurvecoord
= readKSegCoordinate( stream
);
293 (void) relcurvecoord
;
296 // now load the object data..
297 ObjectHolder
* object
= 0;
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;
314 switch( descendtype
)
321 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
327 if ( nparents
!= 0 ) KIG_FILTER_PARSE_ERROR
;
328 Coordinate c
= readKSegCoordinate( stream
);
329 o
= fact
->fixedPointCalcer( c
);
332 case G_CONSTRAINED_POINT
:
337 if ( nparents
!= 1 ) KIG_FILTER_PARSE_ERROR
;
338 ObjectCalcer
* parent
= parents
[0];
340 o
= fact
->constrainedPointCalcer( parent
, p
);
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
;
353 case G_INTERSECTION2_POINT
:
355 o
= intersectionPoint( parents
, 1 );
356 if ( ! o
) KIG_FILTER_PARSE_ERROR
;
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
);
371 KIG_FILTER_PARSE_ERROR
;
373 width
= style
.pointstyle
== SMALL_CIRCLE
? 2 : style
.pointstyle
== MEDIUM_CIRCLE
? 3 : 5;
374 color
= style
.brush
.color();
379 switch( descendtype
)
386 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
389 case G_ENDPOINTS_SEGMENT
:
391 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
392 o
= new ObjectTypeCalcer( SegmentABType::instance(), parents
);
396 KIG_FILTER_PARSE_ERROR
;
402 switch( descendtype
)
409 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
412 case G_TWOPOINTS_RAY
:
414 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
415 o
= new ObjectTypeCalcer( RayABType::instance(), parents
);
420 ObjectTypeCalcer
* angle
= new ObjectTypeCalcer( HalfAngleType::instance(), parents
);
421 angle
->calc( *retdoc
);
422 o
= fact
->propertyObjectCalcer( angle
, "angle-bisector" );
426 KIG_FILTER_PARSE_ERROR
;
432 switch( descendtype
)
439 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
442 case G_TWOPOINTS_LINE
:
444 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
445 o
= new ObjectTypeCalcer( LineABType::instance(), parents
);
448 case G_PARALLEL_LINE
:
450 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
451 o
= new ObjectTypeCalcer( LineParallelLPType::instance(), parents
);
454 case G_PERPENDICULAR_LINE
:
456 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
457 o
= new ObjectTypeCalcer( LinePerpendLPType::instance(), parents
);
461 KIG_FILTER_PARSE_ERROR
;
467 switch( descendtype
)
474 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
477 case G_CENTERPOINT_CIRCLE
:
479 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
480 o
= new ObjectTypeCalcer( CircleBCPType::instance(), parents
);
483 case G_CENTERRADIUS_CIRCLE
:
486 ObjectCalcer
* segment
;
487 if ( parents
[0]->imp()->inherits( PointImp::stype() ) )
490 segment
= 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
);
508 KIG_FILTER_PARSE_ERROR
;
514 switch( descendtype
)
521 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
524 case G_THREEPOINTS_ARC
:
526 if ( nparents
!= 3 ) KIG_FILTER_PARSE_ERROR
;
527 o
= new ObjectTypeCalcer( ArcBTPType::instance(), parents
);
531 KIG_FILTER_PARSE_ERROR
;
537 switch( descendtype
)
544 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
549 if ( nparents
< 3 ) KIG_FILTER_PARSE_ERROR
;
550 o
= new ObjectTypeCalcer( PolygonBNPType::instance(), parents
);
554 // KIG_FILTER_PARSE_ERROR;
557 case G_CIRCLEINTERIOR
:
559 notSupported( file
, i18n( "This KSeg file contains a filled circle, "
560 "which Kig does not currently support." ) );
565 notSupported( file
, i18n( "This KSeg file contains an arc sector, "
566 "which Kig does not currently support." ) );
571 notSupported( file
, i18n( "This KSeg file contains an arc segment, "
572 "which Kig does not currently support." ) );
577 switch( descendtype
)
584 o
= transformObject( file
, *retdoc
, parents
, descendtype
, ok
);
589 if ( nparents
!= 2 ) KIG_FILTER_PARSE_ERROR
;
590 o
= fact
->locusCalcer( parents
[0], parents
[1] );
594 KIG_FILTER_PARSE_ERROR
;
599 KIG_FILTER_PARSE_ERROR
;
601 KIG_FILTER_PARSE_ERROR
;
603 KIG_FILTER_PARSE_ERROR
;
605 KIG_FILTER_PARSE_ERROR
;
607 KIG_FILTER_PARSE_ERROR
;
611 // checking if the object was correctly created
615 KIG_FILTER_PARSE_ERROR
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
);
628 object
= new ObjectHolder( o
, d
);
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.. )
652 stream
>> selgroupcount
;
653 for ( int i
= 0; i
< selgroupcount
; ++i
)
659 for ( int i
= 0; i
< size
; ++i
)
667 // no more data in the file..
668 retdoc
->addObjects( ret
);
669 retdoc
->addObjects( ret2
);
670 retdoc
->setAxes( false );
671 retdoc
->setGrid( false );
675 KigFilterKSeg
* KigFilterKSeg::instance()
677 static KigFilterKSeg f
;