• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

kig

  • sources
  • kde-4.12
  • kdeedu
  • kig
  • misc
kigtransform.cpp
Go to the documentation of this file.
1 
22 #include "kigtransform.h"
23 
24 #include "kignumerics.h"
25 #include "common.h"
26 
27 #include <cmath>
28 
29 #include <klocale.h>
30 #include <kdebug.h>
31 
32 using std::fabs;
33 using std::cos;
34 using std::sin;
35 using std::atan2;
36 
37 // Transformation getProjectiveTransformation ( int argsnum,
38 // Object *transforms[], bool& valid )
39 // {
40 // valid = true;
41 
42 // assert ( argsnum > 0 );
43 // int argn = 0;
44 // Object* transform = transforms[argn++];
45 // if (transform->toVector())
46 // {
47 // // translation
48 // assert (argn == argsnum);
49 // Vector* v = transform->toVector();
50 // Coordinate dir = v->getDir();
51 // return Transformation::translation( dir );
52 // }
53 
54 // if (transform->toPoint())
55 // {
56 // // point reflection ( or is point symmetry the correct term ? )
57 // assert (argn == argsnum);
58 // Point* p = transform->toPoint();
59 // return Transformation::pointReflection( p->getCoord() );
60 // }
61 
62 // if (transform->toLine())
63 // {
64 // // line reflection ( or is it line symmetry ? )
65 // Line* line = transform->toLine();
66 // assert (argn == argsnum);
67 // return Transformation::lineReflection( line->lineData() );
68 // }
69 
70 // if (transform->toRay())
71 // {
72 // // domi: sorry, but what kind of transformation does this do ?
73 // // I'm guessing it's some sort of rotation, but I'm not
74 // // really sure..
75 // Ray* line = transform->toRay();
76 // Coordinate d = line->direction().normalize();
77 // Coordinate t = line->p1();
78 // double alpha = 0.1*M_PI/2; // a small angle for the DrawPrelim
79 // if (argn < argsnum)
80 // {
81 // Angle* angle = transforms[argn++]->toAngle();
82 // alpha = angle->size();
83 // }
84 // assert (argn == argsnum);
85 // return Transformation::projectiveRotation( alpha, d, t );
86 // }
87 
88 // if (transform->toAngle())
89 // {
90 // // rotation..
91 // Coordinate center = Coordinate( 0., 0. );
92 // if (argn < argsnum)
93 // {
94 // Object* arg = transforms[argn++];
95 // assert (arg->toPoint());
96 // center = arg->toPoint()->getCoord();
97 // }
98 // Angle* angle = transform->toAngle();
99 // double alpha = angle->size();
100 
101 // assert (argn == argsnum);
102 
103 // return Transformation::rotation( alpha, center );
104 // }
105 
106 // if (transform->toSegment()) // this is a scaling
107 // {
108 // Segment* segment = transform->toSegment();
109 // Coordinate p = segment->p2() - segment->p1();
110 // double s = p.length();
111 // if (argn < argsnum)
112 // {
113 // Object* arg = transforms[argn++];
114 // if (arg->toSegment()) // s is the length of the first segment
115 // // divided by the length of the second..
116 // {
117 // Segment* segment = arg->toSegment();
118 // Coordinate p = segment->p2() - segment->p1();
119 // s /= p.length();
120 // if (argn < argsnum) arg = transforms[argn++];
121 // }
122 // if (arg->toPoint()) // scaling w.r. to a point
123 // {
124 // Point* p = arg->toPoint();
125 // assert (argn == argsnum);
126 // return Transformation::scaling( s, p->getCoord() );
127 // }
128 // if (arg->toLine()) // scaling w.r. to a line
129 // {
130 // Line* line = arg->toLine();
131 // assert( argn == argsnum );
132 // return Transformation::scaling( s, line->lineData() );
133 // }
134 // }
135 
136 // return Transformation::scaling( s, Coordinate( 0., 0. ) );
137 // }
138 
139 // valid = false;
140 // return Transformation::identity();
141 // }
142 
143 // tWantArgsResult WantTransformation ( Objects::const_iterator& i,
144 // const Objects& os )
145 // {
146 // Object* o = *i++;
147 // if (o->toVector()) return tComplete;
148 // if (o->toPoint()) return tComplete;
149 // if (o->toLine()) return tComplete;
150 // if (o->toAngle())
151 // {
152 // if ( i == os.end() ) return tNotComplete;
153 // o = *i++;
154 // if (o->toPoint()) return tComplete;
155 // if (o->toLine()) return tComplete;
156 // return tNotGood;
157 // }
158 // if (o->toRay())
159 // {
160 // if ( i == os.end() ) return tNotComplete;
161 // o = *i++;
162 // if (o->toAngle()) return tComplete;
163 // return tNotGood;
164 // }
165 // if (o->toSegment())
166 // {
167 // if ( i == os.end() ) return tNotComplete;
168 // o = *i++;
169 // if ( o->toSegment() )
170 // {
171 // if ( i == os.end() ) return tNotComplete;
172 // o = *i++;
173 // }
174 // if (o->toPoint()) return tComplete;
175 // if (o->toLine()) return tComplete;
176 // return tNotGood;
177 // }
178 // return tNotGood;
179 // }
180 
181 // QString getTransformMessage ( const Objects& os, const Object *o )
182 // {
183 // int size = os.size();
184 // switch (size)
185 // {
186 // case 1:
187 // if (o->toVector()) return i18n("translate by this vector");
188 // if (o->toPoint()) return i18n("central symmetry by this point. You"
189 // " can obtain different transformations by clicking on lines (mirror),"
190 // " vectors (translation), angles (rotation), segments (scaling) and rays"
191 // " (projective transformation)");
192 // if (o->toLine()) return i18n("reflect in this line");
193 // if (o->toAngle()) return i18n("rotate by this angle");
194 // if (o->toSegment()) return i18n("scale using the length of this vector");
195 // if (o->toRay()) return i18n("a projective transformation in the direction"
196 // " indicated by this ray, it is a rotation in the projective plane"
197 // " about a point at infinity");
198 // return i18n("Use this transformation");
199 
200 // case 2: // we ask for the first parameter of the transformation
201 // case 3:
202 // if (os[1]->toAngle())
203 // {
204 // if (o->toPoint()) return i18n("about this point");
205 // assert (false);
206 // }
207 // if (os[1]->toSegment())
208 // {
209 // if (o->toSegment())
210 // return i18n("relative to the length of this other vector");
211 // if (o->toPoint())
212 // return i18n("about this point");
213 // if (o->toLine())
214 // return i18n("about this line");
215 // }
216 // if (os[1]->toRay())
217 // {
218 // if (o->toAngle()) return i18n("rotate by this angle in the projective"
219 // " plane");
220 // }
221 // return i18n("Using this object");
222 
223 // default: assert(false);
224 // }
225 
226 // return i18n("Use this transformation");
227 // }
228 
229 
230 /* domi: not necessary anymore, homotheticness is kept as a bool in
231  * the Transformation class..
232  * keeping it here, in case a need for it arises some time in the
233  * future...
234  * decide if the given transformation is homotetic
235  */
236 // bool isHomoteticTransformation ( double transformation[3][3] )
237 // {
238 // if (transformation[0][1] != 0 || transformation[0][2] != 0) return (false);
239 // // test the orthogonality of the matrix 2x2 of second and third rows
240 // // and columns
241 // if (fabs(fabs(transformation[1][1]) -
242 // fabs(transformation[2][2])) > 1e-8) return (false);
243 // if (fabs(fabs(transformation[1][2]) -
244 // fabs(transformation[2][1])) > 1e-8) return (false);
245 
246 // return transformation[1][2] * transformation[2][1] *
247 // transformation[1][1] * transformation[2][2] <= 0.;
248 // }
249 
250 const Transformation Transformation::identity()
251 {
252  Transformation ret;
253  for ( int i = 0; i < 3; ++i )
254  for ( int j = 0; j < 3; ++j )
255  ret.mdata[i][j] = ( i == j ? 1 : 0 );
256  ret.mIsHomothety = ret.mIsAffine = true;
257  return ret;
258 }
259 
260 const Transformation Transformation::scalingOverPoint( double factor, const Coordinate& center )
261 {
262  Transformation ret;
263  for ( int i = 0; i < 3; ++i )
264  for ( int j = 0; j < 3; ++j )
265  ret.mdata[i][j] = ( i == j ? factor : 0 );
266  ret.mdata[0][0] = 1;
267  ret.mdata[1][0] = center.x - factor * center.x;
268  ret.mdata[2][0] = center.y - factor * center.y;
269  ret.mIsHomothety = ret.mIsAffine = true;
270  return ret;
271 }
272 
273 const Transformation Transformation::translation( const Coordinate& c )
274 {
275  Transformation ret = identity();
276  ret.mdata[1][0] = c.x;
277  ret.mdata[2][0] = c.y;
278 
279  // this is already set in the identity() constructor, but just for
280  // clarity..
281  ret.mIsHomothety = ret.mIsAffine = true;
282  return ret;
283 }
284 
285 const Transformation Transformation::pointReflection( const Coordinate& c )
286 {
287  Transformation ret = scalingOverPoint( -1, c );
288  ret.mIsHomothety = ret.mIsAffine = true;
289  return ret;
290 }
291 
292 const Transformation operator*( const Transformation& a, const Transformation& b )
293 {
294  // just multiply the two matrices..
295  Transformation ret;
296 
297  for ( int i = 0; i < 3; ++i )
298  for ( int j = 0; j < 3; ++j )
299  {
300  ret.mdata[i][j] = 0;
301  for ( int k = 0; k < 3; ++k )
302  ret.mdata[i][j] += a.mdata[i][k] * b.mdata[k][j];
303  };
304 
305  // combination of two homotheties is a homothety..
306 
307  ret.mIsHomothety = a.mIsHomothety && b.mIsHomothety;
308 
309  // combination of two affinities is affine..
310 
311  ret.mIsAffine = a.mIsAffine && b.mIsAffine;
312 
313  return ret;
314 }
315 
316 const Transformation Transformation::lineReflection( const LineData& l )
317 {
318  Transformation ret = scalingOverLine( -1, l );
319  // a reflection is a homothety...
320  ret.mIsHomothety = ret.mIsAffine = true;
321  return ret;
322 }
323 
324 const Transformation Transformation::scalingOverLine( double factor, const LineData& l )
325 {
326  Transformation ret = identity();
327 
328  Coordinate a = l.a;
329  Coordinate d = l.dir();
330  double dirnormsq = d.squareLength();
331  ret.mdata[1][1] = (d.x*d.x + factor*d.y*d.y)/dirnormsq;
332  ret.mdata[2][2] = (d.y*d.y + factor*d.x*d.x)/dirnormsq;
333  ret.mdata[1][2] = ret.mdata[2][1] = (d.x*d.y - factor*d.x*d.y)/dirnormsq;
334 
335  ret.mdata[1][0] = a.x - ret.mdata[1][1]*a.x - ret.mdata[1][2]*a.y;
336  ret.mdata[2][0] = a.y - ret.mdata[2][1]*a.x - ret.mdata[2][2]*a.y;
337 
338  // domi: is 1e-8 a good value ?
339  ret.mIsHomothety = ( fabs( factor - 1 ) < 1e-8 || fabs ( factor + 1 ) < 1e-8 );
340  ret.mIsAffine = true;
341  return ret;
342 }
343 
344 const Transformation Transformation::harmonicHomology(
345  const Coordinate& center, const LineData& axis )
346 {
347  // this is a well known projective transformation. We find it by first
348  // computing the homogeneous equation of the axis ax + by + cz = 0
349  // then a straightforward computation shows that the 3x3 matrix describing
350  // the transformation is of the form:
351  //
352  // (r . C) Id - 2 (C tensor r)
353  //
354  // where r = [c, a, b], C = [1, Cx, Cy], Cx and Cy are the coordinates of
355  // the center, '.' denotes the scalar product, Id is the identity matrix,
356  // 'tensor' is the tensor product producing a 3x3 matrix.
357  //
358  // note: here we decide to use coordinate '0' in place of the third coordinate
359  // in homogeneous notation; e.g. C = [1, cx, cy]
360 
361  Coordinate pointa = axis.a;
362  Coordinate pointb = axis.b;
363 
364  double a = pointa.y - pointb.y;
365  double b = pointb.x - pointa.x;
366  double c = pointa.x*pointb.y - pointa.y*pointb.x;
367 
368  double cx = center.x;
369  double cy = center.y;
370 
371  double scalprod = a*cx + b*cy + c;
372  scalprod *= 0.5;
373  Transformation ret;
374 
375  ret.mdata[0][0] = c - scalprod;
376  ret.mdata[0][1] = a;
377  ret.mdata[0][2] = b;
378 
379  ret.mdata[1][0] = c*cx;
380  ret.mdata[1][1] = a*cx - scalprod;
381  ret.mdata[1][2] = b*cx;
382 
383  ret.mdata[2][0] = c*cy;
384  ret.mdata[2][1] = a*cy;
385  ret.mdata[2][2] = b*cy - scalprod;
386 
387  ret.mIsHomothety = ret.mIsAffine = false;
388  return ret;
389 }
390 
391 const Transformation Transformation::affinityGI3P(
392  const std::vector<Coordinate>& FromPoints,
393  const std::vector<Coordinate>& ToPoints,
394  bool& valid )
395 {
396  // construct the (generically) unique affinity that transforms 3 given
397  // point into 3 other given points; i.e. it depends on the coordinates of
398  // a total of 6 points. This actually amounts in solving a 6x6 linear
399  // system to find the entries of a 2x2 linear transformation matrix T
400  // and of a translation vector t.
401  // If Pi denotes one of the starting points and Qi the corresponding
402  // final position we actually have to solve: Qi = t + T Pi, for i=1,2,3
403  // (each one is a vector equation, so that it really gives 2 equations).
404  // In our context T and t are used to build a 3x3 projective transformation
405  // as follows:
406  //
407  // [ 1 0 0 ]
408  // [ t1 T11 T12 ]
409  // [ t2 T21 T22 ]
410  //
411  // In order to take advantage of the two functions "GaussianElimination"
412  // and "BackwardSubstitution", which are specifically aimed at solving
413  // homogeneous underdetermined linear systems, we just add a further
414  // unknown m and solve for t + T Pi - m Qi = 0. Since our functions
415  // returns a nonzero solution we shall have a nonzero 'm' in the end and
416  // can build the 3x3 matrix as follows:
417  //
418  // [ m 0 0 ]
419  // [ t1 T11 T12 ]
420  // [ t2 T21 T22 ]
421  //
422  // we order the unknowns as follows: m, t1, t2, T11, T12, T21, T22
423 
424  double row0[7], row1[7], row2[7], row3[7], row4[7], row5[7];
425 
426  double *matrix[6] = {row0, row1, row2, row3, row4, row5};
427 
428  double solution[7];
429  int scambio[7];
430 
431  assert (FromPoints.size() == 3);
432  assert (ToPoints.size() == 3);
433 
434  // fill in the matrix elements
435  for ( int i = 0; i < 6; i++ )
436  {
437  for ( int j = 0; j < 7; j++ )
438  {
439  matrix[i][j] = 0.0;
440  }
441  }
442 
443  for ( int i = 0; i < 3; i++ )
444  {
445  Coordinate p = FromPoints[i];
446  Coordinate q = ToPoints[i];
447  matrix[i][0] = -q.x;
448  matrix[i][1] = 1.0;
449  matrix[i][3] = p.x;
450  matrix[i][4] = p.y;
451  matrix[i+3][0] = -q.y;
452  matrix[i+3][2] = 1.0;
453  matrix[i+3][5] = p.x;
454  matrix[i+3][6] = p.y;
455  }
456 
457  Transformation ret;
458  valid = true;
459  if ( ! GaussianElimination( matrix, 6, 7, scambio ) )
460  { valid = false; return ret; }
461 
462  // fine della fase di eliminazione
463  BackwardSubstitution( matrix, 6, 7, scambio, solution );
464 
465  // now we can build the 3x3 transformation matrix; remember that
466  // unknown 0 is the multiplicator 'm'
467 
468  ret.mdata[0][0] = solution[0];
469  ret.mdata[0][1] = ret.mdata[0][2] = 0.0;
470  ret.mdata[1][0] = solution[1];
471  ret.mdata[2][0] = solution[2];
472  ret.mdata[1][1] = solution[3];
473  ret.mdata[1][2] = solution[4];
474  ret.mdata[2][1] = solution[5];
475  ret.mdata[2][2] = solution[6];
476 
477  ret.mIsHomothety = false;
478  ret.mIsAffine = true;
479  return ret;
480 }
481 
482 const Transformation Transformation::projectivityGI4P(
483  const std::vector<Coordinate>& FromPoints,
484  const std::vector<Coordinate>& ToPoints,
485  bool& valid )
486 {
487  // construct the (generically) unique projectivity that transforms 4 given
488  // point into 4 other given points; i.e. it depends on the coordinates of
489  // a total of 8 points. This actually amounts in solving an underdetermined
490  // homogeneous linear system.
491 
492  double
493  row0[13], row1[13], row2[13], row3[13], row4[13], row5[13], row6[13], row7[13],
494  row8[13], row9[13], row10[13], row11[13];
495 
496  double *matrix[12] = {row0, row1, row2, row3, row4, row5, row6, row7,
497  row8, row9, row10, row11};
498 
499  double solution[13];
500  int scambio[13];
501 
502  assert (FromPoints.size() == 4);
503  assert (ToPoints.size() == 4);
504 
505  // fill in the matrix elements
506  for ( int i = 0; i < 12; i++ )
507  {
508  for ( int j = 0; j < 13; j++ )
509  {
510  matrix[i][j] = 0.0;
511  }
512  }
513 
514  for ( int i = 0; i < 4; i++ )
515  {
516  Coordinate p = FromPoints[i];
517  Coordinate q = ToPoints[i];
518  matrix[i][0] = matrix[4+i][3] = matrix[8+i][6] = 1.0;
519  matrix[i][1] = matrix[4+i][4] = matrix[8+i][7] = p.x;
520  matrix[i][2] = matrix[4+i][5] = matrix[8+i][8] = p.y;
521  matrix[i][9+i] = -1.0;
522  matrix[4+i][9+i] = -q.x;
523  matrix[8+i][9+i] = -q.y;
524  }
525 
526  Transformation ret;
527  valid = true;
528  if ( ! GaussianElimination( matrix, 12, 13, scambio ) )
529  { valid = false; return ret; }
530 
531  // fine della fase di eliminazione
532  BackwardSubstitution( matrix, 12, 13, scambio, solution );
533 
534  // now we can build the 3x3 transformation matrix; remember that
535  // unknowns from 9 to 13 are just multiplicators that we don't need here
536 
537  int k = 0;
538  for ( int i = 0; i < 3; i++ )
539  {
540  for ( int j = 0; j < 3; j++ )
541  {
542  ret.mdata[i][j] = solution[k++];
543  }
544  }
545 
546  ret.mIsHomothety = ret.mIsAffine = false;
547  return ret;
548 }
549 
550 const Transformation Transformation::castShadow(
551  const Coordinate& lightsrc, const LineData& l )
552 {
553  // first deal with the line l, I need to find an appropriate reflection
554  // that transforms l onto the x-axis
555 
556  Coordinate d = l.dir();
557  Coordinate a = l.a;
558  double k = d.length();
559  if ( d.x < 0 ) k *= -1; // for numerical stability
560  Coordinate w = d + Coordinate( k, 0 );
561  // w /= w.length();
562  // w defines a Householder transformation, but we don't need to normalize
563  // it here.
564  // warning: this w is the orthogonal of the w of the textbooks!
565  // this is fine for us since in this way it indicates the line direction
566  Coordinate ra = Coordinate ( a.x + w.y*a.y/(2*w.x), a.y/2 );
567  Transformation sym = lineReflection ( LineData( ra, ra + w ) );
568 
569  // in the new coordinates the line is the x-axis
570  // I must transform the point
571 
572  Coordinate modlightsrc = sym.apply ( lightsrc );
573  Transformation ret = identity();
574  // parameter t indicates the distance of the light source from
575  // the plane of the drawing. A negative value means that the light
576  // source is behind the plane.
577  double t = -1.0;
578  // double t = -modlightsrc.y; <-- this gives the old transformation!
579  double e = modlightsrc.y - t;
580  ret.mdata[0][0] = e;
581  ret.mdata[0][2] = -1;
582  ret.mdata[1][1] = e;
583  ret.mdata[1][2] = -modlightsrc.x;
584  ret.mdata[2][2] = -t;
585 
586  ret.mIsHomothety = ret.mIsAffine = false;
587  return sym*ret*sym;
588 // return translation( t )*ret*translation( -t );
589 }
590 
591 const Transformation Transformation::projectiveRotation(
592  double alpha, const Coordinate& d, const Coordinate& t )
593 {
594  Transformation ret;
595  double cosalpha = cos( alpha );
596  double sinalpha = sin( alpha );
597  ret.mdata[0][0] = cosalpha;
598  ret.mdata[1][1] = cosalpha*d.x*d.x + d.y*d.y;
599  ret.mdata[0][1] = -sinalpha*d.x;
600  ret.mdata[1][0] = sinalpha*d.x;
601  ret.mdata[0][2] = -sinalpha*d.y;
602  ret.mdata[2][0] = sinalpha*d.y;
603  ret.mdata[1][2] = cosalpha*d.x*d.y - d.x*d.y;
604  ret.mdata[2][1] = cosalpha*d.x*d.y - d.x*d.y;
605  ret.mdata[2][2] = cosalpha*d.y*d.y + d.x*d.x;
606 
607  ret.mIsHomothety = ret.mIsAffine = false;
608  return translation( t )*ret*translation( -t );
609 }
610 
611 const Coordinate Transformation::apply( const double x0,
612  const double x1,
613  const double x2) const
614 {
615  double phom[3] = {x0, x1, x2};
616  double rhom[3] = {0., 0., 0.};
617 
618 
619  for (int i = 0; i < 3; i++)
620  {
621  for (int j = 0; j < 3; j++)
622  {
623  rhom[i] += mdata[i][j]*phom[j];
624  }
625  }
626 
627  if (rhom[0] == 0.)
628  return Coordinate::invalidCoord();
629 
630  return Coordinate (rhom[1]/rhom[0], rhom[2]/rhom[0]);
631 }
632 
633 const Coordinate Transformation::apply( const Coordinate& p ) const
634 {
635  return apply( 1., p.x, p.y );
636 // double phom[3] = {1., p.x, p.y};
637 // double rhom[3] = {0., 0., 0.};
638 //
639 // for (int i = 0; i < 3; i++)
640 // {
641 // for (int j = 0; j < 3; j++)
642 // {
643 // rhom[i] += mdata[i][j]*phom[j];
644 // }
645 // }
646 //
647 // if (rhom[0] == 0.)
648 // return Coordinate::invalidCoord();
649 //
650 // return Coordinate (rhom[1]/rhom[0], rhom[2]/rhom[0]);
651 }
652 
653 const Coordinate Transformation::apply0( const Coordinate& p ) const
654 {
655  return apply( 0., p.x, p.y );
656 }
657 
658 const Transformation Transformation::rotation( double alpha, const Coordinate& center )
659 {
660  Transformation ret = identity();
661 
662  double x = center.x;
663  double y = center.y;
664 
665  double cosalpha = cos( alpha );
666  double sinalpha = sin( alpha );
667 
668  ret.mdata[1][1] = ret.mdata[2][2] = cosalpha;
669  ret.mdata[1][2] = -sinalpha;
670  ret.mdata[2][1] = sinalpha;
671  ret.mdata[1][0] = x - ret.mdata[1][1]*x - ret.mdata[1][2]*y;
672  ret.mdata[2][0] = y - ret.mdata[2][1]*x - ret.mdata[2][2]*y;
673 
674  // this is already set in the identity() constructor, but just for
675  // clarity..
676  ret.mIsHomothety = ret.mIsAffine = true;
677 
678  return ret;
679 }
680 
681 bool Transformation::isHomothetic() const
682 {
683  return mIsHomothety;
684 }
685 
686 bool Transformation::isAffine() const
687 {
688  return mIsAffine;
689 }
690 
691 /*
692  *mp:
693  * this function has the property that it changes sign if computed
694  * on two points that lie on either sides with respect to the critical
695  * line (this is the line that goes to the line at infinity).
696  * For affine transformations the result has always the same sign.
697  * NOTE: the result is *not* invariant under rescaling of all elements
698  * of the transformation matrix.
699  * The typical use is to determine whether a segment is transformed
700  * into a segment or a couple of half-lines.
701  */
702 
703 double Transformation::getProjectiveIndicator( const Coordinate& c ) const
704 {
705  return mdata[0][0] + mdata[0][1]*c.x + mdata[0][2]*c.y;
706 }
707 
708 // assuming that this is an affine transformation, return its
709 // determinant. What is really important here is just the sign
710 // of the determinant.
711 double Transformation::getAffineDeterminant() const
712 {
713  return mdata[1][1]*mdata[2][2] - mdata[1][2]*mdata[2][1];
714 }
715 
716 // this assumes that the 2x2 affine part of the matrix is of the
717 // form [ cos a, sin a; -sin a, cos a] or a multiple
718 double Transformation::getRotationAngle() const
719 {
720  return atan2( mdata[1][2], mdata[1][1] );
721 }
722 
723 const Coordinate Transformation::apply2by2only( const Coordinate& p ) const
724 {
725  double x = p.x;
726  double y = p.y;
727  double nx = mdata[1][1]*x + mdata[1][2]*y;
728  double ny = mdata[2][1]*x + mdata[2][2]*y;
729  return Coordinate( nx, ny );
730 }
731 
732 double Transformation::data( int r, int c ) const
733 {
734  return mdata[r][c];
735 }
736 
737 const Transformation Transformation::inverse( bool& valid ) const
738 {
739  Transformation ret;
740 
741  valid = Invert3by3matrix( mdata, ret.mdata );
742 
743  // the inverse of a homothety is a homothety, same for affinities..
744  ret.mIsHomothety = mIsHomothety;
745  ret.mIsAffine = mIsAffine;
746 
747  return ret;
748 }
749 
750 Transformation::Transformation()
751 {
752  // this is the constructor used by the static Transformation
753  // creation functions, so mIsHomothety is in general false
754  mIsHomothety = mIsAffine = false;
755  for ( int i = 0; i < 3; ++i )
756  for ( int j = 0; j < 3; ++j )
757  mdata[i][j] = ( i == j ) ? 1 : 0;
758 }
759 
760 Transformation::~Transformation()
761 {
762 }
763 
764 double Transformation::apply( double length ) const
765 {
766  assert( isHomothetic() );
767  double det = mdata[1][1]*mdata[2][2] -
768  mdata[1][2]*mdata[2][1];
769  return std::sqrt( fabs( det ) ) * length;
770 }
771 
772 Transformation::Transformation( double data[3][3], bool ishomothety )
773  : mIsHomothety( ishomothety )
774 {
775  for ( int i = 0; i < 3; ++i )
776  for ( int j = 0; j < 3; ++j )
777  mdata[i][j] = data[i][j];
778 
779  //mp: a test for affinity is used to initialize mIsAffine...
780  mIsAffine = false;
781  if ( fabs(mdata[0][1]) + fabs(mdata[0][2]) < 1e-8 * fabs(mdata[0][0]) )
782  mIsAffine = true;
783 }
784 
785 bool operator==( const Transformation& lhs, const Transformation& rhs )
786 {
787  for ( int i = 0; i < 3; ++i )
788  for ( int j = 0; j < 3; ++j )
789  if ( lhs.data( i, j ) != rhs.data( i, j ) )
790  return false;
791  return true;
792 }
793 
794 const Transformation Transformation::similitude(
795  const Coordinate& center, double theta, double factor )
796 {
797  //kDebug() << "theta: " << theta << " factor: " << factor;
798  Transformation ret;
799  ret.mIsHomothety = true;
800  double costheta = cos( theta );
801  double sintheta = sin( theta );
802  ret.mdata[0][0] = 1;
803  ret.mdata[0][1] = 0;
804  ret.mdata[0][2] = 0;
805  ret.mdata[1][0] = ( 1 - factor*costheta )*center.x + factor*sintheta*center.y;
806  ret.mdata[1][1] = factor*costheta;
807  ret.mdata[1][2] = -factor*sintheta;
808  ret.mdata[2][0] = -factor*sintheta*center.x + ( 1 - factor*costheta )*center.y;
809  ret.mdata[2][1] = factor*sintheta;
810  ret.mdata[2][2] = factor*costheta;
811  // fails for factor == infinity
812  //assert( ( ret.apply( center ) - center ).length() < 1e-5 );
813  ret.mIsHomothety = ret.mIsAffine = true;
814  return ret;
815 }
Transformation::translation
static const Transformation translation(const Coordinate &c)
Translation.
Definition: kigtransform.cpp:273
Transformation::scalingOverLine
static const Transformation scalingOverLine(double factor, const LineData &l)
Scaling over Line.
Definition: kigtransform.cpp:324
Transformation::lineReflection
static const Transformation lineReflection(const LineData &l)
Line Reflection.
Definition: kigtransform.cpp:316
LineData
Simple class representing a line.
Definition: misc/common.h:49
Transformation::pointReflection
static const Transformation pointReflection(const Coordinate &c)
Point Reflection.
Definition: kigtransform.cpp:285
LineData::dir
const Coordinate dir() const
The direction of the line.
Definition: misc/common.h:72
LineData::b
Coordinate b
Another point on the line.
Definition: misc/common.h:68
Transformation::~Transformation
~Transformation()
Definition: kigtransform.cpp:760
Transformation::projectiveRotation
static const Transformation projectiveRotation(double alpha, const Coordinate &d, const Coordinate &t)
Projective Rotation.
Definition: kigtransform.cpp:591
Transformation::getProjectiveIndicator
double getProjectiveIndicator(const Coordinate &c) const
Definition: kigtransform.cpp:703
Transformation::isAffine
bool isAffine() const
Definition: kigtransform.cpp:686
Invert3by3matrix
bool Invert3by3matrix(const double m[3][3], double inv[3][3])
Definition: kignumerics.cpp:372
Coordinate
The Coordinate class is the basic class representing a 2D location by its x and y components...
Definition: coordinate.h:33
Coordinate::length
double length() const
Length.
Definition: coordinate.cpp:144
GaussianElimination
bool GaussianElimination(double *matrix[], int numrows, int numcols, int exchange[])
Gaussian Elimination.
Definition: kignumerics.cpp:271
Transformation::isHomothetic
bool isHomothetic() const
Returns whether this is a homothetic (affine) transformation.
Definition: kigtransform.cpp:681
Transformation::getRotationAngle
double getRotationAngle() const
Definition: kigtransform.cpp:718
Transformation::castShadow
static const Transformation castShadow(const Coordinate &ls, const LineData &d)
Cast Shadow.
Definition: kigtransform.cpp:550
Transformation::apply0
const Coordinate apply0(const Coordinate &c) const
Definition: kigtransform.cpp:653
Transformation::apply2by2only
const Coordinate apply2by2only(const Coordinate &c) const
Definition: kigtransform.cpp:723
Transformation::projectivityGI4P
static const Transformation projectivityGI4P(const std::vector< Coordinate > &FromPoints, const std::vector< Coordinate > &ToPoints, bool &valid)
Projectivity given the image of 4 points.
Definition: kigtransform.cpp:482
Transformation::getAffineDeterminant
double getAffineDeterminant() const
Definition: kigtransform.cpp:711
Transformation
Class representing a transformation.
Definition: kigtransform.h:37
Transformation::inverse
const Transformation inverse(bool &valid) const
The inverse Transformation.
Definition: kigtransform.cpp:737
LineData::a
Coordinate a
One point on the line.
Definition: misc/common.h:64
Coordinate::squareLength
double squareLength() const
Square length.
Definition: coordinate.h:163
Transformation::scalingOverPoint
static const Transformation scalingOverPoint(double factor, const Coordinate &center=Coordinate())
Scaling over Point.
Definition: kigtransform.cpp:260
common.h
kigtransform.h
Transformation::apply
const Coordinate apply(const double x0, const double x1, const double x2) const
Apply this Tranformation.
Definition: kigtransform.cpp:611
Coordinate::invalidCoord
static Coordinate invalidCoord()
Create an invalid Coordinate.
Definition: coordinate.cpp:171
Transformation::affinityGI3P
static const Transformation affinityGI3P(const std::vector< Coordinate > &FromPoints, const std::vector< Coordinate > &ToPoints, bool &valid)
Affinity given the image of 3 points.
Definition: kigtransform.cpp:391
Transformation::harmonicHomology
static const Transformation harmonicHomology(const Coordinate &center, const LineData &axis)
Harmonic Homology.
Definition: kigtransform.cpp:344
Transformation::identity
static const Transformation identity()
Identity.
Definition: kigtransform.cpp:250
Transformation::data
double data(int r, int c) const
Definition: kigtransform.cpp:732
Transformation::similitude
static const Transformation similitude(const Coordinate &center, double theta, double factor)
Similitude.
Definition: kigtransform.cpp:794
BackwardSubstitution
void BackwardSubstitution(double *matrix[], int numrows, int numcols, int exchange[], double solution[])
Definition: kignumerics.cpp:340
Coordinate::x
double x
X Component.
Definition: coordinate.h:126
Coordinate::y
double y
Y Component.
Definition: coordinate.h:129
operator==
bool operator==(const Transformation &lhs, const Transformation &rhs)
Definition: kigtransform.cpp:785
kignumerics.h
operator*
const Transformation operator*(const Transformation &a, const Transformation &b)
Definition: kigtransform.cpp:292
Transformation::rotation
static const Transformation rotation(double angle, const Coordinate &center=Coordinate())
Rotation.
Definition: kigtransform.cpp:658
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:35:39 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal