Salome HOME
Fix for test case bugs_10/K4
[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       GEOMImpl_IProjOnCyl aProj (function);
495       const Standard_Real aLengthAngle = aProj.GetAngleLength();
496
497       AddParam(theParams, "Shape",        aProj.GetShape());
498       AddParam(theParams, "Radius",       aProj.GetRadius());
499       AddParam(theParams, "Start angle",  aProj.GetStartAngle());
500
501       if (aLengthAngle >= 0.) {
502         AddParam(theParams, "Length angle", aLengthAngle);
503       }
504
505       break;
506     }
507   default:
508     return false;
509   }
510   
511   return true;
512 }
513
514 //================================================================================
515 /*!
516  * \brief Performs projection of a planar wire or a face on a cylinder.
517  */
518 //================================================================================
519
520 TopoDS_Shape GEOMImpl_ProjectionDriver::projectOnCylinder
521                                 (const TopoDS_Shape  &theShape,
522                                  const Standard_Real  theRadius,
523                                  const Standard_Real  theStartAngle,
524                                  const Standard_Real  theAngleLength) const
525 {
526   TopoDS_Shape aResult;
527
528   // Get the face.
529   const TopAbs_ShapeEnum aType = theShape.ShapeType();
530   TopoDS_Face            aFace;
531
532   if (aType == TopAbs_WIRE) {
533     // Try to create a planar face.
534     TopoDS_Wire             aWire = TopoDS::Wire(theShape);
535     BRepBuilderAPI_MakeFace aMkFace(aWire, Standard_True);
536
537     if (aMkFace.IsDone()) {
538       aFace = aMkFace.Face();
539     } else {
540       // Check if the wire is a straight line.
541       TopExp_Explorer anEExp(aWire, TopAbs_EDGE);
542       TopoDS_Edge     anEdge;
543
544       for (; anEExp.More(); anEExp.Next()) {
545         anEdge = TopoDS::Edge(anEExp.Current());
546
547         if (!BRep_Tool::Degenerated(anEdge)) {
548           break;
549         }
550       }
551
552       if (anEExp.More()) {
553         // Not degenerated edge found. Try to create a plane.
554         Standard_Real      aPar[2];
555         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aPar[0], aPar[1]);
556         gp_Pnt             aP0    = aCurve->Value(aPar[0]);
557         gp_Pnt             aP1    = aCurve->Value(0.5*(aPar[1] + aPar[0]));
558         gp_Vec             aX(aP1.XYZ().Subtracted(aP0.XYZ()));
559         Standard_Real      aTolConf = Precision::Confusion();
560
561         if (aX.Magnitude() > aTolConf) {
562           aX.Normalize();
563
564           // Get the plane normal ortogonal to Z axis.
565           gp_Vec aZ(0., 0., 1.);
566           gp_Vec aN = aX.Crossed(aZ);
567
568           if (aN.Magnitude() <= aTolConf) {
569             // aX is parallel to aZ. Get the plane normal ortogonal to Y axis.
570             gp_Vec aY(0., 1., 0.);
571
572             aN = aX.Crossed(aY);
573           }
574
575           if (aN.Magnitude() >      aTolConf) {
576             gp_Ax3                  anAxis(aP0, gp_Dir(aN), gp_Dir(aX));
577             Handle(Geom_Plane)      aPlane = new Geom_Plane(anAxis);
578             BRepBuilderAPI_MakeFace aMkFace(aPlane, aWire);
579
580             if (aMkFace.IsDone()) {
581               aFace = aMkFace.Face();
582             }
583           }
584         }
585       }
586     }
587   } else if (aType == TopAbs_FACE) {
588     aFace = TopoDS::Face(theShape);
589   }
590
591   if (aFace.IsNull()) {
592     return aResult;
593   }
594
595   // Compute 2d translation transformation.
596   TopoDS_Wire            anOuterWire = BRepTools::OuterWire(aFace);
597   Standard_Real          aU[2];
598   Standard_Real          aV[2];
599   BRepTools_WireExplorer aOWExp(anOuterWire, aFace);
600
601   if (!aOWExp.More()) {
602     // NEVERREACHED
603     return aResult;
604   }
605
606   // Compute anisotropic transformation from a face's 2d space
607   // to cylinder's 2d space.
608   BRepTools::UVBounds(aFace, anOuterWire, aU[0], aU[1], aV[0], aV[1]);
609
610   TopoDS_Vertex       aFirstVertex = aOWExp.CurrentVertex();
611   TopoDS_Edge         aFirstEdge   = aOWExp.Current();
612   gp_Pnt              aPnt         = BRep_Tool::Pnt(aFirstVertex);
613   BRepAdaptor_Curve2d anAdaptorCurve(aFirstEdge, aFace);
614   Standard_Real       aParam       =
615     BRep_Tool::Parameter(aFirstVertex, aFirstEdge, aFace);
616   gp_Pnt2d            aPntUV       = anAdaptorCurve.Value(aParam);
617
618   GEOMUtils::Trsf2d aTrsf2d
619             (1./theRadius, 0., theStartAngle - aU[0]/theRadius,
620              0.,           1., aPnt.Z() - 0.5*(aV[1] - aV[0]) - aPntUV.Y());
621
622   // Compute scaling trsf.
623   const Standard_Boolean isToScale = theAngleLength >= Precision::Angular();
624   gp_Trsf2d aScaleTrsf;
625
626   if (isToScale) {
627     // Perform 2d scaling.
628     gp_Pnt2d            aMidPnt(0.5*(aU[1] + aU[0]), 0.5*(aV[1] + aV[0]));
629     const Standard_Real aScaleFactor = theAngleLength*theRadius/(aU[1] - aU[0]);
630
631     aTrsf2d.TransformD0(aMidPnt);
632
633     aScaleTrsf.SetScale(aMidPnt, aScaleFactor);
634   }
635
636   // Get 2d presentation of a face.
637   Handle(Geom_Surface) aCylinder =
638     new Geom_CylindricalSurface(gp_Ax3(), theRadius);
639   GeomAdaptor_Surface  aGACyl(aCylinder);
640   TopExp_Explorer      anExp(aFace, TopAbs_WIRE);
641   Standard_Real        aPar[2];
642   TopTools_ListOfShape aWires;
643   Standard_Real        aUResol = aGACyl.UResolution(Precision::Confusion());
644   Standard_Real        aVResol = aGACyl.VResolution(Precision::Confusion());
645
646   for (; anExp.More(); anExp.Next()) {
647     TopoDS_Wire             aWire = TopoDS::Wire(anExp.Current());
648     BRepTools_WireExplorer  aWExp(aWire, aFace);
649     BRepBuilderAPI_MakeWire aMkWire;
650
651     for (; aWExp.More(); aWExp.Next()) {
652       TopoDS_Edge                 anEdge   = aWExp.Current();
653       Handle(Geom2d_Curve)        aCurve   =
654         BRep_Tool::CurveOnSurface(anEdge, aFace, aPar[0], aPar[1]);
655
656       if (aCurve.IsNull()) {
657         continue;
658       }
659
660       // Transform the curve to cylinder's parametric space.
661       GEOMUtils::Handle(HTrsfCurve2d) aTrsfCurve =
662         new GEOMUtils::HTrsfCurve2d(aCurve, aPar[0], aPar[1], aTrsf2d);
663       Approx_Curve2d                  aConv (aTrsfCurve, aPar[0], aPar[1],
664                                                          aUResol, aVResol, GeomAbs_C1,
665                                              9, 1000);
666
667       if (!aConv.IsDone() && !aConv.HasResult()) {
668         return aResult;
669       }
670
671       Handle(Geom2d_Curve) aCylCurve = aConv.Curve();
672
673       if (isToScale) {
674         aCylCurve->Transform(aScaleTrsf);
675       }
676
677       // Create edge and add it to the wire.
678       BRepBuilderAPI_MakeEdge aMkEdge(aCylCurve, aCylinder);
679
680       if (!aMkEdge.IsDone()) {
681         return aResult;
682       }
683
684       aMkWire.Add(aMkEdge.Edge());
685
686       if (!aMkWire.IsDone()) {
687         return aResult;
688       }
689     }
690
691     if (aWire.IsSame(anOuterWire)) {
692       // Make the outer wire first.
693       aWires.Prepend(aMkWire.Wire());
694     } else {
695       aWires.Append(aMkWire.Wire());
696     }
697   }
698
699   // Create a face.
700   if (aWires.IsEmpty()) {
701     return aResult;
702   }
703
704   TopTools_ListIteratorOfListOfShape aWIter(aWires);
705   TopoDS_Wire                        aWire = TopoDS::Wire(aWIter.Value());
706   BRepBuilderAPI_MakeFace aMkFace(aCylinder, aWire);
707
708   if (!aMkFace.IsDone()) {
709     return aResult;
710   }
711
712   for (aWIter.Next(); aWIter.More(); aWIter.Next()) {
713     aWire = TopoDS::Wire(aWIter.Value());
714     aMkFace.Add(aWire);
715
716     if (!aMkFace.IsDone()) {
717       return aResult;
718     }
719   }
720
721   // Build 3D curves.
722   TopoDS_Face  aCylFace = aMkFace.Face();
723   TopoDS_Shape aResShape;
724
725   BRepLib::BuildCurves3d(aCylFace);
726
727   // Check shape.
728   if (aType == TopAbs_WIRE) {
729     TopExp_Explorer aResExp(aCylFace, TopAbs_WIRE);
730
731     if (aResExp.More()) {
732       aResShape = aResExp.Current();
733     }
734   } else {
735     aResShape = aCylFace;
736   }
737
738   if (aResShape.IsNull() == Standard_False) {
739     if (!GEOMUtils::CheckShape(aResShape, true)) {
740       if (!GEOMUtils::FixShapeTolerance(aResShape)) {
741         return aResult;
742       }
743     }
744
745     aResult = aResShape;
746   }
747
748   return aResult;
749 }
750
751 IMPLEMENT_STANDARD_HANDLE (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);
752 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_ProjectionDriver,GEOM_BaseDriver);