MeshLib Documentation
Loading...
Searching...
No Matches
MRIntersection.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRPlane3.h"
4#include "MRLine3.h"
5#include "MRLineSegm.h"
6#include "MRVector2.h"
7#include "MRBox.h"
8#include "MRSphere.h"
9#include <optional>
10
11namespace MR
12{
13
17
21template<typename T>
22std::optional<Line3<T>> intersection( const Plane3<T>& plane1, const Plane3<T>& plane2,
23 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
24{
25 const auto crossDir = cross( plane1.n, plane2.n );
26
27 if ( crossDir.lengthSq() < errorLimit * errorLimit )
28 return {};
29
30 Matrix3<T> matrix( plane1.n, plane2.n, crossDir );
31 const auto point = matrix.inverse() * Vector3<T>( plane1.d, plane2.d, 0 );
32
33 return Line3<T>( point, crossDir.normalized() );
34}
35
39template<typename T>
40std::optional<Vector3<T>> intersection( const Plane3<T>& plane, const Line3<T>& line,
41 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
42{
43 const auto den = dot( plane.n, line.d );
44 if ( std::abs(den) < errorLimit )
45 return {};
46 return line.p + ( plane.d - dot( plane.n, line.p ) ) / den * line.d;
47}
48
52template<typename T>
53std::optional<Vector3<T>> intersection( const Line3<T>& line1, const Line3<T>& line2,
54 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
55{
56 const auto crossDir = cross( line1.d, line2.d );
57 if ( crossDir.lengthSq() < errorLimit * errorLimit )
58 return {};
59
60 const auto p1 = dot( crossDir, line1.p );
61 const auto p2 = dot( crossDir, line2.p );
62 if ( std::abs( p1 - p2 ) >= errorLimit )
63 return {};
64
65 const auto n2 = cross( line2.d, crossDir );
66 const T den = dot( line1.d, n2 );
67 if ( den == 0 ) // check for calculation
68 return {};
69 return line1.p + dot( ( line2.p - line1.p ), n2 ) / den * line1.d;
70}
71
74inline std::optional<Vector2f> intersection( const LineSegm2f& segm1, const LineSegm2f& segm2 )
75{
76 auto avec = segm1.b - segm1.a;
77 if ( cross( avec, segm2.a - segm1.a ) * cross( segm2.b - segm1.a, avec ) <= 0 )
78 return {};
79 auto bvec = segm2.b - segm2.a;
80 auto cda = cross( bvec, segm1.a - segm2.a );
81 auto cbd = cross( segm1.b - segm2.a, bvec );
82 if ( cda * cbd <= 0 )
83 return {};
84 return ( segm1.b * cda + segm1.a * cbd ) / ( cda + cbd );
85}
86
89template<typename T>
90std::optional<T> distanceSq( const Plane3<T>& plane1, const Plane3<T>& plane2,
91 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
92{
93 const auto crossDir = cross( plane1.n, plane2.n );
94
95 if ( crossDir.lengthSq() >= errorLimit * errorLimit )
96 return {};
97
98 return ( plane2.n * plane2.d - plane1.n * plane1.d ).lengthSq();
99}
100
103template<typename T>
104std::optional<T> distance( const Plane3<T>& plane1, const Plane3<T>& plane2,
105 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
106{
107 std::optional<T> res = distanceSq( plane1, plane2, errorLimit );
108 if ( res )
109 *res = std::sqrt( *res );
110 return res;
111}
112
115template<typename T>
116std::optional<T> distance( const Plane3<T>& plane, const Line3<T>& line,
117 T errorLimit = std::numeric_limits<T>::epsilon() * T( 20 ) )
118{
119 const auto den = dot( plane.n, line.d );
120 if ( std::abs( den ) >= errorLimit )
121 return {};
122
123 return std::abs( dot( line.p, plane.n ) - plane.d );
124}
125
129template<typename T>
130LineSegm3<T> closestPoints( const Line3<T>& line1, const Line3<T>& line2 )
131{
132 const auto d11 = line1.d.lengthSq();
133 const auto d12 = dot( line1.d, line2.d );
134 const auto d22 = line2.d.lengthSq();
135 const auto det = d12 * d12 - d11 * d22;
136 if ( det == 0 )
137 {
138 // lines are parallel
139 return { line1.p, line2.project( line1.p ) };
140 }
141
142 const auto dp = line2.p - line1.p;
143 const auto x = dot( dp, line1.d ) / det;
144 const auto y = dot( dp, line2.d ) / det;
145 const auto a = d12 * y - d22 * x;
146 const auto b = d11 * y - d12 * x;
147 return { line1( a ), line2( b ) };
148}
149
153template<typename T>
155{
156 const auto d11 = ln.d.lengthSq();
157 const auto d12 = dot( ln.d, ls.dir() );
158 const auto d22 = ls.lengthSq();
159 const auto det = d12 * d12 - d11 * d22;
160 if ( det == 0 ) // lines are parallel
161 return { ln.project( ls.a ), ls.a };
162
163 const auto dp = ls.a - ln.p;
164 const auto x = dot( dp, ln.d ) / det;
165 const auto y = dot( dp, ls.dir() ) / det;
166 const auto b = d11 * y - d12 * x;
167 if ( b <= 0 )
168 return { ln.project( ls.a ), ls.a };
169 if ( b >= 1 )
170 return { ln.project( ls.b ), ls.b };
171 const auto a = d12 * y - d22 * x;
172 return { ln( a ), ls( b ) };
173}
174
176template<typename T>
177LineSegm3<T> closestPoints( const Line3<T>& line, const Box3<T> & box )
178{
179 LineSegm3<T> res;
180 const auto dd = line.d.lengthSq();
181 if ( dd <= 0 )
182 {
183 res.a = line.p;
184 res.b = box.getBoxClosestPointTo( res.a );
185 return res;
186 }
187 const auto rdd = 1 / dd;
188
189 T bestDistSq = std::numeric_limits<T>::max();
190
191 static constexpr int otherDir[3][2] = { { 1, 2 }, { 2, 0 }, { 0, 1 } };
192 for ( int iDir = 0; iDir < 3; ++iDir )
193 {
194 // consider box edges parallel to unit vector #iDir
195 Vector3<T> q[4] = { box.min, box.min, box.min, box.min };
196 {
197 const int iDir1 = otherDir[iDir][0];
198 const int iDir2 = otherDir[iDir][1];
199
200 q[1][iDir2] = box.max[iDir2];
201
202 q[2][iDir1] = box.max[iDir1];
203 q[2][iDir2] = box.max[iDir2];
204
205 q[3][iDir1] = box.max[iDir1];
206 }
207
208 const auto e = box.max[iDir] - box.min[iDir];
209 const auto ee = e * e;
210 const auto db = line.d[iDir] * e;
211 const auto denom = dd * ee - db * db;
212 const bool par = denom <= 0; // line is parallel to box edge
213 const auto rdenom = par ? 0 : 1 / denom;
214 for ( int j = 0; j < 4; ++j )
215 {
216 LineSegm3<T> cand;
217 if ( par )
218 {
219 cand.a = line.p;
220 cand.a[iDir] = q[j][iDir];
221 cand.b = q[j];
222 }
223 else
224 {
225 const auto s = q[j] - line.p;
226 const auto dt = dot( line.d, s );
227 const auto bt = s[iDir] * e;
228
229 // t is line parameter: 0 - line.p, 1 - line.p + line.d
230 const auto t = ( dt * ee - bt * db ) * rdenom;
231 assert( !std::isnan( t ) );
232
233 // u is box edge parameter, find the point closest to line(t)
234 const auto u = ( t * db - bt ) / ee;
235 assert( !std::isnan( u ) );
236
237 if ( u <= 0 )
238 {
239 cand.a = line( dt * rdd );
240 cand.b = q[j];
241 }
242 else if ( u >= 1 )
243 {
244 cand.a = line( ( db + dt ) * rdd );
245 cand.b = q[j];
246 cand.b[iDir] = box.max[iDir];
247 }
248 else
249 {
250 cand.a = line( t );
251 cand.b = q[j];
252 cand.b[iDir] += e * u;
253 }
254 }
255 const auto distSq = cand.lengthSq();
256 if ( distSq < bestDistSq )
257 {
258 bestDistSq = distSq;
259 res = cand;
260 }
261 }
262 }
263 return res;
264}
265
268template<typename V>
269auto intersection( const Line<V>& line, const Sphere<V>& sphere )
270{
271 using T = typename V::ValueType;
272 std::optional<std::pair<T,T>> res;
273 const auto p = line.p - sphere.center;
274 const auto d = line.d;
275 const auto dd = dot( d, d );
276 const auto pd = dot( p, d );
277 const auto des4 = sqr( pd ) - dd * ( dot( p, p ) - sqr( sphere.radius ) );
278 if ( des4 < 0 )
279 return res;
280 const auto sqrtDes4 = std::sqrt( des4 );
281 res.emplace();
282 res->first = ( -sqrtDes4 - pd ) / dd;
283 res->second = ( sqrtDes4 - pd ) / dd;
284 return res;
285}
286
288
289} // namespace MR
std::optional< Line3< T > > intersection(const Plane3< T > &plane1, const Plane3< T > &plane2, T errorLimit=std::numeric_limits< T >::epsilon() *T(20))
Definition MRIntersection.h:22
std::optional< T > distanceSq(const Plane3< T > &plane1, const Plane3< T > &plane2, T errorLimit=std::numeric_limits< T >::epsilon() *T(20))
Definition MRIntersection.h:90
std::optional< T > distance(const Plane3< T > &plane1, const Plane3< T > &plane2, T errorLimit=std::numeric_limits< T >::epsilon() *T(20))
Definition MRIntersection.h:104
LineSegm3< T > closestPoints(const Line3< T > &line1, const Line3< T > &line2)
Definition MRIntersection.h:130
Definition MRCameraOrientationPlugin.h:8
constexpr T sqr(T x) noexcept
Definition MRMesh/MRMeshFwd.h:600
Line< Vector3< T > > Line3
Definition MRMesh/MRMeshFwd.h:239
MRMESH_CLASS Vector3
Definition MRMesh/MRMeshFwd.h:137
Box given by its min- and max- corners.
Definition MRMesh/MRBox.h:25
V getBoxClosestPointTo(const V &pt) const
returns closest point in the box to given point
Definition MRMesh/MRBox.h:111
V max
Definition MRMesh/MRBox.h:31
V min
Definition MRMesh/MRBox.h:31
Definition MRLineSegm.h:11
V a
Definition MRLineSegm.h:13
T lengthSq() const
returns squared length of this line segment
Definition MRLineSegm.h:22
V dir() const
returns directional vector of the line
Definition MRLineSegm.h:20
V b
Definition MRLineSegm.h:13
Definition MRLine.h:12
V d
Definition MRLine.h:15
V p
Definition MRLine.h:15
V project(const V &x) const
finds the closest point on line
Definition MRLine.h:37
Definition MRMesh/MRMatrix3.h:13
Definition MRPlane3.h:12
Vector3< T > n
Definition MRPlane3.h:13
T d
Definition MRPlane3.h:14
Definition MRSphere.h:9
V center
Definition MRSphere.h:12
T radius
Definition MRSphere.h:13
Definition MRMesh/MRVector3.h:19