File: distance3.h

package info (click to toggle)
meshlab 1.3.2%2Bdfsg1-4
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 21,096 kB
  • ctags: 33,630
  • sloc: cpp: 224,813; ansic: 8,170; xml: 119; makefile: 80
file content (521 lines) | stat: -rw-r--r-- 16,510 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
/****************************************************************************
* VCGLib                                                            o o     *
* Visual and Computer Graphics Library                            o     o   *
*                                                                _   O  _   *
* Copyright(C) 2004                                                \/)\/    *
* Visual Computing Lab                                            /\/|      *
* ISTI - Italian National Research Council                           |      *
*                                                                    \      *
* All rights reserved.                                                      *
*                                                                           *
* This program is free software; you can redistribute it and/or modify      *   
* it under the terms of the GNU General Public License as published by      *
* the Free Software Foundation; either version 2 of the License, or         *
* (at your option) any later version.                                       *
*                                                                           *
* This program is distributed in the hope that it will be useful,           *
* but WITHOUT ANY WARRANTY; without even the implied warranty of            *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
* for more details.                                                         *
*                                                                           *
****************************************************************************/
/****************************************************************************/

#ifndef __VCG_DISTANCE3
#define __VCG_DISTANCE3

#include <limits>
#include <vcg/space/intersection3.h>

namespace vcg {


/*
* Computes the minimum distance between a 3D box and a point
* @param[in] p				The input point
* @param[in] b				The input bounding box
* return			The distance
* This function returns 0 for points Inside the bbox while the next one return the distance from the surface
*/
template<class Scalar>
Scalar PointFilledBoxDistance(const Point3<Scalar> &p, const Box3<Scalar> &bbox)
{
	Scalar dist2 = 0.;
	Scalar aux;
	for (int k=0 ; k<3 ; ++k)
	{
		if ( (aux = (p[k]-bbox.min[k]))<0. )
			dist2 += aux*aux;
		else if ( (aux = (bbox.max[k]-p[k]))<0. )
			dist2 += aux*aux;
	}
	return sqrt(dist2);
}

/*
* Computes the minimum distance between a 3D box and a point
* @param[in] p				The input point
* @param[in] b				The input bounding box
* @param[out] dist			The distance
* Note that this function with respect to the previous one compute the distance between a point
* and the 'surface' of a Box3. 
* 
*/
template <class ScalarType> 
void PointBoxDistance(const Point3<ScalarType> &p,
										const Box3<ScalarType> &b,
										ScalarType& dist)
{
	///if fall inside return distance to a face
	if (b.IsIn(p))
	{
		const ScalarType dx = std::min<ScalarType>(b.max.X()-p.X(), p.X()-b.min.X());
		const ScalarType dy = std::min<ScalarType>(b.max.Y()-p.Y(), p.Y()-b.min.Y());
		const ScalarType dz = std::min<ScalarType>(b.max.Z()-p.Z(), p.Z()-b.min.Z());

		dist= std::min<ScalarType>(dx, std::min<ScalarType>(dy, dz));
		return;
	}
    
	{
		ScalarType sq_dist = ScalarType(0);
		for (int i=0; i<3; ++i)
		{
			ScalarType delta = ScalarType(0);
			if       (p[i] < b.min[i])  delta = p[i] - b.min[i];
			else if  (p[i] > b.max[i])  delta = p[i] - b.max[i];
			sq_dist += delta * delta;
		}

    dist= math::Sqrt(sq_dist);
	}
}

/*
* Computes the minimum distance between a sphere and a point
* @param[in] p				The input point
* @param[in] sphere		The input sphere
* @param[out] dist			The distance
*/
template <class ScalarType> 
void SpherePointDistance(const Sphere3<ScalarType> &sphere, 
															 const Point3<ScalarType> &p,
															 ScalarType& dist) 
{
  dist = Distance(p, sphere.Center()) - sphere.Radius();
  if(dist < 0) dist = 0;
}

/*
* Computes the minimum distance between two spheres
* @param[in] sphere0				The input sphere
* @param[in] sphere1				The input sphere
* @param[out] dist			The distance
*/
template <class ScalarType> 
void SphereSphereDistance(const Sphere3<ScalarType> &sphere0, 
													const Sphere3<ScalarType> &sphere1,
													ScalarType& dist) 
{
  dist = (sphere1.Center()-sphere0.Center()).Norm()
                    - sphere0.Radius() - sphere1.Radius();
  if(dist < 0) dist = 0;
  return dist;
}


/*
* Computes the minimum squared distance between a between a point and a line
* @param[in] l				The input line
* @param[in] p				The input point
* @param[out] closest	The closest point
* @param[out] dist		The squared distance
*/
template <class ScalarType> 
void  LinePointSquaredDistance(const Line3<ScalarType> &l,const Point3<ScalarType> &p,
												Point3<ScalarType> &closest,ScalarType &dist) 
{
	closest=l.P(l.Projection(p));
  dist= (closest - p).SquaredNorm();
}

/*
* Computes the minimum  distance between a between a point and a line
* @param[in] l				The input line
* @param[in] p				The input point
* @param[out] closest				The closest point
* @param[out] dist			The distance
*/
template <class ScalarType> 
void  LinePointDistance(const Line3<ScalarType> &l,const Point3<ScalarType> &p,
												Point3<ScalarType> &closest,ScalarType &dist) 
{
	LinePointSquaredDistance(l,p,closest,dist);
	dist=sqrt(dist);
}

/*
* Computes the minimum  distance between two lines
* @param[in] mLine0				The input line0
* @param[in] mLine1				The input line1
* @param[out] parallel		true if the two lines are parallel
* @param[mClosestPoint0]  the closest point on line0
* @param[mClosestPoint1]  the closest point on line1
*/
template <class ScalarType>
void LineLineDistance(const vcg::Line3<ScalarType> &mLine0,
											const vcg::Line3<ScalarType> &mLine1,
											bool &parallel,
											ScalarType &dist,
											vcg::Point3<ScalarType> &mClosestPoint0,
											vcg::Point3<ScalarType> &mClosestPoint1)
{
  const ScalarType loc_EPSILON=ScalarType(0.000000001);
	typedef typename vcg::Point3<ScalarType> CoordType;
  CoordType diff = mLine0.Origin() - mLine1.Origin();
  ScalarType a01 = -mLine0.Direction()* mLine1.Direction();
  ScalarType b0 = diff *(mLine0.Direction());
  ScalarType c = diff.SquaredNorm();
  ScalarType det = fabs((ScalarType)1 - a01*a01);
  ScalarType b1, s0, s1, sqrDist;

    if (det >=loc_EPSILON)
    {
        // Lines are not parallel.
        b1 = -diff*(mLine1.Direction());
        ScalarType invDet = ((ScalarType)1)/det;
        s0 = (a01*b1 - b0)*invDet;
        s1 = (a01*b0 - b1)*invDet;
        sqrDist = s0*(s0 + a01*s1 + ((ScalarType)2)*b0) +
            s1*(a01*s0 + s1 + ((ScalarType)2)*b1) + c;
				parallel=false;
    }
    else
    {
        // Lines are parallel, select any closest pair of points.
        s0 = -b0;
        s1 = (ScalarType)0;
        sqrDist = b0*s0 + c;
				parallel=true;
    }
		///find the two closest points
    mClosestPoint0 = mLine0.Origin() + mLine0.Direction()*s0;
    mClosestPoint1 = mLine1.Origin() + mLine1.Direction()*s1;
    /*mLine0Parameter = s0;
    mLine1Parameter = s1;*/

    // Account for numerical round-off errors.
    if (sqrDist < (ScalarType)0)
    {
        sqrDist = (ScalarType)0;
    }
    dist=sqrt(sqrDist);
}


/*
* Computes the minimum distance between a segment and a point
* @param[in] segment	The input segment
* @param[in] p				The input point
* @param[in] clos			The closest point
* @param[in] sqr_dist The squared distance
*/
template <class ScalarType> 
void SegmentPointSquaredDistance( const Segment3<ScalarType> &s,
																							 const Point3<ScalarType> & p,
																							 Point3< ScalarType > &closest,
																							 ScalarType &sqr_dist) 
{
	Point3<ScalarType> e = s.P1()-s.P0();
	ScalarType eSquaredNorm = e.SquaredNorm();
	if (eSquaredNorm < std::numeric_limits<ScalarType>::min())
	{
		closest=s.MidPoint();
		sqr_dist=SquaredDistance(closest,p);
	}
	else
	{
		ScalarType  t = ((p-s.P0())*e)/eSquaredNorm;
		if(t<0)      t = 0;
		else if(t>1) t = 1;
		closest = s.P0()+e*t;
		sqr_dist = SquaredDistance(p,closest);
		assert(!math::IsNAN(sqr_dist));
	}
}

/*
* Computes the minimum distance between a segment and a point
* @param[in] segment	The input segment
* @param[in] p				The input point
* @param[in] clos			The closest point
* @param[in] dist The distance
*/
template <class ScalarType> 
void SegmentPointDistance( Segment3<ScalarType> s, 
													const Point3<ScalarType> & p,
													Point3< ScalarType > &clos,
													ScalarType &dist) 
{
	SegmentPointSquaredDistance(s,p,clos,dist);
	dist=sqrt(dist);
}

/*
* Computes the minimum distance between two segments
* @param[in] s0				The input segment0
* @param[in] s1				The input segment1
* @param[out] parallel		true if the two segments are parallel
* @param[out] dist		the distance
* @param[closest0]  the closest point on segment0
* @param[closest1]  the closest point on segment1
*/
template <class ScalarType>
void SegmentSegmentDistance(const vcg::Segment3<ScalarType> &s0,
														const vcg::Segment3<ScalarType> &s1,
														ScalarType &dist,
														bool &parallel,
														vcg::Point3<ScalarType> &closest0,
														vcg::Point3<ScalarType> &closest1)

{
	typedef typename vcg::Point3<ScalarType> CoordType;

	vcg::Line3<ScalarType> l0,l1;

	///construct two lines
	l0.SetOrigin(s0.P0());
	l0.SetDirection((s0.P1()-s0.P0()).Normalize());

	l1.SetOrigin(s1.P0());
	l1.SetDirection((s1.P1()-s1.P0()).Normalize());

	///then find closest point
	ScalarType line_dist;
	CoordType closest_test0,closest_test1;
	LineLineDistance(l0,l1,parallel,line_dist,closest_test0,closest_test1);
	///special case if the two lines are parallel
	if (parallel)
	{
		///find the minimum distance between extremes to segments
		ScalarType dist_test;
		CoordType clos_test;
    //CoordType to_test[4]={s1.P0(),s1.P1(),s0.P0(),s1.P1()};

		///find combination of distances between all extremes and segments
		SegmentPointSquaredDistance(s0,s1.P0(),clos_test,dist);
		closest0=clos_test;
		closest1=s1.P0();
		///and find the minimum updating coherently the closest points
		SegmentPointSquaredDistance(s0,s1.P1(),clos_test,dist_test);
		if (dist_test<dist)
		{
			dist=dist_test;
			closest0=clos_test;
			closest1=s1.P1();
		}
		SegmentPointSquaredDistance(s1,s0.P0(),clos_test,dist_test);
		if (dist_test<dist)
		{
			dist=dist_test;
			closest0=s0.P0();
			closest1=clos_test;
		}
		SegmentPointSquaredDistance(s1,s0.P1(),clos_test,dist_test);
		if (dist_test<dist)
		{
			dist=dist_test;
			closest0=s0.P1();
			closest1=clos_test;
		}
		dist=sqrt(dist);
		return;
	}

	///then ffind the closest segments points... 
	///means that if it is not an extreme then take 
	///the closest extreme
	ScalarType sqr_dist0;
	SegmentPointSquaredDistance(s0,closest_test0,closest0,sqr_dist0);
	ScalarType sqr_dist1;
	SegmentPointSquaredDistance(s1,closest_test1,closest1,sqr_dist1);

	///then return the distance
	dist=(closest0-closest1).Norm();
}

 /* @brief Computes the distance between a triangle and a point.
 *
 * @param t         reference to the triangle
 * @param q         point location
 * @param dist      distance from p to t
 * @param closest   perpendicular projection of p onto t
 */
template<class ScalarType>
void TrianglePointDistance(const vcg::Triangle3<ScalarType> &t,
                           const typename vcg::Point3<ScalarType> & q,
                           ScalarType & dist,
                           typename vcg::Point3<ScalarType> & closest )
{
	typedef typename vcg::Point3<ScalarType> CoordType;

	CoordType clos[3];
	ScalarType distv[3];
	CoordType clos_proj;
	ScalarType distproj;

	///find distance on the plane
	vcg::Plane3<ScalarType> plane;
	plane.Init(t.P(0),t.P(1),t.P(2));
	clos_proj=plane.Projection(q);

	///control if inside/outside
	CoordType n=(t.P(1)-t.P(0))^(t.P(2)-t.P(0));
	CoordType n0=(t.P(0)-clos_proj)^(t.P(1)-clos_proj);
	CoordType n1=(t.P(1)-clos_proj)^(t.P(2)-clos_proj);
	CoordType n2=(t.P(2)-clos_proj)^(t.P(0)-clos_proj);
	distproj=(clos_proj-q).Norm();
	if (((n*n0)>=0)&&((n*n1)>=0)&&((n*n2)>=0))
	{
		closest=clos_proj;
		dist=distproj;
		return;
	}
	

	//distance from the edges
	vcg::Segment3<ScalarType> e0=vcg::Segment3<ScalarType>(t.P(0),t.P(1));
	vcg::Segment3<ScalarType> e1=vcg::Segment3<ScalarType>(t.P(1),t.P(2));
	vcg::Segment3<ScalarType> e2=vcg::Segment3<ScalarType>(t.P(2),t.P(0));
	SegmentPointDistance(e0,q,clos[0],distv[0]);
	SegmentPointDistance(e1,q,clos[1],distv[1]);
	SegmentPointDistance(e2,q,clos[2],distv[2]);
	/*clos[0]=ClosestPoint<ScalarType>( e0, q);
	clos[1]=ClosestPoint<ScalarType>( e1, q);
	clos[2]=ClosestPoint<ScalarType>( e2, q);
	*/
	//distv[0]=(clos[0]-q).Norm();
	//distv[1]=(clos[1]-q).Norm();
	//distv[2]=(clos[2]-q).Norm();
	int min=0;

	///find minimum distance
	for (int i=1;i<3;i++)
	{
		if (distv[i]<distv[min])
			min=i;
	}

	closest=clos[min];
	dist=distv[min];
}


/*
* return the distance between a triangle and a segment
* @param[in] t				The input triangle
* @param[in] s				The input segment
* @param[out] dist		the distance
*/
template<class ScalarType>
void TriangleSegmentDistance(const vcg::Triangle3<ScalarType> &t,
														 const vcg::Segment3<ScalarType> &s,
														 ScalarType & dist)
{
	dist=std::numeric_limits<ScalarType>::max();
	///test the intersection
	ScalarType a,b;
	typedef typename vcg::Point3<ScalarType> CoordType;

	bool intersect=IntersectionSegmentTriangle<vcg::Triangle3<ScalarType> >(s,t,a,b);
	if (intersect)
	{
		dist=0;
		return;
	}
	///project endpoints and see if they fall into the triangle
	vcg::Plane3<ScalarType> pl3;
	pl3.Init(t.P(0),t.P(1),t.P(2));
	CoordType pj0=pl3.Projection(s.P(0));
	CoordType pj1=pl3.Projection(s.P(1));
	///take distances
	ScalarType dpj0=(pj0-s.P(0)).Norm();
	ScalarType dpj1=(pj1-s.P(1)).Norm();

	///test if they fall inside the triangle
	CoordType bary0,bary1;
	bool Inside0=vcg::InterpolationParameters(t,pj0,bary0);
	bool Inside1=vcg::InterpolationParameters(t,pj1,bary1);
	if (Inside0&&Inside1)
	{
		dist=std::min(dpj0,dpj1);
		return;
	}
	///initialize with the sdistance if only once falls into
	if (Inside0)
		dist=dpj0;
	if (Inside1)
		dist=dpj1;

	///then test segment-to segment distance with edges of the triangle
	for (int i=0;i<3;i++)
 {
	 vcg::Segment3<ScalarType> edge=vcg::Segment3<ScalarType>(t.P0(i),t.P0((i+1)%3));
	 ScalarType test_dist;
	 CoordType clos1,clos2;
	 bool parallel;
	 vcg::SegmentSegmentDistance<ScalarType>(s,edge,test_dist,parallel,clos1,clos2);
	 if (test_dist<dist)
		 dist=test_dist;
 }
}

/*
* return the minimum distance between two triangles
* @param[in] t0				The input triangle0
* @param[in] t1				The input triangle1
* @param[out] dist		the distance
*/
template<class ScalarType>
void TriangleTriangleDistance(const  vcg::Triangle3<ScalarType> &t0,
															const  vcg::Triangle3<ScalarType> &t1,
															ScalarType &dist)
{
  const ScalarType loc_EPSILON=(vcg::DoubleArea(t0)+vcg::DoubleArea(t1))*(ScalarType)0.0000001;
 dist=std::numeric_limits<ScalarType>::max();

 ///test each segment of t1 with t0 
 ///keeping the minimum distance
 for (int i=0;i<3;i++)
 {
	 vcg::Segment3<ScalarType> edge=vcg::Segment3<ScalarType>(t0.P0(i),t0.P0((i+1)%3));
	 ScalarType test_dist;
	 vcg::TriangleSegmentDistance<ScalarType>(t1,edge,test_dist);
   if (test_dist<loc_EPSILON)
	 {
		 dist=0;
		 return;
	 }
	 if (test_dist<dist)
		 dist=test_dist;
 }
 ///then viceversa
 for (int i=0;i<3;i++)
 {
	 vcg::Segment3<ScalarType> edge=vcg::Segment3<ScalarType>(t1.P0(i),t1.P0((i+1)%3));
	 ScalarType test_dist;
	 vcg::TriangleSegmentDistance<ScalarType>(t0,edge,test_dist);
   if (test_dist<loc_EPSILON)
	 {
		 dist=0;
		 return;
	 }
	 if (test_dist<dist)
		 dist=test_dist;
 }
}

}///end namespace vcg

#endif