1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_GF_PLANE_H
25 #define PXR_BASE_GF_PLANE_H
26 
27 /// \file gf/plane.h
28 /// \ingroup group_gf_BasicGeometry
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/gf/vec3d.h"
32 #include "pxr/base/gf/api.h"
33 
34 #include <iosfwd>
35 
36 PXR_NAMESPACE_OPEN_SCOPE
37 
38 class GfRange3d;
39 class GfMatrix4d;
40 class GfVec4d;
41 
42 /// \class GfPlane
43 /// \ingroup group_gf_BasicGeometry
44 ///
45 /// Basic type: 3-dimensional plane
46 ///
47 /// This class represents a three-dimensional plane as a normal vector
48 /// and the distance of the plane from the origin, measured along the
49 /// normal. The plane can also be used to represent a half-space: the
50 /// side of the plane in the direction of the normal.
51 ///
52 class GfPlane
53 {
54   public:
55 
56     /// The default constructor leaves the plane parameters undefined.
GfPlane()57     GfPlane() {
58     }
59 
60     /// This constructor sets this to the plane perpendicular to \p normal and
61     /// at \p distance units from the origin. The passed-in normal is
62     /// normalized to unit length first.
GfPlane(const GfVec3d & normal,double distanceToOrigin)63     GfPlane(const GfVec3d &normal, double distanceToOrigin) {
64         Set(normal, distanceToOrigin);
65     }
66 
67     /// This constructor sets this to the plane perpendicular to \p normal and
68     /// that passes through \p point. The passed-in normal is normalized to
69     /// unit length first.
GfPlane(const GfVec3d & normal,const GfVec3d & point)70     GfPlane(const GfVec3d &normal, const GfVec3d &point) {
71         Set(normal, point);
72     }
73 
74     /// This constructor sets this to the plane that contains the three given
75     /// points. The normal is constructed from the cross product of (\p p1 -
76     /// \p p0) (\p p2 - \p p0). Results are undefined if the points are
77     /// collinear.
GfPlane(const GfVec3d & p0,const GfVec3d & p1,const GfVec3d & p2)78     GfPlane(const GfVec3d &p0, const GfVec3d &p1, const GfVec3d &p2) {
79         Set(p0, p1, p2);
80     }
81 
82     /// This constructor creates a plane given by the equation
83     /// \p eqn[0] * x + \p eqn[1] * y + \p eqn[2] * z + \p eqn[3] = 0.
GfPlane(const GfVec4d & eqn)84     GfPlane(const GfVec4d &eqn) {
85         Set(eqn);
86     }
87 
88     /// Sets this to the plane perpendicular to \p normal and at \p distance
89     /// units from the origin. The passed-in normal is normalized to unit
90     /// length first.
Set(const GfVec3d & normal,double distanceToOrigin)91     void                Set(const GfVec3d &normal, double distanceToOrigin) {
92         _normal = normal.GetNormalized();
93         _distance = distanceToOrigin;
94     }
95 
96     /// This constructor sets this to the plane perpendicular to \p normal and
97     /// that passes through \p point. The passed-in normal is normalized to
98     /// unit length first.
99     GF_API
100     void                Set(const GfVec3d &normal, const GfVec3d &point);
101 
102     /// This constructor sets this to the plane that contains the three given
103     /// points. The normal is constructed from the cross product of (\p p1 -
104     /// \p p0) (\p p2 - \p p0). Results are undefined if the points are
105     /// collinear.
106     GF_API
107     void                Set(const GfVec3d &p0,
108                             const GfVec3d &p1,
109                             const GfVec3d &p2);
110 
111     /// This method sets this to the plane given by the equation
112     /// \p eqn[0] * x + \p eqn[1] * y + \p eqn[2] * z + \p eqn[3] = 0.
113     GF_API
114     void                Set(const GfVec4d &eqn);
115 
116     /// Returns the unit-length normal vector of the plane.
GetNormal()117     const GfVec3d &     GetNormal() const {
118         return _normal;
119     }
120 
121     /// Returns the distance of the plane from the origin.
GetDistanceFromOrigin()122     double              GetDistanceFromOrigin() const {
123         return _distance;
124     }
125 
126     /// Give the coefficients of the equation of the plane. Suitable
127     /// to OpenGL calls to set the clipping plane.
128     GF_API
129     GfVec4d             GetEquation() const;
130 
131     /// Component-wise equality test. The normals and distances must match
132     /// exactly for planes to be considered equal.
133     bool		operator ==(const GfPlane &p) const {
134 	return (_normal   == p._normal &&
135 		_distance == p._distance);
136     }
137 
138     /// Component-wise inequality test. The normals and distances must match
139     /// exactly for planes to be considered equal.
140     bool		operator !=(const GfPlane &p) const {
141 	return ! (*this == p);
142     }
143 
144     /// Returns the distance of point \p from the plane. This distance will be
145     /// positive if the point is on the side of the plane containing the
146     /// normal.
GetDistance(const GfVec3d & p)147     double              GetDistance(const GfVec3d &p) const {
148         return p * _normal - _distance;
149     }
150 
151     /// Return the projection of \p p onto the plane.
Project(const GfVec3d & p)152     GfVec3d             Project(const GfVec3d& p) const {
153         return p - GetDistance(p) * _normal;
154     }
155 
156     /// Transforms the plane by the given matrix.
157     GF_API
158     GfPlane &           Transform(const GfMatrix4d &matrix);
159 
160     /// Flip the plane normal (if necessary) so that \p p is in the positive
161     /// halfspace.
Reorient(const GfVec3d & p)162     void                Reorient(const GfVec3d& p) {
163         if (GetDistance(p) < 0) {
164             _normal = -_normal;
165             _distance = -_distance;
166         }
167     }
168 
169     /// Returns \c true if the given aligned bounding box is at least
170     /// partially on the positive side (the one the normal points into) of the
171     /// plane.
172     GF_API
173     bool IntersectsPositiveHalfSpace(const GfRange3d &box) const;
174 
175     /// Returns true if the given point is on the plane or within its positive
176     /// half space.
IntersectsPositiveHalfSpace(const GfVec3d & pt)177     bool IntersectsPositiveHalfSpace(const GfVec3d &pt) const {
178         return GetDistance(pt) >= 0.0;
179     }
180 
181   private:
182     /// The normal to the plane. Points in direction of half-space.
183     GfVec3d             _normal;
184 
185     /// Distance from the plane to the origin.
186     double              _distance;
187 };
188 
189 /// Fits a plane to the given \p points. There must be at least three points in
190 /// order to fit the plane; if the size of \p points is less than three, this
191 /// issues a coding error.
192 ///
193 /// If the \p points are all collinear, then no plane can be determined, and
194 /// this function returns \c false. Otherwise, if the fitting is successful,
195 /// it returns \c true and sets \p *fitPlane to the fitted plane. If \p points
196 /// contains exactly three points, then the resulting plane is the exact plane
197 /// defined by the three points. If \p points contains more than three points,
198 /// then this function determines the best-fitting plane for the given points.
199 /// The orientation of the plane normal is arbitrary with regards to the
200 /// plane's positive and negative half-spaces; you can use GfPlane::Reorient()
201 /// to flip the plane if necessary.
202 ///
203 /// The current implementation uses linear least squares and thus defines
204 /// "best-fitting" as minimizing the sum of the squares of the vertical
205 /// distances between points and the plane surface.
206 GF_API
207 bool GfFitPlaneToPoints(const std::vector<GfVec3d>& points, GfPlane* fitPlane);
208 
209 /// Output a GfPlane using the format [(nx ny nz) distance].
210 /// \ingroup group_gf_DebuggingOutput
211 GF_API std::ostream& operator<<(std::ostream&, const GfPlane&);
212 
213 PXR_NAMESPACE_CLOSE_SCOPE
214 
215 #endif // PXR_BASE_GF_PLANE_H
216