• 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
conic-common.cpp
Go to the documentation of this file.
1 
21 #include "conic-common.h"
22 
23 #include <math.h>
24 
25 #include "common.h"
26 #include "kigtransform.h"
27 
28 #include <cmath>
29 #include <algorithm>
30 
31 #include <config-kig.h>
32 
33 #ifdef HAVE_IEEEFP_H
34 #include <ieeefp.h>
35 #endif
36 
37 ConicCartesianData::ConicCartesianData(
38  const ConicPolarData& polardata
39  )
40 {
41  double ec = polardata.ecostheta0;
42  double es = polardata.esintheta0;
43  double p = polardata.pdimen;
44  double fx = polardata.focus1.x;
45  double fy = polardata.focus1.y;
46 
47  double a = 1 - ec*ec;
48  double b = 1 - es*es;
49  double c = - 2*ec*es;
50  double d = - 2*p*ec;
51  double e = - 2*p*es;
52  double f = - p*p;
53 
54  f += a*fx*fx + b*fy*fy + c*fx*fy - d*fx - e*fy;
55  d -= 2*a*fx + c*fy;
56  e -= 2*b*fy + c*fx;
57 
58  coeffs[0] = a;
59  coeffs[1] = b;
60  coeffs[2] = c;
61  coeffs[3] = d;
62  coeffs[4] = e;
63  coeffs[5] = f;
64 }
65 
66 ConicPolarData::ConicPolarData( const ConicCartesianData& cartdata )
67 {
68  double a = cartdata.coeffs[0];
69  double b = cartdata.coeffs[1];
70  double c = cartdata.coeffs[2];
71  double d = cartdata.coeffs[3];
72  double e = cartdata.coeffs[4];
73  double f = cartdata.coeffs[5];
74 
75  // 1. Compute theta (tilt of conic)
76  double theta = std::atan2(c, b - a)/2;
77 
78  // now I should possibly add pi/2...
79  double costheta = std::cos(theta);
80  double sintheta = std::sin(theta);
81  // compute new coefficients (c should now be zero)
82  double aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
83  double bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
84  if (aa*bb < 0)
85  { // we have a hyperbola we need to check the correct orientation
86  double dd = d*costheta - e*sintheta;
87  double ee = d*sintheta + e*costheta;
88  double xc = - dd / ( 2*aa );
89  double yc = - ee / ( 2*bb );
90  double ff = f + aa*xc*xc + bb*yc*yc + dd*xc + ee*yc;
91  if (ff*aa > 0) // wrong orientation
92  {
93  if (theta > 0) theta -= M_PI/2;
94  else theta += M_PI/2;
95  costheta = cos(theta);
96  sintheta = sin(theta);
97  aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
98  bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
99  }
100  }
101  else
102  {
103  if ( std::fabs (bb) < std::fabs (aa) )
104  {
105  if (theta > 0) theta -= M_PI/2;
106  else theta += M_PI/2;
107  costheta = cos(theta);
108  sintheta = sin(theta);
109  aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
110  bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
111  }
112  }
113 
114  double cc = 2*(a - b)*sintheta*costheta +
115  c*(costheta*costheta - sintheta*sintheta);
116  // cc should be zero!!! cout << "cc = " << cc << "\n";
117  double dd = d*costheta - e*sintheta;
118  double ee = d*sintheta + e*costheta;
119 
120  a = aa;
121  b = bb;
122  c = cc;
123  d = dd;
124  e = ee;
125 
126  // now b cannot be zero (otherwise conic is degenerate)
127  a /= b;
128  c /= b;
129  d /= b;
130  e /= b;
131  f /= b;
132  b = 1.0;
133 
134  // 2. compute y coordinate of focuses
135 
136  double yf = - e/2;
137 
138  // new values:
139  f += yf*yf + e*yf;
140  e += 2*yf; // this should be zero!
141 
142  // now: a > 0 -> ellipse
143  // a = 0 -> parabula
144  // a < 0 -> hyperbola
145 
146  double eccentricity = sqrt(1.0 - a);
147 
148  double sqrtdiscrim = sqrt(d*d - 4*a*f);
149  if (d < 0.0) sqrtdiscrim = -sqrtdiscrim;
150  double xf = (4*a*f - 4*f - d*d)/(d + eccentricity*sqrtdiscrim) / 2;
151 
152  // 3. the focus needs to be rotated back into position
153  focus1.x = xf*costheta + yf*sintheta;
154  focus1.y = -xf*sintheta + yf*costheta;
155 
156  // 4. final touch: the pdimen
157  pdimen = -sqrtdiscrim/2;
158 
159  ecostheta0 = eccentricity*costheta;
160  esintheta0 = -eccentricity*sintheta;
161  if ( pdimen < 0)
162  {
163  pdimen = -pdimen;
164  ecostheta0 = -ecostheta0;
165  esintheta0 = -esintheta0;
166  }
167 }
168 
169 const ConicCartesianData calcConicThroughPoints (
170  const std::vector<Coordinate>& points,
171  const LinearConstraints c1,
172  const LinearConstraints c2,
173  const LinearConstraints c3,
174  const LinearConstraints c4,
175  const LinearConstraints c5 )
176 {
177  assert( 0 < points.size() && points.size() <= 5 );
178  // points is a vector of up to 5 points through which the conic is
179  // constrained.
180  // this routine should compute the coefficients in the cartesian equation
181  // a x^2 + b y^2 + c xy + d x + e y + f = 0
182  // they are defined up to a multiplicative factor.
183  // since we don't know (in advance) which one of them is nonzero, we
184  // simply keep all 6 parameters, obtaining a 5x6 linear system which
185  // we solve using gaussian elimination with complete pivoting
186  // If there are too few, then we choose some cool way to fill in the
187  // empty parts in the matrix according to the LinearConstraints
188  // given..
189 
190  // 5 rows, 6 columns..
191  double row0[6];
192  double row1[6];
193  double row2[6];
194  double row3[6];
195  double row4[6];
196  double *matrix[5] = {row0, row1, row2, row3, row4};
197  double solution[6];
198  int scambio[6];
199  LinearConstraints constraints[] = {c1, c2, c3, c4, c5};
200 
201  int numpoints = points.size();
202  int numconstraints = 5;
203 
204  // fill in the matrix elements
205  for ( int i = 0; i < numpoints; ++i )
206  {
207  double xi = points[i].x;
208  double yi = points[i].y;
209  matrix[i][0] = xi*xi;
210  matrix[i][1] = yi*yi;
211  matrix[i][2] = xi*yi;
212  matrix[i][3] = xi;
213  matrix[i][4] = yi;
214  matrix[i][5] = 1.0;
215  }
216 
217  for ( int i = 0; i < numconstraints; i++ )
218  {
219  if (numpoints >= 5) break; // don't add constraints if we have enough
220  for (int j = 0; j < 6; ++j) matrix[numpoints][j] = 0.0;
221  // force the symmetry axes to be
222  // parallel to the coordinate system (zero tilt): c = 0
223  if (constraints[i] == zerotilt) matrix[numpoints][2] = 1.0;
224  // force a parabula (if zerotilt): b = 0
225  if (constraints[i] == parabolaifzt) matrix[numpoints][1] = 1.0;
226  // force a circle (if zerotilt): a = b
227  if (constraints[i] == circleifzt) {
228  matrix[numpoints][0] = 1.0;
229  matrix[numpoints][1] = -1.0; }
230  // force an equilateral hyperbola: a + b = 0
231  if (constraints[i] == equilateral) {
232  matrix[numpoints][0] = 1.0;
233  matrix[numpoints][1] = 1.0; }
234  // force symmetry about y-axis: d = 0
235  if (constraints[i] == ysymmetry) matrix[numpoints][3] = 1.0;
236  // force symmetry about x-axis: e = 0
237  if (constraints[i] == xsymmetry) matrix[numpoints][4] = 1.0;
238 
239  if (constraints[i] != noconstraint) ++numpoints;
240  }
241 
242  if ( ! GaussianElimination( matrix, numpoints, 6, scambio ) )
243  return ConicCartesianData::invalidData();
244  // fine della fase di eliminazione
245  BackwardSubstitution( matrix, numpoints, 6, scambio, solution );
246 
247  // now solution should contain the correct coefficients..
248  return ConicCartesianData( solution );
249 }
250 
251 const ConicPolarData calcConicBFFP(
252  const std::vector<Coordinate>& args,
253  int type )
254 {
255  assert( args.size() >= 2 && args.size() <= 3 );
256  assert( type == 1 || type == -1 );
257 
258  ConicPolarData ret;
259 
260  Coordinate f1 = args[0];
261  Coordinate f2 = args[1];
262  Coordinate d;
263  double eccentricity, d1, d2, dl;
264 
265  Coordinate f2f1 = f2 - f1;
266  double f2f1l = f2f1.length();
267  ret.ecostheta0 = f2f1.x / f2f1l;
268  ret.esintheta0 = f2f1.y / f2f1l;
269 
270  if ( args.size() == 3 )
271  {
272  d = args[2];
273  d1 = ( d - f1 ).length();
274  d2 = ( d - f2 ).length();
275  dl = fabs( d1 + type * d2 );
276  eccentricity = f2f1l/dl;
277  }
278  else
279  {
280  if ( type > 0 ) eccentricity = 0.7; else eccentricity = 2.0;
281  dl = f2f1l/eccentricity;
282  }
283 
284  double rhomax = (dl + f2f1l) /2.0;
285 
286  ret.ecostheta0 *= eccentricity;
287  ret.esintheta0 *= eccentricity;
288  ret.pdimen = type*(1 - eccentricity)*rhomax;
289  ret.focus1 = type == 1 ? f1 : f2;
290  return ret;
291 }
292 
293 const LineData calcConicPolarLine (
294  const ConicCartesianData& data,
295  const Coordinate& cpole,
296  bool& valid )
297 {
298  double x = cpole.x;
299  double y = cpole.y;
300  double a = data.coeffs[0];
301  double b = data.coeffs[1];
302  double c = data.coeffs[2];
303  double d = data.coeffs[3];
304  double e = data.coeffs[4];
305  double f = data.coeffs[5];
306 
307  double alpha = 2*a*x + c*y + d;
308  double beta = c*x + 2*b*y + e;
309  double gamma = d*x + e*y + 2*f;
310 
311  double normsq = alpha*alpha + beta*beta;
312 
313  if (normsq < 1e-10) // line at infinity
314  {
315  valid = false;
316  return LineData();
317  }
318  valid = true;
319 
320  Coordinate reta = -gamma/normsq * Coordinate (alpha, beta);
321  Coordinate retb = reta + Coordinate (-beta, alpha);
322  return LineData( reta, retb );
323 }
324 
325 const Coordinate calcConicPolarPoint (
326  const ConicCartesianData& data,
327  const LineData& polar )
328 {
329  Coordinate p1 = polar.a;
330  Coordinate p2 = polar.b;
331 
332  double alpha = p2.y - p1.y;
333  double beta = p1.x - p2.x;
334  double gamma = p1.y*p2.x - p1.x*p2.y;
335 
336  double a11 = data.coeffs[0];
337  double a22 = data.coeffs[1];
338  double a12 = data.coeffs[2]/2.0;
339  double a13 = data.coeffs[3]/2.0;
340  double a23 = data.coeffs[4]/2.0;
341  double a33 = data.coeffs[5];
342 
343 // double detA = a11*a22*a33 - a11*a23*a23 - a22*a13*a13 - a33*a12*a12 +
344 // 2*a12*a23*a13;
345 
346  double a11inv = a22*a33 - a23*a23;
347  double a22inv = a11*a33 - a13*a13;
348  double a33inv = a11*a22 - a12*a12;
349  double a12inv = a23*a13 - a12*a33;
350  double a23inv = a12*a13 - a23*a11;
351  double a13inv = a12*a23 - a13*a22;
352 
353  double x = a11inv*alpha + a12inv*beta + a13inv*gamma;
354  double y = a12inv*alpha + a22inv*beta + a23inv*gamma;
355  double z = a13inv*alpha + a23inv*beta + a33inv*gamma;
356 
357  if (fabs(z) < 1e-10) // point at infinity
358  {
359  return Coordinate::invalidCoord();
360  }
361 
362  x /= z;
363  y /= z;
364  return Coordinate (x, y);
365 }
366 
367 const Coordinate calcConicLineIntersect( const ConicCartesianData& c,
368  const LineData& l,
369  double knownparam,
370  int which )
371 {
372  assert( which == 1 || which == -1 || which == 0 );
373 
374  double aa = c.coeffs[0];
375  double bb = c.coeffs[1];
376  double cc = c.coeffs[2];
377  double dd = c.coeffs[3];
378  double ee = c.coeffs[4];
379  double ff = c.coeffs[5];
380 
381  double x = l.a.x;
382  double y = l.a.y;
383  double dx = l.b.x - l.a.x;
384  double dy = l.b.y - l.a.y;
385 
386  double aaa = aa*dx*dx + bb*dy*dy + cc*dx*dy;
387  double bbb = 2*aa*x*dx + 2*bb*y*dy + cc*x*dy + cc*y*dx + dd*dx + ee*dy;
388  double ccc = aa*x*x + bb*y*y + cc*x*y + dd*x + ee*y + ff;
389 
390  double t;
391  if ( which == 0 ) /* i.e. we have a known intersection */
392  {
393  t = - bbb/aaa - knownparam;
394  return l.a + t*(l.b - l.a);
395  }
396 
397  double discrim = bbb*bbb - 4*aaa*ccc;
398  if (discrim < 0.0)
399  {
400  return Coordinate::invalidCoord();
401  }
402  else
403  {
404  if ( which*bbb > 0 )
405  {
406  t = bbb + which*sqrt(discrim);
407  t = - 2*ccc/t;
408  } else {
409  t = -bbb + which*sqrt(discrim);
410  t /= 2*aaa;
411  /* mp: this threshold test for a point at infinity allows to
412  * solve Bug https://bugs.kde.org/show_bug.cgi?id=316693
413  */
414  if (fabs(t) > 1e15) return Coordinate::invalidCoord();
415  }
416 
417  return l.a + t*(l.b - l.a);
418  }
419 }
420 
421 ConicPolarData::ConicPolarData(
422  const Coordinate& f, double d,
423  double ec, double es )
424  : focus1( f ), pdimen( d ), ecostheta0( ec ), esintheta0( es )
425 {
426 }
427 
428 ConicPolarData::ConicPolarData()
429  : focus1(), pdimen( 0 ), ecostheta0( 0 ), esintheta0( 0 )
430 {
431 }
432 
433 const ConicPolarData calcConicBDFP(
434  const LineData& directrix,
435  const Coordinate& cfocus,
436  const Coordinate& cpoint )
437 {
438  ConicPolarData ret;
439 
440  Coordinate ba = directrix.dir();
441  double bal = ba.length();
442  ret.ecostheta0 = -ba.y / bal;
443  ret.esintheta0 = ba.x / bal;
444 
445  Coordinate pa = cpoint - directrix.a;
446 
447  double distpf = (cpoint - cfocus).length();
448  double distpd = ( pa.y*ba.x - pa.x*ba.y)/bal;
449 
450  double eccentricity = distpf/distpd;
451  ret.ecostheta0 *= eccentricity;
452  ret.esintheta0 *= eccentricity;
453 
454  Coordinate fa = cfocus - directrix.a;
455  ret.pdimen = ( fa.y*ba.x - fa.x*ba.y )/bal;
456  ret.pdimen *= eccentricity;
457  ret.focus1 = cfocus;
458 
459  return ret;
460 }
461 
462 ConicCartesianData::ConicCartesianData( const double incoeffs[6] )
463 {
464  std::copy( incoeffs, incoeffs + 6, coeffs );
465 }
466 
467 const LineData calcConicAsymptote(
468  const ConicCartesianData data,
469  int which, bool &valid )
470 {
471  assert( which == -1 || which == 1 );
472 
473  LineData ret;
474  double a=data.coeffs[0];
475  double b=data.coeffs[1];
476  double c=data.coeffs[2];
477  double d=data.coeffs[3];
478  double e=data.coeffs[4];
479 
480  double normabc = a*a + b*b + c*c;
481  double delta = c*c - 4*a*b;
482  if (fabs(delta) < 1e-6*normabc) { valid = false; return ret; }
483 
484  double yc = (2*a*e - c*d)/delta;
485  double xc = (2*b*d - c*e)/delta;
486  // let c be nonnegative; we no longer need d, e, f.
487  if (c < 0)
488  {
489  c *= -1;
490  a *= -1;
491  b *= -1;
492  }
493 
494  if ( delta < 0 )
495  {
496  valid = false;
497  return ret;
498  }
499 
500  double sqrtdelta = sqrt(delta);
501  Coordinate displacement;
502  if (which > 0)
503  displacement = Coordinate(-2*b, c + sqrtdelta);
504  else
505  displacement = Coordinate(c + sqrtdelta, -2*a);
506  ret.a = Coordinate(xc, yc);
507  ret.b = ret.a + displacement;
508  return ret;
509 }
510 
511 const ConicCartesianData calcConicByAsymptotes(
512  const LineData& line1,
513  const LineData& line2,
514  const Coordinate& p )
515 {
516  Coordinate p1 = line1.a;
517  Coordinate p2 = line1.b;
518  double x = p.x;
519  double y = p.y;
520 
521  double c1 = p1.x*p2.y - p2.x*p1.y;
522  double b1 = p2.x - p1.x;
523  double a1 = p1.y - p2.y;
524 
525  p1 = line2.a;
526  p2 = line2.b;
527 
528  double c2 = p1.x*p2.y - p2.x*p1.y;
529  double b2 = p2.x - p1.x;
530  double a2 = p1.y - p2.y;
531 
532  double a = a1*a2;
533  double b = b1*b2;
534  double c = a1*b2 + a2*b1;
535  double d = a1*c2 + a2*c1;
536  double e = b1*c2 + c1*b2;
537 
538  double f = a*x*x + b*y*y + c*x*y + d*x + e*y;
539  f = -f;
540 
541  return ConicCartesianData( a, b, c, d, e, f );
542 }
543 
544 const LineData calcConicRadical( const ConicCartesianData& cequation1,
545  const ConicCartesianData& cequation2,
546  int which, int zeroindex, bool& valid )
547 {
548  assert( which == 1 || which == -1 );
549  assert( 0 < zeroindex && zeroindex < 4 );
550  LineData ret;
551  valid = true;
552 
553  double a = cequation1.coeffs[0];
554  double b = cequation1.coeffs[1];
555  double c = cequation1.coeffs[2];
556  double d = cequation1.coeffs[3];
557  double e = cequation1.coeffs[4];
558  double f = cequation1.coeffs[5];
559 
560  double a2 = cequation2.coeffs[0];
561  double b2 = cequation2.coeffs[1];
562  double c2 = cequation2.coeffs[2];
563  double d2 = cequation2.coeffs[3];
564  double e2 = cequation2.coeffs[4];
565  double f2 = cequation2.coeffs[5];
566 
567 // background: the family of conics c + lambda*c2 has members that
568 // degenerate into a union of two lines. The values of lambda giving
569 // such degenerate conics is the solution of a third degree equation.
570 // The coefficients of such equation are given by:
571 // (Thanks to Dominique Devriese for the suggestion of this approach)
572 // domi: (And thanks to Maurizio for implementing it :)
573 
574  double df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
575  double cf = 4*a2*b*f + 4*a*b2*f + 4*a*b*f2
576  - 2*a*e*e2 - 2*b*d*d2 - 2*f*c*c2
577  - a2*e*e - b2*d*d - f2*c*c
578  + c2*d*e + c*d2*e + c*d*e2;
579  double bf = 4*a*b2*f2 + 4*a2*b*f2 + 4*a2*b2*f
580  - 2*a2*e2*e - 2*b2*d2*d - 2*f2*c2*c
581  - a*e2*e2 - b*d2*d2 - f*c2*c2
582  + c*d2*e2 + c2*d*e2 + c2*d2*e;
583  double af = 4*a2*b2*f2 - a2*e2*e2 - b2*d2*d2 - c2*c2*f2 + c2*d2*e2;
584 
585 // assume both conics are nondegenerate, renormalize so that af = 1
586 
587  df /= af;
588  cf /= af;
589  bf /= af;
590  af = 1.0; // not needed, just for consistency
591 
592 // computing the coefficients of the Sturm sequence
593 
594  double p1a = 2*bf*bf - 6*cf;
595  double p1b = bf*cf - 9*df;
596  double p0a = cf*p1a*p1a + p1b*(3*p1b - 2*bf*p1a);
597  double fval, fpval, lambda;
598 
599  if (p0a < 0 && p1a < 0)
600  {
601  // -+-- ---+
602  valid = false;
603  return ret;
604  }
605 
606  lambda = -bf/3.0; //inflection point
607  double displace = 1.0;
608  if (p1a > 0) // with two stationary points
609  {
610  displace += sqrt(p1a); // should be enough. The important
611  // thing is that it is larger than the
612  // semidistance between the stationary points
613  }
614  // compute the value at the inflection point using Horner scheme
615  fval = bf + lambda; // b + x
616  fval = cf + lambda*fval; // c + xb + xx
617  fval = df + lambda*fval; // d + xc + xxb + xxx
618 
619  if (fabs(p0a) < 1e-7)
620  { // this is the case if we intersect two vertical parabulas!
621  p0a = 1e-7; // fall back to the one zero case
622  }
623  if (p0a < 0)
624  {
625  // we have three roots..
626  // we select the one we want ( defined by mzeroindex.. )
627  lambda += ( 2 - zeroindex )* displace;
628  }
629  else
630  {
631  // we have just one root
632  if( zeroindex > 1 ) // cannot find second and third root
633  {
634  valid = false;
635  return ret;
636  }
637 
638  if (fval > 0) // zero on the left
639  {
640  lambda -= displace;
641  } else { // zero on the right
642  lambda += displace;
643  }
644 
645  // p0a = 0 means we have a root with multiplicity two
646  }
647 
648 //
649 // find a root of af*lambda^3 + bf*lambda^2 + cf*lambda + df = 0
650 // (use a Newton method starting from lambda = 0. Hope...)
651 //
652 
653  double delta;
654 
655  int iterations = 0;
656  const int maxiterations = 30;
657  while (iterations++ < maxiterations) // using Newton, iterations should be very few
658  {
659  // compute value of function and polinomial
660  fval = fpval = af;
661  fval = bf + lambda*fval; // b + xa
662  fpval = fval + lambda*fpval; // b + 2xa
663  fval = cf + lambda*fval; // c + xb + xxa
664  fpval = fval + lambda*fpval; // c + 2xb + 3xxa
665  fval = df + lambda*fval; // d + xc + xxb + xxxa
666 
667  delta = fval/fpval;
668  lambda -= delta;
669  if (fabs(delta) < 1e-6) break;
670  }
671  if (iterations >= maxiterations) { valid = false; return ret; }
672 
673  // now we have the degenerate conic: a, b, c, d, e, f
674 
675  a += lambda*a2;
676  b += lambda*b2;
677  c += lambda*c2;
678  d += lambda*d2;
679  e += lambda*e2;
680  f += lambda*f2;
681 
682  // domi:
683  // this is the determinant of the matrix of the new conic. It
684  // should be zero, for the new conic to be degenerate.
685  df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
686 
687  //lets work in homogeneous coordinates...
688 
689  double dis1 = e*e - 4*b*f;
690  double maxval = fabs(dis1);
691  int maxind = 1;
692  double dis2 = d*d - 4*a*f;
693  if (fabs(dis2) > maxval)
694  {
695  maxval = fabs(dis2);
696  maxind = 2;
697  }
698  double dis3 = c*c - 4*a*b;
699  if (fabs(dis3) > maxval)
700  {
701  maxval = fabs(dis3);
702  maxind = 3;
703  }
704  // one of these must be nonzero (otherwise the matrix is ...)
705  // exchange elements so that the largest is the determinant of the
706  // first 2x2 minor
707  double temp;
708  switch (maxind)
709  {
710  case 1: // exchange 1 <-> 3
711  temp = a; a = f; f = temp;
712  temp = c; c = e; e = temp;
713  temp = dis1; dis1 = dis3; dis3 = temp;
714  break;
715 
716  case 2: // exchange 2 <-> 3
717  temp = b; b = f; f = temp;
718  temp = c; c = d; d = temp;
719  temp = dis2; dis2 = dis3; dis3 = temp;
720  break;
721  }
722 
723  // domi:
724  // this is the negative of the determinant of the top left of the
725  // matrix. If it is 0, then the conic is a parabola, if it is < 0,
726  // then the conic is an ellipse, if positive, the conic is a
727  // hyperbola. In this case, it should be positive, since we have a
728  // degenerate conic, which is a degenerate case of a hyperbola..
729  // note that it is negative if there is no valid conic to be
730  // found ( e.g. not enough intersections.. )
731  // double discrim = c*c - 4*a*b;
732 
733  if (dis3 < 0)
734  {
735  // domi:
736  // i would put an assertion here, but well, i guess it doesn't
737  // really matter, and this prevents crashes if the math i still
738  // recall from high school happens to be wrong :)
739  valid = false;
740  return ret;
741  };
742 
743  double r[3]; // direction of the null space
744  r[0] = 2*b*d - c*e;
745  r[1] = 2*a*e - c*d;
746  r[2] = dis3;
747 
748  // now remember the switch:
749  switch (maxind)
750  {
751  case 1: // exchange 1 <-> 3
752  temp = a; a = f; f = temp;
753  temp = c; c = e; e = temp;
754  temp = dis1; dis1 = dis3; dis3 = temp;
755  temp = r[0]; r[0] = r[2]; r[2] = temp;
756  break;
757 
758  case 2: // exchange 2 <-> 3
759  temp = b; b = f; f = temp;
760  temp = c; c = d; d = temp;
761  temp = dis2; dis2 = dis3; dis3 = temp;
762  temp = r[1]; r[1] = r[2]; r[2] = temp;
763  break;
764  }
765 
766  // Computing a Householder reflection transformation that
767  // maps r onto [0, 0, k]
768 
769  double w[3];
770  double rnormsq = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
771  double k = sqrt( rnormsq );
772  if ( k*r[2] < 0) k = -k;
773  double wnorm = sqrt( 2*rnormsq + 2*k*r[2] );
774  w[0] = r[0]/wnorm;
775  w[1] = r[1]/wnorm;
776  w[2] = (r[2] + k)/wnorm;
777 
778  // matrix transformation using Householder matrix, the resulting
779  // matrix is zero on third row and column
780  // [q0,q1,q2]^t = A w
781  // alpha = w^t A w
782  double q0 = a*w[0] + c*w[1]/2 + d*w[2]/2;
783  double q1 = b*w[1] + c*w[0]/2 + e*w[2]/2;
784  double alpha = a*w[0]*w[0] + b*w[1]*w[1] + c*w[0]*w[1] +
785  d*w[0]*w[2] + e*w[1]*w[2] + f*w[2]*w[2];
786  double a00 = a - 4*w[0]*q0 + 4*w[0]*w[0]*alpha;
787  double a11 = b - 4*w[1]*q1 + 4*w[1]*w[1]*alpha;
788  double a01 = c/2 - 2*w[1]*q0 - 2*w[0]*q1 + 4*w[0]*w[1]*alpha;
789 
790  double dis = a01*a01 - a00*a11;
791  assert ( dis >= 0 );
792  double sqrtdis = sqrt( dis );
793  double px, py;
794  if ( which*a01 > 0 )
795  {
796  px = a01 + which*sqrtdis;
797  py = a11;
798  } else {
799  px = a00;
800  py = a01 - which*sqrtdis;
801  }
802  double p[3]; // vector orthogonal to one of the two planes
803  double pscalw = w[0]*px + w[1]*py;
804  p[0] = px - 2*pscalw*w[0];
805  p[1] = py - 2*pscalw*w[1];
806  p[2] = - 2*pscalw*w[2];
807 
808  // "r" is the solution of the equation A*(x,y,z) = (0,0,0) where
809  // A is the matrix of the degenerate conic. This is what we
810  // called in the conic theory we saw in high school a "double
811  // point". It has the unique property that any line going through
812  // it is a "polar line" of the conic at hand. It only exists for
813  // degenerate conics. It has another unique property that if you
814  // take any other point on the conic, then the line between it and
815  // the double point is part of the conic.
816  // this is what we use here: we find the double point ( ret.a
817  // ), and then find another points on the conic.
818 
819  ret.a = -p[2]/(p[0]*p[0] + p[1]*p[1]) * Coordinate (p[0],p[1]);
820  ret.b = ret.a + Coordinate (-p[1],p[0]);
821  valid = true;
822 
823  return ret;
824 }
825 
826 const ConicCartesianData calcConicTransformation (
827  const ConicCartesianData& data, const Transformation& t, bool& valid )
828 {
829  double a[3][3];
830  double b[3][3];
831 
832  a[1][1] = data.coeffs[0];
833  a[2][2] = data.coeffs[1];
834  a[1][2] = a[2][1] = data.coeffs[2]/2;
835  a[0][1] = a[1][0] = data.coeffs[3]/2;
836  a[0][2] = a[2][0] = data.coeffs[4]/2;
837  a[0][0] = data.coeffs[5];
838 
839  Transformation ti = t.inverse( valid );
840  if ( ! valid ) return ConicCartesianData();
841 
842  double supnorm = 0.0;
843  for (int i = 0; i < 3; i++)
844  {
845  for (int j = 0; j < 3; j++)
846  {
847  b[i][j] = 0.;
848  for (int ii = 0; ii < 3; ii++)
849  {
850  for (int jj = 0; jj < 3; jj++)
851  {
852  b[i][j] += a[ii][jj]*ti.data( ii, i )*ti.data( jj, j );
853  }
854  }
855  if ( std::fabs( b[i][j] ) > supnorm ) supnorm = std::fabs( b[i][j] );
856  }
857  }
858 
859  for (int i = 0; i < 3; i++)
860  {
861  for (int j = 0; j < 3; j++)
862  {
863  b[i][j] /= supnorm;
864  }
865  }
866 
867  return ConicCartesianData ( b[1][1], b[2][2], b[1][2] + b[2][1],
868  b[0][1] + b[1][0], b[0][2] + b[2][0], b[0][0] );
869 }
870 
871 ConicCartesianData::ConicCartesianData()
872 {
873 }
874 
875 bool operator==( const ConicPolarData& lhs, const ConicPolarData& rhs )
876 {
877  return lhs.focus1 == rhs.focus1 &&
878  lhs.pdimen == rhs.pdimen &&
879  lhs.ecostheta0 == rhs.ecostheta0 &&
880  lhs.esintheta0 == rhs.esintheta0;
881 }
882 
883 ConicCartesianData ConicCartesianData::invalidData()
884 {
885  ConicCartesianData ret;
886  ret.coeffs[0] = double_inf;
887  return ret;
888 }
889 
890 bool ConicCartesianData::valid() const
891 {
892  return finite( coeffs[0] );
893 }
894 
calcConicPolarLine
const LineData calcConicPolarLine(const ConicCartesianData &data, const Coordinate &cpole, bool &valid)
This function calculates the polar line of the point cpole with respect to the given conic data...
Definition: conic-common.cpp:293
LinearConstraints
LinearConstraints
These are the constraint values that can be passed to the calcConicThroughPoints function.
Definition: conic-common.h:137
ConicPolarData::esintheta0
double esintheta0
The esintheta0 value from the polar equation.
Definition: conic-common.h:118
LineData
Simple class representing a line.
Definition: misc/common.h:49
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
ConicPolarData::ConicPolarData
ConicPolarData()
Definition: conic-common.cpp:428
calcConicAsymptote
const LineData calcConicAsymptote(const ConicCartesianData data, int which, bool &valid)
This function calculates the asymptote of the given conic ( data ).
Definition: conic-common.cpp:467
ConicCartesianData
Cartesian Conic Data.
Definition: conic-common.h:37
calcConicThroughPoints
const ConicCartesianData calcConicThroughPoints(const std::vector< Coordinate > &points, const LinearConstraints c1, const LinearConstraints c2, const LinearConstraints c3, const LinearConstraints c4, const LinearConstraints c5)
Calculate a conic through a given set of points.
Definition: conic-common.cpp:169
calcConicPolarPoint
const Coordinate calcConicPolarPoint(const ConicCartesianData &data, const LineData &polar)
This function calculates the polar point of the line polar with respect to the given conic data...
Definition: conic-common.cpp:325
circleifzt
Definition: conic-common.h:138
ConicCartesianData::invalidData
static ConicCartesianData invalidData()
Invalid conic.
Definition: conic-common.cpp:883
ConicCartesianData::coeffs
double coeffs[6]
Definition: conic-common.h:40
parabolaifzt
Definition: conic-common.h:138
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
equilateral
Definition: conic-common.h:139
calcConicBDFP
const ConicPolarData calcConicBDFP(const LineData &directrix, const Coordinate &cfocus, const Coordinate &cpoint)
function used by ConicBDFP.
Definition: conic-common.cpp:433
calcConicLineIntersect
const Coordinate calcConicLineIntersect(const ConicCartesianData &c, const LineData &l, double knownparam, int which)
This function calculates the intersection of a given line ( l ) and a given conic ( c )...
Definition: conic-common.cpp:367
xsymmetry
Definition: conic-common.h:139
conic-common.h
Transformation
Class representing a transformation.
Definition: kigtransform.h:37
ConicPolarData::focus1
Coordinate focus1
The first focus of this conic.
Definition: conic-common.h:106
calcConicRadical
const LineData calcConicRadical(const ConicCartesianData &cequation1, const ConicCartesianData &cequation2, int which, int zeroindex, bool &valid)
This function calculates the radical line of two conics.
Definition: conic-common.cpp:544
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
ConicPolarData::pdimen
double pdimen
The pdimen value from the polar equation.
Definition: conic-common.h:110
ConicPolarData::ecostheta0
double ecostheta0
The ecostheta0 value from the polar equation.
Definition: conic-common.h:114
ysymmetry
Definition: conic-common.h:139
common.h
kigtransform.h
Coordinate::invalidCoord
static Coordinate invalidCoord()
Create an invalid Coordinate.
Definition: coordinate.cpp:171
double_inf
const double double_inf
Definition: common.cpp:509
ConicCartesianData::ConicCartesianData
ConicCartesianData()
Definition: conic-common.cpp:871
calcConicBFFP
const ConicPolarData calcConicBFFP(const std::vector< Coordinate > &args, int type)
This function is used by ConicBFFP.
Definition: conic-common.cpp:251
operator==
bool operator==(const ConicPolarData &lhs, const ConicPolarData &rhs)
Definition: conic-common.cpp:875
noconstraint
Definition: conic-common.h:138
calcConicByAsymptotes
const ConicCartesianData calcConicByAsymptotes(const LineData &line1, const LineData &line2, const Coordinate &p)
This calcs the hyperbola defined by its two asymptotes line1 and line2, and a point p on the edge...
Definition: conic-common.cpp:511
ConicCartesianData::valid
bool valid() const
Test validity.
Definition: conic-common.cpp:890
Transformation::data
double data(int r, int c) const
Definition: kigtransform.cpp:732
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
zerotilt
Definition: conic-common.h:138
Coordinate::y
double y
Y Component.
Definition: coordinate.h:129
calcConicTransformation
const ConicCartesianData calcConicTransformation(const ConicCartesianData &data, const Transformation &t, bool &valid)
This calculates the image of the given conic ( data ) through the given transformation ( t )...
Definition: conic-common.cpp:826
ConicPolarData
This class represents an equation of a conic in the form .
Definition: conic-common.h:85
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