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