d3c4d5627575421695b103053edd5cd888b8cd97
[occt.git] / src / BRepFill / BRepFill_TrimEdgeTool.cxx
1 // Created on: 1995-04-24
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <BRepFill_TrimEdgeTool.ixx>
18 #include <BRep_Tool.hxx>
19 #include <Bisector_BisecAna.hxx>
20 #include <Geom2d_Curve.hxx>
21 #include <Geom2d_TrimmedCurve.hxx>
22 #include <Geom2d_CartesianPoint.hxx>
23 #include <Geom_Curve.hxx>
24 #include <GeomProjLib.hxx>
25 #include <Geom_TrimmedCurve.hxx>
26 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
27 #include <Geom2dInt_GInter.hxx>
28 #include <gp_Pnt.hxx>
29 #include <TopLoc_Location.hxx>
30 #include <TopoDS.hxx>
31 #include <Precision.hxx>
32 #include <IntRes2d_IntersectionPoint.hxx>
33 #include <IntRes2d_IntersectionSegment.hxx>
34
35 #include <StdFail_NotDone.hxx>
36
37 #ifdef DRAW
38 #include <DrawTrSurf.hxx>
39 #include <DBRep.hxx>
40 static Standard_Boolean Affich       = Standard_False;
41 #endif
42
43
44 //=======================================================================
45 //function : SimpleExpression
46 //purpose  : 
47 //=======================================================================
48
49 static void SimpleExpression (const Bisector_Bisec&        B, 
50                                     Handle(Geom2d_Curve)&  Bis)
51 {
52   Bis = B.Value();
53
54   Handle(Standard_Type) BT = Bis->DynamicType();
55   if (BT == STANDARD_TYPE(Geom2d_TrimmedCurve)) {
56     Handle(Geom2d_TrimmedCurve) TrBis 
57       = Handle(Geom2d_TrimmedCurve)::DownCast(Bis);
58     Handle(Geom2d_Curve) BasBis = TrBis->BasisCurve();
59     BT = BasBis->DynamicType();
60     if (BT == STANDARD_TYPE(Bisector_BisecAna)) {
61       Bis = Handle(Bisector_BisecAna)::DownCast(BasBis)->Geom2dCurve();
62       Bis = new Geom2d_TrimmedCurve (Bis,
63                                      TrBis->FirstParameter(),
64                                      TrBis->LastParameter());
65     }
66   }
67 }
68
69
70 //=======================================================================
71 //function : BRepFill_TrimEdgeTool
72 //purpose  : 
73 //=======================================================================
74
75 BRepFill_TrimEdgeTool::BRepFill_TrimEdgeTool()
76 {
77 }
78
79
80 //=======================================================================
81 //function : BRepFill_TrimEdgeTool
82 //purpose  : 
83 //=======================================================================
84
85 BRepFill_TrimEdgeTool::BRepFill_TrimEdgeTool
86 (const Bisector_Bisec& Bisec,
87  const Handle(Geom2d_Geometry)& S1,
88  const Handle(Geom2d_Geometry)& S2,
89  const Standard_Real   Offset) :
90 myOffset(Offset),
91 myBisec(Bisec)
92 {
93   isPoint1 = (S1->DynamicType() == STANDARD_TYPE(Geom2d_CartesianPoint));
94   isPoint2 = (S2->DynamicType() == STANDARD_TYPE(Geom2d_CartesianPoint));
95
96 // return geometries of shapes.
97 //  Standard_Real f,l;
98   if (isPoint1) {
99     myP1 = Handle(Geom2d_Point)::DownCast(S1)->Pnt2d();
100   }
101   else {
102     myC1 = Handle(Geom2d_Curve)::DownCast(S1);
103 #ifdef DRAW
104     if ( Affich) {
105 //POP pour NT
106       char* myC1name = "myC1";
107       DrawTrSurf::Set(myC1name,myC1);
108 //      DrawTrSurf::Set("myC1",myC1);
109     }
110 #endif
111   }
112   if (isPoint2) {
113     myP2 = Handle(Geom2d_Point)::DownCast(S2)->Pnt2d();
114   }
115   else {
116     myC2 = Handle(Geom2d_Curve)::DownCast(S2);
117 #ifdef DRAW
118     if ( Affich) {
119       char* myC2name = "myC2";
120       DrawTrSurf::Set(myC2name,myC2);
121 //      DrawTrSurf::Set("myC2",myC2);
122     }
123 #endif
124   }
125   // return the simple expression of the bissectrice
126   Handle(Geom2d_Curve) Bis;
127   SimpleExpression(myBisec, Bis);
128   myBis = Geom2dAdaptor_Curve(Bis);
129 #ifdef DRAW
130   if ( Affich) {
131       char* myBisname = "myBis";
132       DrawTrSurf::Set(myBisname,Bis);
133   }
134 #endif
135
136 }
137
138 //=======================================================================
139 //function : Bubble
140 //purpose  : Order the sequence of points by increasing x. 
141 //=======================================================================
142
143 static void Bubble(TColgp_SequenceOfPnt& Seq) 
144 {
145   Standard_Boolean Invert = Standard_True;
146   Standard_Integer NbPoints = Seq.Length();
147   while (Invert) {
148     Invert = Standard_False;
149     for ( Standard_Integer i = 1; i < NbPoints; i++) {
150       gp_Pnt P1 = Seq.Value(i);
151       gp_Pnt P2 = Seq.Value(i+1);
152       if (P2.X()<P1.X())  {
153         Seq.Exchange(i,i+1);
154         Invert = Standard_True;
155       }
156     }
157   }
158 }
159
160
161 //=======================================================================
162 //function : EvalParameters  
163 //purpose  : 
164 //=======================================================================
165
166 static void EvalParameters(const Geom2dAdaptor_Curve& Bis,
167                            const Geom2dAdaptor_Curve& AC,
168                                  TColgp_SequenceOfPnt& Params)
169 {
170   Geom2dInt_GInter Intersector;
171   Standard_Real Tol = Precision::Confusion();
172 //  Standard_Real TolC = 1.e-9;
173
174   Geom2dAdaptor_Curve CBis(Bis);
175   Geom2dAdaptor_Curve CAC (AC);
176
177   //Intersector = Geom2dInt_GInter(CBis, CAC, TolC, Tol);
178   Intersector = Geom2dInt_GInter(CAC, CBis, Tol, Tol);
179
180   Standard_Integer NbPoints, NbSegments;
181   Standard_Real U1, U2;
182   gp_Pnt P;
183
184   if ( !Intersector.IsDone()) {
185     StdFail_NotDone::Raise("BRepFill_TrimSurfaceTool::IntersectWith");
186   }
187   
188   NbPoints = Intersector.NbPoints();
189   
190   if (NbPoints > 0) {
191     for ( Standard_Integer i = 1; i <= NbPoints; i++) {
192       U1 = Intersector.Point(i).ParamOnSecond();
193       U2 = Intersector.Point(i).ParamOnFirst();
194       P = gp_Pnt(U1,U2,0.);
195       Params.Append(P);
196     }
197     
198   }
199   
200   NbSegments = Intersector.NbSegments();
201   
202   if (NbSegments > 0) {
203     IntRes2d_IntersectionSegment Seg;
204     for ( Standard_Integer i = 1; i <= NbSegments; i++) {
205       Seg = Intersector.Segment(i);
206       U1  = Seg.FirstPoint().ParamOnSecond();
207       Standard_Real Ulast = Seg.LastPoint().ParamOnSecond();
208       if ( Abs(U1    - CBis.FirstParameter()) <= Tol &&
209            Abs(Ulast - CBis.LastParameter())  <= Tol    ) {
210         P = gp_Pnt(U1,Seg.FirstPoint().ParamOnFirst(),0.);
211         Params.Append(P);
212         P = gp_Pnt(Ulast,Seg.LastPoint().ParamOnFirst(),0.);
213         Params.Append(P);
214       }
215       else {
216         U1 += Seg.LastPoint().ParamOnSecond();
217         U1 /= 2.;
218         U2  = Seg.FirstPoint().ParamOnFirst();
219         U2 += Seg.LastPoint().ParamOnFirst();
220         U2 /= 2.;
221         P = gp_Pnt(U1,U2,0.);
222         Params.Append(P);
223       }
224     }
225   }
226
227   // Order the sequence by growing parameter on the bissectrice.
228   Bubble( Params);
229 }
230                            
231 static void EvalParametersBis(const Geom2dAdaptor_Curve& Bis,
232                               const Geom2dAdaptor_Curve& AC,
233                               TColgp_SequenceOfPnt& Params,
234                               const Standard_Real Tol)
235 {
236   Geom2dInt_GInter Intersector;
237   Standard_Real TolC = Tol;
238   
239   Geom2dAdaptor_Curve CBis(Bis);
240   Geom2dAdaptor_Curve CAC (AC);
241
242   Intersector = Geom2dInt_GInter(CAC, CBis, TolC, Tol);
243
244   Standard_Integer NbPoints, NbSegments;
245   Standard_Real U1, U2;
246   gp_Pnt P;
247
248   if ( !Intersector.IsDone()) {
249     StdFail_NotDone::Raise("BRepFill_TrimSurfaceTool::IntersectWith");
250   }
251   
252   NbPoints = Intersector.NbPoints();
253   
254   if (NbPoints > 0) {
255     for ( Standard_Integer i = 1; i <= NbPoints; i++) {
256       U1 = Intersector.Point(i).ParamOnSecond();
257       U2 = Intersector.Point(i).ParamOnFirst();
258       P = gp_Pnt(U1,U2,0.);
259       Params.Append(P);
260     }
261     
262   }
263   
264   NbSegments = Intersector.NbSegments();
265   
266   if (NbSegments > 0) {
267     IntRes2d_IntersectionSegment Seg;
268     for ( Standard_Integer i = 1; i <= NbSegments; i++) {
269       Seg = Intersector.Segment(i);
270       U1  = Seg.FirstPoint().ParamOnSecond();
271       Standard_Real Ulast = Seg.LastPoint().ParamOnSecond();
272       if ( Abs(U1    - CBis.FirstParameter()) <= Tol &&
273            Abs(Ulast - CBis.LastParameter())  <= Tol    ) {
274         P = gp_Pnt(U1,Seg.FirstPoint().ParamOnFirst(),0.);
275         Params.Append(P);
276         P = gp_Pnt(Ulast,Seg.LastPoint().ParamOnFirst(),0.);
277         Params.Append(P);
278       }
279       else {
280         U1 += Seg.LastPoint().ParamOnSecond();
281         U1 /= 2.;
282         U2  = Seg.FirstPoint().ParamOnFirst();
283         U2 += Seg.LastPoint().ParamOnFirst();
284         U2 /= 2.;
285         P = gp_Pnt(U1,U2,0.);
286         Params.Append(P);
287       }
288     }
289   }
290
291   // Order the sequence by parameter growing on the bissectrice.
292   Bubble( Params);
293 }
294
295
296 //=======================================================================
297 //function : IntersectWith
298 //purpose  : 
299 //=======================================================================
300
301 void BRepFill_TrimEdgeTool::IntersectWith(const TopoDS_Edge& Edge1,
302                                           const TopoDS_Edge& Edge2,
303                                                 TColgp_SequenceOfPnt& Params)
304 {
305   Params.Clear();
306
307   // return curves associated to edges.
308   TopLoc_Location L;
309   Standard_Real   f,l;
310   Handle(Geom_Surface) Surf;
311
312   Handle(Geom2d_Curve) C1;
313   BRep_Tool::CurveOnSurface(Edge1,C1,Surf,L,f,l);
314   Geom2dAdaptor_Curve AC1(C1,f,l);
315
316   Handle(Geom2d_Curve) C2;
317   BRep_Tool::CurveOnSurface(Edge2,C2,Surf,L,f,l);
318   Geom2dAdaptor_Curve AC2(C2,f,l);
319
320 #ifdef DRAW
321   if ( Affich) {
322     f = AC1.FirstParameter();
323     l = AC1.LastParameter();
324     char* CURVE1name = "CURVE1";
325     DrawTrSurf::Set(CURVE1name, new Geom2d_TrimmedCurve(C1,f,l));
326     f = AC2.FirstParameter();
327     l = AC2.LastParameter();
328     char* CURVE2name = "CURVE2";
329     DrawTrSurf::Set(CURVE2name, new Geom2d_TrimmedCurve(C2,f,l));
330     f = myBis.FirstParameter();
331     l = myBis.LastParameter();
332     char* bisname = "BIS";
333     DrawTrSurf::Set(bisname, new Geom2d_TrimmedCurve(myBis.Curve(),f,l));
334     char* Edge1name = "E1";
335     DBRep::Set(Edge1name, Edge1);
336     char* Edge2name = "E2";
337     DBRep::Set(Edge2name, Edge2);
338
339   }
340 #endif
341   
342   // Calculate intersection
343   TColgp_SequenceOfPnt Points2;
344   gp_Pnt PSeq;
345
346   EvalParameters (myBis,AC1,Params);
347   EvalParameters (myBis,AC2,Points2);
348
349
350   Standard_Integer SeanceDeRattrapage=0;
351   Standard_Real TolInit= 1.e-9;
352   Standard_Integer nn = 7;
353
354   if((AC1.GetType() != GeomAbs_Circle && AC1.GetType() != GeomAbs_Line) ||
355      (AC2.GetType() != GeomAbs_Circle && AC2.GetType() != GeomAbs_Line)) {
356
357     TolInit = 1.e-8;
358     nn = 6;
359   }
360   
361   while (     SeanceDeRattrapage < nn // TolInit <= 0.01
362          && ( Points2.Length() != Params.Length() || 
363              (Points2.Length() == 0 && Params.Length() == 0) ) ) {
364
365 #ifdef OCCT_DEBUG
366     cout << "BRepFill_TrimEdgeTool: incoherent intersection. Try with a greater tolerance" << endl;
367 #endif
368
369     Params.Clear();
370     Points2.Clear();
371     
372     TolInit*=10.0;
373     
374     EvalParametersBis(myBis,AC1,Params,TolInit);
375     EvalParametersBis(myBis,AC2,Points2,TolInit); 
376     SeanceDeRattrapage++;
377   }
378
379 #ifdef OCCT_DEBUG
380   if(SeanceDeRattrapage != 0) cout << "SeanceDeRattrapage = " << SeanceDeRattrapage << endl;
381   if(SeanceDeRattrapage == nn) { 
382     cout << "BRepFill_TrimEdgeTool: incoherent intersection" << endl;
383   }
384 #endif
385
386
387   if(Params.Length() == 0 && Points2.Length() == 1) {
388
389     //cout << "Params.Length() == 0 && Points2.Length() == 1" << endl;
390     Standard_Real dmin;
391     Standard_Real tBis = Points2(1).X();
392     gp_Pnt2d PBis = myBis.Value(tBis);
393
394     Standard_Real t = AC1.FirstParameter();
395     gp_Pnt2d PC = AC1.Value(t);
396     dmin = PC.SquareDistance(PBis);
397     gp_Pnt P(tBis, t, 0.);
398     Params.Append(P);
399
400     t = AC1.LastParameter();
401     PC = AC1.Value(t);
402     if(dmin > PC.SquareDistance(PBis)) {
403       P.SetY(t);
404       Params.SetValue(1,P);
405     }
406   }
407   else if(Params.Length() == 1 && Points2.Length() == 0) {
408
409     //cout << "Params.Length() == 1 && Points2.Length() == 0" << endl;
410     Standard_Real dmin;
411     Standard_Real tBis = Params(1).X();
412     gp_Pnt2d PBis = myBis.Value(tBis);
413
414     Standard_Real t = AC2.FirstParameter();
415     gp_Pnt2d PC = AC2.Value(t);
416     dmin = PC.SquareDistance(PBis);
417     gp_Pnt P(tBis, t, 0.);
418     Points2.Append(P);
419
420     t = AC2.LastParameter();
421     PC = AC2.Value(t);
422     if(dmin > PC.SquareDistance(PBis)) {
423       P.SetY(t);
424       Points2.SetValue(1,P);
425     }
426   }
427
428   // small manipulation to remove incorrect intersections:
429   // return only common intersections (same parameter
430   // on the bissectrice.).
431   // The tolerance can be eventually changed.
432
433   gp_Pnt P1,P2;
434   Standard_Real Tol = 4 * 100 * Precision::PConfusion();
435   Standard_Integer i = 1;
436   Standard_Integer NbPoints = Params.Length();
437
438   if(NbPoints == 1 && Points2.Length() == 1) {
439     //cout << "NbPoints == 1 && Points2.Length() == 1" << endl;
440     for ( i = 1; i <= NbPoints; i++) {
441       PSeq = Params(i);
442       PSeq.SetZ((Points2.Value(i)).Y());
443       Params.SetValue(i,PSeq);
444     }
445     return;
446   }    
447
448   i = 1;
449   while ( i <= Min( Params.Length(), Points2.Length())) {
450     P1 = Params(i);
451     P2 = Points2(i);
452     Standard_Real P1xP2x=Abs( P1.X() - P2.X());
453
454     if ( P1xP2x > Tol ) {
455 #ifdef OCCT_DEBUG
456       cout << "BRepFill_TrimEdgeTool: no same parameter on the bissectrice" << endl;
457 #endif
458       if(P1xP2x>TolInit) { 
459 #ifdef OCCT_DEBUG
460       cout << "BRepFill_TrimEdgeTool: Continue somehow" << endl;
461 #endif  
462       i++;
463       }
464       else { 
465         if ( P1.X() < P2.X()) Params.Remove(i);
466         else                  Points2.Remove(i);
467       }
468     }
469     else i++;
470   }
471
472   if ( Params.Length() > Points2.Length()) {
473     Params.Remove(Points2.Length()+1, Params.Length());
474   }
475   else if ( Params.Length() < Points2.Length()) {
476     Points2.Remove(Params.Length()+1, Points2.Length());
477   }
478
479   NbPoints = Params.Length();
480   for ( i = 1; i <= NbPoints; i++) {
481     PSeq = Params(i);
482     PSeq.SetZ((Points2.Value(i)).Y());
483     Params.SetValue(i,PSeq);
484   }
485 }
486
487 //=======================================================================
488 //function : AddOrConfuse
489 //purpose  : the first or the last point of the bissectrice is on the 
490 //           parallel if it was not found in the intersections, 
491 //           it is projected on parallel lines and added in the parameters 
492 //=======================================================================
493
494 void BRepFill_TrimEdgeTool::AddOrConfuse(const Standard_Boolean  Start,
495                                          const TopoDS_Edge&      Edge1,
496                                          const TopoDS_Edge&      Edge2,
497                                          TColgp_SequenceOfPnt&   Params) 
498 const 
499 {
500   Standard_Boolean  ToProj = Standard_True;
501   gp_Pnt2d          PBis;
502   Standard_Real     Tol = 10*Precision::Confusion(); 
503
504   // return curves associated to edges.
505   TopLoc_Location L;
506   Standard_Real   f,l;
507   Handle(Geom_Surface) Surf;
508
509   Handle(Geom2d_Curve) C1;
510   BRep_Tool::CurveOnSurface(Edge1,C1,Surf,L,f,l);
511   Geom2dAdaptor_Curve AC1(C1,f,l);
512
513
514   if (Start) PBis = myBis.Value(myBis.FirstParameter());
515   else       PBis = myBis.Value(myBis.LastParameter ()); 
516
517   // Test if the end of the bissectrice is in the set of intersection points.
518   if (!Params.IsEmpty()) {
519     gp_Pnt2d P;
520     if (Start) P = AC1.Value(Params.First().Y());
521     else       P = AC1.Value(Params.Last ().Y()); 
522     ToProj     = !PBis.IsEqual(P,Tol);
523   }
524   
525   if (ToProj) {
526 #ifdef OCCT_DEBUG
527     cout << " project extremity bissectrice on parallel."<<endl;
528 #endif
529
530     // Project point on parallels and add in Params
531
532     Standard_Real f2,l2;
533     Handle(Geom2d_Curve) C2;
534     BRep_Tool::CurveOnSurface(Edge2,C2,Surf,L,f2,l2);
535
536     Geom2dAPI_ProjectPointOnCurve Projector1(PBis,C1,f,l);    
537     Geom2dAPI_ProjectPointOnCurve Projector2(PBis,C2,f2,l2);
538
539     if (Projector1.NbPoints() == 0) {
540 #ifdef OCCT_DEBUG
541       cout << "Failed projection in BRepFill_TrimEdgeTool::AddOrConfuse"<<endl;
542 #endif
543       return;
544     }
545     if (!Projector1.NearestPoint().IsEqual(PBis,Tol)) {
546 #ifdef OCCT_DEBUG
547       cout <<"Incorrect solution in BRepFill_TrimEdgeTool::AddOrConfuse"<<endl;
548 #endif
549       return;
550     }
551     if (Projector2.NbPoints() == 0) {
552 #ifdef OCCT_DEBUG
553       cout << "Failed projection in BRepFill_TrimEdgeTool::AddOrConfuse"<<endl;
554 #endif
555       return;
556     }
557     if (!Projector2.NearestPoint().IsEqual(PBis,Tol)) {
558 #ifdef OCCT_DEBUG
559       cout <<" Mauvaisesolution dans BRepFill_TrimEdgeTool::AddOrConfuse"<<endl;
560 #endif
561       return;
562     }
563     gp_Pnt PInt (0,
564                  Projector1.LowerDistanceParameter(),
565                  Projector2.LowerDistanceParameter());
566     if (Start) {
567       PInt.SetX (myBis.FirstParameter());
568       Params.Prepend(PInt);
569     }
570     else {
571       PInt.SetX (myBis.LastParameter());
572       Params.Append(PInt);
573     }
574   }
575 }
576
577 //=======================================================================
578 //function : IsInside
579 //purpose  : 
580 //=======================================================================
581
582 Standard_Boolean BRepFill_TrimEdgeTool::IsInside(const gp_Pnt2d& P) const 
583 {
584 //  Modified by Sergey KHROMOV - Fri Sep 27 11:43:12 2002 Begin
585 //   Standard_Real Dist;
586   Standard_Real Dist = RealLast();
587 //  Modified by Sergey KHROMOV - Fri Sep 27 11:43:12 2002 End
588   if (isPoint1) 
589     Dist = P.Distance(myP1);
590   else if (isPoint2) 
591     Dist = P.Distance(myP2);
592   else {
593     Geom2dAPI_ProjectPointOnCurve Projector(P,myC1);
594     if (Projector.NbPoints() > 0) {
595       Dist = Projector.LowerDistance();
596     }
597 //  Modified by Sergey KHROMOV - Fri Sep 27 11:43:43 2002 Begin
598 //     else {
599 //       gp_Pnt2d PF = myC1->Value(myC1->FirstParameter());
600 //       gp_Pnt2d PL = myC1->Value(myC1->LastParameter());
601 //       Dist = Min (P.Distance(PF),P.Distance(PL));
602 //     }
603
604 // Check of distances between P and first and last point of the first curve
605 // should be performed in any case, despite of the results of projection.
606     gp_Pnt2d      PF       = myC1->Value(myC1->FirstParameter());
607     gp_Pnt2d      PL       = myC1->Value(myC1->LastParameter());
608     Standard_Real aDistMin = Min (P.Distance(PF),P.Distance(PL));
609
610     if (Dist > aDistMin)
611       Dist = aDistMin;
612 //  Modified by Sergey KHROMOV - Fri Sep 27 11:43:44 2002 End
613   }
614   
615 //  return (Dist < Abs(myOffset);
616 // return (Dist < Abs(myOffset) + Precision::Confusion());
617   return (Dist < Abs(myOffset) - Precision::Confusion());
618 }
619