1 // Copyright (C) 2005 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
18 #include "inversion_type.h"
19 #include "point_imp.h"
21 #include "circle_imp.h"
22 #include "bogus_imp.h"
24 #include "../misc/common.h"
28 static const char str1
[] = I18N_NOOP( "Invert with respect to this circle" );
29 static const char str2
[] = I18N_NOOP( "Select the circle we want to invert against..." );
31 static const ArgsParser::spec argsspecInvertPoint
[] =
33 { PointImp::stype(), I18N_NOOP( "Compute the inversion of this point" ),
34 I18N_NOOP( "Select the point to invert..." ), false },
35 { CircleImp::stype(), str1
, str2
, false }
38 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertPointType
)
40 InvertPointType::InvertPointType()
41 : ArgsParserObjectType( "InvertPoint", argsspecInvertPoint
, 2 )
45 InvertPointType::~InvertPointType()
49 const InvertPointType
* InvertPointType::instance()
51 static const InvertPointType s
;
55 const ObjectImpType
* InvertPointType::resultId() const
57 return PointImp::stype();
60 ObjectImp
* InvertPointType::calc( const Args
& args
, const KigDocument
& ) const
62 if ( ! margsparser
.checkArgs( args
) ) return new InvalidImp
;
64 const CircleImp
* c
= static_cast<const CircleImp
*>( args
[1] );
65 Coordinate center
= c
->center();
66 Coordinate relp
= static_cast<const PointImp
*>( args
[0] )->coordinate() - center
;
67 double radiussq
= c
->squareRadius();
68 double normsq
= relp
.x
*relp
.x
+ relp
.y
*relp
.y
;
69 if ( normsq
== 0 ) return new InvalidImp
;
70 return new PointImp( center
+ (radiussq
/normsq
)*relp
);
77 static const ArgsParser::spec argsspecInvertLine
[] =
79 { LineImp::stype(), I18N_NOOP( "Compute the inversion of this line" ),
80 I18N_NOOP( "Select the line to invert..." ), false },
81 { CircleImp::stype(), str1
, str2
, false }
84 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertLineType
)
86 InvertLineType::InvertLineType()
87 : ArgsParserObjectType( "InvertLine", argsspecInvertLine
, 2 )
91 InvertLineType::~InvertLineType()
95 const InvertLineType
* InvertLineType::instance()
97 static const InvertLineType s
;
101 const ObjectImpType
* InvertLineType::resultId() const
103 return CircleImp::stype();
106 ObjectImp
* InvertLineType::calc( const Args
& args
, const KigDocument
& ) const
108 if ( ! margsparser
.checkArgs( args
) ) return new InvalidImp
;
110 const CircleImp
* c
= static_cast<const CircleImp
*>( args
[1] );
111 Coordinate center
= c
->center();
112 double radiussq
= c
->squareRadius();
113 const LineData line
= static_cast<const AbstractLineImp
*>( args
[0] )->data();
114 Coordinate relb
= line
.b
- center
;
115 Coordinate ab
= line
.b
- line
.a
;
116 double t
= (relb
.x
*ab
.x
+ relb
.y
*ab
.y
)/(ab
.x
*ab
.x
+ ab
.y
*ab
.y
);
117 Coordinate relh
= relb
- t
*ab
;
118 double normhsq
= relh
.x
*relh
.x
+ relh
.y
*relh
.y
;
119 if ( normhsq
< 1e-12*radiussq
) return new LineImp( line
.a
, line
.b
);
120 Coordinate newcenter
= center
+ 0.5*radiussq
/normhsq
*relh
;
121 double newradius
= 0.5*radiussq
/sqrt(normhsq
);
123 return new CircleImp( newcenter
, newradius
);
127 * inversion of a circle
130 static const ArgsParser::spec argsspecInvertCircle
[] =
132 { CircleImp::stype(), I18N_NOOP( "Compute the inversion of this circle" ),
133 I18N_NOOP( "Select the circle to invert..." ), false },
134 { CircleImp::stype(), str1
, str2
, false }
137 KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertCircleType
)
139 InvertCircleType::InvertCircleType()
140 : ArgsParserObjectType( "InvertCircle", argsspecInvertCircle
, 2 )
144 InvertCircleType::~InvertCircleType()
148 const InvertCircleType
* InvertCircleType::instance()
150 static const InvertCircleType s
;
154 const ObjectImpType
* InvertCircleType::resultId() const
156 return CircleImp::stype();
159 ObjectImp
* InvertCircleType::calc( const Args
& args
, const KigDocument
& ) const
161 if ( ! margsparser
.checkArgs( args
) ) return new InvalidImp
;
163 const CircleImp
* refcircle
= static_cast<const CircleImp
*>( args
[1] );
164 Coordinate refc
= refcircle
->center();
165 double refrsq
= refcircle
->squareRadius();
166 const CircleImp
* circle
= static_cast<const CircleImp
*>( args
[0] );
167 Coordinate c
= circle
->center() - refc
;
168 double rsq
= circle
->squareRadius();
169 if ( c
.length() == 0.0 ) return new InvalidImp
;
170 double t
= sqrt( rsq
)/c
.length();
171 Coordinate b
= (1 + t
)*c
;
172 double bsq
= b
.x
*b
.x
+ b
.y
*b
.y
;
173 Coordinate bprime
= refrsq
*b
/bsq
;
174 if ( std::fabs( 1 - t
) < 1e-6 ) // circle through origin -> line
176 return new LineImp( bprime
+refc
, bprime
+refc
+Coordinate( -c
.y
, c
.x
) );
179 Coordinate a
= (1 - t
)*c
;
180 double asq
= a
.x
*a
.x
+ a
.y
*a
.y
;
181 Coordinate aprime
= refrsq
*a
/asq
;
183 Coordinate cprime
= 0.5*(aprime
+ bprime
);
184 double rprime
= 0.5*( bprime
- aprime
).length();
186 return new CircleImp( cprime
+ refc
, rprime
);