]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_ProjectionDriver.cxx
Salome HOME
0c34bc8c26570c689a3dc37fbcb9bb5dc3b0b483
[modules/geom.git] / src / GEOMImpl / GEOMImpl_ProjectionDriver.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include <Standard_Stream.hxx>
24
25 #include <GEOMImpl_ProjectionDriver.hxx>
26
27 #include <GEOMImpl_IMirror.hxx>
28 #include <GEOMImpl_IProjection.hxx>
29 #include <GEOMImpl_IProjOnCyl.hxx>
30 #include <GEOMImpl_Types.hxx>
31 #include <GEOM_Function.hxx>
32 #include <GEOMUtils.hxx>
33 #include <GEOMUtils_HTrsfCurve2d.hxx>
34
35 #include <Approx_Curve2d.hxx>
36 #include <BRep_Tool.hxx>
37 #include <BRepAdaptor_Curve2d.hxx>
38 #include <BRepBuilderAPI_Transform.hxx>
39 #include <BRepBuilderAPI_MakeEdge.hxx>
40 #include <BRepBuilderAPI_MakeFace.hxx>
41 #include <BRepBuilderAPI_MakeVertex.hxx>
42 #include <BRepBuilderAPI_MakeWire.hxx>
43 #include <BRepClass_FaceClassifier.hxx>
44 #include <BRepExtrema_DistShapeShape.hxx>
45 #include <BRepLib.hxx>
46 #include <BRepOffsetAPI_NormalProjection.hxx>
47 #include <BRepTools.hxx>
48 #include <BRepTools_WireExplorer.hxx>
49
50 #include <TopAbs.hxx>
51 #include <TopExp.hxx>
52 #include <TopoDS.hxx>
53 #include <TopoDS_Shape.hxx>
54 #include <TopoDS_Edge.hxx>
55 #include <TopoDS_Face.hxx>
56 #include <TopoDS_Vertex.hxx>
57 #include <TopoDS_Wire.hxx>
58 #include <TopTools_ListIteratorOfListOfShape.hxx>
59
60 #include <GeomAPI_ProjectPointOnSurf.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_CylindricalSurface.hxx>
63 #include <Geom_Plane.hxx>
64 #include <Geom2d_TrimmedCurve.hxx>
65
66 #include <gp_Trsf.hxx>
67 #include <gp_Pnt.hxx>
68 #include <gp_Vec.hxx>
69
70 //=======================================================================
71 //function : GetID
72 //purpose  :
73 //======================================================================= 
74 const Standard_GUID& GEOMImpl_ProjectionDriver::GetID()
75 {
76   static Standard_GUID aProjectionDriver ("FF1BBB70-5D14-4df2-980B-3A668264EA16");
77   return aProjectionDriver; 
78 }
79
80
81 //=======================================================================
82 //function : GEOMImpl_ProjectionDriver
83 //purpose  : 
84 //=======================================================================
85
86 GEOMImpl_ProjectionDriver::GEOMImpl_ProjectionDriver() 
87 {
88 }
89
90 //=======================================================================
91 //function : Execute
92 //purpose  :
93 //======================================================================= 
94 Standard_Integer GEOMImpl_ProjectionDriver::Execute(TFunction_Logbook& log) const
95 {
96   if (Label().IsNull())  return 0;    
97   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
98
99   if (aFunction.IsNull()) return 0;
100
101   Standard_Integer aType = aFunction->GetType();
102
103   if (aType == PROJECTION_COPY) {
104     // Projection
105     TopoDS_Shape aShape;
106     gp_Trsf aTrsf;
107
108     GEOMImpl_IMirror TI (aFunction);
109
110     Handle(GEOM_Function) anOriginalFunction = TI.GetOriginal();
111     if (anOriginalFunction.IsNull()) return 0;
112
113     TopoDS_Shape anOriginal = anOriginalFunction->GetValue();
114     if (anOriginal.IsNull()) return 0;
115
116     // Source shape (point, edge or wire)
117     if (anOriginal.ShapeType() != TopAbs_VERTEX &&
118         anOriginal.ShapeType() != TopAbs_EDGE &&
119         anOriginal.ShapeType() != TopAbs_WIRE) {
120       Standard_ConstructionError::Raise
121         ("Projection aborted : the source shape is neither a vertex, nor an edge or a wire");
122     }
123
124     // Target face
125     Handle(GEOM_Function) aTargetFunction = TI.GetPlane();
126     if (aTargetFunction.IsNull()) return 0;
127     TopoDS_Shape aFaceShape = aTargetFunction->GetValue();
128     //if (aFaceShape.IsNull() || aFaceShape.ShapeType() != TopAbs_FACE) {
129     //  Standard_ConstructionError::Raise
130     //    ("Projection aborted : the target shape is not a face");
131     //}
132
133     Standard_Real tol = 1.e-4;        
134
135     if (anOriginal.ShapeType() == TopAbs_VERTEX) {
136       if (aFaceShape.IsNull() || aFaceShape.ShapeType() != TopAbs_FACE) {
137         Standard_ConstructionError::Raise
138           ("Projection aborted : the target shape is not a face");
139       }
140       TopoDS_Face aFace = TopoDS::Face(aFaceShape);
141       Handle(Geom_Surface) surface = BRep_Tool::Surface(aFace);
142       double U1, U2, V1, V2;
143       //surface->Bounds(U1, U2, V1, V2);
144       BRepTools::UVBounds(aFace, U1, U2, V1, V2);
145
146       // projector
147       GeomAPI_ProjectPointOnSurf proj;
148       proj.Init(surface, U1, U2, V1, V2, tol);
149
150       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(anOriginal));
151       proj.Perform(aPnt);
152       if (!proj.IsDone()) {
153         Standard_ConstructionError::Raise
154           ("Projection aborted : the algorithm failed");
155       }
156       int nbPoints = proj.NbPoints();
157       if (nbPoints < 1) {
158         Standard_ConstructionError::Raise("No solution found");
159       }
160
161       Quantity_Parameter U, V;
162       proj.LowerDistanceParameters(U, V);
163       gp_Pnt2d aProjPnt (U, V);
164
165       // classifier
166       BRepClass_FaceClassifier aClsf (aFace, aProjPnt, tol);
167       if (aClsf.State() != TopAbs_IN && aClsf.State() != TopAbs_ON) {
168         bool isSol = false;
169         double minDist = RealLast();
170         for (int i = 1; i <= nbPoints; i++) {
171           Quantity_Parameter Ui, Vi;
172           proj.Parameters(i, Ui, Vi);
173           aProjPnt = gp_Pnt2d(Ui, Vi);
174           aClsf.Perform(aFace, aProjPnt, tol);
175           if (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON) {
176             isSol = true;
177             double dist = proj.Distance(i);
178             if (dist < minDist) {
179               minDist = dist;
180               U = Ui;
181               V = Vi;
182             }
183           }
184         }
185         if (!isSol) {
186           Standard_ConstructionError::Raise("No solution found");
187         }
188       }
189
190       gp_Pnt surfPnt = surface->Value(U, V);
191
192       aShape = BRepBuilderAPI_MakeVertex(surfPnt).Shape();
193     }
194     else {
195       //see BRepTest_BasicCommands.cxx for example of BRepOffsetAPI_NormalProjection
196       BRepOffsetAPI_NormalProjection OrtProj (aFaceShape);
197       OrtProj.Add(anOriginal);
198
199       // Compute maximal tolerance of projection.
200       TopExp_Explorer anExp(anOriginal,TopAbs_VERTEX);
201       Standard_Real   aMaxTol = Precision::Confusion();
202
203       for(; anExp.More(); anExp.Next()) { 
204         const TopoDS_Vertex aVtx    = TopoDS::Vertex(anExp.Current());
205         const Standard_Real aCurTol = BRep_Tool::Tolerance(aVtx);
206
207         if (aMaxTol < aCurTol) {
208           aMaxTol = aCurTol;
209         }
210       }
211
212       Standard_Real tol2d = Pow(aMaxTol, 2./3);
213       GeomAbs_Shape Continuity = GeomAbs_C2;
214       Standard_Integer MaxDeg = 14;
215       Standard_Integer MaxSeg = 16;
216
217       OrtProj.SetParams(aMaxTol, tol2d, Continuity, MaxDeg, MaxSeg);
218
219       try {
220         OrtProj.Build();
221       } catch (Standard_Failure) {
222         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
223         TCollection_AsciiString aMsg (aFail->GetMessageString());
224         if (!aMsg.Length())
225           aMsg = "Projection aborted : possibly the source shape intersects the cylinder's axis";
226         Standard_ConstructionError::Raise(aMsg.ToCString());
227       }
228       if (!OrtProj.IsDone()) {
229         Standard_ConstructionError::Raise
230           ("Projection aborted : BRepOffsetAPI_NormalProjection failed");
231       }
232
233       aShape = OrtProj.Shape();
234
235       // check that the result shape is an empty compound
236       // (IPAL22905: TC650: Projection on face dialog problems)
237       if( !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND )
238       {
239         TopoDS_Iterator anIter( aShape );
240         if( !anIter.More() )
241           Standard_ConstructionError::Raise("Projection aborted : empty compound produced");
242       }
243     }
244
245     if (aShape.IsNull()) return 0;
246
247     aFunction->SetValue(aShape);
248     log.SetTouched(Label()); 
249   } else if (aType == PROJECTION_ON_WIRE) {
250     // Perform projection of point on a wire or an edge.
251     GEOMImpl_IProjection aProj (aFunction);
252     Handle(GEOM_Function) aPointFunction = aProj.GetPoint();
253     Handle(GEOM_Function) aShapeFunction = aProj.GetShape();
254
255     if (aPointFunction.IsNull() || aShapeFunction.IsNull()) {
256       return 0;
257     }
258
259     TopoDS_Shape aPoint = aPointFunction->GetValue();
260     TopoDS_Shape aShape = aShapeFunction->GetValue();
261
262     if (aPoint.IsNull() || aShape.IsNull()) {
263       return 0;
264     }
265
266     // Check shape types.
267     if (aPoint.ShapeType() != TopAbs_VERTEX) {
268       Standard_ConstructionError::Raise
269         ("Projection aborted : the point is not a vertex");
270     }
271
272     if (aShape.ShapeType() != TopAbs_EDGE &&
273         aShape.ShapeType() != TopAbs_WIRE) {
274       Standard_ConstructionError::Raise
275         ("Projection aborted : the shape is neither an edge nor a wire");
276     }
277
278     // Perform projection.
279     BRepExtrema_DistShapeShape aDistShSh(aPoint, aShape, Extrema_ExtFlag_MIN);
280
281     if (aDistShSh.IsDone() == Standard_False) {
282       Standard_ConstructionError::Raise("Projection not done");
283     }
284
285     Standard_Boolean hasValidSolution = Standard_False;
286     Standard_Integer aNbSolutions     = aDistShSh.NbSolution();
287     Standard_Integer i;
288     double           aParam   = 0.;
289     Standard_Real    aTolConf = BRep_Tool::Tolerance(TopoDS::Vertex(aPoint));
290     Standard_Real    aTolAng  = 1.e-4;        
291
292     for (i = 1; i <= aNbSolutions; i++) {
293       Standard_Boolean        isValid       = Standard_False;
294       BRepExtrema_SupportType aSupportType  = aDistShSh.SupportTypeShape2(i);
295       TopoDS_Shape            aSupportShape = aDistShSh.SupportOnShape2(i);
296
297       if (aSupportType == BRepExtrema_IsOnEdge) {
298         // Minimal distance inside edge is really a projection.
299         isValid = Standard_True;
300         aDistShSh.ParOnEdgeS2(i, aParam);
301       } else if (aSupportType == BRepExtrema_IsVertex) {
302         TopExp_Explorer anExp(aShape, TopAbs_EDGE);
303
304         if (aDistShSh.Value() <= aTolConf) {
305           // The point lies on the shape. This means this point
306           // is really a projection.
307           for (; anExp.More() && !isValid; anExp.Next()) {
308             TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
309
310             if (aCurEdge.IsNull() == Standard_False) {
311               TopoDS_Vertex aVtx[2];
312                         
313               TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
314
315               for (int j = 0; j < 2; j++) {
316                 if (aSupportShape.IsSame(aVtx[j])) {
317                   // The current edge is a projection edge.
318                   isValid       = Standard_True;
319                   aSupportShape = aCurEdge;
320                   aParam        = BRep_Tool::Parameter(aVtx[j], aCurEdge);
321                   break;
322                 }
323               }
324             }
325           }
326         } else {
327           // Minimal distance to vertex is not always a real projection.
328           gp_Pnt aPnt    = BRep_Tool::Pnt(TopoDS::Vertex(aPoint));
329           gp_Pnt aPrjPnt = BRep_Tool::Pnt(TopoDS::Vertex(aSupportShape));
330           gp_Vec aDProjP(aPrjPnt, aPnt);
331
332           for (; anExp.More() && !isValid; anExp.Next()) {
333             TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
334  
335             if (aCurEdge.IsNull() == Standard_False) {
336               TopoDS_Vertex aVtx[2];
337                           
338               TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
339  
340               for (int j = 0; j < 2; j++) {
341                 if (aSupportShape.IsSame(aVtx[j])) {
342                   // Check if the point is a projection to the current edge.
343                   Standard_Real      anEdgePars[2];
344                   Handle(Geom_Curve) aCurve =
345                     BRep_Tool::Curve(aCurEdge, anEdgePars[0], anEdgePars[1]);
346                   gp_Pnt             aVal;
347                   gp_Vec             aD1;
348
349                   aParam = BRep_Tool::Parameter(aVtx[j], aCurEdge);
350                   aCurve->D1(aParam, aVal, aD1);
351
352                   if (Abs(aD1.Dot(aDProjP)) <= aTolAng) {
353                     // The current edge is a projection edge.
354                     isValid       = Standard_True;
355                     aSupportShape = aCurEdge;
356                     break;
357                   }
358                 }
359               }
360             }
361           }
362         }
363       }
364       
365
366       if (isValid) {
367         if (hasValidSolution) {
368           Standard_ConstructionError::Raise
369             ("Projection aborted : multiple solutions");
370         }
371
372         // Store the valid solution.
373         hasValidSolution = Standard_True;
374
375         // Normalize parameter.
376         TopoDS_Edge aSupportEdge = TopoDS::Edge(aSupportShape);
377         Standard_Real aF, aL;
378
379         BRep_Tool::Range(aSupportEdge, aF, aL);
380
381         if (Abs(aL - aF) <= aTolConf) {
382           Standard_ConstructionError::Raise
383             ("Projection aborted : degenerated projection edge");
384         }
385
386         aParam = (aParam - aF)/(aL - aF);
387         aProj.SetU(aParam);
388
389         // Compute edge index.
390         TopExp_Explorer anExp(aShape, TopAbs_EDGE);
391         int anIndex = 0;
392
393         for (; anExp.More(); anExp.Next(), anIndex++) {
394           if (aSupportShape.IsSame(anExp.Current())) {
395             aProj.SetIndex(anIndex);
396             break;
397           }
398         }
399
400         if (!anExp.More()) {
401           Standard_ConstructionError::Raise
402             ("Projection aborted : Can't define edge index");
403         }
404
405         // Construct a projection vertex.
406         const gp_Pnt &aPntProj = aDistShSh.PointOnShape2(i);
407         TopoDS_Shape  aProj    = BRepBuilderAPI_MakeVertex(aPntProj).Shape();
408         
409         aFunction->SetValue(aProj);
410       }
411     }
412
413     if (!hasValidSolution) {
414       Standard_ConstructionError::Raise("Projection aborted : no projection");
415     }
416   } else if (aType == PROJECTION_ON_CYLINDER) {
417     GEOMImpl_IProjOnCyl   aProj (aFunction);
418     Handle(GEOM_Function) aShapeFunction = aProj.GetShape();
419       
420     if (aShapeFunction.IsNull()) {
421       return 0;
422     }
423
424     TopoDS_Shape aShape = aShapeFunction->GetValue();
425
426     if (aShape.IsNull()) {
427       return 0;
428     }
429
430     // Get the face.
431     const TopAbs_ShapeEnum aType        = aShape.ShapeType();
432     const Standard_Real    aRadius      = aProj.GetRadius();
433     const Standard_Real    aStartAngle  = aProj.GetStartAngle();
434     const Standard_Real    aLengthAngle = aProj.GetAngleLength();
435
436     if (aType != TopAbs_WIRE && aType != TopAbs_FACE) {
437       return 0;
438     }
439
440     if (aRadius <= Precision::Confusion()) {
441       return 0;
442     }
443
444     TopoDS_Shape aProjShape =
445       projectOnCylinder(aShape, aRadius, aStartAngle, aLengthAngle);
446
447     if (aProjShape.IsNull()) {
448       return 0;
449     }
450
451     aFunction->SetValue(aProjShape);
452   }
453
454   return 1;
455 }
456
457 //================================================================================
458 /*!
459  * \brief Returns a name of creation operation and names and values of creation parameters
460  */
461 //================================================================================
462
463 bool GEOMImpl_ProjectionDriver::
464 GetCreationInformation(std::string&             theOperationName,
465                        std::vector<GEOM_Param>& theParams)
466 {
467   if (Label().IsNull()) return 0;
468   Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
469
470   Standard_Integer aType = function->GetType();
471
472   theOperationName = "PROJECTION";
473
474   switch ( aType ) {
475   case PROJECTION_COPY:
476   {
477     GEOMImpl_IMirror aCI( function );
478
479     AddParam( theParams, "Source object", aCI.GetOriginal() );
480     AddParam( theParams, "Target face", aCI.GetPlane() );
481     break;
482   }
483   case PROJECTION_ON_WIRE:
484   {
485     GEOMImpl_IProjection aProj (function);
486
487     AddParam(theParams, "Point", aProj.GetPoint());
488     AddParam(theParams, "Shape", aProj.GetShape());
489
490     break;
491   }
492   case PROJECTION_ON_CYLINDER:
493   {
494     theOperationName = "PROJ_ON_CYL";
495
496     GEOMImpl_IProjOnCyl aProj (function);
497     const Standard_Real aLengthAngle = aProj.GetAngleLength();
498
499     AddParam(theParams, "Shape",        aProj.GetShape());
500     AddParam(theParams, "Radius",       aProj.GetRadius());
501     AddParam(theParams, "Start angle",  aProj.GetStartAngle());
502
503     if (aLengthAngle >= 0.) {
504       AddParam(theParams, "Length angle", aLengthAngle);
505     }
506
507     break;
508   }
509   default:
510     return false;
511   }
512
513   return true;
514 }
515
516 //================================================================================
517 /*!
518  * \brief Performs projection of a planar wire or a face on a cylinder.
519  */
520 //================================================================================
521
522 TopoDS_Shape GEOMImpl_ProjectionDriver::projectOnCylinder
523                                 (const TopoDS_Shape  &theShape,
524                                  const Standard_Real  theRadius,
525                                  const Standard_Real  theStartAngle,
526                                  const Standard_Real  theAngleLength) const
527 {
528   TopoDS_Shape aResult;
529
530   // Get the face.
531   const TopAbs_ShapeEnum aType = theShape.ShapeType();
532   TopoDS_Face            aFace;
533
534   if (aType == TopAbs_WIRE) {
535     // Try to create a planar face.
536     TopoDS_Wire             aWire = TopoDS::Wire(theShape);
537     BRepBuilderAPI_MakeFace aMkFace(aWire, Standard_True);
538
539     if (aMkFace.IsDone()) {
540       aFace = aMkFace.Face();
541     } else {
542       // Check if the wire is a straight line.
543       TopExp_Explorer anEExp(aWire, TopAbs_EDGE);
544       TopoDS_Edge     anEdge;
545
546       for (; anEExp.More(); anEExp.Next()) {
547         anEdge = TopoDS::Edge(anEExp.Current());
548
549         if (!BRep_Tool::Degenerated(anEdge)) {
550           break;
551         }
552       }
553
554       if (anEExp.More()) {
555         // Not degenerated edge found. Try to create a plane.
556         Standard_Real      aPar[2];
557         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aPar[0], aPar[1]);
558         gp_Pnt             aP0    = aCurve->Value(aPar[0]);
559         gp_Pnt             aP1    = aCurve->Value(0.5*(aPar[1] + aPar[0]));
560         gp_Vec             aX(aP1.XYZ().Subtracted(aP0.XYZ()));
561         Standard_Real      aTolConf = Precision::Confusion();
562
563         if (aX.Magnitude() > aTolConf) {
564           aX.Normalize();
565
566           // Get the plane normal ortogonal to Z axis.
567           gp_Vec aZ(0., 0., 1.);
568           gp_Vec aN = aX.Crossed(aZ);
569
570           if (aN.Magnitude() <= aTolConf) {
571             // aX is parallel to aZ. Get the plane normal ortogonal to Y axis.
572             gp_Vec aY(0., 1., 0.);
573
574             aN = aX.Crossed(aY);
575           }
576
577           if (aN.Magnitude() >      aTolConf) {
578             gp_Ax3                  anAxis(aP0, gp_Dir(aN), gp_Dir(aX));
579             Handle(Geom_Plane)      aPlane = new Geom_Plane(anAxis);
580             BRepBuilderAPI_MakeFace aMkFace(aPlane, aWire);
581
582             if (aMkFace.IsDone()) {
583               aFace = aMkFace.Face();
584             }
585           }
586         }
587       }
588     }
589   } else if (aType == TopAbs_FACE) {
590     aFace = TopoDS::Face(theShape);
591   }
592
593   if (aFace.IsNull()) {
594     return aResult;
595   }
596
597   // Compute 2d translation transformation.
598   TopoDS_Wire            anOuterWire = BRepTools::OuterWire(aFace);
599   Standard_Real          aU[2];
600   Standard_Real          aV[2];
601   BRepTools_WireExplorer aOWExp(anOuterWire, aFace);
602
603   if (!aOWExp.More()) {
604     // NEVERREACHED
605     return aResult;
606   }
607
608   // Compute anisotropic transformation from a face's 2d space
609   // to cylinder's 2d space.
610   BRepTools::UVBounds(aFace, anOuterWire, aU[0], aU[1], aV[0], aV[1]);
611
612   TopoDS_Vertex       aFirstVertex = aOWExp.CurrentVertex();
613   TopoDS_Edge         aFirstEdge   = aOWExp.Current();
614   gp_Pnt              aPnt         = BRep_Tool::Pnt(aFirstVertex);
615   BRepAdaptor_Curve2d anAdaptorCurve(aFirstEdge, aFace);
616   Standard_Real       aParam       =
617     BRep_Tool::Parameter(aFirstVertex, aFirstEdge, aFace);
618   gp_Pnt2d            aPntUV       = anAdaptorCurve.Value(aParam);
619
620   GEOMUtils::Trsf2d aTrsf2d
621             (1./theRadius, 0., theStartAngle - aU[0]/theRadius,
622              0.,           1., aPnt.Z() - 0.5*(aV[1] - aV[0]) - aPntUV.Y());
623
624   // Compute scaling trsf.
625   const Standard_Boolean isToScale = theAngleLength >= Precision::Angular();
626   gp_Trsf2d aScaleTrsf;
627
628   if (isToScale) {
629     // Perform 2d scaling.
630     gp_Pnt2d            aMidPnt(0.5*(aU[1] + aU[0]), 0.5*(aV[1] + aV[0]));
631     const Standard_Real aScaleFactor = theAngleLength*theRadius/(aU[1] - aU[0]);
632
633     aTrsf2d.TransformD0(aMidPnt);
634
635     aScaleTrsf.SetScale(aMidPnt, aScaleFactor);
636   }
637
638   // Get 2d presentation of a face.
639   Handle(Geom_Surface) aCylinder =
640     new Geom_CylindricalSurface(gp_Ax3(), theRadius);
641   GeomAdaptor_Surface  aGACyl(aCylinder);
642   TopExp_Explorer      anExp(aFace, TopAbs_WIRE);
643   Standard_Real        aPar[2];
644   TopTools_ListOfShape aWires;
645   Standard_Real        aUResol = aGACyl.UResolution(Precision::Confusion());
646   Standard_Real        aVResol = aGACyl.VResolution(Precision::Confusion());
647
648   for (; anExp.More(); anExp.Next()) {
649     TopoDS_Wire             aWire = TopoDS::Wire(anExp.Current());
650     BRepTools_WireExplorer  aWExp(aWire, aFace);
651     BRepBuilderAPI_MakeWire aMkWire;
652
653     for (; aWExp.More(); aWExp.Next()) {
654       TopoDS_Edge                 anEdge   = aWExp.Current();
655       Handle(Geom2d_Curve)        aCurve   =
656         BRep_Tool::CurveOnSurface(anEdge, aFace, aPar[0], aPar[1]);
657
658       if (aCurve.IsNull()) {
659         continue;
660       }
661
662       // Transform the curve to cylinder's parametric space.
663       GEOMUtils::Handle(HTrsfCurve2d) aTrsfCurve =
664         new GEOMUtils::HTrsfCurve2d(aCurve, aPar[0], aPar[1], aTrsf2d);
665       Approx_Curve2d                  aConv (aTrsfCurve, aPar[0], aPar[1],
666                                                          aUResol, aVResol, GeomAbs_C1,
667                                              9, 1000);
668
669       if (!aConv.IsDone() && !aConv.HasResult()) {
670         return aResult;
671       }
672
673       Handle(Geom2d_Curve) aCylCurve = aConv.Curve();
674
675       if (isToScale) {
676         aCylCurve->Transform(aScaleTrsf);
677       }
678
679       // Create edge and add it to the wire.
680       BRepBuilderAPI_MakeEdge aMkEdge(aCylCurve, aCylinder);
681
682       if (!aMkEdge.IsDone()) {
683         return aResult;
684       }
685
686       aMkWire.Add(aMkEdge.Edge());
687
688       if (!aMkWire.IsDone()) {
689         return aResult;
690       }
691     }
692
693     if (aWire.IsSame(anOuterWire)) {
694       // Make the outer wire first.
695       aWires.Prepend(aMkWire.Wire());
696     } else {
697       aWires.Append(aMkWire.Wire());
698     }
699   }
700
701   // Create a face.
702   if (aWires.IsEmpty()) {
703     return aResult;
704   }
705
706   TopTools_ListIteratorOfListOfShape aWIter(aWires);
707   TopoDS_Wire                        aWire = TopoDS::Wire(aWIter.Value());
708   BRepBuilderAPI_MakeFace aMkFace(aCylinder, aWire);
709
710   if (!aMkFace.IsDone()) {
711     return aResult;
712   }
713
714   for (aWIter.Next(); aWIter.More(); aWIter.Next()) {
715     aWire = TopoDS::Wire(aWIter.Value());
716     aMkFace.Add(aWire);
717
718     if (!aMkFace.IsDone()) {
719       return aResult;
720     }
721   }
722
723   // Build 3D curves.
724   TopoDS_Face  aCylFace = aMkFace.Face();
725   TopoDS_Shape aResShape;
726
727   BRepLib::BuildCurves3d(aCylFace);
728
729   // Check shape.
730   if (aType == TopAbs_WIRE) {
731     TopExp_Explorer aResExp(aCylFace, TopAbs_WIRE);
732
733     if (aResExp.More()) {
734       aResShape = aResExp.Current();
735     }
736   } else {
737     aResShape = aCylFace;
738   }
739
740   if (aResShape.IsNull() == Standard_False) {
741     if (!GEOMUtils::CheckShape(aResShape, true)) {
742       if (!GEOMUtils::FixShapeTolerance(aResShape)) {
743         return aResult;
744       }
745     }
746
747     aResult = aResShape;
748   }
749
750   return aResult;
751 }
752
753 IMPLEMENT_STANDARD_HANDLE (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);
754 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);