Apollo  v5.5.0
Open source self driving car software
i_plane.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2018 The Apollo Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16 #pragma once
17 
24 
25 namespace apollo {
26 namespace perception {
27 namespace common {
28 // General plane equation pi: ax+by+cz+d = 0
29 
30 // Another 3D Plane Data structure:
31 template <typename T>
32 struct PlanePara {
33  PlanePara(const PlanePara<T> &pi) {
34  ICopy4(pi.p, p);
35  ICopy3(pi.t, t);
37  }
39  ICopy4(pi.p, this->p);
40  ICopy3(pi.t, this->t);
41  ICopy2(pi.data_stat, this->data_stat);
42  return (*this);
43  }
44  // first 3 elements: normal with unit norm, last elemet: d
45  T p[4];
46  T t[3]; // centroid
47  // mean distance and standard deviation of
48  // the point to plane distance distribution
49  T data_stat[2];
50  void Clear() {
51  IZero4(p);
52  IZero3(t);
53  IZero2(data_stat);
54  }
55  void Assign(const T *pi) {
56  ICopy4(pi, p);
57  ICopy3(pi + 4, t);
58  ICopy2(pi + 7, data_stat);
59  }
60  bool IsValid() { return (ISqrt(IQquaresum3(p)) > static_cast<T>(0)); }
61  PlanePara() { Clear(); }
62 };
63 
64 // Compute the projection (q) of a 3D point (p) on a plane (pi) in 3D space
65 template <typename T>
66 inline void IPointOnPlaneProjection(const T *pi, const T *p, T *q) {
67  T npi[4];
68  ICopy4(pi, npi);
69  T sf = IRec(IL2Norm3(npi));
70  IScale4(npi, sf); // plane with unit norm
71  sf = -(IDot3(npi, p) + npi[3]);
72  q[0] = p[0] + sf * npi[0];
73  q[1] = p[1] + sf * npi[1];
74  q[2] = p[2] + sf * npi[2];
75 }
76 
77 // Measure point to plane distance in 3D space, point p is in inhomogeneous
78 // coordinates
79 template <typename T>
80 inline T IPlaneToPointDistance(const T *pi, const T *p) {
81  return IDiv(IAbs(IDot3(pi, p) + pi[3]), IL2Norm3(pi));
82 }
83 
84 // Measure point to plane distance in 3D space, point p is in inhomogeneous
85 // coordinates
86 template <typename T>
87 inline T IPlaneToPointDistance(const T *pi, const T *p, T l2_norm3_pi) {
88  return IDiv(IAbs(IDot3(pi, p) + pi[3]), l2_norm3_pi);
89 }
90 
91 // Measure point to plane distance in 3D space, point p is in inhomogeneous
92 // coordinates
93 template <typename T>
94 inline T IPlaneToPointDistanceWUnitNorm(const T *pi, const T *p) {
95  return IAbs(IDot3(pi, p) + pi[3]);
96 }
97 
98 // Measure point to plane distance (signed) in 3D space, point p is in
99 // inhomogeneous coordinates
100 // distance is positive if p is on the same side of the plane pi as the normal
101 // vector and negative if it is on the opposite side
102 template <typename T>
103 inline T IPlaneToPointSignedDistanceWUnitNorm(const T *pi, const T *p) {
104  return IDot3(pi, p) + pi[3];
105 }
106 
107 // Measure point to plane distance in 3D space, point p is in inhomogeneous
108 // coordinates
109 template <typename T>
110 inline T IPlaneToPointDistanceWNormalizedPlaneNorm(const T *pi, const T *p) {
111  return IAbs(IDot3(pi, p) + pi[3]);
112 }
113 
114 // Measure the normal angle in degree between two planes
115 template <typename T>
116 inline T IPlaneToPlaneNormalDeltaDegreeZUp(const T *pi_p, const T *pi_q) {
117  T normal_p[3], normal_q[3];
118  ICopy3(pi_p, normal_p);
119  ICopy3(pi_q, normal_q);
120 
121  // Z is up
122  if (normal_p[2] < static_cast<T>(0.0)) {
123  INeg3(normal_p);
124  }
125  if (normal_q[2] < static_cast<T>(0.0)) {
126  INeg3(normal_q);
127  }
128 
129  IScale3(normal_p, IRec(ISqrt(IQquaresum3(normal_p)))); // normalize
130  IScale3(normal_q, IRec(ISqrt(IQquaresum3(normal_q)))); // normalize
131  return IRadiansToDegree(IAcos(IDot3(normal_p, normal_q)));
132 }
133 
134 // Fit a plane pi (ax+by+cz+d = 0): in 3D space using
135 // total least square method (Orthogonal Distance Regression). The input n 3D
136 // points are in inhomogeneous coordinates. Array X has Size n * 3 and points
137 // are stored as[x0,y0, z0, x1, y1, z1, ...].
138 // pi is stored as 4 - vector[a, b, c, d]. x will be destroyed after calling
139 // this routine.
140 template <typename T>
141 inline void IPlaneFitTotalLeastSquare(T *X, T *pi, int n) {
142  IZero4(pi);
143  if (n < 3) {
144  return;
145  }
146  int i, j;
147  T mat_a[9], eigv[3], mat_q[9];
148  // compute the centroid of input Data points
149  T xm = static_cast<T>(0.0);
150  T ym = static_cast<T>(0.0);
151  T zm = static_cast<T>(0.0);
152  for (i = 0, j = 0; i < n; i++) {
153  xm += X[j++];
154  ym += X[j++];
155  zm += X[j++];
156  }
157  xm /= static_cast<T>(n);
158  ym /= static_cast<T>(n);
159  zm /= static_cast<T>(n);
160  for (i = 0, j = 0; i < n; i++) {
161  X[j++] -= xm;
162  X[j++] -= ym;
163  X[j++] -= zm;
164  }
165  IMultAtAnx3(X, mat_a, n);
166  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
167  // pi's normal vector is the eigen vector of
168  // mat_a corresponding to its smallest eigen value
169  pi[0] = mat_q[2];
170  pi[1] = mat_q[5];
171  pi[2] = mat_q[8];
172  // the optimal plane should pass [xm, ym, zm]:
173  pi[3] = -(pi[0] * xm + pi[1] * ym + pi[2] * zm);
174 }
175 
176 // Fit a plane pi (ax+by+cz+d = 0): in 3D space using
177 // total least square method (Orthogonal Distance Regression). The input n 3D
178 // points are in inhomogeneous coordinates. Array X has Size 3 * 3 and points
179 // are stored as[x0, y0, z0, x1, y1, z1, ...].
180 // pi is stored as 4 - vector[a, b, c, d]. x will be destroyed after calling
181 // this routine.
182 template <typename T>
183 inline void IPlaneFitTotalLeastSquare3(T *X, T *pi) {
184  T mat_a[9];
185  T eigv[3];
186  T mat_q[9];
187  // compute the centroid of input Data points
188  IZero4(pi);
189  T xm = (X[0] + X[3] + X[6]) / 3;
190  T ym = (X[1] + X[4] + X[7]) / 3;
191  T zm = (X[2] + X[5] + X[8]) / 3;
192  X[0] -= xm;
193  X[1] -= ym;
194  X[2] -= zm;
195  X[3] -= xm;
196  X[4] -= ym;
197  X[5] -= zm;
198  X[6] -= xm;
199  X[7] -= ym;
200  X[8] -= zm;
201  IMultAtA3x3(X, mat_a);
202  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
203  // pi's normal vector is the eigen vector of
204  // mat_a corresponding to its smallest eigen value
205  pi[0] = mat_q[2];
206  pi[1] = mat_q[5];
207  pi[2] = mat_q[8];
208  // the optimal plane should pass [xm, ym, zm]:
209  pi[3] = -(pi[0] * xm + pi[1] * ym + pi[2] * zm);
210 }
211 
212 // Fit a plane pi: {[a,b,c,d], [x,y,z]} in 3D space using
213 // total least square method (Orthogonal Distance Regression). The input n 3D
214 // points are in inhomogeneous coordinates. Array X has Size n * 3 and points
215 // are stored as[x0, y0, z0, x1, y1, z1, ...].
216 // The routine needs n * 3 positions of scratch space in Xp.
217 template <typename T>
218 inline void IPlaneFitTotalLeastSquare(const T *X, T *pi, int n, T *Xp,
219  T *centroid, T *err_stat) {
220  IZero4(pi);
221  if (centroid != nullptr) {
222  IZero3(centroid);
223  }
224  if (err_stat != nullptr) {
225  IZero2(err_stat);
226  }
227  if (n < 3) {
228  return;
229  }
230 
231  int i, j, n3 = n * 3;
232  T mat_a[9], eigv[3], mat_q[9], t[3];
233  // compute the centroid of input Data points
234  T xm = static_cast<T>(0.0);
235  T ym = static_cast<T>(0.0);
236  T zm = static_cast<T>(0.0);
237  for (i = 0, j = 0; i < n; i++) {
238  xm += X[j++];
239  ym += X[j++];
240  zm += X[j++];
241  }
242  t[0] = xm / n;
243  t[1] = ym / n;
244  t[2] = zm / n;
245  for (i = 0; i < n3; i += 3) {
246  ISub3(X + i, t, Xp + i);
247  }
248  IMultAtANx3(Xp, mat_a, n);
249  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
250  // pi's normal vector is the eigen vector of
251  // mat_a corresponding to its smallest eigen value
252  pi[0] = mat_q[2];
253  pi[1] = mat_q[5];
254  pi[2] = mat_q[8];
255  IUnitize3(pi);
256  // the optimal plane should pass [xm, ym, zm]:
257  pi[3] = -IDot3(pi, t);
258 
259  if (centroid != nullptr) {
260  ICopy3(t, centroid);
261  }
262 
263  // Data stat:
264  if (err_stat != nullptr) {
265  const T *cptr_data = X;
266  for (i = 0; i < n; ++i) {
267  Xp[i] = IPlaneToPointDistance(pi, cptr_data);
268  cptr_data += 3;
269  }
270  err_stat[0] = IMean(Xp, n); // mean
271  err_stat[1] = ISdv(Xp, err_stat[0], n); // sdv
272  }
273 }
274 
275 // Fit a plane pi (ax+by+cz+d = 0): in 3D space using
276 // total least square method (Orthogonal Distance Regression). The input n 3D
277 // points are in inhomogeneous coordinates. Array X has Size n * 3 and points
278 // are stored as[x0, y0, z0, x1, y1, z1, ...].
279 // pi is stored as 4 - vector[a, b, c, d]. x and indices will be destroyed after
280 // calling this routine.
281 template <typename T>
282 inline void IPlaneFitTotalLeastSquare(T *X, int *indices, T *pi, int m, int n) {
283  IZero4(pi);
284  if (n < 3 || n > m) {
285  return;
286  }
287  IIndexedShuffle(X, indices, m, 3, n);
288  int i, j;
289  T mat_a[9], eigv[3], mat_q[9];
290  // compute the centroid of input Data points
291  T xm = static_cast<T>(0.0);
292  T ym = static_cast<T>(0.0);
293  T zm = static_cast<T>(0.0);
294  for (i = 0, j = 0; i < n; i++) {
295  xm += X[j++];
296  ym += X[j++];
297  zm += X[j++];
298  }
299  xm /= n;
300  ym /= n;
301  zm /= n;
302  for (i = 0, j = 0; i < n; i++) {
303  X[j++] -= xm;
304  X[j++] -= ym;
305  X[j++] -= zm;
306  }
307  IMultAtANx3(X, mat_a, n);
308  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
309  // pi's normal vector is the eigen vector of
310  // mat_a corresponding to its smallest eigen value
311  pi[0] = mat_q[2];
312  pi[1] = mat_q[5];
313  pi[2] = mat_q[8];
314  // the optimal plane should pass [xm, ym, zm]:
315  pi[3] = -(pi[0] * xm + pi[1] * ym + pi[2] * zm);
316 }
317 
318 // Fit a plane pi (ax+by+cz+d = 0): in 3D space using
319 // total least square method (Orthogonal Distance Regression). The input n 3D
320 // points are in inhomogeneous coordinates. Array X has Size n * 3 and points
321 // are stored as[x0, y0, z0, x1, y1, z1, ...].
322 // pi is stored as 4 - vector[a, b, c, d]. x and indices will be destroyed after
323 // calling this routine.
324 template <typename T>
325 inline void IPlaneFitTotalLeastSquare(T *X, int *indices, T *pi, T *centroid,
326  int m, int n) {
327  IZero4(pi);
328  if (n < 3 || n > m) {
329  return;
330  }
331  IIndexedShuffle(X, indices, m, 3, n);
332  int i, j;
333  T mat_a[9], eigv[3], mat_q[9];
334  // compute the centroid of input Data points
335  T xm = static_cast<T>(0.0);
336  T ym = static_cast<T>(0.0);
337  T zm = static_cast<T>(0.0);
338  for (i = 0, j = 0; i < n; i++) {
339  xm += X[j++];
340  ym += X[j++];
341  zm += X[j++];
342  }
343  xm /= n;
344  ym /= n;
345  zm /= n;
346  for (i = 0, j = 0; i < n; i++) {
347  X[j++] -= xm;
348  X[j++] -= ym;
349  X[j++] -= zm;
350  }
351  IMultAtANx3(X, mat_a, n);
352  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
353  // pi's normal vector is the eigen vector of
354  // mat_a corresponding to its smallest eigen value
355  pi[0] = mat_q[2];
356  pi[1] = mat_q[5];
357  pi[2] = mat_q[8];
358  // the optimal plane should pass [xm, ym, zm]:
359  pi[3] = -(pi[0] * xm + pi[1] * ym + pi[2] * zm);
360 
361  if (centroid != nullptr) {
362  centroid[0] = xm;
363  centroid[1] = ym;
364  centroid[2] = zm;
365  }
366 }
367 
368 // Fit a plane i: {[a,b,c,d], [x,y,z]} in 3D space using
369 // total least square method (Orthogonal Distance Regression). The input n 3D
370 // points are in inhomogeneous coordinates. Array X has Size n * 3 and points
371 // are stored as[x0, y0, z0, x1, y1, z1, ...].
372 template <typename T>
373 inline void IPlaneFitTotalLeastSquareAdv(T *X, int *indices, T *para, int m,
374  int n) {
375  IZero9(para);
376  if (n < 3 || n > m) {
377  return;
378  }
379  int i, j;
380  T *xp = IAlloc<T>(n * 3);
381  for (i = 0; i < n; i++) {
382  j = indices[i];
383  ICopy3(X + j * 3, xp + i * 3);
384  }
385  T mat_a[9], eigv[3], mat_q[9];
386  // compute the centroid of input Data points
387  T xm = static_cast<T>(0.0);
388  T ym = static_cast<T>(0.0);
389  T zm = static_cast<T>(0.0);
390  for (i = 0, j = 0; i < n; i++) {
391  xm += xp[j++];
392  ym += xp[j++];
393  zm += xp[j++];
394  }
395  xm /= n;
396  ym /= n;
397  zm /= n;
398  for (i = 0, j = 0; i < n; i++) {
399  xp[j++] -= xm;
400  xp[j++] -= ym;
401  xp[j++] -= zm;
402  }
403  IMultAtANx3(xp, mat_a, n);
404  IEigSymmetric3x3Closed(mat_a, eigv, mat_q);
405  // pi's normal vector is the eigen vector of
406  // mat_a corresponding to its smallest eigen value
407  para[0] = mat_q[2];
408  para[1] = mat_q[5];
409  para[2] = mat_q[8];
410  IUnitize3(para);
411  // the optimal plane should pass [xm, ym, zm]:
412  para[4] = xm;
413  para[5] = ym;
414  para[6] = zm;
415  para[3] = -IDot3(para, para + 4);
416  // Data stat:
417 
418  for (i = 0; i < n; ++i) {
419  j = indices[i];
420  xp[i] = IPlaneToPointDistance(para, X + j * 3);
421  }
422  para[7] = IMean(xp, n);
423  para[8] = ISdv(xp, para[7], n);
424  IFree<T>(&xp);
425 }
426 
427 // Fit a plane pi (ax+by+cz+d = 0) with three 3D points in inhomogeneous
428 // space - minimal solution
429 template <typename T>
430 inline void IPlaneFit(const T *X1, const T *X2, const T *X3, T *pi) {
431  T mat_a[9] = {X1[0], X1[1], X1[2], X2[0], X2[1], X2[2], X3[0], X3[1], X3[2]};
432  IPlaneFitTotalLeastSquare(mat_a, pi, 3);
433 }
434 
435 // Fit a plane pi (ax+by+cz+d = 0) with three 3D points in inhomogeneous
436 // space - minimal solution
437 template <typename T>
438 inline void IPlaneFit(const T *Xs, T *pi) {
439  T mat_a[9];
440  ICopy9(Xs, mat_a);
441  IPlaneFitTotalLeastSquare(mat_a, pi, 3);
442 }
443 
444 // Fit a plane pi (ax+by+cz+d = 0) with three 3D points in inhomogeneous
445 // space - minimal solution,
446 // note that the input Xs will be destroyed
447 template <typename T>
448 inline void IPlaneFitDestroyed(T *Xs, T *pi) {
450 }
451 
452 // Fit a plane pi: {[a,b,c,d], [x,y,z]} with three 3D points in inhomogeneous
453 // space - minimal solution
454 template <typename T>
455 inline void IPlaneFitAdv(const T *Xs, T *para) {
456  T mat_a[9], mat_ap[9];
457  PlanePara<T> pi;
458  ICopy9(Xs, mat_a);
459  IPlaneFitTotalLeastSquare(mat_a, pi, mat_ap, 3);
460  ICopy4(pi.p, para);
461  ICopy3(pi.t, para + 4);
462  ICopy2(pi.data_stat, para + 7);
463 }
464 
465 } // namespace common
466 } // namespace perception
467 } // namespace apollo
void IZero3(T a[3])
Definition: i_blas.h:334
void IMultAtAnx3(const T *A, T AtA[9], int n)
Definition: i_blas.h:4840
float IAbs(float a)
Definition: i_basic.h:29
T ISdv(const T *x, T mean, int n)
Definition: i_blas.h:2500
T IPlaneToPlaneNormalDeltaDegreeZUp(const T *pi_p, const T *pi_q)
Definition: i_plane.h:116
PlanePara & operator=(const PlanePara< T > &pi)
Definition: i_plane.h:38
void IScale4(T x[4], T sf)
Definition: i_blas.h:1874
T IL2Norm3(const T x[3])
Definition: i_blas.h:2812
T data_stat[2]
Definition: i_plane.h:49
void IPlaneFitTotalLeastSquareAdv(T *X, int *indices, T *para, int m, int n)
Definition: i_plane.h:373
void Assign(const T *pi)
Definition: i_plane.h:55
Definition: blob.h:72
PlanePara(const PlanePara< T > &pi)
Definition: i_plane.h:33
void ICopy3(const T src[3], T dst[3])
Definition: i_blas.h:40
float IRec(float a)
Definition: i_basic.h:69
void IPlaneFitDestroyed(T *Xs, T *pi)
Definition: i_plane.h:448
void IPlaneFitTotalLeastSquare(T *X, T *pi, int n)
Definition: i_plane.h:141
T IPlaneToPointSignedDistanceWUnitNorm(const T *pi, const T *p)
Definition: i_plane.h:103
float IRadiansToDegree(float r)
Definition: i_basic.h:260
T IPlaneToPointDistanceWNormalizedPlaneNorm(const T *pi, const T *p)
Definition: i_plane.h:110
T IMean(const T *x, int n)
Definition: i_blas.h:2434
void IPointOnPlaneProjection(const T *pi, const T *p, T *q)
Definition: i_plane.h:66
void Clear()
Definition: i_plane.h:50
void IPlaneFitAdv(const T *Xs, T *para)
Definition: i_plane.h:455
void IEigSymmetric3x3Closed(const T *A, T *EV, T *Q)
Definition: i_util.h:56
void ISub3(const T x[3], const T y[3], T z[3])
Definition: i_blas.h:1405
void IZero9(T a[9])
Definition: i_blas.h:358
void ICopy2(const T src[2], T dst[2])
Definition: i_blas.h:35
float IDiv(float a, float b)
Definition: i_basic.h:35
PlanePara()
Definition: i_plane.h:61
void IZero4(T a[4])
Definition: i_blas.h:338
void IPlaneFitTotalLeastSquare3(T *X, T *pi)
Definition: i_plane.h:183
float IAcos(float alpha)
Definition: i_basic.h:239
void IPlaneFit(const T *X1, const T *X2, const T *X3, T *pi)
Definition: i_plane.h:430
void IMultAtA3x3(const T A[9], T AtA[9])
Definition: i_blas.h:4830
T p[4]
Definition: i_plane.h:45
void INeg3(T x[3])
Definition: i_blas.h:415
T t[3]
Definition: i_plane.h:46
T IDot3(const T x[3], const T y[3])
Definition: i_blas.h:2260
float ISqrt(float a)
Definition: i_basic.h:76
void IUnitize3(T x[3])
Definition: i_blas.h:2955
void IIndexedShuffle(T *a, int *indices, int n, int element_size, int nr_indexed_elements, bool is_sort_indices=true)
Definition: i_sort.h:80
T IPlaneToPointDistanceWUnitNorm(const T *pi, const T *p)
Definition: i_plane.h:94
T IPlaneToPointDistance(const T *pi, const T *p)
Definition: i_plane.h:80
void IZero2(T a[2])
Definition: i_blas.h:330
void IScale3(T x[3], T sf)
Definition: i_blas.h:1868
bool IsValid()
Definition: i_plane.h:60
void ICopy9(const T src[9], T dst[9])
Definition: i_blas.h:91
void ICopy4(const T src[4], T dst[4])
Definition: i_blas.h:46