• 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
cubic-common.cc
Go to the documentation of this file.
1 // Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
2 
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.
7 
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.
12 
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., 51 Franklin Street, Fifth Floor, Boston, MA
16 // 02110-1301, USA.
17 
18 #include "cubic-common.h"
19 #include "kignumerics.h"
20 #include "kigtransform.h"
21 
22 #include <config-kig.h>
23 
24 #ifdef HAVE_IEEEFP_H
25 #include <ieeefp.h>
26 #endif
27 
28 /*
29  * coefficients of the cartesian equation for cubics
30  */
31 
32 CubicCartesianData::CubicCartesianData()
33 {
34  std::fill( coeffs, coeffs + 10, 0 );
35 }
36 
37 CubicCartesianData::CubicCartesianData(
38  const double incoeffs[10] )
39 {
40  std::copy( incoeffs, incoeffs + 10, coeffs );
41  normalize();
42 }
43 
44 void CubicCartesianData::normalize()
45 {
46  double norm = 0.0;
47  for ( int i = 0; i < 10; ++i )
48  {
49  if ( std::fabs( coeffs[i] ) > norm ) norm = std::fabs( coeffs[i] );
50  }
51  if ( norm < 1e-8 ) return;
52  for ( int i = 0; i < 10; ++i )
53  {
54  coeffs[i] /= norm;
55  }
56 }
57 
58 const CubicCartesianData calcCubicThroughPoints (
59  const std::vector<Coordinate>& points )
60 {
61  // points is a vector of at most 9 points through which the cubic is
62  // constrained.
63  // this routine should compute the coefficients in the cartesian equation
64  // they are defined up to a multiplicative factor.
65  // since we don't know (in advance) which one of them is nonzero, we
66  // simply keep all 10 parameters, obtaining a 9x10 linear system which
67  // we solve using gaussian elimination with complete pivoting
68  // If there are too few, then we choose some cool way to fill in the
69  // empty parts in the matrix according to the LinearConstraints
70  // given..
71 
72  // 9 rows, 10 columns..
73  double row0[10];
74  double row1[10];
75  double row2[10];
76  double row3[10];
77  double row4[10];
78  double row5[10];
79  double row6[10];
80  double row7[10];
81  double row8[10];
82  double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
83  double solution[10];
84  int scambio[10];
85 
86  int numpoints = points.size();
87  int numconstraints = 9;
88 
89  // fill in the matrix elements
90  for ( int i = 0; i < numpoints; ++i )
91  {
92  double xi = points[i].x;
93  double yi = points[i].y;
94  matrix[i][0] = 1.0;
95  matrix[i][1] = xi;
96  matrix[i][2] = yi;
97  matrix[i][3] = xi*xi;
98  matrix[i][4] = xi*yi;
99  matrix[i][5] = yi*yi;
100  matrix[i][6] = xi*xi*xi;
101  matrix[i][7] = xi*xi*yi;
102  matrix[i][8] = xi*yi*yi;
103  matrix[i][9] = yi*yi*yi;
104  }
105 
106  for ( int i = 0; i < numconstraints; i++ )
107  {
108  if (numpoints >= 9) break; // don't add constraints if we have enough
109  for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
110  bool addedconstraint = true;
111  switch (i)
112  {
113  case 0:
114  matrix[numpoints][7] = 1.0;
115  matrix[numpoints][8] = -1.0;
116  break;
117  case 1:
118  matrix[numpoints][7] = 1.0;
119  break;
120  case 2:
121  matrix[numpoints][9] = 1.0;
122  break;
123  case 3:
124  matrix[numpoints][4] = 1.0;
125  break;
126  case 4:
127  matrix[numpoints][5] = 1.0;
128  break;
129  case 5:
130  matrix[numpoints][3] = 1.0;
131  break;
132  case 6:
133  matrix[numpoints][1] = 1.0;
134  break;
135 
136  default:
137  addedconstraint = false;
138  break;
139  }
140 
141  if (addedconstraint) ++numpoints;
142  }
143 
144  if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
145  return CubicCartesianData::invalidData();
146  // fine della fase di eliminazione
147  BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
148 
149  // now solution should contain the correct coefficients..
150  return CubicCartesianData( solution );
151 }
152 
153 const CubicCartesianData calcCubicCuspThroughPoints (
154  const std::vector<Coordinate>& points )
155 {
156  // points is a vector of at most 4 points through which the cubic is
157  // constrained. Moreover the cubic is required to have a cusp at the
158  // origin.
159 
160  // 9 rows, 10 columns..
161  double row0[10];
162  double row1[10];
163  double row2[10];
164  double row3[10];
165  double row4[10];
166  double row5[10];
167  double row6[10];
168  double row7[10];
169  double row8[10];
170  double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
171  double solution[10];
172  int scambio[10];
173 
174  int numpoints = points.size();
175  int numconstraints = 9;
176 
177  // fill in the matrix elements
178  for ( int i = 0; i < numpoints; ++i )
179  {
180  double xi = points[i].x;
181  double yi = points[i].y;
182  matrix[i][0] = 1.0;
183  matrix[i][1] = xi;
184  matrix[i][2] = yi;
185  matrix[i][3] = xi*xi;
186  matrix[i][4] = xi*yi;
187  matrix[i][5] = yi*yi;
188  matrix[i][6] = xi*xi*xi;
189  matrix[i][7] = xi*xi*yi;
190  matrix[i][8] = xi*yi*yi;
191  matrix[i][9] = yi*yi*yi;
192  }
193 
194  for ( int i = 0; i < numconstraints; i++ )
195  {
196  if (numpoints >= 9) break; // don't add constraints if we have enough
197  for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
198  bool addedconstraint = true;
199  switch (i)
200  {
201  case 0:
202  matrix[numpoints][0] = 1.0; // through the origin
203  break;
204  case 1:
205  matrix[numpoints][1] = 1.0;
206  break;
207  case 2:
208  matrix[numpoints][2] = 1.0; // no first degree term
209  break;
210  case 3:
211  matrix[numpoints][3] = 1.0; // a011 (x^2 coeff) = 0
212  break;
213  case 4:
214  matrix[numpoints][4] = 1.0; // a012 (xy coeff) = 0
215  break;
216  case 5:
217  matrix[numpoints][7] = 1.0;
218  matrix[numpoints][8] = -1.0;
219  break;
220  case 6:
221  matrix[numpoints][7] = 1.0;
222  break;
223  case 7:
224  matrix[numpoints][9] = 1.0;
225  break;
226  case 8:
227  matrix[numpoints][6] = 1.0;
228  break;
229 
230  default:
231  addedconstraint = false;
232  break;
233  }
234 
235  if (addedconstraint) ++numpoints;
236  }
237 
238  if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
239  return CubicCartesianData::invalidData();
240  // fine della fase di eliminazione
241  BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
242 
243  // now solution should contain the correct coefficients..
244  return CubicCartesianData( solution );
245 }
246 
247 const CubicCartesianData calcCubicNodeThroughPoints (
248  const std::vector<Coordinate>& points )
249 {
250  // points is a vector of at most 6 points through which the cubic is
251  // constrained. Moreover the cubic is required to have a node at the
252  // origin.
253 
254  // 9 rows, 10 columns..
255  double row0[10];
256  double row1[10];
257  double row2[10];
258  double row3[10];
259  double row4[10];
260  double row5[10];
261  double row6[10];
262  double row7[10];
263  double row8[10];
264  double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
265  double solution[10];
266  int scambio[10];
267 
268  int numpoints = points.size();
269  int numconstraints = 9;
270 
271  // fill in the matrix elements
272  for ( int i = 0; i < numpoints; ++i )
273  {
274  double xi = points[i].x;
275  double yi = points[i].y;
276  matrix[i][0] = 1.0;
277  matrix[i][1] = xi;
278  matrix[i][2] = yi;
279  matrix[i][3] = xi*xi;
280  matrix[i][4] = xi*yi;
281  matrix[i][5] = yi*yi;
282  matrix[i][6] = xi*xi*xi;
283  matrix[i][7] = xi*xi*yi;
284  matrix[i][8] = xi*yi*yi;
285  matrix[i][9] = yi*yi*yi;
286  }
287 
288  for ( int i = 0; i < numconstraints; i++ )
289  {
290  if (numpoints >= 9) break; // don't add constraints if we have enough
291  for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
292  bool addedconstraint = true;
293  switch (i)
294  {
295  case 0:
296  matrix[numpoints][0] = 1.0;
297  break;
298  case 1:
299  matrix[numpoints][1] = 1.0;
300  break;
301  case 2:
302  matrix[numpoints][2] = 1.0;
303  break;
304  case 3:
305  matrix[numpoints][7] = 1.0;
306  matrix[numpoints][8] = -1.0;
307  break;
308  case 4:
309  matrix[numpoints][7] = 1.0;
310  break;
311  case 5:
312  matrix[numpoints][9] = 1.0;
313  break;
314  case 6:
315  matrix[numpoints][4] = 1.0;
316  break;
317  case 7:
318  matrix[numpoints][5] = 1.0;
319  break;
320  case 8:
321  matrix[numpoints][3] = 1.0;
322  break;
323 
324  default:
325  addedconstraint = false;
326  break;
327  }
328 
329  if (addedconstraint) ++numpoints;
330  }
331 
332  if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
333  return CubicCartesianData::invalidData();
334  // fine della fase di eliminazione
335  BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
336 
337  // now solution should contain the correct coefficients..
338  return CubicCartesianData( solution );
339 }
340 
341 /*
342  * computation of the y value corresponding to some x value
343  */
344 
345 double calcCubicYvalue ( double x, double ymin, double ymax, int root,
346  CubicCartesianData data, bool& valid,
347  int &numroots )
348 {
349  valid = true;
350 
351  // compute the third degree polinomial:
352  double a000 = data.coeffs[0];
353  double a001 = data.coeffs[1];
354  double a002 = data.coeffs[2];
355  double a011 = data.coeffs[3];
356  double a012 = data.coeffs[4];
357  double a022 = data.coeffs[5];
358  double a111 = data.coeffs[6];
359  double a112 = data.coeffs[7];
360  double a122 = data.coeffs[8];
361  double a222 = data.coeffs[9];
362 
363  // first the y^3 coefficient, it coming only from a222:
364  double a = a222;
365  // next the y^2 coefficient (from a122 and a022):
366  double b = a122*x + a022;
367  // next the y coefficient (from a112, a012 and a002):
368  double c = a112*x*x + a012*x + a002;
369  // finally the constant coefficient (from a111, a011, a001 and a000):
370  double d = a111*x*x*x + a011*x*x + a001*x + a000;
371 
372  return calcCubicRoot ( ymin, ymax, a, b, c, d, root, valid, numroots );
373 }
374 
375 const Coordinate calcCubicLineIntersect( const CubicCartesianData& cu,
376  const LineData& l,
377  int root, bool& valid )
378 {
379  assert( root == 1 || root == 2 || root == 3 );
380 
381  double a, b, c, d;
382  calcCubicLineRestriction ( cu, l.a, l.b-l.a, a, b, c, d );
383  int numroots;
384  double param =
385  calcCubicRoot ( -1e10, 1e10, a, b, c, d, root, valid, numroots );
386  return l.a + param*(l.b - l.a);
387 }
388 
389 /*
390  * calculate the cubic polynomial resulting from the restriction
391  * of a cubic to a line (defined by two "Coordinates": a point and a
392  * direction)
393  */
394 
395 void calcCubicLineRestriction ( CubicCartesianData data,
396  Coordinate p, Coordinate v,
397  double& a, double& b, double& c, double& d )
398 {
399  a = b = c = d = 0;
400 
401  double a000 = data.coeffs[0];
402  double a001 = data.coeffs[1];
403  double a002 = data.coeffs[2];
404  double a011 = data.coeffs[3];
405  double a012 = data.coeffs[4];
406  double a022 = data.coeffs[5];
407  double a111 = data.coeffs[6];
408  double a112 = data.coeffs[7];
409  double a122 = data.coeffs[8];
410  double a222 = data.coeffs[9];
411 
412  // zero degree term
413  d += a000;
414 
415  // first degree terms
416  d += a001*p.x + a002*p.y;
417  c += a001*v.x + a002*v.y;
418 
419  // second degree terms
420  d += a011*p.x*p.x + a012*p.x*p.y + a022*p.y*p.y;
421  c += 2*a011*p.x*v.x + a012*(p.x*v.y + v.x*p.y) + 2*a022*p.y*v.y;
422  b += a011*v.x*v.x + a012*v.x*v.y + a022*v.y*v.y;
423 
424  // third degree terms: a111 x^3 + a222 y^3
425  d += a111*p.x*p.x*p.x + a222*p.y*p.y*p.y;
426  c += 3*(a111*p.x*p.x*v.x + a222*p.y*p.y*v.y);
427  b += 3*(a111*p.x*v.x*v.x + a222*p.y*v.y*v.y);
428  a += a111*v.x*v.x*v.x + a222*v.y*v.y*v.y;
429 
430  // third degree terms: a112 x^2 y + a122 x y^2
431  d += a112*p.x*p.x*p.y + a122*p.x*p.y*p.y;
432  c += a112*(p.x*p.x*v.y + 2*p.x*v.x*p.y) + a122*(v.x*p.y*p.y + 2*p.x*p.y*v.y);
433  b += a112*(v.x*v.x*p.y + 2*v.x*p.x*v.y) + a122*(p.x*v.y*v.y + 2*v.x*v.y*p.y);
434  a += a112*v.x*v.x*v.y + a122*v.x*v.y*v.y;
435 }
436 
437 
438 const CubicCartesianData calcCubicTransformation (
439  const CubicCartesianData& data,
440  const Transformation& t, bool& valid )
441 {
442  double a[3][3][3];
443  double b[3][3][3];
444  CubicCartesianData dataout;
445 
446  int icount = 0;
447  for (int i=0; i < 3; i++)
448  {
449  for (int j=i; j < 3; j++)
450  {
451  for (int k=j; k < 3; k++)
452  {
453  a[i][j][k] = data.coeffs[icount++];
454  if ( i < k )
455  {
456  if ( i == j ) // case aiik
457  {
458  a[i][i][k] /= 3.;
459  a[i][k][i] = a[k][i][i] = a[i][i][k];
460  }
461  else if ( j == k ) // case aijj
462  {
463  a[i][j][j] /= 3.;
464  a[j][i][j] = a[j][j][i] = a[i][j][j];
465  }
466  else // case aijk (i<j<k)
467  {
468  a[i][j][k] /= 6.;
469  a[i][k][j] = a[j][i][k] = a[j][k][i] =
470  a[k][i][j] = a[k][j][i] = a[i][j][k];
471  }
472  }
473  }
474  }
475  }
476 
477  Transformation ti = t.inverse( valid );
478  if ( ! valid ) return dataout;
479 
480  for (int i = 0; i < 3; i++)
481  {
482  for (int j = 0; j < 3; j++)
483  {
484  for (int k = 0; k < 3; k++)
485  {
486  b[i][j][k] = 0.;
487  for (int ii = 0; ii < 3; ii++)
488  {
489  for (int jj = 0; jj < 3; jj++)
490  {
491  for (int kk = 0; kk < 3; kk++)
492  {
493  b[i][j][k] += a[ii][jj][kk]*ti.data( ii, i )*ti.data( jj, j )*ti.data( kk, k );
494  }
495  }
496  }
497  }
498  }
499  }
500 
501 // assert (fabs(b[0][1][2] - b[1][2][0]) < 1e-8); // test a couple of cases
502 // assert (fabs(b[0][1][1] - b[1][1][0]) < 1e-8);
503 
504  // apparently, the above assertions are wrong ( due to rounding
505  // errors, Maurizio and I hope :) ), so since the symmetry is not
506  // present, we just take the sum of the parts of the matrix elements
507  // that should be symmetric, instead of taking one of them, and
508  // multiplying it..
509 
510  dataout.coeffs[0] = b[0][0][0];
511  dataout.coeffs[1] = b[0][0][1] + b[0][1][0] + b[1][0][0];
512  dataout.coeffs[2] = b[0][0][2] + b[0][2][0] + b[2][0][0];
513  dataout.coeffs[3] = b[0][1][1] + b[1][0][1] + b[1][1][0];
514  dataout.coeffs[4] = b[0][1][2] + b[0][2][1] + b[1][2][0] + b[1][0][2] + b[2][1][0] + b[2][0][1];
515  dataout.coeffs[5] = b[0][2][2] + b[2][0][2] + b[2][2][0];
516  dataout.coeffs[6] = b[1][1][1];
517  dataout.coeffs[7] = b[1][1][2] + b[1][2][1] + b[2][1][1];
518  dataout.coeffs[8] = b[1][2][2] + b[2][1][2] + b[2][2][1];
519  dataout.coeffs[9] = b[2][2][2];
520 
521  return dataout;
522 }
523 
524 bool operator==( const CubicCartesianData& lhs, const CubicCartesianData& rhs )
525 {
526  for ( int i = 0; i < 10; ++i )
527  if ( lhs.coeffs[i] != rhs.coeffs[i] )
528  return false;
529  return true;
530 }
531 
532 CubicCartesianData CubicCartesianData::invalidData()
533 {
534  CubicCartesianData ret;
535  ret.coeffs[0] = double_inf;
536  return ret;
537 }
538 
539 bool CubicCartesianData::valid() const
540 {
541  return finite( coeffs[0] );
542 }
calcCubicLineRestriction
void calcCubicLineRestriction(CubicCartesianData data, Coordinate p, Coordinate v, double &a, double &b, double &c, double &d)
Definition: cubic-common.cc:395
CubicCartesianData::coeffs
double coeffs[10]
Definition: cubic-common.h:34
calcCubicRoot
double calcCubicRoot(double xmin, double xmax, double a, double b, double c, double d, int root, bool &valid, int &numroots)
This file is part of Kig, a KDE program for Interactive Geometry...
Definition: kignumerics.cpp:32
calcCubicCuspThroughPoints
const CubicCartesianData calcCubicCuspThroughPoints(const std::vector< Coordinate > &points)
Definition: cubic-common.cc:153
LineData
Simple class representing a line.
Definition: misc/common.h:49
LineData::b
Coordinate b
Another point on the line.
Definition: misc/common.h:68
CubicCartesianData::CubicCartesianData
CubicCartesianData()
Default Constructor.
Definition: cubic-common.cc:32
Coordinate
The Coordinate class is the basic class representing a 2D location by its x and y components...
Definition: coordinate.h:33
GaussianElimination
bool GaussianElimination(double *matrix[], int numrows, int numcols, int exchange[])
Gaussian Elimination.
Definition: kignumerics.cpp:271
cubic-common.h
calcCubicYvalue
double calcCubicYvalue(double x, double ymin, double ymax, int root, CubicCartesianData data, bool &valid, int &numroots)
Definition: cubic-common.cc:345
Transformation
Class representing a transformation.
Definition: kigtransform.h:37
CubicCartesianData::valid
bool valid() const
Return whether this is a valid CubicCartesianData.
Definition: cubic-common.cc:539
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
CubicCartesianData
This class represents an equation of a cubic in the form (in homogeneous coordinates, ), .
Definition: cubic-common.h:31
kigtransform.h
double_inf
const double double_inf
Definition: common.cpp:509
calcCubicNodeThroughPoints
const CubicCartesianData calcCubicNodeThroughPoints(const std::vector< Coordinate > &points)
Definition: cubic-common.cc:247
calcCubicLineIntersect
const Coordinate calcCubicLineIntersect(const CubicCartesianData &cu, const LineData &l, int root, bool &valid)
Definition: cubic-common.cc:375
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
Coordinate::y
double y
Y Component.
Definition: coordinate.h:129
kignumerics.h
calcCubicThroughPoints
const CubicCartesianData calcCubicThroughPoints(const std::vector< Coordinate > &points)
This function calcs a cartesian cubic equation such that the given points are on the cubic...
Definition: cubic-common.cc:58
CubicCartesianData::normalize
void normalize()
Definition: cubic-common.cc:44
operator==
bool operator==(const CubicCartesianData &lhs, const CubicCartesianData &rhs)
Definition: cubic-common.cc:524
CubicCartesianData::invalidData
static CubicCartesianData invalidData()
Create an invalid CubicCartesianData.
Definition: cubic-common.cc:532
calcCubicTransformation
const CubicCartesianData calcCubicTransformation(const CubicCartesianData &data, const Transformation &t, bool &valid)
Definition: cubic-common.cc:438
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