PRAgMaTIc  master
generate_Steiner_ellipse_3d.py
Go to the documentation of this file.
1 from __future__ import print_function
2 from sympy import *
3 import sys
4 
5 # Lets work this out symbolically first and perform python unit test.
6 
7 # From http://en.wikipedia.org/wiki/Steiner_ellipse
8 x1=symbols('x1[:3]')
9 x2=symbols('x2[:3]')
10 x3=symbols('x3[:3]')
11 x4=symbols('x4[:3]')
12 
13 Mij=symbols('Mij[:36]')
14 
15 M = Matrix([
16  [(x1[0] - x2[0])**2, (x1[1] - x2[1])**2, (x1[2] - x2[2])**2, (x1[1] - x2[1])*(x1[2] - x2[2]), (x1[0] - x2[0])*(x1[2] - x2[2]), (x1[0] - x2[0])*(x1[1] - x2[1])],
17  [(x2[0] - x3[0])**2, (x2[1] - x3[1])**2, (x2[2] - x3[2])**2, (x2[1] - x3[1])*(x2[2] - x3[2]), (x2[0] - x3[0])*(x2[2] - x3[2]), (x2[0] - x3[0])*(x2[1] - x3[1])],
18  [(x3[0] - x1[0])**2, (x3[1] - x1[1])**2, (x3[2] - x1[2])**2, (x3[1] - x1[1])*(x3[2] - x1[2]), (x3[0] - x1[0])*(x3[2] - x1[2]), (x3[0] - x1[0])*(x3[1] - x1[1])],
19  [(x1[0] - x4[0])**2, (x1[1] - x4[1])**2, (x1[2] - x4[2])**2, (x1[1] - x4[1])*(x1[2] - x4[2]), (x1[0] - x4[0])*(x1[2] - x4[2]), (x1[0] - x4[0])*(x1[1] - x4[1])],
20  [(x2[0] - x4[0])**2, (x2[1] - x4[1])**2, (x2[2] - x4[2])**2, (x2[1] - x4[1])*(x2[2] - x4[2]), (x2[0] - x4[0])*(x2[2] - x4[2]), (x2[0] - x4[0])*(x2[1] - x4[1])],
21  [(x3[0] - x4[0])**2, (x3[1] - x4[1])**2, (x3[2] - x4[2])**2, (x3[1] - x4[1])*(x3[2] - x4[2]), (x3[0] - x4[0])*(x3[2] - x4[2]), (x3[0] - x4[0])*(x3[1] - x4[1])]])
22 
23 R=Matrix([[1], [1], [1], [1], [1], [1]])
24 
25 # http://en.wikipedia.org/wiki/Tetrahedron#Formulas_for_a_regular_tetrahedron
26 tetrahedron = {x1[0]:1, x1[1]:0, x1[2]:-4/sqrt(2),
27  x2[0]:-1, x2[1]:0, x2[2]:-4/sqrt(2),
28  x3[0]:0, x3[1]:2, x3[2]:4/sqrt(2),
29  x4[0]:0, x4[1]:-2, x4[2]:4/sqrt(2)}
30 
31 Mi = M.evalf(subs=tetrahedron)
32 
33 Sxx, Syy, Szz, Syz, Sxz, Sxy = Mi.inv()*R
34 
35 SteinerEllipse = Matrix([
36  [Sxx, Sxy, Sxz],
37  [Sxy, Syy, Syz],
38  [Sxz, Syz, Szz]])
39 
40 print("SteinerEllipse = ")
41 pprint(SteinerEllipse)
42 
43 if Sxx==1./2**2 and Syy==1./4**2 and Szz==1./8**2 and Syz==0.0 and Sxz==0.0 and Sxy==0.0:
44  print("pass")
45 else:
46  print("fail")
47  sys.exit(-1)
48 
49 # Move onto code generation.
50 
51 pyname=sys.argv[0].split('/')[-1]
52 
53 # Write header file
54 hname=pyname[:-3]+".h"
55 macro = pyname[:-3].upper()+"_H"
56 header="""/* Start of code generated by %s. Warning - be careful about modifying
57 any of the generated code directly. Any changes/fixes should be done
58 in the code generation script generation.*/\n
59 
60 #ifndef %s
61 #define %s
62 
63 namespace pragmatic
64 {
65 
66 void generate_Steiner_ellipse(const double *x1, const double *x2, const double *x3, const double *x4, double *sm);
67 
68 }
69 
70 #endif
71 """%(pyname, macro, macro)
72 
73 hfile = open(hname, 'w')
74 hfile.write(header)
75 hfile.close()
76 
77 # Write source file
78 cxxname=pyname[:-3]+".cpp"
79 
80 src="""
81 /* Start of code generated by %s. Warning - be careful about modifying
82  any of the generated code directly. Any changes/fixes should be done
83  in the code generation script generation.
84  */
85 
86 #include <Eigen/Core>
87 #include <Eigen/Dense>
88 
89 #include <%s>
90 
91 """%(pyname, hname)
92 
93 src += """
94 void pragmatic::generate_Steiner_ellipse(const double *x1, const double *x2, const double *x3, const double *x4, double *sm){
95  // # From http://en.wikipedia.org/wiki/Steiner_ellipse
96 
97  Eigen::Matrix<double, 6, 6> M;
98 
99  M <<"""
100 for i in range(6):
101  for j in range(6):
102  src+=ccode(M[i,j], contract=False)
103  if not (i==5 and j==5):
104  src+=", "
105  if i==5:
106  src+=";\n"
107  else:
108  src+="\n"
109 src+="""
110  Eigen::Matrix<double, 6, 1> R;
111  R<<1,1,1,1,1,1;
112  Eigen::Matrix<double, 6, 1> S;
113 
114  M.svd().solve(R, &S);
115 
116  sm[0] = S[0]; sm[1] = S[5]; sm[2] = S[4];
117  sm[3] = S[1]; sm[4] = S[3];
118  sm[5] = S[2];
119  return;
120 }
121 
122 /* End of code generated by %s. Warning - be careful about
123  modifying any of the generated code directly. Any changes/fixes
124  should be done in the code generation script generation.*/\n"""%pyname
125 
126 cxxfile = open(cxxname, "w")
127 cxxfile.write(src)
128 cxxfile.close()
129 
130 # Write unit test code.
131 testname="test_"+pyname[:-3]+".cpp"
132 testsrc="""
133 #include <cmath>
134 #include <cfloat>
135 #include <iostream>
136 
137 #include <%s>
138 
139 int main(){
140  double x1[]={ 1, 0, -4/sqrt(2)};
141  double x2[]={-1, 0, -4/sqrt(2)};
142  double x3[]={ 0, 2, 4/sqrt(2)};
143  double x4[]={ 0, -2, 4/sqrt(2)};
144  double sm[6];
145  pragmatic::generate_Steiner_ellipse(x1, x2, x3, x4, sm);
146 
147  // Test
148  if(fabs(sm[0]-1./sqrt(2))<DBL_EPSILON && fabs(sm[1])<DBL_EPSILON && fabs(sm[2])<DBL_EPSILON &&
149  fabs(sm[3]-1./sqrt(4))<DBL_EPSILON && fabs(sm[4])<DBL_EPSILON &&
150  fabs(sm[5]-1./sqrt(8))<DBL_EPSILON){
151  std::cout<<"pass"<<std::endl;
152  }else{
153  std::cout<<"fail"<<std::endl;
154  }
155 
156  return 0;
157 }
158 """%(hname)
159 
160 testfile = open(testname, "w")
161 testfile.write(testsrc)
162 testfile.close()
163 
164 
165 
166