vgl_plane_3d.hxx
Go to the documentation of this file.
1 // This is core/vgl/vgl_plane_3d.hxx
2 #ifndef vgl_plane_3d_hxx_
3 #define vgl_plane_3d_hxx_
4 //:
5 // \file
6 
7 #include <cmath>
8 #include <iostream>
9 #include <string>
10 #include "vgl_plane_3d.h"
11 #include <vgl/vgl_homg_plane_3d.h>
12 #include <vgl/vgl_point_3d.h>
13 #include <vgl/vgl_point_2d.h>
14 #include <vgl/vgl_ray_3d.h>
15 #include <vgl/vgl_closest_point.h>
16 #include <vgl/vgl_distance.h>
17 #include <vgl/vgl_tolerance.h>
18 #ifdef _MSC_VER
19 # include <vcl_msvc_warnings.h>
20 #endif
21 #include <cassert>
22 
23 //: Construct from homogeneous plane
24 template <class T>
26  : a_(p.a()), b_(p.b()), c_(p.c()), d_(p.d()) {assert (a_||b_||c_);}
27 
28 //: Construct from three points
29 template <class T>
31  vgl_point_3d<T> const& p2,
32  vgl_point_3d<T> const& p3)
33 : a_(p2.y()*p3.z()-p2.z()*p3.y()
34  +p3.y()*p1.z()-p3.z()*p1.y()
35  +p1.y()*p2.z()-p1.z()*p2.y())
36 , b_(p2.z()*p3.x()-p2.x()*p3.z()
37  +p3.z()*p1.x()-p3.x()*p1.z()
38  +p1.z()*p2.x()-p1.x()*p2.z())
39 , c_(p2.x()*p3.y()-p2.y()*p3.x()
40  +p3.x()*p1.y()-p3.y()*p1.x()
41  +p1.x()*p2.y()-p1.y()*p2.x())
42 , d_(p1.x()*(p2.z()*p3.y()-p2.y()*p3.z())
43  +p2.x()*(p3.z()*p1.y()-p3.y()*p1.z())
44  +p3.x()*(p1.z()*p2.y()-p1.y()*p2.z()))
45 {
46  assert(a_||b_||c_); // points should not be collinear or coinciding
47 }
48 
49 //: Construct from normal and a point
50 template <class T>
52  vgl_point_3d<T> const& p)
53  : a_(n.x()), b_(n.y()), c_(n.z()), d_(-(n.x()*p.x()+n.y()*p.y()+n.z()*p.z()))
54 {
55  assert(a_||b_||c_); // normal vector should not be the null vector
56 }
57 
58 template <class T>
60  vgl_ray_3d<T> const& r1){
61  // check if the rays are parallel
62  const vgl_vector_3d<T>& v0 = r0.direction();
63  const vgl_vector_3d<T>& v1 = r1.direction();
64  double para = std::fabs(1.0-std::fabs(cos_angle(v0, v1)));
65  bool parallel = para < vgl_tolerance<double>::position;
66  // check if the ray origins are coincident
67  const vgl_point_3d<T>& p0 = r0.origin();
68  const vgl_point_3d<T>& p1 = r1.origin();
69  double d01 = length(p1-p0);
70  bool coincident = d01 < vgl_tolerance<double>::position;
71 
72  // assert the rays are distinct
73  bool distinct = !parallel || (parallel&&!coincident);
74  assert(distinct);
75  // assert the rays are not skew
76  bool not_skew = (parallel&&distinct) || (!parallel&&coincident);
77  assert(not_skew);
78 
79  // Case I: coincident
80  if(coincident){
81  vgl_vector_3d<T> norm = cross_product(v0, v1);
82  vgl_plane_3d<T> pln(norm, p0);
83  a_=pln.a(); b_=pln.b(); c_=pln.c(); d_=pln.d();
84  return;
85  }
86  // Case II: parallel
87  vgl_vector_3d<T> v01 = p1-p0;
88  vgl_vector_3d<T> norm = cross_product(v0, v01);
89  vgl_plane_3d<T> pln(norm, p0);
90  a_=pln.a(); b_=pln.b(); c_=pln.c(); d_=pln.d();
91 }
92 template <class T>
94  double sum = a_*a_ + b_*b_ + c_*c_;
95  if (sum<1e-12) // don't normalize plane at infinity
96  return false;
97  double den = std::sqrt(sum);
98  double an= (double)a()/den; a_ = (T)an;
99  double bn= (double)b()/den; b_ = (T)bn;
100  double cn= (double)c()/den; c_ = (T)cn;
101  double dn= (double)d()/den; d_ = (T)dn;
102  //standardize so that largest of (|a|,|b|,|c|) is positive
103  if ((std::fabs(an)>=std::fabs(bn) && std::fabs(an)>=std::fabs(cn) && an < 0) ||
104  (std::fabs(bn)>std::fabs(an) && std::fabs(bn)>=std::fabs(cn) && bn < 0) ||
105  (std::fabs(cn)>std::fabs(an) && std::fabs(cn)>std::fabs(bn) && cn < 0))
106  a_ = -a_, b_ = -b_, c_ = -c_, d_ = -d_;
107  return true;
108 }
109 //: Return true if p is on the plane
110 template <class T>
111 bool vgl_plane_3d<T>::contains(vgl_point_3d<T> const& p, T tol) const
112 {
113  //to maintain a consistent distance metric the plane should be normalized
114  vgl_vector_3d<T> n(a_, b_, c_), pv(p.x(), p.y(), p.z());
115  T dist = (dot_product(n,pv) + d_) / static_cast<T>(length(n));
116  return dist >= -tol && dist <= tol;
117 }
118 
119 template <class T>
121 {
122  return (this==&p) ||
123  ( (a()*p.b()==p.a()*b())
124  && (a()*p.c()==p.a()*c())
125  && (a()*p.d()==p.a()*d())
126  && (b()*p.c()==p.b()*c())
127  && (b()*p.d()==p.b()*d())
128  && (c()*p.d()==p.c()*d()) );
129 }
130 
131 #define vp(os,v,s) os<<' '<< v << ' ' <<s;
132 
133 template <class T>
134 std::ostream& operator<<(std::ostream& os, const vgl_plane_3d<T>& p)
135 {
136  os << "<vgl_plane_3d"; vp(os,p.a(),"x"); vp(os,p.b(),"y"); vp(os,p.c(),"z");
137  vp(os,p.d(),""); return os << " = 0 >";
138 }
139 
140 #undef vp
141 
142 template <class T>
143 std::istream& operator>>(std::istream& is, vgl_plane_3d<T>& p)
144 {
145  if (! is.good()) return is; // (TODO: should throw an exception)
146  bool paren = false;
147  bool formatted = false;
148  is >> std::ws; // jump over any leading whitespace
149  char ch;
150  ch = is.peek();
151  if(ch == '<'){
152  std::string temp;
153  is >> temp;
154  formatted = true;
155  }
156  is >> std::ws;
157  T a, b, c, d;
158  if (is.eof()) return is; // nothing to be set because of EOF (TODO: should throw an exception)
159  if (is.peek() == '(') { is.ignore(); paren=true; }
160  is >> std::ws >> a >> std::ws;
161  if (is.eof()) return is;
162  if (is.peek() == ',') is.ignore();
163  else if (is.peek() == 'x') { is.ignore(); formatted=true; }
164  is >> std::ws >> b >> std::ws;
165  if (is.eof()) return is;
166  if (formatted) {
167  if (is.eof()) return is;
168  if (is.peek() == 'y') is.ignore();
169  else return is; // formatted input incorrect (TODO: throw an exception)
170  }
171  else if (is.peek() == ',') is.ignore();
172  is >> std::ws >> c >> std::ws;
173  if (is.eof()) return is;
174  if (formatted) {
175  if (is.eof()) return is;
176  if (is.peek() == 'z') is.ignore();
177  else return is; // formatted input incorrect (TODO: throw an exception)
178  }
179  else if (is.peek() == ',') is.ignore();
180  is >> std::ws >> d >> std::ws;
181  if (paren) {
182  if (is.eof()) return is;
183  if (is.peek() == ')') is.ignore();
184  else return is; // closing parenthesis is missing (TODO: throw an exception)
185  }
186  if (formatted) {
187  if (is.eof()) return is;
188  if (is.peek() == '=') is.ignore();
189  else return is; // = 0 is missing (TODO: throw an exception)
190  is >> std::ws;
191  if (is.peek() == '0') is.ignore();
192  else return is; // = 0 is missing (TODO: throw an exception)
193  is >> std::ws;
194  if (!paren && is.peek() == '>') is.ignore();
195  else return is; // closing > is missing (TODO: throw an exception)
196  }
197  p.set(a,b,c,d);
198  return is;
199 }
200 
201 template <class T>
204 {
205  vgl_vector_3d<T> Y((T)0, (T)1, (T)0);
206  vgl_vector_3d<T> n = this->normal();
207 
208  // Since we have an int Template definition, we need to static cast input so VS is happy.
209  // Note* currently there are only float and double Template defs. If long double is ever created,
210  // this cast will need to get expanded to prevent loss of precision issues.
211  T dp = (T)1 - (T)std::fabs(static_cast<double>(dot_product(n, Y)));
212  T tol = ((T)1)/((T)10);
213  if (dp>tol)//ok to use the Y axis to form the coordinate system
214  {
215  uvec = normalized(cross_product(Y, n));
216  vvec = normalized(cross_product(n, uvec));
217  }
218  else { // the normal is parallel to the Y axis
219  vgl_vector_3d<T> Z((T)0, (T)0, (T)1);
220  uvec = normalized(cross_product(n, Z));
221  vvec = normalized(cross_product(uvec, n));
222  }
223 }
224 
225 template <class T>
227  vgl_point_2d<T>& p2d, T tol) const
228 {
229  // check if point is on the plane
230  vgl_point_3d<T> pt_on_plane = vgl_closest_point(p3d, *this);
231  double dist = vgl_distance(p3d, pt_on_plane), dtol = static_cast<double>(tol);
232  if (dist>dtol)
233  return false;
234  // use the plane point to compute coordinates
235  // construct the axis vectors
236  vgl_point_3d<T> origin_pt = vgl_closest_point_origin(*this);
237  vgl_vector_3d<T> p = pt_on_plane - origin_pt;
238  vgl_vector_3d<T> uvec, vvec;
239  this->plane_coord_vectors(uvec, vvec);
240  T u = dot_product(uvec, p), v = dot_product(vvec, p);
241  p2d.set(u, v);
242  return true;
243 }
244 
245 template <class T>
248 {
249  vgl_point_3d<T> origin_pt = vgl_closest_point_origin(*this);
250  vgl_vector_3d<T> uvec, vvec;
251  this->plane_coord_vectors(uvec, vvec);
252  vgl_point_3d<T> p3d = origin_pt + uvec*p2d.x() + vvec*p2d.y();
253  return p3d;
254 }
255 
256 #undef VGL_PLANE_3D_INSTANTIATE
257 #define VGL_PLANE_3D_INSTANTIATE(T) \
258 template class vgl_plane_3d<T >; \
259 template std::ostream& operator<<(std::ostream&, vgl_plane_3d<T >const&); \
260 template std::istream& operator>>(std::istream&, vgl_plane_3d<T >&)
261 
262 #endif // vgl_plane_3d_hxx_
homogeneous plane in 3D projective space
v normalized(v const &a)
Return a normalised version of a.
T dot_product(v const &a, v const &b)
dot product or inner product of two vectors.
a point in 2D nonhomogeneous space
T a() const
Return x coefficient.
Definition: vgl_plane_3d.h:89
#define vp(os, v, s)
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
A 3-d ray defined by an origin and a direction vector.
double length(v const &a)
Return the length of a vector.
Definition: vgl_vector_2d.h:94
Type & z()
Definition: vgl_point_3d.h:73
void plane_coord_vectors(vgl_vector_3d< T > &uvec, vgl_vector_3d< T > &vvec) const
plane coordinate unit vectors.
#define v
Definition: vgl_vector_2d.h:74
Set of closest-point functions.
vgl_point_2d< T > vgl_closest_point_origin(vgl_line_2d< T > const &l)
Return the point on the given line closest to the origin.
T b() const
Return y coefficient.
Definition: vgl_plane_3d.h:92
a point in 3D nonhomogeneous space
vgl_point_2d< T > vgl_closest_point(vgl_line_2d< T > const &l, vgl_point_2d< T > const &p)
Return the point on the given line closest to the given point.
bool normalize()
void set(Type px, Type py)
Set x and y.
Definition: vgl_point_2d.h:79
T cross_product(v const &a, v const &b)
cross product of two vectors (area of enclosed parallellogram).
bool plane_coords(vgl_point_3d< T > const &p3d, vgl_point_2d< T > &p2d, T tol=(T) 0) const
Given a 3-d point, return a 2-d point in the coord. system of the plane.
Type & y()
Definition: vgl_point_2d.h:72
Represents a Euclidean 3D plane.
Definition: vgl_fwd.h:23
Represents a 3-d ray.
Definition: vgl_fwd.h:21
T d() const
Return constant coefficient.
Definition: vgl_plane_3d.h:98
vgl_point_3d< Type > origin() const
Accessors.
Definition: vgl_ray_3d.h:66
Type & x()
Definition: vgl_point_3d.h:71
Direction vector in Euclidean 3D space, templated by type of element.
Definition: vgl_fwd.h:13
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
double vgl_distance(vgl_point_2d< T >const &p1, vgl_point_2d< T >const &p2)
return the distance between two points.
Definition: vgl_distance.h:104
void set(T ta, T tb, T tc, T td)
Set this vgl_plane_3d to have the equation $ax+by+cz+d=0$.
Definition: vgl_plane_3d.h:101
a plane in 3D nonhomogeneous space
vgl_point_3d< T > world_coords(vgl_point_2d< T > const &p2d) const
inverse map from plane coordinates to world coordinates.
bool operator==(vgl_plane_3d< T > const &p) const
the comparison operator.
bool parallel(v const &a, v const &b, double eps=0.0)
are two vectors parallel, i.e., is one a scalar multiple of the other?.
Set of distance functions.
double cos_angle(v const &a, v const &b)
cosine of the angle between two vectors.
bool contains(vgl_point_3d< T > const &p, T tol=(T) 0) const
Return true if p is on the plane.
vgl_vector_3d< Type > direction() const
Definition: vgl_ray_3d.h:68
T c() const
Return z coefficient.
Definition: vgl_plane_3d.h:95
Type & y()
Definition: vgl_point_3d.h:72
Type & x()
Definition: vgl_point_2d.h:71