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