1 // This is core/vgl/vgl_affine_coordinates.hxx
2 #ifndef vgl_affine_coordinates_hxx_
3 #define vgl_affine_coordinates_hxx_
4 #include <cassert>
5 #include <cmath>
6 #include "vgl_affine_coordinates.h"
7 #include "vgl_vector_2d.h"
8 #include "vgl_vector_3d.h"
9 #include "vgl_tolerance.h"
10 // Points are all coplanar. The first three points in pts are the basis, pts[0] is the origin
11 template <class T>
vgl_affine_coordinates_2d(std::vector<vgl_point_2d<T>> const & pts,std::vector<vgl_point_2d<T>> & affine_pts)12 void vgl_affine_coordinates_2d(std::vector<vgl_point_2d<T> > const& pts, std::vector<vgl_point_2d<T> >& affine_pts)
13 {
14   assert(pts.size()>=3);
15   vgl_vector_2d<T> v0 = pts[1]-pts[0];
16   vgl_vector_2d<T> v1 = pts[2]-pts[0];
17   T dv0v0 = dot_product(v0,v0);
18   T dv0v1 = dot_product(v0,v1);
19   T dv1v1 = dot_product(v1,v1);
20   T det = dv0v0*dv1v1 - dv0v1*dv0v1;
21   T tol = vgl_tolerance<T>::position;
22   assert(fabs(det)>tol);
23   for(unsigned i =0; i<pts.size(); ++i){
24     vgl_vector_2d<T> vp = pts[i]-pts[0];
25     T dvpv0 = dot_product(vp, v0);
26     T dvpv1 = dot_product(vp, v1);
27     T alpha = (dvpv0*dv1v1-dv0v1*dvpv1)/det;
28     T beta  = (dv0v0*dvpv1-dvpv0*dv0v1)/det;
29     affine_pts.push_back(vgl_point_2d<T>(alpha, beta));
30   }
31 }
32 // The first four points in pts are the basis.
33 template <class T>
vgl_affine_coordinates_3d(std::vector<vgl_point_3d<T>> const & pts,std::vector<vgl_point_3d<T>> & affine_pts)34 void vgl_affine_coordinates_3d(std::vector<vgl_point_3d<T> > const& pts, std::vector<vgl_point_3d<T> >& affine_pts)
35 {
36     assert(pts.size()>=4);
37     vgl_vector_3d<T> v0 = pts[1]-pts[0];
38     vgl_vector_3d<T> v1 = pts[2]-pts[0];
39     vgl_vector_3d<T> v2 = pts[3]-pts[0];
40     T dv0v0 = dot_product(v0,v0);
41     T dv0v1 = dot_product(v0,v1);
42     T dv0v2 = dot_product(v0,v2);
43     T dv1v1 = dot_product(v1,v1);
44     T dv1v2 = dot_product(v1,v2);
45     T dv2v2 = dot_product(v2,v2);
46     T det = -dv0v2*dv0v2*dv1v1 + 2*dv0v1*dv0v2*dv1v2 - dv0v0*dv1v2*dv1v2 - dv0v1*dv0v1*dv2v2 + dv0v0*dv1v1*dv2v2;
47     T tol = vgl_tolerance<T>::position;
48     assert(fabs(det)>tol);
49     for(unsigned i =0; i<pts.size(); ++i){
50       vgl_vector_3d<T> vp = pts[i]-pts[0];
51       T dvpv0 = dot_product(vp, v0);
52       T dvpv1 = dot_product(vp, v1);
53       T dvpv2 = dot_product(vp, v2);
54       T alpha = (-dv1v2*dv1v2*dvpv0 + dv1v1*dv2v2*dvpv0 + dv0v2*dv1v2*dvpv1 -
55                  dv0v1*dv2v2*dvpv1 - dv0v2*dv1v1*dvpv2 + dv0v1*dv1v2*dvpv2)/det;
56       T beta = (dv0v2*dv1v2*dvpv0 - dv0v1*dv2v2*dvpv0 - dv0v2*dv0v2*dvpv1 +
57               dv0v0*dv2v2*dvpv1 + dv0v1*dv0v2*dvpv2 - dv0v0*dv1v2*dvpv2)/det;
58       T gamma = (-dv0v2*dv1v1*dvpv0 + dv0v1*dv1v2*dvpv0 + dv0v1*dv0v2*dvpv1 -
59                dv0v0*dv1v2*dvpv1 - dv0v1*dv0v1*dvpv2 + dv0v0*dv1v1*dvpv2)/det;
60       affine_pts.push_back(vgl_point_3d<T>(alpha, beta, gamma));
61     }
62 }
63 
64 // Two 2-d pointsets define the 3-d basis. The first four points in pts1 and pts2 are the basis.
65 template <class T>
vgl_affine_coordinates_3d(std::vector<vgl_point_2d<T>> const & pts1,std::vector<vgl_point_2d<T>> const & pts2,std::vector<vgl_point_3d<T>> & affine_pts)66 void vgl_affine_coordinates_3d(std::vector<vgl_point_2d<T> > const& pts1, std::vector<vgl_point_2d<T> > const& pts2,
67                                std::vector<vgl_point_3d<T> >& affine_pts)
68 {
69   unsigned n1 = pts1.size(), n2 = pts2.size();
70   assert(n1>=4);
71   assert(n1==n2);
72   T tol = vgl_tolerance<T>::position;
73   //normalize 2-d pointsets
74   T x1=T(0), x2=T(0), y1 = T(0), y2 = T(0);
75   T dist_1 = T(0), dist_2 = T(0);
76   for(unsigned i = 0; i<n1;++i){
77     x1+=pts1[i].x(); y1+=pts1[i].y();
78     x2+=pts2[i].x(); y2+=pts2[i].y();
79   }
80   vgl_point_2d<T> cent_1(x1/n1, y1/n1), cent_2(x2/n1, y2/n1);
81   for(unsigned i = 0; i<n1;++i){
82     dist_1+=(pts1[i]-cent_1).length();
83     dist_2+=(pts2[i]-cent_2).length();
84   }
85   dist_1/=n1; dist_2/=n2;
86   std::vector<vgl_point_2d<T> > norm_pts1, norm_pts2;
87   for(unsigned i = 0; i<n1;++i){
88     vgl_point_2d<T> np1(pts1[i].x()-cent_1.x(), pts1[i].y()-cent_1.y());
89     if(dist_1>tol)
90       np1.set(np1.x()/dist_1, np1.y()/dist_1);
91     vgl_point_2d<T> np2(pts2[i].x()-cent_2.x(), pts2[i].y()-cent_2.y());
92     if(dist_2>tol)
93       np2.set(np2.x()/dist_2, np2.y()/dist_2);
94     norm_pts1.push_back(np1);
95     norm_pts2.push_back(np2);
96   }
97   // 2-d basis for pts1
98   vgl_vector_2d<T> v01 = norm_pts1[1]-norm_pts1[0];
99   vgl_vector_2d<T> v11 = norm_pts1[2]-norm_pts1[0];
100   T dv01v01 = dot_product(v01,v01);
101   T dv01v11 = dot_product(v01,v11);
102   T dv11v11 = dot_product(v11,v11);
103   T det1 = dv01v01*dv11v11 - dv01v11*dv01v11;
104   assert(fabs(det1)>tol);
105   //affine coordinates for V2' (pts1)
106   vgl_vector_2d<T> v21 = norm_pts1[3]-norm_pts1[0];
107   T dv21v01 = dot_product(v01, v21);
108   T dv21v11 = dot_product(v11, v21);
109   T alpha_1 = (dv21v01*dv11v11-dv01v11*dv21v11)/det1;
110   T beta_1  = (dv01v01*dv21v11-dv21v01*dv01v11)/det1;
111   // 2-d basis for pts2
112   vgl_vector_2d<T> v02 = norm_pts2[1]-norm_pts2[0];
113   vgl_vector_2d<T> v12 = norm_pts2[2]-norm_pts2[0];
114   T dv02v02 = dot_product(v02,v02);
115   T dv02v12 = dot_product(v02,v12);
116   T dv12v12 = dot_product(v12,v12);
117   T det2 = dv02v02*dv12v12 - dv02v12*dv02v12;
118   assert(fabs(det2)>tol);
119   //affine coordinates for V2 (pts2)
120   vgl_vector_2d<T> v22 = norm_pts2[3]-norm_pts2[0];
121   T dv22v02 = dot_product(v02, v22);
122   T dv22v12 = dot_product(v12, v22);
123   T alpha_2 = (dv22v02*dv12v12-dv02v12*dv22v12)/det2;
124   T beta_2  = (dv02v02*dv22v12-dv22v02*dv02v12)/det2;
125   //length of V2'V2 in pts2
126   vgl_vector_2d<T> V2pV2 = (alpha_2-alpha_1)*v02 + (beta_2-beta_1)*v12;
127   T L2 = V2pV2.length();
128   assert(L2>tol);// otherwise the views are the same or the basis points are coplanar
129   //determine sign of L2
130   T s2 = (alpha_2-alpha_1), fs2 = fabs(s2);
131   if(fs2<tol){
132     s2 = (beta_2-beta_1);
133     fs2 = fabs(s2);
134     if(fs2<tol){
135       s2 = 1.0;
136       fs2 = 1.0;
137     }
138   }
139   L2 *= s2/fs2;
140   for(unsigned i = 0; i<n1; ++i){
141     //affine coordinates for p in pts1
142     vgl_vector_2d<T> vp1 = norm_pts1[i]-norm_pts1[0];
143     T dvp1v01 = dot_product(vp1, v01);
144     T dvp1v11 = dot_product(vp1, v11);
145     T alpha_p1 = (dvp1v01*dv11v11-dv01v11*dvp1v11)/det1;
146     T beta_p1  = (dv01v01*dvp1v11-dvp1v01*dv01v11)/det1;
147     //affine coordinates for p in pts2
148     vgl_vector_2d<T> vp2 = norm_pts2[i]-norm_pts2[0];
149     T dvp2v02 = dot_product(vp2, v02);
150     T dvp2v12 = dot_product(vp2, v12);
151     T alpha_p2 = (dvp2v02*dv12v12-dv02v12*dvp2v12)/det2;
152     T beta_p2  = (dv02v02*dvp2v12-dvp2v02*dv02v12)/det2;
153     // length of PP' in pts 2
154     vgl_vector_2d<T> PpP = (alpha_p2-alpha_p1)*v02 + (beta_p2-beta_p1)*v12;
155     T Lp = PpP.length();
156     //determine sign of PP'
157     T sp = (alpha_p2-alpha_p1), fsp = fabs(sp);
158     if(fsp<tol){
159       sp = (beta_p2-beta_p1);
160       fsp = fabs(sp);
161       if(fsp<tol){
162         sp = 1.0;
163         fsp= 1.0;
164       }
165     }
166     Lp *= sp/fsp;
167     T gamma_p = Lp/L2;
168     T alpha_p = (alpha_p1-gamma_p*alpha_1);
169     T beta_p = (beta_p1-gamma_p*beta_1);
170     affine_pts.push_back(vgl_point_3d<T>(alpha_p, beta_p, gamma_p));
171   }
172 }
173 #undef VGL_AFFINE_COORDINATES_INSTANTIATE
174 #define VGL_AFFINE_COORDINATES_INSTANTIATE(T) \
175   template void vgl_affine_coordinates_2d(std::vector<vgl_point_2d<T> > const& pts, std::vector<vgl_point_2d<T> >& affine_pts); \
176   template void vgl_affine_coordinates_3d(std::vector<vgl_point_3d<T> > const& pts, std::vector<vgl_point_3d<T> >& affine_pts); \
177   template void vgl_affine_coordinates_3d(std::vector<vgl_point_2d<T> > const& pts1, std::vector<vgl_point_2d<T> > const& pts2, \
178                                           std::vector<vgl_point_3d<T> >& affine_pts)
179 #endif // vgl_affine_coordinates_h_
180