Salome HOME
ce24d4b0af99dc73fc8c198b1c0b8f02396e1f31
[modules/homard.git] / src / FrontTrack / FrontTrack_Projector.cxx
1 // File      : FrontTrack_Projector.cxx
2 // Created   : Wed Apr 26 20:33:55 2017
3 // Author    : Edward AGAPOV (eap)
4
5 #include "FrontTrack_Projector.hxx"
6
7 #include <BRepAdaptor_Curve.hxx>
8 #include <BRepBndLib.hxx>
9 #include <BRepTopAdaptor_FClass2d.hxx>
10 #include <BRep_Tool.hxx>
11 #include <ElCLib.hxx>
12 #include <ElSLib.hxx>
13 #include <GCPnts_UniformDeflection.hxx>
14 #include <GeomAdaptor_Curve.hxx>
15 #include <GeomLib_IsPlanarSurface.hxx>
16 #include <ShapeAnalysis_Curve.hxx>
17 #include <ShapeAnalysis_Surface.hxx>
18 #include <TopExp.hxx>
19 #include <TopoDS.hxx>
20 #include <TopoDS_Edge.hxx>
21 #include <TopoDS_Face.hxx>
22 #include <TopoDS_Vertex.hxx>
23 #include <gp_Circ.hxx>
24 #include <gp_Cylinder.hxx>
25 #include <gp_Dir.hxx>
26 #include <gp_Pln.hxx>
27 #include <gp_Pnt.hxx>
28 #include <gp_Sphere.hxx>
29 #include <gp_Vec.hxx>
30
31 #include <limits>
32
33 //-----------------------------------------------------------------------------
34 /*!
35  * \brief Root class of a projector of a point to a boundary shape
36  */
37 struct FT_RealProjector
38 {
39   virtual ~FT_RealProjector() {}
40
41   /*!
42    * \brief Project a point to a boundary shape
43    *  \param [in] point - the point to project
44    *  \param [out] newSolution - position on the shape (U or UV) found during the projection
45    *  \param [in] prevSolution - position already found during the projection of a neighbor point
46    *  \return gp_Pnt - the projection point
47    */
48   virtual gp_Pnt project( const gp_Pnt& point,
49                           double*       newSolution,
50                           const double* prevSolution = 0) = 0;
51
52   /*!
53    * \brief Project a point to a boundary shape and check if the projection is within
54    *        the shape boundary
55    *  \param [in] point - the point to project
56    *  \param [in] maxDist2 - the maximal allowed square distance between point and projection
57    *  \param [out] projection - the projection point
58    *  \param [out] newSolution - position on the shape (U or UV) found during the projection
59    *  \param [in] prevSolution - position already found during the projection of a neighbor point
60    *  \return bool - false if the projection point lies out of the shape boundary or
61    the distance the point and the projection is more than sqrt(maxDist2)
62   */
63   virtual bool projectAndClassify( const gp_Pnt& point,
64                                    const double  maxDist2,
65                                    gp_Pnt&       projection,
66                                    double*       newSolution,
67                                    const double* prevSolution = 0) = 0;
68
69   // return true if a previously found solution can be used to speed up the projection
70
71   virtual bool canUsePrevSolution() const { return false; }
72
73
74   double _dist; // distance between the point being projected and its projection
75 };
76
77 namespace // actual projection algorithms
78 {
79   const double theEPS = 1e-12;
80
81   //================================================================================
82   /*!
83    * \brief Projector to any curve
84    */
85   //================================================================================
86
87   struct CurveProjector : public FT_RealProjector
88   {
89     BRepAdaptor_Curve   _curve;
90     double              _tol;
91     ShapeAnalysis_Curve _projector;
92     double              _uRange[2];
93
94     //-----------------------------------------------------------------------------
95     CurveProjector( const TopoDS_Edge& e, const double tol ):
96       _curve( e ), _tol( tol )
97     {
98       BRep_Tool::Range( e, _uRange[0], _uRange[1] );
99     }
100
101     //-----------------------------------------------------------------------------
102     // project a point to the curve
103     virtual gp_Pnt project( const gp_Pnt& P,
104                             double*       newSolution,
105                             const double* prevSolution = 0)
106     {
107       gp_Pnt         proj;
108       Standard_Real param;
109       
110       if ( prevSolution )
111       {
112         _dist = _projector.NextProject( prevSolution[0], _curve, P, _tol, proj, param );
113       }
114       else
115       {
116         _dist = _projector.Project( _curve, P, _tol, proj, param, false );
117         proj  = _curve.Value( param );
118       }
119
120       newSolution[0] = param;
121
122       return proj;
123     }
124
125     //-----------------------------------------------------------------------------
126     // project a point to a curve and check if the projection is within the curve boundary
127     virtual bool projectAndClassify( const gp_Pnt& point,
128                                      const double  maxDist2,
129                                      gp_Pnt&       projection,
130                                      double*       newSolution,
131                                      const double* prevSolution = 0)
132     {
133       projection = project( point, newSolution, prevSolution );
134       return ( _uRange[0] < newSolution[0] && newSolution[0] < _uRange[1] &&
135                _dist * _dist < maxDist2 );
136     }
137
138     //-----------------------------------------------------------------------------
139     // return true if a previously found solution can be used to speed up the projection
140     virtual bool canUsePrevSolution() const { return true; }
141   };
142
143   //================================================================================
144   /*!
145    * \brief Projector to a straight curve. Don't project, classify only
146    */
147   //================================================================================
148
149   struct LineProjector : public FT_RealProjector
150   {
151     gp_Pnt _p0, _p1;
152
153     //-----------------------------------------------------------------------------
154     LineProjector( TopoDS_Edge e )
155     {
156       e.Orientation( TopAbs_FORWARD );
157       _p0 = BRep_Tool::Pnt( TopExp::FirstVertex( e ));
158       _p1 = BRep_Tool::Pnt( TopExp::LastVertex ( e ));
159     }
160
161     //-----------------------------------------------------------------------------
162     // does nothing
163     virtual gp_Pnt project( const gp_Pnt& P,
164                             double*       newSolution,
165                             const double* prevSolution = 0)
166     {
167       return P;
168     }
169     //-----------------------------------------------------------------------------
170     // check if a point lies within the line segment
171     virtual bool projectAndClassify( const gp_Pnt& point,
172                                      const double  maxDist2,
173                                      gp_Pnt&       projection,
174                                      double*       newSolution,
175                                      const double* prevSolution = 0)
176     {
177       gp_Vec edge( _p0, _p1 );
178       gp_Vec p0p ( _p0, point  );
179       double u = ( edge * p0p ) / edge.SquareMagnitude();  // param [0,1] on the edge
180       projection = ( 1. - u ) * _p0.XYZ() + u * _p1.XYZ(); // projection of the point on the edge
181       if ( u < 0 || 1 < u )
182         return false;
183
184       // check distance
185       return point.SquareDistance( projection ) < theEPS * theEPS;
186     }
187   };
188
189   //================================================================================
190   /*!
191    * \brief Projector to a circular edge
192    */
193   //================================================================================
194
195   struct CircleProjector : public FT_RealProjector
196   {
197     gp_Circ _circle;
198     double _uRange[2];
199
200     //-----------------------------------------------------------------------------
201     CircleProjector( const gp_Circ& c, const double f, const double l ):
202       _circle( c )
203     {
204       _uRange[0] = f;
205       _uRange[1] = l;
206     }
207
208     //-----------------------------------------------------------------------------
209     // project a point to the circle
210     virtual gp_Pnt project( const gp_Pnt& P,
211                             double*       newSolution,
212                             const double* prevSolution = 0)
213     {
214       // assume that P is already on the the plane of circle, since
215       // it is in the middle of two points lying on the circle
216
217       // move P to the circle
218       const gp_Pnt& O = _circle.Location();
219       gp_Vec radiusVec( O, P );
220       double radius = radiusVec.Magnitude();
221       if ( radius < std::numeric_limits<double>::min() )
222         return P; // P in on the axe
223
224       gp_Pnt proj = O.Translated( radiusVec.Multiplied( _circle.Radius() / radius ));
225
226       _dist = _circle.Radius() - radius;
227
228       return proj;
229     }
230
231     //-----------------------------------------------------------------------------
232     // project and check if a projection lies within the circular edge
233     virtual bool projectAndClassify( const gp_Pnt& point,
234                                      const double  maxDist2,
235                                      gp_Pnt&       projection,
236                                      double*       newSolution,
237                                      const double* prevSolution = 0)
238     {
239       _dist = -1;
240       projection = project( point, newSolution );
241       if ( _dist < 0 || // ?
242            _dist * _dist > maxDist2 )
243         return false;
244
245       newSolution[0] = ElCLib::Parameter( _circle, projection );
246       return ( _uRange[0] < newSolution[0] && newSolution[0] < _uRange[1] );
247     }
248   };
249
250   //================================================================================
251   /*!
252    * \brief Projector to any surface
253    */
254   //================================================================================
255
256   struct SurfaceProjector : public FT_RealProjector
257   {
258     ShapeAnalysis_Surface    _projector;
259     double                   _tol;
260     BRepTopAdaptor_FClass2d* _classifier;
261
262     //-----------------------------------------------------------------------------
263     SurfaceProjector( const TopoDS_Face& face, const double tol, BRepTopAdaptor_FClass2d* cls ):
264       _projector( BRep_Tool::Surface( face )),
265       _tol( tol ),
266       _classifier( cls )
267     {
268     }
269     //-----------------------------------------------------------------------------
270     // delete _classifier
271     ~SurfaceProjector()
272     {
273       delete _classifier;
274     }
275
276     //-----------------------------------------------------------------------------
277     // project a point to a surface
278     virtual gp_Pnt project( const gp_Pnt& P,
279                             double*       newSolution,
280                             const double* prevSolution = 0)
281     {
282       gp_Pnt2d uv;
283
284       if ( prevSolution )
285       {
286         gp_Pnt2d prevUV( prevSolution[0], prevSolution[1] );
287         uv = _projector.NextValueOfUV( prevUV, P, _tol );
288       }
289       else
290       {
291         uv = _projector.ValueOfUV( P, _tol );
292       }
293
294       uv.Coord( newSolution[0], newSolution[1] );
295
296       gp_Pnt proj = _projector.Value( uv );
297
298       _dist = _projector.Gap();
299
300       return proj;
301     }
302
303     //-----------------------------------------------------------------------------
304     // project a point to a surface and check if the projection is within the surface boundary
305     virtual bool projectAndClassify( const gp_Pnt& point,
306                                      const double  maxDist2,
307                                      gp_Pnt&       projection,
308                                      double*       newSolution,
309                                      const double* prevSolution = 0)
310     {
311       projection = project( point, newSolution, prevSolution );
312       return ( _dist * _dist < maxDist2 )  &&  classify( newSolution );
313     }
314
315     //-----------------------------------------------------------------------------
316     // check if the projection is within the shape boundary
317     bool classify( const double* newSolution )
318     {
319       TopAbs_State state = _classifier->Perform( gp_Pnt2d( newSolution[0], newSolution[1]) );
320       return ( state != TopAbs_OUT );
321     }
322
323     //-----------------------------------------------------------------------------
324     // return true if a previously found solution can be used to speed up the projection
325     virtual bool canUsePrevSolution() const { return true; }
326   };
327
328   //================================================================================
329   /*!
330    * \brief Projector to a plane. Don't project, classify only
331    */
332   //================================================================================
333
334   struct PlaneProjector : public SurfaceProjector
335   {
336     gp_Pln _plane;
337     bool   _isRealPlane; // false means that a surface is planar but parametrization is different
338
339     //-----------------------------------------------------------------------------
340     PlaneProjector( const gp_Pln&            pln,
341                     const TopoDS_Face&       face,
342                     BRepTopAdaptor_FClass2d* cls,
343                     bool                     isRealPlane=true):
344       SurfaceProjector( face, 0, cls ),
345       _plane( pln ),
346       _isRealPlane( isRealPlane )
347     {}
348
349     //-----------------------------------------------------------------------------
350     // does nothing
351     virtual gp_Pnt project( const gp_Pnt& P,
352                             double*       newSolution,
353                             const double* prevSolution = 0)
354     {
355       return P;
356     }
357     //-----------------------------------------------------------------------------
358     // check if a point lies within the boundry of the planar face
359     virtual bool projectAndClassify( const gp_Pnt& point,
360                                      const double  maxDist2,
361                                      gp_Pnt&       projection,
362                                      double*       newSolution,
363                                      const double* prevSolution = 0)
364     {
365       if ( _isRealPlane )
366       {
367         ElSLib::PlaneParameters( _plane.Position(), point, newSolution[0], newSolution[1]);
368         projection = ElSLib::PlaneValue ( newSolution[0], newSolution[1], _plane.Position() );
369         if ( projection.SquareDistance( point ) > theEPS * theEPS )
370           return false;
371
372         return SurfaceProjector::classify( newSolution );
373       }
374       else
375       {
376         return SurfaceProjector::projectAndClassify( point, maxDist2, projection,
377                                                      newSolution, prevSolution );
378       }
379     }
380     //-----------------------------------------------------------------------------
381     // return true if a previously found solution can be used to speed up the projection
382     virtual bool canUsePrevSolution() const { return false; }
383   };
384
385   //================================================================================
386   /*!
387    * \brief Projector to a cylinder
388    */
389   //================================================================================
390
391   struct CylinderProjector : public SurfaceProjector
392   {
393     gp_Cylinder _cylinder;
394
395     //-----------------------------------------------------------------------------
396     CylinderProjector( const gp_Cylinder&       c,
397                        const TopoDS_Face&       face,
398                        BRepTopAdaptor_FClass2d* cls ):
399       SurfaceProjector( face, 0, cls ),
400       _cylinder( c )
401     {}
402
403     //-----------------------------------------------------------------------------
404     // project a point to the cylinder
405     virtual gp_Pnt project( const gp_Pnt& P,
406                             double*       newSolution,
407                             const double* prevSolution = 0)
408     {
409       // project the point P to the cylinder axis -> Pp
410       const gp_Pnt& O   = _cylinder.Position().Location();
411       const gp_Dir& axe = _cylinder.Position().Direction();
412       gp_Vec       trsl = gp_Vec( axe ).Multiplied( gp_Vec( O, P ).Dot( axe ));
413       gp_Pnt       Pp   = O.Translated( trsl );
414
415       // move Pp to the cylinder
416       gp_Vec radiusVec( Pp, P );
417       double radius = radiusVec.Magnitude();
418       if ( radius < std::numeric_limits<double>::min() )
419         return P; // P in on the axe
420
421       gp_Pnt proj = Pp.Translated( radiusVec.Multiplied( _cylinder.Radius() / radius ));
422
423       _dist = _cylinder.Radius() - radius;
424
425       return proj;
426     }
427     //-----------------------------------------------------------------------------
428     // project a point to the cylinder and check if the projection is within the surface boundary
429     virtual bool projectAndClassify( const gp_Pnt& point,
430                                      const double  maxDist2,
431                                      gp_Pnt&       projection,
432                                      double*       newSolution,
433                                      const double* prevSolution = 0)
434     {
435       ElSLib::CylinderParameters( _cylinder.Position(), _cylinder.Radius(), point,
436                                   newSolution[0], newSolution[1]);
437       projection = ElSLib::CylinderValue( newSolution[0], newSolution[1],
438                                           _cylinder.Position(), _cylinder.Radius() );
439
440       return ( _dist * _dist < maxDist2 )  &&  SurfaceProjector::classify( newSolution );
441     }
442     //-----------------------------------------------------------------------------
443     // return true if a previously found solution can be used to speed up the projection
444     virtual bool canUsePrevSolution() const { return false; }
445   };
446
447   //================================================================================
448   /*!
449    * \brief Projector to a cone
450    */
451   //================================================================================
452
453   struct ConeProjector : public SurfaceProjector
454   {
455     gp_Cone _cone;
456
457     //-----------------------------------------------------------------------------
458     ConeProjector( const gp_Cone&           c,
459                    const TopoDS_Face&       face,
460                    BRepTopAdaptor_FClass2d* cls ):
461       SurfaceProjector( face, 0, cls ),
462       _cone( c )
463     {}
464
465     //-----------------------------------------------------------------------------
466     // project a point to the cone
467     virtual gp_Pnt project( const gp_Pnt& point,
468                             double*       newSolution,
469                             const double* prevSolution = 0)
470     {
471       ElSLib::ConeParameters( _cone.Position(), _cone.RefRadius(), _cone.SemiAngle(),
472                               point, newSolution[0], newSolution[1]);
473       gp_Pnt proj = ElSLib::ConeValue( newSolution[0], newSolution[1],
474                                        _cone.Position(), _cone.RefRadius(), _cone.SemiAngle() );
475       _dist = point.Distance( proj );
476
477       return proj;
478     }
479
480     //-----------------------------------------------------------------------------
481     // project a point to the cone and check if the projection is within the surface boundary
482     virtual bool projectAndClassify( const gp_Pnt& point,
483                                      const double  maxDist2,
484                                      gp_Pnt&       projection,
485                                      double*       newSolution,
486                                      const double* prevSolution = 0)
487     {
488       projection = project( point, newSolution, prevSolution );
489
490       return ( _dist * _dist < maxDist2 )  &&  SurfaceProjector::classify( newSolution );
491     }
492     //-----------------------------------------------------------------------------
493     // return true if a previously found solution can be used to speed up the projection
494     virtual bool canUsePrevSolution() const { return false; }
495   };
496
497   //================================================================================
498   /*!
499    * \brief Projector to a sphere
500    */
501   //================================================================================
502
503   struct SphereProjector : public SurfaceProjector
504   {
505     gp_Sphere _sphere;
506
507     //-----------------------------------------------------------------------------
508     SphereProjector( const gp_Sphere&         s,
509                      const TopoDS_Face&       face,
510                      BRepTopAdaptor_FClass2d* cls ):
511       SurfaceProjector( face, 0, cls ),
512       _sphere( s )
513     {}
514
515     //-----------------------------------------------------------------------------
516     // project a point to the sphere
517     virtual gp_Pnt project( const gp_Pnt& P,
518                             double*       newSolution,
519                             const double* prevSolution = 0)
520     {
521       // move Pp to the Sphere
522       const gp_Pnt& O = _sphere.Location();
523       gp_Vec radiusVec( O, P );
524       double radius = radiusVec.Magnitude();
525       if ( radius < std::numeric_limits<double>::min() )
526         return P; // P is on O
527
528       gp_Pnt proj = O.Translated( radiusVec.Multiplied( _sphere.Radius() / radius ));
529
530       _dist = _sphere.Radius() - radius;
531
532       return proj;
533     }
534
535     //-----------------------------------------------------------------------------
536     // project a point to the sphere and check if the projection is within the surface boundary
537     virtual bool projectAndClassify( const gp_Pnt& point,
538                                      const double  maxDist2,
539                                      gp_Pnt&       projection,
540                                      double*       newSolution,
541                                      const double* prevSolution = 0)
542     {
543       ElSLib::SphereParameters( _sphere.Position(), _sphere.Radius(), point,
544                                   newSolution[0], newSolution[1]);
545       projection = ElSLib::SphereValue( newSolution[0], newSolution[1],
546                                         _sphere.Position(), _sphere.Radius() );
547
548       return ( _dist * _dist < maxDist2 )  &&  SurfaceProjector::classify( newSolution );
549     }
550     //-----------------------------------------------------------------------------
551     // return true if a previously found solution can be used to speed up the projection
552     virtual bool canUsePrevSolution() const { return false; }
553   };
554
555   //================================================================================
556   /*!
557    * \brief Projector to a torus
558    */
559   //================================================================================
560
561   struct TorusProjector : public SurfaceProjector
562   {
563     gp_Torus _torus;
564
565     //-----------------------------------------------------------------------------
566     TorusProjector( const gp_Torus&          t,
567                     const TopoDS_Face&       face,
568                     BRepTopAdaptor_FClass2d* cls ):
569       SurfaceProjector( face, 0, cls ),
570       _torus( t )
571     {}
572
573     //-----------------------------------------------------------------------------
574     // project a point to the torus
575     virtual gp_Pnt project( const gp_Pnt& point,
576                             double*       newSolution,
577                             const double* prevSolution = 0)
578     {
579       ElSLib::TorusParameters( _torus.Position(), _torus.MajorRadius(), _torus.MinorRadius(),
580                                point, newSolution[0], newSolution[1]);
581       gp_Pnt proj = ElSLib::TorusValue( newSolution[0], newSolution[1],
582                                         _torus.Position(), _torus.MajorRadius(), _torus.MinorRadius() );
583       _dist = point.Distance( proj );
584
585       return proj;
586     }
587
588     //-----------------------------------------------------------------------------
589     // project a point to the torus and check if the projection is within the surface boundary
590     virtual bool projectAndClassify( const gp_Pnt& point,
591                                      const double  maxDist2,
592                                      gp_Pnt&       projection,
593                                      double*       newSolution,
594                                      const double* prevSolution = 0)
595     {
596       projection = project( point, newSolution, prevSolution );
597
598       return ( _dist * _dist < maxDist2 )  &&  SurfaceProjector::classify( newSolution );
599     }
600     //-----------------------------------------------------------------------------
601     // return true if a previously found solution can be used to speed up the projection
602     virtual bool canUsePrevSolution() const { return false; }
603   };
604
605   //================================================================================
606   /*!
607    * \brief Check if a curve can be considered straight
608    */
609   //================================================================================
610
611   bool isStraight( const GeomAdaptor_Curve& curve, const double tol )
612   {
613     // rough check: evaluate how far from a straight line connecting the curve ends
614     // stand several internal points of the curve 
615
616     const double  f = curve.FirstParameter();
617     const double  l = curve.LastParameter();
618     const gp_Pnt pf = curve.Value( f );
619     const gp_Pnt pl = curve.Value( l );
620     const gp_Vec lineVec( pf, pl );
621     const double lineLen2 = lineVec.SquareMagnitude();
622     if ( lineLen2 < std::numeric_limits< double >::min() )
623       return false; // E seems closed
624
625     const double nbSamples = 7;
626     for ( int i = 0; i < nbSamples; ++i )
627     {
628       const double  r = ( i + 1 ) / nbSamples;
629       const gp_Pnt pi = curve.Value( f * r + l * ( 1 - r ));
630       const gp_Vec vi( pf, pi );
631       const double h2 = lineVec.Crossed( vi ).SquareMagnitude() / lineLen2;
632       if ( h2 > tol * tol )
633         return false;
634     }
635
636     // thorough check
637     GCPnts_UniformDeflection divider( curve, tol );
638     return ( divider.IsDone() && divider.NbPoints() < 3 );
639   }
640 }
641
642 //================================================================================
643 /*!
644  * \brief Initialize with a boundary shape
645  */
646 //================================================================================
647
648 FT_Projector::FT_Projector(const TopoDS_Shape& shape)
649 {
650   _realProjector = 0;
651   setBoundaryShape( shape );
652 }
653
654 //================================================================================
655 /*!
656  * \brief Copy another projector
657  */
658 //================================================================================
659
660 FT_Projector::FT_Projector(const FT_Projector& other)
661 {
662   _realProjector = 0;
663   _shape = other._shape;
664   _bndBox = other._bndBox;
665 }
666
667 //================================================================================
668 /*!
669  * \brief Destructor. Delete _realProjector
670  */
671 //================================================================================
672
673 FT_Projector::~FT_Projector()
674 {
675   delete _realProjector;
676 }
677
678 //================================================================================
679 /*!
680  * \brief Initialize with a boundary shape. Compute the bounding box
681  */
682 //================================================================================
683
684 void FT_Projector::setBoundaryShape(const TopoDS_Shape& shape)
685 {
686   delete _realProjector; _realProjector = 0;
687   _shape = shape;
688   if ( shape.IsNull() )
689     return;
690
691   BRepBndLib::Add( shape, _bndBox );
692   _bndBox.Enlarge( 1e-5 * sqrt( _bndBox.SquareExtent() ));
693 }
694
695 //================================================================================
696 /*!
697  * \brief Create a real projector
698  */
699 //================================================================================
700
701 void FT_Projector::prepareForProjection()
702 {
703   if ( _shape.IsNull() || _realProjector )
704     return;
705
706   if ( _shape.ShapeType() == TopAbs_EDGE )
707   {
708     const TopoDS_Edge& edge = TopoDS::Edge( _shape );
709
710     double tol = 1e-6 * sqrt( _bndBox.SquareExtent() );
711
712     double f,l;
713     Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, f,l );
714     if ( curve.IsNull() )
715       return; // degenerated edge
716
717     GeomAdaptor_Curve acurve( curve, f, l );
718     switch ( acurve.GetType() )
719     {
720     case GeomAbs_Line:
721       _realProjector = new LineProjector( edge );
722       break;
723     case GeomAbs_Circle:
724       _realProjector = new CircleProjector( acurve.Circle(), f, l );
725       break;
726     case GeomAbs_BezierCurve:
727     case GeomAbs_BSplineCurve:
728     case GeomAbs_OffsetCurve:
729     case GeomAbs_OtherCurve:
730       if ( isStraight( acurve, tol ))
731       {
732         _realProjector = new LineProjector( edge );
733         break;
734       }
735     case GeomAbs_Ellipse:
736     case GeomAbs_Hyperbola:
737     case GeomAbs_Parabola:
738       _realProjector = new CurveProjector( edge, tol );
739     }
740   }
741   else if ( _shape.ShapeType() == TopAbs_FACE )
742   {
743     TopoDS_Face face = TopoDS::Face( _shape );
744
745     Handle(Geom_Surface) surface = BRep_Tool::Surface( face );
746     if ( surface.IsNull() )
747       return;
748
749     GeomAdaptor_Surface asurface( surface );
750     Standard_Real tol   = BRep_Tool::Tolerance( face );
751     Standard_Real toluv = Min( asurface.UResolution( tol ), asurface.VResolution( tol ));
752     BRepTopAdaptor_FClass2d* classifier = new BRepTopAdaptor_FClass2d( face, toluv );
753
754     switch ( asurface.GetType() )
755     {
756     case GeomAbs_Plane:
757       _realProjector = new PlaneProjector( asurface.Plane(), face, classifier );
758       break;
759     case GeomAbs_Cylinder:
760       _realProjector = new CylinderProjector( asurface.Cylinder(), face, classifier );
761       break;
762     case GeomAbs_Sphere:
763       _realProjector = new SphereProjector( asurface.Sphere(), face, classifier );
764       break;
765     case GeomAbs_Cone:
766       _realProjector = new ConeProjector( asurface.Cone(), face, classifier );
767       break;
768     case GeomAbs_Torus:
769       _realProjector = new TorusProjector( asurface.Torus(), face, classifier );
770       break;
771     case GeomAbs_BezierSurface:
772     case GeomAbs_BSplineSurface:
773     case GeomAbs_SurfaceOfRevolution:
774     case GeomAbs_SurfaceOfExtrusion:
775     case GeomAbs_OffsetSurface:
776     case GeomAbs_OtherSurface:
777       GeomLib_IsPlanarSurface isPlaneCheck( surface, tol );
778       if ( isPlaneCheck.IsPlanar() )
779       {
780         _realProjector = new PlaneProjector( isPlaneCheck.Plan(), face, classifier,
781                                              /*isRealPlane=*/false);
782       }
783       else
784       {
785         _realProjector = new SurfaceProjector( face, tol, classifier );
786       }
787       break;
788     }
789   }
790 }
791
792 //================================================================================
793 /*!
794  * \brief Return true if projection is not needed
795  */
796 //================================================================================
797
798 bool FT_Projector::isPlanarBoundary() const
799 {
800   return ( dynamic_cast< LineProjector*  >( _realProjector ) ||
801            dynamic_cast< PlaneProjector* >( _realProjector ) );
802 }
803
804 //================================================================================
805 /*!
806  * \brief Check if a point lies on the boundary shape
807  *  \param [in] point - the point to check
808  *  \param [in] tol2 - a square tolerance allowing to decide whether a point is on the shape
809  *  \param [in] newSolution - position on the shape (U or UV) of the point found
810  *         during projecting
811  *  \param [in] prevSolution - position on the shape (U or UV) of a neighbor point
812  *  \return bool - \c true if the point lies on the boundary shape
813  *
814  * This method is used to select a shape by checking if all neighbor nodes of a node to move
815  * lie on a shape.
816  */
817 //================================================================================
818
819 bool FT_Projector::isOnShape( const gp_Pnt& point,
820                               const double  tol2,
821                               double*       newSolution,
822                               const double* prevSolution)
823 {
824   if ( _bndBox.IsOut( point ) || !_realProjector )
825     return false;
826
827   gp_Pnt proj;
828   if ( isPlanarBoundary() )
829     return projectAndClassify( point, tol2, proj, newSolution, prevSolution );
830
831   return project( point, tol2, proj, newSolution, prevSolution );
832 }
833
834 //================================================================================
835 /*!
836  * \brief Project a point to the boundary shape
837  *  \param [in] point - the point to project
838  *  \param [in] maxDist2 - the maximal square distance between the point and the projection
839  *  \param [out] projection - the projection
840  *  \param [out] newSolution - position on the shape (U or UV) of the point found
841  *         during projecting
842  *  \param [in] prevSolution - already found position on the shape (U or UV) of a neighbor point
843  *  \return bool - false if the distance between the point and the projection
844  *         is more than sqrt(maxDist2)
845  *
846  * This method is used to project a node in the case where only one shape is found by name
847  */
848 //================================================================================
849
850 bool FT_Projector::project( const gp_Pnt& point,
851                             const double  maxDist2,
852                             gp_Pnt&       projection,
853                             double*       newSolution,
854                             const double* prevSolution)
855 {
856   if ( !_realProjector )
857     return false;
858
859   _realProjector->_dist = 1e100;
860   projection = _realProjector->project( point, newSolution, prevSolution );
861
862   return ( _realProjector->_dist * _realProjector->_dist < maxDist2 );
863 }
864
865 //================================================================================
866 /*!
867  * \brief Project a point to the boundary shape and check if the projection lies within
868  *        the shape boundary
869  *  \param [in] point - the point to project
870  *  \param [in] maxDist2 - the maximal square distance between the point and the projection
871  *  \param [out] projection - the projection
872  *  \param [out] newSolution - position on the shape (U or UV) of the point found
873  *         during projecting
874  *  \param [in] prevSolution - already found position on the shape (U or UV) of a neighbor point
875  *  \return bool - false if the projection point lies out of the shape boundary or
876  *          the distance between the point and the projection is more than sqrt(maxDist2)
877  *
878  * This method is used to project a node in the case where several shapes are selected for
879  * projection of a node group
880  */
881 //================================================================================
882
883 bool FT_Projector::projectAndClassify( const gp_Pnt& point,
884                                        const double  maxDist2,
885                                        gp_Pnt&       projection,
886                                        double*       newSolution,
887                                        const double* prevSolution)
888 {
889   if ( _bndBox.IsOut( point ) || !_realProjector )
890     return false;
891
892   return _realProjector->projectAndClassify( point, maxDist2, projection,
893                                              newSolution, prevSolution );
894 }
895
896 //================================================================================
897 /*!
898  * \brief Return true if a previously found solution can be used to speed up the projection
899  */
900 //================================================================================
901
902 bool FT_Projector::canUsePrevSolution() const
903 {
904   return ( _realProjector && _realProjector->canUsePrevSolution() );
905 }