moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kig / objects / polygon_type.cc
blobde29654c2475b070ddeaa305497f5df388e296ce
1 // Copyright (C) 2003 Maurizio Paolini <paolini@dmf.unicatt.it>
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 "polygon_type.h"
20 #include "bogus_imp.h"
21 #include "line_imp.h"
22 #include "point_imp.h"
23 #include "polygon_imp.h"
24 #include "object_calcer.h"
26 #include "../misc/common.h"
28 #include <klocale.h>
29 #include <cmath>
30 #include <vector>
33 * triangle by its vertices
36 static const char triangle_constructstatement[] = I18N_NOOP( "Construct a triangle with this vertex" );
37 static const char triangle_constructstatement2[] = I18N_NOOP( "Select a point to be a vertex of the new triangle..." );
39 static const struct ArgsParser::spec argsspecTriangleB3P[] =
41 { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
42 { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
43 { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true }
46 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TriangleB3PType )
48 TriangleB3PType::TriangleB3PType()
49 : ArgsParserObjectType( "TriangleB3P", argsspecTriangleB3P, 3 )
53 TriangleB3PType::~TriangleB3PType()
57 const TriangleB3PType* TriangleB3PType::instance()
59 static const TriangleB3PType s;
60 return &s;
63 ObjectImp* TriangleB3PType::calc( const Args& parents, const KigDocument& ) const
65 if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
66 std::vector<Coordinate> points;
68 Coordinate centerofmass3 = Coordinate( 0, 0 );
69 for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
71 Coordinate point = static_cast<const PointImp*>( *i )->coordinate();
72 centerofmass3 += point;
73 points.push_back( point );
75 return new PolygonImp( 3, points, centerofmass3/3 );
78 const ObjectImpType* TriangleB3PType::resultId() const
80 return PolygonImp::stype();
83 bool TriangleB3PType::canMove( const ObjectTypeCalcer& o ) const
85 return isFreelyTranslatable( o );
88 bool TriangleB3PType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
90 std::vector<ObjectCalcer*> parents = o.parents();
91 return parents[0]->isFreelyTranslatable() &&
92 parents[1]->isFreelyTranslatable() &&
93 parents[2]->isFreelyTranslatable();
96 void TriangleB3PType::move( ObjectTypeCalcer& o, const Coordinate& to,
97 const KigDocument& d ) const
99 std::vector<ObjectCalcer*> parents = o.parents();
100 assert( margsparser.checkArgs( parents ) );
101 const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
102 const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
103 const Coordinate c = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
104 if ( parents[0]->canMove() )
105 parents[0]->move( to, d );
106 if ( parents[1]->canMove() )
107 parents[1]->move( to + b - a, d );
108 if ( parents[2]->canMove() )
109 parents[2]->move( to + c - a, d );
112 const Coordinate TriangleB3PType::moveReferencePoint( const ObjectTypeCalcer& o ) const
114 std::vector<ObjectCalcer*> parents = o.parents();
115 assert( margsparser.checkArgs( parents ) );
116 return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
119 std::vector<ObjectCalcer*> TriangleB3PType::movableParents( const ObjectTypeCalcer& ourobj ) const
121 std::vector<ObjectCalcer*> parents = ourobj.parents();
122 std::set<ObjectCalcer*> ret;
123 std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
124 ret.insert( tmp.begin(), tmp.end() );
125 tmp = parents[1]->movableParents();
126 ret.insert( tmp.begin(), tmp.end() );
127 tmp = parents[2]->movableParents();
128 ret.insert( tmp.begin(), tmp.end() );
129 ret.insert( parents.begin(), parents.end() );
130 return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
134 * generic polygon
137 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBNPType )
139 PolygonBNPType::PolygonBNPType()
140 : ObjectType( "PolygonBNP" )
144 PolygonBNPType::~PolygonBNPType()
148 const PolygonBNPType* PolygonBNPType::instance()
150 static const PolygonBNPType s;
151 return &s;
154 ObjectImp* PolygonBNPType::calc( const Args& parents, const KigDocument& ) const
156 uint count = parents.size();
157 assert (count >= 3); /* non sono ammessi poligoni con meno di tre lati */
158 // if ( parents[0] != parents[count] ) return new InvalidImp;
159 std::vector<Coordinate> points;
161 uint npoints = 0;
162 Coordinate centerofmassn = Coordinate( 0, 0 );
164 for ( uint i = 0; i < count; ++i )
166 npoints++;
167 Coordinate point = static_cast<const PointImp*>( parents[i] )->coordinate();
168 centerofmassn += point;
169 points.push_back( point );
171 return new PolygonImp( npoints, points, centerofmassn/npoints );
174 const ObjectImpType* PolygonBNPType::resultId() const
176 return PolygonImp::stype();
179 const ObjectImpType* PolygonBNPType::impRequirement( const ObjectImp*, const Args& ) const
181 return PointImp::stype();
184 bool PolygonBNPType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
186 return false; /* should be true? */
189 std::vector<ObjectCalcer*> PolygonBNPType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
191 return args; /* should already be in correct order */
194 Args PolygonBNPType::sortArgs( const Args& args ) const
196 return args;
199 bool PolygonBNPType::canMove( const ObjectTypeCalcer& o ) const
201 return isFreelyTranslatable( o );
204 bool PolygonBNPType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
206 std::vector<ObjectCalcer*> parents = o.parents();
207 for ( uint i = 0; i < parents.size(); ++i )
209 if ( !parents[i]->isFreelyTranslatable() ) return false;
211 return true;
214 void PolygonBNPType::move( ObjectTypeCalcer& o, const Coordinate& to,
215 const KigDocument& d ) const
217 std::vector<ObjectCalcer*> parents = o.parents();
218 const Coordinate ref = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
219 for ( uint i = 0; i < parents.size(); ++i )
221 const Coordinate a = static_cast<const PointImp*>( parents[i]->imp() )->coordinate();
222 parents[i]->move( to + a - ref, d );
226 const Coordinate PolygonBNPType::moveReferencePoint( const ObjectTypeCalcer& o
227 ) const
229 std::vector<ObjectCalcer*> parents = o.parents();
230 return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
233 std::vector<ObjectCalcer*> PolygonBNPType::movableParents( const ObjectTypeCalcer& ourobj ) const
235 std::vector<ObjectCalcer*> parents = ourobj.parents();
236 std::set<ObjectCalcer*> ret;
237 for ( uint i = 0; i < parents.size(); ++i )
239 std::vector<ObjectCalcer*> tmp = parents[i]->movableParents();
240 ret.insert( tmp.begin(), tmp.end() );
242 ret.insert( parents.begin(), parents.end() );
243 return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
247 * regular polygon by center and vertex
250 //static const char constructpoligonthroughpointstat[] = I18N_NOOP( "Construct a polygon with this vertex" );
252 //static const char constructpoligonwithcenterstat[] = I18N_NOOP( "Construct a polygon with this center" );
254 //static const ArgsParser::spec argsspecPoligonBCV[] =
256 // { PointImp::stype(), constructpoligonwithcenterstat,
257 // I18N_NOOP( "Select the center of the new polygon..." ), false },
258 // { PointImp::stype(), constructpoligonthroughpointstat,
259 // I18N_NOOP( "Select a vertex for the new polygon..." ), true },
260 // { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
261 //};
263 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBCVType )
265 PolygonBCVType::PolygonBCVType()
266 : ObjectType( "PoligonBCV" )
267 // we keep the name "PoligonBCV" although syntactically incorrect for
268 // compatibility reasons with old kig files
269 // : ArgsParserObjectType( "PoligonBCV", argsspecPoligonBCV, 3 )
273 PolygonBCVType::~PolygonBCVType()
277 const PolygonBCVType* PolygonBCVType::instance()
279 static const PolygonBCVType s;
280 return &s;
283 ObjectImp* PolygonBCVType::calc( const Args& parents, const KigDocument& ) const
285 if ( parents.size() < 3 || parents.size() > 4 ) return new InvalidImp;
286 for ( uint i = 0; i < 2; ++i )
288 if ( ! parents[0]->inherits( PointImp::stype() ) ) return new InvalidImp;
291 if ( ! parents[2]->inherits( IntImp::stype() ) ) return new InvalidImp;
293 const Coordinate center =
294 static_cast<const PointImp*>( parents[0] )->coordinate();
295 const Coordinate vertex =
296 static_cast<const PointImp*>( parents[1] )->coordinate();
297 const int sides =
298 static_cast<const IntImp*>( parents[2] )->data();
299 int twist = 1;
300 if ( parents.size() == 4 )
302 if ( ! parents[3]->inherits( IntImp::stype() ) ) return new InvalidImp;
303 twist = static_cast<const IntImp*>( parents[3] )->data();
305 std::vector<Coordinate> vertexes;
307 double dx = vertex.x - center.x;
308 double dy = vertex.y - center.y;
310 for ( int i = 1; i <= sides; i++ )
312 double alfa = 2*twist*M_PI/sides;
313 double theta1 = alfa*i - alfa;
314 double ctheta1 = cos(theta1);
315 double stheta1 = sin(theta1);
317 Coordinate v1 = center + Coordinate( ctheta1*dx - stheta1*dy,
318 stheta1*dx + ctheta1*dy );
319 vertexes.push_back( v1 );
321 return new PolygonImp( uint (sides), vertexes, center );
324 const ObjectImpType* PolygonBCVType::resultId() const
326 return SegmentImp::stype();
329 const ObjectImpType* PolygonBCVType::impRequirement( const ObjectImp* obj, const Args& ) const
331 if ( obj->inherits( PointImp::stype() ) )
332 return PointImp::stype();
334 if ( obj->inherits( IntImp::stype() ) )
335 return IntImp::stype();
337 return 0;
340 bool PolygonBCVType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
342 return false; /* should be true? */
345 std::vector<ObjectCalcer*> PolygonBCVType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
347 return args; /* should already be in correct order */
350 Args PolygonBCVType::sortArgs( const Args& args ) const
352 return args;
355 bool PolygonBCVType::canMove( const ObjectTypeCalcer& o ) const
357 return isFreelyTranslatable( o );
360 bool PolygonBCVType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
362 std::vector<ObjectCalcer*> parents = o.parents();
363 return parents[0]->isFreelyTranslatable() &&
364 parents[1]->isFreelyTranslatable();
367 void PolygonBCVType::move( ObjectTypeCalcer& o, const Coordinate& to,
368 const KigDocument& d ) const
370 std::vector<ObjectCalcer*> parents = o.parents();
371 // assert( margsparser.checkArgs( parents ) );
372 if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ||
373 ! parents[1]->imp()->inherits( PointImp::stype() ) ) return;
375 const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
376 const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
377 parents[0]->move( to, d );
378 parents[1]->move( to + b - a, d );
381 const Coordinate PolygonBCVType::moveReferencePoint( const ObjectTypeCalcer& o) const
383 std::vector<ObjectCalcer*> parents = o.parents();
384 // assert( margsparser.checkArgs( parents ) );
385 if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ) return Coordinate::invalidCoord();
387 return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
390 std::vector<ObjectCalcer*> PolygonBCVType::movableParents( const ObjectTypeCalcer& ourobj ) const
392 std::vector<ObjectCalcer*> parents = ourobj.parents();
393 std::set<ObjectCalcer*> ret;
394 std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
395 ret.insert( tmp.begin(), tmp.end() );
396 tmp = parents[1]->movableParents();
397 ret.insert( tmp.begin(), tmp.end() );
398 ret.insert( &parents[0], &parents[1] );
399 return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
402 /* polygon-line intersection */
404 static const ArgsParser::spec argsspecPolygonLineIntersection[] =
406 { PolygonImp::stype(), I18N_NOOP( "Intersect this polygon with a line" ),
407 I18N_NOOP( "Select the polygon of which you want the intersection with a line..." ), false },
408 { AbstractLineImp::stype(), "Intersect this line with a polygon", "Select the line of which you want the intersection with a polygon...", false }
411 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonLineIntersectionType )
413 PolygonLineIntersectionType::PolygonLineIntersectionType()
414 : ArgsParserObjectType( "PolygonLineIntersection", argsspecPolygonLineIntersection, 2 )
418 PolygonLineIntersectionType::~PolygonLineIntersectionType()
422 const PolygonLineIntersectionType* PolygonLineIntersectionType::instance()
424 static const PolygonLineIntersectionType t;
425 return &t;
429 * Intersection of a polygon and a line/ray/segment.
431 * geometrically speaking the result is always a collection of
432 * collinear nonintersecting open segments (at most one if the
433 * polygon is convex). Since we don't know in advance how many
434 * segments will result, the obvious choice is to return an
435 * InvalidImp in cases when the result is *not* a single segment
437 * computing the two ends of this segment is more tricky then one
438 * expects especially when intersecting segments/rays.
440 * particularly "difficult" situations are those where we intersect
441 * a segment/ray with an/the endpoint coinciding with a vertex of
442 * the polygon, especially if that vertex is a "reentrant" (concave)
443 * vertex of the polygon.
446 ObjectImp* PolygonLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
448 if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
450 const PolygonImp* polygon = static_cast<const PolygonImp*>( parents[0] );
451 const std::vector<Coordinate> ppoints = polygon->points();
452 const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
453 Coordinate intersections[2];
454 uint whichintersection = 0;
456 bool boundleft = false;
457 bool boundright = false;
458 if ( parents[1]->inherits( SegmentImp::stype() ) )
460 boundleft = boundright = true;
462 if ( parents[1]->inherits( RayImp::stype() ) )
464 boundleft = true;
466 Coordinate a = line.a;
467 double abx = line.b.x - a.x;
468 double aby = line.b.y - a.y;
470 double leftendinside = false;
471 double rightendinside = false;
472 Coordinate prevpoint = ppoints.back() - a;
473 bool prevpointbelow = ( abx*prevpoint.y <= aby*prevpoint.x );
474 for ( uint i = 0; i < ppoints.size(); ++i )
476 Coordinate point = ppoints[i] - a;
477 bool pointbelow = ( abx*point.y <= aby*point.x );
478 if ( pointbelow != prevpointbelow )
480 /* found an intersection with the support line
481 * compute the value of the parameter...
483 double dcx = point.x - prevpoint.x;
484 double dcy = point.y - prevpoint.y;
485 double num = point.x*dcy - point.y*dcx;
486 double den = abx*dcy - aby*dcx;
487 if ( std::fabs( den ) <= 1.e-6*std::fabs( num ) ) continue; //parallel
488 double t = num/den;
489 if ( boundleft && t <= 0 )
491 leftendinside = !leftendinside;
493 else if ( boundright && t >= 1 )
495 rightendinside = !rightendinside;
497 else
499 if ( whichintersection >= 2 ) return new InvalidImp;
500 intersections[whichintersection++] = a + t*Coordinate( abx, aby );
503 prevpoint = point;
504 prevpointbelow = pointbelow;
507 if ( leftendinside )
509 if ( whichintersection >= 2 ) return new InvalidImp;
510 intersections[whichintersection++] = a;
513 if ( rightendinside )
515 if ( whichintersection >= 2 ) return new InvalidImp;
516 intersections[whichintersection++] = line.b;
519 switch (whichintersection)
521 case 1: /* just for completeness: this should never happen */
522 return new PointImp( intersections[0] );
523 break;
524 case 2:
525 return new SegmentImp( intersections[0], intersections[1] );
526 break;
527 case 0:
528 default:
529 return new InvalidImp;
530 break;
534 const ObjectImpType* PolygonLineIntersectionType::resultId() const
536 return SegmentImp::stype();
539 /* polygon vertices */
541 static const ArgsParser::spec argsspecPolygonVertex[] =
543 { PolygonImp::stype(), I18N_NOOP( "Construct the vertices of this polygon" ),
544 I18N_NOOP( "Select the polygon of which you want to construct the vertices..." ), true },
545 { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
548 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonVertexType )
550 PolygonVertexType::PolygonVertexType()
551 : ArgsParserObjectType( "PolygonVertex", argsspecPolygonVertex, 2 )
555 PolygonVertexType::~PolygonVertexType()
559 const PolygonVertexType* PolygonVertexType::instance()
561 static const PolygonVertexType t;
562 return &t;
565 ObjectImp* PolygonVertexType::calc( const Args& parents, const KigDocument& ) const
567 if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
569 const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
570 const uint i = static_cast<const IntImp*>( parents[1] )->data();
572 if ( i >= ppoints.size() ) return new InvalidImp;
574 return new PointImp( ppoints[i] );
577 const ObjectImpType* PolygonVertexType::resultId() const
579 return PointImp::stype();
582 /* polygon sides */
584 static const ArgsParser::spec argsspecPolygonSide[] =
586 { PolygonImp::stype(), I18N_NOOP( "Construct the sides of this polygon" ),
587 I18N_NOOP( "Select the polygon of which you want to construct the sides..." ), false },
588 { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
591 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonSideType )
593 PolygonSideType::PolygonSideType()
594 : ArgsParserObjectType( "PolygonSide", argsspecPolygonSide, 2 )
598 PolygonSideType::~PolygonSideType()
602 const PolygonSideType* PolygonSideType::instance()
604 static const PolygonSideType t;
605 return &t;
608 ObjectImp* PolygonSideType::calc( const Args& parents, const KigDocument& ) const
610 if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
612 const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
613 const uint i = static_cast<const IntImp*>( parents[1] )->data();
615 if ( i >= ppoints.size() ) return new InvalidImp;
617 uint nexti = i + 1;
618 if ( nexti >= ppoints.size() ) nexti = 0;
620 return new SegmentImp( ppoints[i], ppoints[nexti] );
623 const ObjectImpType* PolygonSideType::resultId() const
625 return SegmentImp::stype();
628 /* convex hull of a polygon */
630 static const ArgsParser::spec argsspecConvexHull[] =
632 { PolygonImp::stype(), I18N_NOOP( "Construct the convex hull of this polygon" ),
633 I18N_NOOP( "Select the polygon of which you want to construct the convex hull..." ), false }
636 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConvexHullType )
638 ConvexHullType::ConvexHullType()
639 : ArgsParserObjectType( "ConvexHull", argsspecConvexHull, 1 )
643 ConvexHullType::~ConvexHullType()
647 const ConvexHullType* ConvexHullType::instance()
649 static const ConvexHullType t;
650 return &t;
653 ObjectImp* ConvexHullType::calc( const Args& parents, const KigDocument& ) const
655 if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
657 const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
659 if ( ppoints.size() < 3 ) return new InvalidImp;
661 std::vector<Coordinate> hull = computeConvexHull( ppoints );
662 if ( hull.size() < 3 ) return new InvalidImp;
663 return new PolygonImp( hull );
666 const ObjectImpType* ConvexHullType::resultId() const
668 return PolygonImp::stype();