9da9e9dd36c74ad4b9adcc636faa22df4a3db574
[occt.git] / src / IntPatch / IntPatch_WLineTool.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <IntPatch_WLineTool.hxx>
15
16 #include <Adaptor3d_HSurface.hxx>
17 #include <Adaptor3d_TopolTool.hxx>
18
19 //=======================================================================
20 //function : MinMax
21 //purpose  : Replaces theParMIN = MIN(theParMIN, theParMAX),
22 //                    theParMAX = MAX(theParMIN, theParMAX).
23 //
24 //           Static subfunction in IsSeamOrBound.
25 //=======================================================================
26 static inline void MinMax(Standard_Real& theParMIN, Standard_Real& theParMAX)
27 {
28   if(theParMIN > theParMAX)
29   {
30     const Standard_Real aTmp = theParMAX;
31     theParMAX = theParMIN;
32     theParMIN = aTmp;
33   }
34 }
35
36 //=========================================================================
37 // function : FillPointsHash
38 // purpose  : Fill points hash by input data.
39 //            Static subfunction in ComputePurgedWLine.
40 //=========================================================================
41 static void FillPointsHash(const Handle(IntPatch_WLine)         &theWLine,
42                            NCollection_Array1<Standard_Integer> &thePointsHash)
43 {
44   // 1 - Delete point.
45   // 0 - Store point.
46   // -1 - Vertex point (not delete).
47   Standard_Integer i, v;
48
49   for(i = 1; i <= theWLine->NbPnts(); i++)
50     thePointsHash.SetValue(i, 0);
51
52   for(v = 1; v <= theWLine->NbVertex(); v++) 
53   {
54     IntPatch_Point aVertex = theWLine->Vertex(v);
55     Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
56     thePointsHash.SetValue(avertexindex, -1);
57   }
58 }
59
60 //=========================================================================
61 // function : MakeNewWLine
62 // purpose  : Makes new walking line according to the points hash
63 //            Static subfunction in ComputePurgedWLine and DeleteOuter.
64 //=========================================================================
65 static Handle(IntPatch_WLine) MakeNewWLine(const Handle(IntPatch_WLine)         &theWLine,
66                                            const NCollection_Array1<Standard_Integer> &thePointsHash)
67 {
68   Standard_Integer i;
69
70   Handle(IntSurf_LineOn2S) aPurgedLineOn2S = new IntSurf_LineOn2S();
71   Handle(IntPatch_WLine) aLocalWLine = new IntPatch_WLine(aPurgedLineOn2S, Standard_False);
72   Standard_Integer anOldLineIdx = 1, aVertexIdx = 1;
73   for(i = 1; i <= thePointsHash.Upper(); i++)
74   {
75     if (thePointsHash(i) == 0)
76     {
77       // Store this point.
78       aPurgedLineOn2S->Add(theWLine->Point(i));
79       anOldLineIdx++;
80     }
81     else if (thePointsHash(i) == -1)
82     {
83       // Add vertex.
84       IntPatch_Point aVertex = theWLine->Vertex(aVertexIdx++);
85       aVertex.SetParameter(anOldLineIdx++);
86       aLocalWLine->AddVertex(aVertex);
87       aPurgedLineOn2S->Add(theWLine->Point(i));
88     }
89   }
90
91   return aLocalWLine;
92 }
93
94 //=========================================================================
95 // function : MovePoint
96 // purpose  : Move point into surface param space. No interpolation used 
97 //            because walking algorithm should care for closeness to the param space.
98 //            Static subfunction in ComputePurgedWLine.
99 //=========================================================================
100 static void MovePoint(const Handle(Adaptor3d_HSurface)   &theS1,
101                       Standard_Real &U1, Standard_Real &V1)
102 {
103   if (U1 < theS1->FirstUParameter())
104     U1 = theS1->FirstUParameter();
105
106   if (U1 > theS1->LastUParameter())
107     U1 = theS1->LastUParameter();
108
109   if (V1 < theS1->FirstVParameter())
110     V1 = theS1->FirstVParameter();
111
112   if (V1 > theS1->LastVParameter())
113    V1 = theS1->LastVParameter();
114 }
115
116 //=========================================================================
117 // function : DeleteOuterPoints
118 // purpose  : Check and delete out of bounds points on walking line.
119 //            Static subfunction in ComputePurgedWLine.
120 //=========================================================================
121 static Handle(IntPatch_WLine)
122   DeleteOuterPoints(const Handle(IntPatch_WLine)       &theWLine,
123                     const Handle(Adaptor3d_HSurface)   &theS1,
124                     const Handle(Adaptor3d_HSurface)   &theS2,
125                     const Handle(Adaptor3d_TopolTool)  &theDom1,
126                     const Handle(Adaptor3d_TopolTool)  &theDom2)
127 {
128   Standard_Integer i;
129
130   NCollection_Array1<Standard_Integer> aDelOuterPointsHash(1, theWLine->NbPnts());
131   FillPointsHash(theWLine, aDelOuterPointsHash);
132
133   if (theS1->IsUPeriodic() || theS1->IsVPeriodic() ||
134       theS2->IsUPeriodic() || theS2->IsVPeriodic() )
135       return theWLine;
136
137   gp_Pnt2d aPntOnF1, aPntOnF2;
138   Standard_Real aX1, aY1, aX2, aY2;
139
140   // Iterate over points in walking line and delete which are out of bounds.
141   // Forward.
142   Standard_Boolean isAllDeleted = Standard_True;
143   Standard_Boolean aChangedFirst = Standard_False;
144   Standard_Integer aFirstGeomIdx = 1;
145   for(i = 1; i <= theWLine->NbPnts(); i++)
146   {
147     theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
148     aPntOnF1.SetCoord(aX1, aY1);
149     aPntOnF2.SetCoord(aX2, aY2);
150
151     TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
152     TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
153
154     if (aState1 == TopAbs_OUT ||
155         aState2 == TopAbs_OUT )
156     {
157       aDelOuterPointsHash(i) = 1;
158       aChangedFirst = Standard_True;
159     }
160     else
161     {
162       isAllDeleted = Standard_False;
163
164       aFirstGeomIdx = Max (i - 1, 1);
165       if (aDelOuterPointsHash(i) == -1)
166         aFirstGeomIdx = i; // Use data what lies in (i) point / vertex.
167
168       aDelOuterPointsHash(i) = -1;
169       break;
170     }
171   }
172
173   if (isAllDeleted)
174   {
175     // ALL points are out of bounds:
176     // case boolean bcut_complex F5 and similar.
177     return theWLine;
178   }
179
180   // Backward.
181   Standard_Boolean aChangedLast = Standard_False;
182   Standard_Integer aLastGeomIdx = theWLine->NbPnts();
183   for(i = theWLine->NbPnts(); i >= 1; i--)
184   {
185     theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
186     aPntOnF1.SetCoord(aX1, aY1);
187     aPntOnF2.SetCoord(aX2, aY2);
188
189     TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
190     TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
191
192     if (aState1 == TopAbs_OUT ||
193         aState2 == TopAbs_OUT )
194     {
195       aDelOuterPointsHash(i) = 1;
196       aChangedLast = Standard_True; // Move vertex to first good point
197     }
198     else
199     {
200       aLastGeomIdx = Min (i + 1, theWLine->NbPnts());
201       if (aDelOuterPointsHash(i) == -1)
202         aLastGeomIdx = i; // Use data what lies in (i) point / vertex.
203
204       aDelOuterPointsHash(i) = -1;
205       break;
206     }
207   }
208
209   if (!aChangedFirst && !aChangedLast)
210   {
211     // Nothing is done, return input.
212     return theWLine;
213   }
214
215   // Build new line and modify geometry of necessary vertexes.
216   Handle(IntPatch_WLine) aLocalWLine = MakeNewWLine(theWLine, aDelOuterPointsHash);
217
218   if (aChangedFirst)
219   {
220     // Vertex geometry.
221     IntPatch_Point aVertex = aLocalWLine->Vertex(1);
222     aVertex.SetValue(theWLine->Point(aFirstGeomIdx).Value());
223     Standard_Real aU1, aU2, aV1, aV2;
224     theWLine->Point(aFirstGeomIdx).Parameters(aU1, aV1, aU2, aV2);
225     MovePoint(theS1, aU1, aV1);
226     MovePoint(theS2, aU2, aV2);
227     aVertex.SetParameters(aU1, aV1, aU2, aV2);
228     aLocalWLine->Replace(1, aVertex);
229     // Change point in walking line.
230     aLocalWLine->SetPoint(1, aVertex);
231   }
232
233   if (aChangedLast)
234   {
235     // Vertex geometry.
236     IntPatch_Point aVertex = aLocalWLine->Vertex(aLocalWLine->NbVertex());
237     aVertex.SetValue(theWLine->Point(aLastGeomIdx).Value());
238     Standard_Real aU1, aU2, aV1, aV2;
239     theWLine->Point(aLastGeomIdx).Parameters(aU1, aV1, aU2, aV2);
240     MovePoint(theS1, aU1, aV1);
241     MovePoint(theS2, aU2, aV2);
242     aVertex.SetParameters(aU1, aV1, aU2, aV2);
243     aLocalWLine->Replace(aLocalWLine->NbVertex(), aVertex);
244     // Change point in walking line.
245     aLocalWLine->SetPoint(aLocalWLine->NbPnts(), aVertex);
246   }
247
248
249   return aLocalWLine;
250 }
251
252 //=========================================================================
253 // function : IsInsideIn2d
254 // purpose  : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
255 //            In 2d space. Static subfunction in DeleteByTube.
256 //=========================================================================
257 static Standard_Boolean IsInsideIn2d(const gp_Pnt2d& aBasePnt,
258                                      const gp_Vec2d& aBaseVec,
259                                      const gp_Pnt2d& aNextPnt,
260                                      const Standard_Real aSquareMaxDist)
261 {
262   gp_Vec2d aVec2d(aBasePnt, aNextPnt);
263
264   //d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
265   Standard_Real aCross = aVec2d.Crossed(aBaseVec);
266   Standard_Real aSquareDist = aCross * aCross
267                             / aBaseVec.SquareMagnitude();
268
269   return (aSquareDist <= aSquareMaxDist);
270 }
271
272 //=========================================================================
273 // function : IsInsideIn3d
274 // purpose  : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
275 //            In 3d space. Static subfunction in DeleteByTube.
276 //=========================================================================
277 static Standard_Boolean IsInsideIn3d(const gp_Pnt& aBasePnt,
278                                      const gp_Vec& aBaseVec,
279                                      const gp_Pnt& aNextPnt,
280                                      const Standard_Real aSquareMaxDist)
281 {
282   gp_Vec aVec(aBasePnt, aNextPnt);
283
284   //d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
285   Standard_Real aSquareDist = aVec.CrossSquareMagnitude(aBaseVec)
286                             / aBaseVec.SquareMagnitude();
287
288   return (aSquareDist <= aSquareMaxDist);
289 }
290
291 static const Standard_Integer aMinNbBadDistr = 15;
292 static const Standard_Integer aNbSingleBezier = 30;
293
294 //=========================================================================
295 // function : DeleteByTube
296 // purpose  : Check and delete points using tube criteria.
297 //            Static subfunction in ComputePurgedWLine.
298 //=========================================================================
299 static Handle(IntPatch_WLine)
300   DeleteByTube(const Handle(IntPatch_WLine)       &theWLine,
301                const Handle(Adaptor3d_HSurface)   &theS1,
302                const Handle(Adaptor3d_HSurface)   &theS2)
303 {
304   // III: Check points for tube criteria:
305   // Workaround to handle case of small amount points after purge.
306   // Test "boolean boptuc_complex B5" and similar.
307   Standard_Integer aNbPnt = 0 , i;
308
309   if (theWLine->NbPnts() <= 2)
310     return theWLine;
311
312   NCollection_Array1<Standard_Integer> aNewPointsHash(1, theWLine->NbPnts());
313   FillPointsHash(theWLine, aNewPointsHash);
314   
315   // Inital computations.
316   Standard_Real UonS1[3], VonS1[3], UonS2[3], VonS2[3];
317   theWLine->Point(1).ParametersOnS1(UonS1[0], VonS1[0]);
318   theWLine->Point(2).ParametersOnS1(UonS1[1], VonS1[1]);
319   theWLine->Point(1).ParametersOnS2(UonS2[0], VonS2[0]);
320   theWLine->Point(2).ParametersOnS2(UonS2[1], VonS2[1]);
321
322   gp_Pnt2d aBase2dPnt1(UonS1[0], VonS1[0]);
323   gp_Pnt2d aBase2dPnt2(UonS2[0], VonS2[0]);
324   gp_Vec2d aBase2dVec1(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
325   gp_Vec2d aBase2dVec2(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
326   gp_Pnt   aBase3dPnt = theWLine->Point(1).Value();
327   gp_Vec   aBase3dVec(theWLine->Point(1).Value(), theWLine->Point(2).Value());
328
329   // Choose base tolerance and scale it to pipe algorithm.
330   const Standard_Real aBaseTolerance = Precision::Approximation();
331   Standard_Real aResS1Tol = Min(theS1->UResolution(aBaseTolerance),
332                                 theS1->VResolution(aBaseTolerance));
333   Standard_Real aResS2Tol = Min(theS2->UResolution(aBaseTolerance),
334                                 theS2->VResolution(aBaseTolerance));
335   Standard_Real aTol1 = aResS1Tol * aResS1Tol;
336   Standard_Real aTol2 = aResS2Tol * aResS2Tol;
337   Standard_Real aTol3d = aBaseTolerance * aBaseTolerance;
338
339   const Standard_Real aLimitCoeff = 0.99 * 0.99;
340   for(i = 3; i <= theWLine->NbPnts(); i++)
341   {
342     Standard_Boolean isDeleteState = Standard_False;
343
344     theWLine->Point(i).ParametersOnS1(UonS1[2], VonS1[2]);
345     theWLine->Point(i).ParametersOnS2(UonS2[2], VonS2[2]);
346     gp_Pnt2d aPnt2dOnS1(UonS1[2], VonS1[2]);
347     gp_Pnt2d aPnt2dOnS2(UonS2[2], VonS2[2]);
348     const gp_Pnt& aPnt3d = theWLine->Point(i).Value();
349
350     if (aNewPointsHash(i - 1) != - 1 &&
351         IsInsideIn2d(aBase2dPnt1, aBase2dVec1, aPnt2dOnS1, aTol1) &&
352         IsInsideIn2d(aBase2dPnt2, aBase2dVec2, aPnt2dOnS2, aTol2) &&
353         IsInsideIn3d(aBase3dPnt, aBase3dVec, aPnt3d, aTol3d) )
354     {
355       // Handle possible uneven parametrization on one of 2d subspaces.
356       // Delete point only when expected lengths are close to each other (aLimitCoeff).
357       // Example:
358       // c2d1 - line
359       // c3d - line
360       // c2d2 - geometrically line, but have uneven parametrization -> c2d2 is bspline.
361       gp_XY aPntOnS1[2]= { gp_XY(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0])
362                          , gp_XY(UonS1[2] - UonS1[1], VonS1[2] - VonS1[1])};
363       gp_XY aPntOnS2[2]= { gp_XY(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0])
364                          , gp_XY(UonS2[2] - UonS2[1], VonS2[2] - VonS2[1])};
365
366       Standard_Real aStepOnS1 = aPntOnS1[0].SquareModulus() / aPntOnS1[1].SquareModulus();
367       Standard_Real aStepOnS2 = aPntOnS2[0].SquareModulus() / aPntOnS2[1].SquareModulus();
368
369       Standard_Real aStepCoeff = Min(aStepOnS1, aStepOnS2) / Max(aStepOnS1, aStepOnS2);
370
371       if (aStepCoeff > aLimitCoeff)
372       {
373         // Set hash flag to "Delete" state.
374         isDeleteState = Standard_True;
375         aNewPointsHash.SetValue(i - 1, 1);
376
377         // Change middle point.
378         UonS1[1] = UonS1[2];
379         UonS2[1] = UonS2[2];
380         VonS1[1] = VonS1[2];
381         VonS2[1] = VonS2[2];
382       }
383     }
384
385     if (!isDeleteState)
386     {
387       // Compute new pipe parameters.
388       UonS1[0] = UonS1[1];
389       VonS1[0] = VonS1[1];
390       UonS2[0] = UonS2[1];
391       VonS2[0] = VonS2[1];
392
393       UonS1[1] = UonS1[2];
394       VonS1[1] = VonS1[2];
395       UonS2[1] = UonS2[2];
396       VonS2[1] = VonS2[2];
397
398       aBase2dPnt1.SetCoord(UonS1[0], VonS1[0]);
399       aBase2dPnt2.SetCoord(UonS2[0], VonS2[0]);
400       aBase2dVec1.SetCoord(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
401       aBase2dVec2.SetCoord(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
402       aBase3dPnt = theWLine->Point(i - 1).Value();
403       aBase3dVec = gp_Vec(theWLine->Point(i - 1).Value(), theWLine->Point(i).Value());
404
405       aNbPnt++;
406     }
407   }
408
409   // Workaround to handle case of small amount of points after purge.
410   // Test "boolean boptuc_complex B5" and similar.
411   // This is possible since there are at least two points.
412   if (aNewPointsHash(1) == -1 &&
413       aNewPointsHash(2) == -1 &&
414       aNbPnt <= 3)
415   {
416     // Delete first.
417     aNewPointsHash(1) = 1;
418   }
419   if (aNewPointsHash(theWLine->NbPnts() - 1) == -1 &&
420       aNewPointsHash(theWLine->NbPnts()    ) == -1 &&
421       aNbPnt <= 3)
422   {
423     // Delete last.
424     aNewPointsHash(theWLine->NbPnts()) = 1;
425   }
426
427   // Purgre when too small amount of points left.
428   if (aNbPnt <= 2)
429   {
430     for(i = aNewPointsHash.Lower(); i <= aNewPointsHash.Upper(); i++)
431     {
432       if (aNewPointsHash(i) != -1)
433       {
434         aNewPointsHash(i) = 1;
435       }
436     }
437   }
438
439   // Handle possible bad distribution of points, 
440   // which are will converted into one single bezier curve (less than 30 points).
441   // Make distribution more even:
442   // max step will be nearly to 0.1 of param distance.
443   if (aNbPnt + 2 > aMinNbBadDistr &&
444       aNbPnt + 2 < aNbSingleBezier )
445   {
446     for(Standard_Integer anIdx = 1; anIdx <= 8; anIdx++)
447     {
448       Standard_Integer aHashIdx = 
449         Standard_Integer(anIdx * theWLine->NbPnts() / 9);
450
451       //Vertex must be stored as VERTEX (HASH = -1)
452       if (aNewPointsHash(aHashIdx) != -1)
453         aNewPointsHash(aHashIdx) = 0;
454     }
455   }
456
457   return MakeNewWLine(theWLine, aNewPointsHash);
458 }
459
460 //=======================================================================
461 //function : IsSeam
462 //purpose  : Returns:
463 //            0 - if interval [theU1, theU2] does not intersect the "seam-edge"
464 //                or if "seam-edge" do not exist;
465 //            1 - if interval (theU1, theU2) intersect the "seam-edge".
466 //            2 - if theU1 or/and theU2 lie ON the "seam-edge"
467 //
468 //ATTENTION!!!
469 //  If (theU1 == theU2) then this function will return only both 0 or 2.
470 //
471 //           Static subfunction in IsSeamOrBound.
472 //=======================================================================
473 static Standard_Integer IsSeam( const Standard_Real theU1,
474                                 const Standard_Real theU2,
475                                 const Standard_Real thePeriod)
476 {
477   if(IsEqual(thePeriod, 0.0))
478     return 0;
479
480   //If interval [theU1, theU2] intersect seam-edge then there exists an integer
481   //number N such as 
482   //    (theU1 <= T*N <= theU2) <=> (theU1/T <= N <= theU2/T),
483   //where T is the period.
484   //I.e. the inerval [theU1/T, theU2/T] must contain at least one
485   //integer number. In this case, Floor(theU1/T) and Floor(theU2/T)
486   //return different values or theU1/T is strictly integer number.
487   //Examples:
488   //  1. theU1/T==2.8, theU2/T==3.5 => Floor(theU1/T) == 2, Floor(theU2/T) == 3.
489   //  2. theU1/T==2.0, theU2/T==2.6 => Floor(theU1/T) == Floor(theU2/T) == 2.
490
491   const Standard_Real aVal1 = theU1/thePeriod,
492                       aVal2 = theU2/thePeriod;
493   const Standard_Integer aPar1 = static_cast<Standard_Integer>(Floor(aVal1));
494   const Standard_Integer aPar2 = static_cast<Standard_Integer>(Floor(aVal2));
495   if(aPar1 != aPar2)
496   {//Interval (theU1, theU2] intersects seam-edge
497     if(IsEqual(aVal2, static_cast<Standard_Real>(aPar2)))
498     {//aVal2 is an integer number => theU2 lies ON the "seam-edge"
499       return 2;
500     }
501
502     return 1;
503   }
504
505   //Here, aPar1 == aPar2. 
506
507   if(IsEqual(aVal1, static_cast<Standard_Real>(aPar1)))
508   {//aVal1 is an integer number => theU1 lies ON the "seam-edge"
509     return 2;
510   }
511
512   //If aVal2 is a true integer number then always (aPar1 != aPar2).
513
514   return 0;
515 }
516
517 //=======================================================================
518 //function : IsSeamOrBound
519 //purpose  : Returns TRUE if segment [thePtf, thePtl] intersects "seam-edge"
520 //            (if it exist) or surface boundaries and both thePtf and thePtl do
521 //            not match "seam-edge" or boundaries.
522 //           Point thePtmid lies in this segment (in both 3D and 2D-space).
523 //           If thePtmid match "seam-edge" or boundaries strictly 
524 //            (without any tolerance) then the function will return TRUE.
525 //            See comments in function body for detail information.
526 //=======================================================================
527 static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
528                                       const IntSurf_PntOn2S& thePtl,
529                                       const IntSurf_PntOn2S& thePtmid,
530                                       const Standard_Real theU1Period,
531                                       const Standard_Real theU2Period,
532                                       const Standard_Real theV1Period,
533                                       const Standard_Real theV2Period,
534                                       const Standard_Real theUfSurf1,
535                                       const Standard_Real theUlSurf1,
536                                       const Standard_Real theVfSurf1,
537                                       const Standard_Real theVlSurf1,
538                                       const Standard_Real theUfSurf2,
539                                       const Standard_Real theUlSurf2,
540                                       const Standard_Real theVfSurf2,
541                                       const Standard_Real theVlSurf2)
542 {
543   Standard_Real aU11 = 0.0, aU12 = 0.0, aV11 = 0.0, aV12 = 0.0;
544   Standard_Real aU21 = 0.0, aU22 = 0.0, aV21 = 0.0, aV22 = 0.0;
545   thePtf.Parameters(aU11, aV11, aU12, aV12);
546   thePtl.Parameters(aU21, aV21, aU22, aV22);
547
548   MinMax(aU11, aU21);
549   MinMax(aV11, aV21);
550   MinMax(aU12, aU22);
551   MinMax(aV12, aV22);
552
553   if((aU11 - theUfSurf1)*(aU21 - theUfSurf1) < 0.0)
554   {//Interval [aU11, aU21] intersects theUfSurf1
555     return Standard_True;
556   }
557
558   if((aU11 - theUlSurf1)*(aU21 - theUlSurf1) < 0.0)
559   {//Interval [aU11, aU21] intersects theUlSurf1
560     return Standard_True;
561   }
562
563   if((aV11 - theVfSurf1)*(aV21 - theVfSurf1) < 0.0)
564   {//Interval [aV11, aV21] intersects theVfSurf1
565     return Standard_True;
566   }
567
568   if((aV11 - theVlSurf1)*(aV21 - theVlSurf1) < 0.0)
569   {//Interval [aV11, aV21] intersects theVlSurf1
570     return Standard_True;
571   }
572
573   if((aU12 - theUfSurf2)*(aU22 - theUfSurf2) < 0.0)
574   {//Interval [aU12, aU22] intersects theUfSurf2
575     return Standard_True;
576   }
577
578   if((aU12 - theUlSurf2)*(aU22 - theUlSurf2) < 0.0)
579   {//Interval [aU12, aU22] intersects theUlSurf2
580     return Standard_True;
581   }
582
583   if((aV12 - theVfSurf2)*(aV22 - theVfSurf2) < 0.0)
584   {//Interval [aV12, aV22] intersects theVfSurf2
585     return Standard_True;
586   }
587
588   if((aV12 - theVlSurf2)*(aV22 - theVlSurf2) < 0.0)
589   {//Interval [aV12, aV22] intersects theVlSurf2
590     return Standard_True;
591   }
592
593   if(IsSeam(aU11, aU21, theU1Period))
594     return Standard_True;
595
596   if(IsSeam(aV11, aV21, theV1Period))
597     return Standard_True;
598
599   if(IsSeam(aU12, aU22, theU2Period))
600     return Standard_True;
601
602   if(IsSeam(aV12, aV22, theV2Period))
603     return Standard_True;
604
605   /*
606     The segment [thePtf, thePtl] does not intersect the boundaries and
607     the seam-edge of the surfaces.
608     Nevertheless, following situation is possible:
609
610                   seam or
611                    bound
612                      |
613         thePtf  *    |
614                      |
615                      * thePtmid
616           thePtl  *  |
617                      |
618
619     This case must be processed, too.
620   */
621
622   Standard_Real aU1 = 0.0, aU2 = 0.0, aV1 = 0.0, aV2 = 0.0;
623   thePtmid.Parameters(aU1, aV1, aU2, aV2);
624
625   if(IsEqual(aU1, theUfSurf1) || IsEqual(aU1, theUlSurf1))
626     return Standard_True;
627
628   if(IsEqual(aU2, theUfSurf2) || IsEqual(aU2, theUlSurf2))
629     return Standard_True;
630
631   if(IsEqual(aV1, theVfSurf1) || IsEqual(aV1, theVlSurf1))
632     return Standard_True;
633
634   if(IsEqual(aV2, theVfSurf2) || IsEqual(aV2, theVlSurf2))
635     return Standard_True;
636
637   if(IsSeam(aU1, aU1, theU1Period))
638     return Standard_True;
639
640   if(IsSeam(aU2, aU2, theU2Period))
641     return Standard_True;
642
643   if(IsSeam(aV1, aV1, theV1Period))
644     return Standard_True;
645
646   if(IsSeam(aV2, aV2, theV2Period))
647     return Standard_True;
648
649   return Standard_False;
650 }
651
652 //=======================================================================
653 //function : AbjustPeriodicToPrevPoint
654 //purpose  : Returns theCurrentParam in order to the distance betwen 
655 //            theRefParam and theCurrentParam is less than 0.5*thePeriod.
656 //=======================================================================
657 static void AbjustPeriodicToPrevPoint(const Standard_Real theRefParam,
658                                       const Standard_Real thePeriod,
659                                       Standard_Real& theCurrentParam)
660 {
661   if(thePeriod == 0.0)
662     return;
663
664   Standard_Real aDeltaPar = 2.0*(theRefParam - theCurrentParam);
665   const Standard_Real anIncr = Sign(thePeriod, aDeltaPar);
666   while(Abs(aDeltaPar) > thePeriod)
667   {
668     theCurrentParam += anIncr;
669     aDeltaPar = 2.0*(theRefParam-theCurrentParam);
670   }
671 }
672
673 //=======================================================================
674 //function : IsIntersectionPoint
675 //purpose  : Returns True if thePmid is intersection point
676 //            between theS1 and theS2 with given tolerance.
677 //           In this case, parameters of thePmid on every quadric
678 //            will be recomputed and returned.
679 //=======================================================================
680 static Standard_Boolean IsIntersectionPoint(const gp_Pnt& thePmid,
681                                             const IntSurf_Quadric& theS1,
682                                             const IntSurf_Quadric& theS2,
683                                             const IntSurf_PntOn2S& theRefPt,
684                                             const Standard_Real theTol,
685                                             const Standard_Real theU1Period,
686                                             const Standard_Real theU2Period,
687                                             const Standard_Real theV1Period,
688                                             const Standard_Real theV2Period,
689                                             Standard_Real &theU1,
690                                             Standard_Real &theV1,
691                                             Standard_Real &theU2,
692                                             Standard_Real &theV2)
693 {
694   Standard_Real aU1Ref = 0.0, aV1Ref = 0.0, aU2Ref = 0.0, aV2Ref = 0.0;
695   theRefPt.Parameters(aU1Ref, aV1Ref, aU2Ref, aV2Ref);
696   theS1.Parameters(thePmid, theU1, theV1);
697   theS2.Parameters(thePmid, theU2, theV2);
698
699   AbjustPeriodicToPrevPoint(aU1Ref, theU1Period, theU1);
700   AbjustPeriodicToPrevPoint(aV1Ref, theV1Period, theV1);
701   AbjustPeriodicToPrevPoint(aU2Ref, theU2Period, theU2);
702   AbjustPeriodicToPrevPoint(aV2Ref, theV2Period, theV2);
703
704   const gp_Pnt aP1(theS1.Value(theU1, theV1));
705   const gp_Pnt aP2(theS2.Value(theU2, theV2));
706
707   return (aP1.SquareDistance(aP2) <= theTol*theTol);
708 }
709
710 //=======================================================================
711 //function : ExtendFirst
712 //purpose  : Adds thePOn2S to the begin of theWline
713 //=======================================================================
714 static void ExtendFirst(const Handle(IntPatch_WLine)& theWline,
715                         const IntSurf_PntOn2S &thePOn2S)
716 {
717   theWline->Curve()->InsertBefore(1, thePOn2S);
718
719   IntPatch_Point &aVert = theWline->ChangeVertex(1);
720
721   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
722   thePOn2S.Parameters(aU1, aV1, aU2, aV2);
723
724   aVert.SetParameters(aU1, aV1, aU2, aV2);
725   aVert.SetValue(thePOn2S.Value());
726
727   for(Standard_Integer i = 2; i <= theWline->NbVertex(); i++)
728   {
729     IntPatch_Point &aV = theWline->ChangeVertex(i);
730     aV.SetParameter(aV.ParameterOnLine()+1);
731   }
732 }
733
734 //=======================================================================
735 //function : ExtendLast
736 //purpose  : Adds thePOn2S to the end of theWline
737 //=======================================================================
738 static void ExtendLast(const Handle(IntPatch_WLine)& theWline,
739                        const IntSurf_PntOn2S &thePOn2S)
740 {
741   theWline->Curve()->Add(thePOn2S);
742
743   IntPatch_Point &aVert = theWline->ChangeVertex(theWline->NbVertex());
744
745   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
746   thePOn2S.Parameters(aU1, aV1, aU2, aV2);
747
748   aVert.SetParameters(aU1, aV1, aU2, aV2);
749   aVert.SetValue(thePOn2S.Value());
750   aVert.SetParameter(theWline->NbPnts());
751 }
752
753 //=========================================================================
754 // function : ComputePurgedWLine
755 // purpose  :
756 //=========================================================================
757 Handle(IntPatch_WLine) IntPatch_WLineTool::
758   ComputePurgedWLine(const Handle(IntPatch_WLine)       &theWLine,
759                      const Handle(Adaptor3d_HSurface)   &theS1,
760                      const Handle(Adaptor3d_HSurface)   &theS2,
761                      const Handle(Adaptor3d_TopolTool)  &theDom1,
762                      const Handle(Adaptor3d_TopolTool)  &theDom2)
763 {
764   Standard_Integer i, k, v, nb, nbvtx;
765   Handle(IntPatch_WLine) aResult;
766   nbvtx = theWLine->NbVertex();
767   nb = theWLine->NbPnts();
768   if (nb==2)
769   {
770     const IntSurf_PntOn2S& p1 = theWLine->Point(1);
771     const IntSurf_PntOn2S& p2 = theWLine->Point(2);
772     if(p1.Value().IsEqual(p2.Value(), gp::Resolution()))
773       return aResult;
774   }
775
776   Handle(IntPatch_WLine) aLocalWLine;
777   Handle(IntPatch_WLine) aTmpWLine = theWLine;
778   Handle(IntSurf_LineOn2S) aLineOn2S = new IntSurf_LineOn2S();
779   aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
780   for(i = 1; i <= nb; i++)
781     aLineOn2S->Add(theWLine->Point(i));
782
783   for(v = 1; v <= nbvtx; v++)
784     aLocalWLine->AddVertex(theWLine->Vertex(v));
785
786   // I: Delete equal points
787   for(i = 1; i <= aLineOn2S->NbPoints(); i++)
788   {
789     Standard_Integer aStartIndex = i + 1;
790     Standard_Integer anEndIndex = i + 5;
791     nb = aLineOn2S->NbPoints();
792     anEndIndex = (anEndIndex > nb) ? nb : anEndIndex;
793
794     if((aStartIndex > nb) || (anEndIndex <= 1))
795       continue;
796
797     k = aStartIndex;
798
799     while(k <= anEndIndex)
800     {
801       if(i != k)
802       {
803         IntSurf_PntOn2S p1 = aLineOn2S->Value(i);
804         IntSurf_PntOn2S p2 = aLineOn2S->Value(k);
805         
806         Standard_Real UV[8];
807         p1.Parameters(UV[0], UV[1], UV[2], UV[3]);
808         p2.Parameters(UV[4], UV[5], UV[6], UV[7]);
809
810         Standard_Real aMax = Abs(UV[0]);
811         for(Standard_Integer anIdx = 1; anIdx < 8; anIdx++)
812         {
813           if (aMax < Abs(UV[anIdx]))
814             aMax = Abs(UV[anIdx]);
815         }
816
817         if(p1.Value().IsEqual(p2.Value(), gp::Resolution()) ||
818            Abs(UV[0] - UV[4]) + Abs(UV[1] - UV[5]) < 1.0e-16 * aMax ||
819            Abs(UV[2] - UV[6]) + Abs(UV[3] - UV[7]) < 1.0e-16 * aMax )
820         {
821           aTmpWLine = aLocalWLine;
822           aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
823           
824           for(v = 1; v <= aTmpWLine->NbVertex(); v++)
825           {
826             IntPatch_Point aVertex = aTmpWLine->Vertex(v);
827             Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
828
829             if(avertexindex >= k)
830             {
831               aVertex.SetParameter(aVertex.ParameterOnLine() - 1.);
832             }
833             aLocalWLine->AddVertex(aVertex);
834           }
835           aLineOn2S->RemovePoint(k);
836           anEndIndex--;
837           continue;
838         }
839       }
840       k++;
841     }
842   }
843
844   if (aLineOn2S->NbPoints() <= 2)
845   {
846     if (aLineOn2S->NbPoints() == 2)
847       return aLocalWLine;
848     else
849       return aResult;
850   }
851
852   // Avoid purge in case of C0 continuity:
853   // Intersection approximator may produce invalid curve after purge, example:
854   // bugs modalg_5 bug24731.
855   // Do not run purger when base number of points is too small.
856   if (theS1->UContinuity() == GeomAbs_C0 ||
857       theS1->VContinuity() == GeomAbs_C0 ||
858       theS2->UContinuity() == GeomAbs_C0 ||
859       theS2->VContinuity() == GeomAbs_C0 ||
860       nb < aNbSingleBezier)
861   {
862     return aLocalWLine;
863   }
864
865   // II: Delete out of borders points.
866   Handle(IntPatch_WLine) aLocalWLineOuter = 
867     DeleteOuterPoints(aLocalWLine, theS1, theS2, theDom1, theDom2);
868
869   // III: Delete points by tube criteria.
870   Handle(IntPatch_WLine) aLocalWLineTube = 
871     DeleteByTube(aLocalWLineOuter, theS1, theS2);
872
873   if(aLocalWLineTube->NbPnts() > 1)
874   {
875     aResult = aLocalWLineTube;
876   }
877   return aResult;
878 }
879
880
881 //=======================================================================
882 //function : JoinWLines
883 //purpose  :
884 //=======================================================================
885 void IntPatch_WLineTool::JoinWLines(IntPatch_SequenceOfLine& theSlin,
886                                     IntPatch_SequenceOfPoint& theSPnt,
887                                     const Standard_Real theTol3D,
888                                     const Standard_Real theU1Period,
889                                     const Standard_Real theU2Period,
890                                     const Standard_Real theV1Period,
891                                     const Standard_Real theV2Period,
892                                     const Standard_Real theUfSurf1,
893                                     const Standard_Real theUlSurf1,
894                                     const Standard_Real theVfSurf1,
895                                     const Standard_Real theVlSurf1,
896                                     const Standard_Real theUfSurf2,
897                                     const Standard_Real theUlSurf2,
898                                     const Standard_Real theVfSurf2,
899                                     const Standard_Real theVlSurf2)
900 {
901   if(theSlin.Length() == 0)
902     return;
903
904   for(Standard_Integer aNumOfLine1 = 1; aNumOfLine1 <= theSlin.Length(); aNumOfLine1++)
905   {
906     Handle(IntPatch_WLine) aWLine1 (Handle(IntPatch_WLine)::DownCast(theSlin.Value(aNumOfLine1)));
907
908     if(aWLine1.IsNull())
909     {//We must have failed to join not-point-lines
910       continue;
911     }
912
913     const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
914     const IntSurf_PntOn2S& aPntFW1 = aWLine1->Point(1);
915     const IntSurf_PntOn2S& aPntLW1 = aWLine1->Point(aNbPntsWL1);
916
917     for(Standard_Integer aNPt = 1; aNPt <= theSPnt.Length(); aNPt++)
918     {
919       const IntSurf_PntOn2S aPntCur = theSPnt.Value(aNPt).PntOn2S();
920
921       if( aPntCur.IsSame(aPntFW1, Precision::Confusion()) ||
922         aPntCur.IsSame(aPntLW1, Precision::Confusion()))
923       {
924         theSPnt.Remove(aNPt);
925         aNPt--;
926       }
927     }
928
929     Standard_Boolean hasBeenRemoved = Standard_False;
930     for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1; aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
931     {
932       Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::DownCast(theSlin.Value(aNumOfLine2)));
933
934       if(aWLine2.IsNull())
935         continue;
936
937       const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
938
939       const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
940       const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
941
942       const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
943       const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
944
945       if(aPntFWL1.IsSame(aPntFWL2, Precision::Confusion()))
946       {
947         const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2);
948         const IntSurf_PntOn2S& aPt2 = aWLine2->Point(2);
949         if(!IsSeamOrBound(aPt1, aPt2, aPntFWL1, theU1Period, theU2Period,
950                           theV1Period, theV2Period, theUfSurf1, theUlSurf1,
951                           theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2,
952                           theVfSurf2, theVlSurf2))
953         {
954           aWLine1->ClearVertexes();
955           for(Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
956           {
957             const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
958             aWLine1->Curve()->InsertBefore(1, aPt);
959           }
960
961           aWLine1->ComputeVertexParameters(theTol3D);
962
963           theSlin.Remove(aNumOfLine2);
964           aNumOfLine2--;
965           hasBeenRemoved = Standard_True;
966
967           continue;
968         }
969       }
970
971       if(aPntFWL1.IsSame(aPntLWL2, Precision::Confusion()))
972       {
973         const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2);
974         const IntSurf_PntOn2S& aPt2 = aWLine2->Point(aNbPntsWL2-1);
975         if(!IsSeamOrBound(aPt1, aPt2, aPntFWL1, theU1Period, theU2Period,
976                           theV1Period, theV2Period, theUfSurf1, theUlSurf1,
977                           theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2,
978                           theVfSurf2, theVlSurf2))
979         {
980           aWLine1->ClearVertexes();
981           for(Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
982           {
983             const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
984             aWLine1->Curve()->InsertBefore(1, aPt);
985           }
986
987           aWLine1->ComputeVertexParameters(theTol3D);
988
989           theSlin.Remove(aNumOfLine2);
990           aNumOfLine2--;
991           hasBeenRemoved = Standard_True;
992
993           continue;
994         }
995       }
996
997       if(aPntLWL1.IsSame(aPntFWL2, Precision::Confusion()))
998       {
999         const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1-1);
1000         const IntSurf_PntOn2S& aPt2 = aWLine2->Point(2);
1001         if(!IsSeamOrBound(aPt1, aPt2, aPntLWL1, theU1Period, theU2Period,
1002                           theV1Period, theV2Period, theUfSurf1, theUlSurf1,
1003                           theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2,
1004                           theVfSurf2, theVlSurf2))
1005         {
1006           aWLine1->ClearVertexes();
1007           for(Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
1008           {
1009             const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1010             aWLine1->Curve()->Add(aPt);
1011           }
1012
1013           aWLine1->ComputeVertexParameters(theTol3D);
1014
1015           theSlin.Remove(aNumOfLine2);
1016           aNumOfLine2--;
1017           hasBeenRemoved = Standard_True;
1018
1019           continue;
1020         }
1021       }
1022
1023       if(aPntLWL1.IsSame(aPntLWL2, Precision::Confusion()))
1024       {
1025         const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1-1);
1026         const IntSurf_PntOn2S& aPt2 = aWLine2->Point(aNbPntsWL2-1);
1027         if(!IsSeamOrBound(aPt1, aPt2, aPntLWL1, theU1Period, theU2Period,
1028                           theV1Period, theV2Period, theUfSurf1, theUlSurf1,
1029                           theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2,
1030                           theVfSurf2, theVlSurf2))
1031         {
1032           aWLine1->ClearVertexes();
1033           for(Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
1034           {
1035             const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1036             aWLine1->Curve()->Add(aPt);
1037           }
1038
1039           aWLine1->ComputeVertexParameters(theTol3D);
1040
1041           theSlin.Remove(aNumOfLine2);
1042           aNumOfLine2--;
1043           hasBeenRemoved = Standard_True;
1044
1045           continue;
1046         }
1047       }
1048     }
1049
1050     if(hasBeenRemoved)
1051       aNumOfLine1--;
1052   }
1053 }
1054
1055 //=======================================================================
1056 //function : ExtendTwoWlinesToEachOther
1057 //purpose  : 
1058 //=======================================================================
1059 void IntPatch_WLineTool::ExtendTwoWlinesToEachOther(IntPatch_SequenceOfLine& theSlin,
1060                                                     const IntSurf_Quadric& theS1,
1061                                                     const IntSurf_Quadric& theS2,
1062                                                     const Standard_Real theToler3D,
1063                                                     const Standard_Real theU1Period,
1064                                                     const Standard_Real theU2Period,
1065                                                     const Standard_Real theV1Period,
1066                                                     const Standard_Real theV2Period)
1067 {
1068   if(theSlin.Length() < 2)
1069     return;
1070
1071   const Standard_Real aMaxAngle = M_PI/6; //30 degree
1072   const Standard_Real aSqToler = theToler3D*theToler3D;
1073   Standard_Real aU1=0.0, aV1=0.0, aU2=0.0, aV2=0.0;
1074   gp_Pnt aPmid;
1075   gp_Vec aVec1, aVec2, aVec3;
1076
1077   for(Standard_Integer aNumOfLine1 = 1; aNumOfLine1 <= theSlin.Length(); aNumOfLine1++)
1078   {
1079     Handle(IntPatch_WLine) aWLine1 (Handle(IntPatch_WLine)::
1080                                     DownCast(theSlin.Value(aNumOfLine1)));
1081
1082     if(aWLine1.IsNull())
1083     {//We must have failed to join not-point-lines
1084       continue;
1085     }
1086     
1087     const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
1088
1089     for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1;
1090         aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
1091     {
1092       Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::
1093                                     DownCast(theSlin.Value(aNumOfLine2)));
1094
1095       if(aWLine2.IsNull())
1096         continue;
1097
1098       //Enable/Disable of some ckeck. Bit-mask is used for it.
1099       //E.g. if 1st point of aWLine1 matches with
1100       //1st point of aWLine2 then we do not need in check
1101       //1st point of aWLine1 and last point of aWLine2 etc.
1102       enum
1103       {
1104         IntPatchWT_EnAll = 0x00,
1105         IntPatchWT_DisLastLast = 0x01,
1106         IntPatchWT_DisLastFirst = 0x02,
1107         IntPatchWT_DisFirstLast = 0x04,
1108         IntPatchWT_DisFirstFirst = 0x08
1109       };
1110
1111       unsigned int aCheckResult = IntPatchWT_EnAll;
1112
1113       const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
1114
1115       const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
1116       const IntSurf_PntOn2S& aPntFp1WL1 = aWLine1->Point(2);
1117
1118       const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
1119       const IntSurf_PntOn2S& aPntLm1WL1 = aWLine1->Point(aNbPntsWL1-1);
1120       
1121       const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
1122       const IntSurf_PntOn2S& aPntFp1WL2 = aWLine2->Point(2);
1123
1124       const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
1125       const IntSurf_PntOn2S& aPntLm1WL2 = aWLine2->Point(aNbPntsWL2-1);
1126       
1127       //if(!(aCheckResult & IntPatchWT_DisFirstFirst))
1128       {// First/First
1129         aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
1130         aVec2.SetXYZ(aPntFWL2.Value().XYZ() - aPntFp1WL2.Value().XYZ());
1131         aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntFWL2.Value().XYZ());
1132
1133         if(aVec3.SquareMagnitude() > aSqToler)
1134         {
1135           if( (aVec1.Angle(aVec2) < aMaxAngle) &&
1136               (aVec1.Angle(aVec3) < aMaxAngle) &&
1137               (aVec2.Angle(aVec3) < aMaxAngle))
1138           {
1139             aPmid.SetXYZ(0.5*(aPntFWL1.Value().XYZ()+aPntFWL2.Value().XYZ()));
1140             if(IsIntersectionPoint(aPmid, theS1, theS2, aPntFWL1, theToler3D,
1141                                    theU1Period, theU2Period, theV1Period, theV2Period,
1142                                    aU1, aV1, aU2, aV2))
1143             {
1144               IntSurf_PntOn2S aPOn2S;
1145               aPOn2S.SetValue(aPmid, aU1, aV1, aU2, aV2);
1146               
1147               Standard_Real aU11 = 0.0, aV11 = 0.0, aU21 = 0.0, aV21 = 0.0,
1148                             aU12 = 0.0, aV12 = 0.0, aU22 = 0.0, aV22 = 0.0;
1149               aPntFWL1.Parameters(aU11, aV11, aU21, aV21);
1150               aPntFWL2.Parameters(aU12, aV12, aU22, aV22);
1151
1152               if(!IsSeam(aU11, aU12, theU1Period) &&
1153                  !IsSeam(aV11, aV12, theV1Period) &&
1154                  !IsSeam(aU21, aU22, theU2Period) &&
1155                  !IsSeam(aV21, aV22, theV2Period))
1156               {
1157                 aCheckResult |= (IntPatchWT_DisFirstLast |
1158                                  IntPatchWT_DisLastFirst);
1159
1160                 if(!aPOn2S.IsSame(aPntFWL1, Precision::Confusion()))
1161                 {
1162                   ExtendFirst(aWLine1, aPOn2S);
1163                 }
1164                 else
1165                 {
1166                   aWLine1->Curve()->Value(1, aPOn2S);
1167                 }
1168
1169                 if(!aPOn2S.IsSame(aPntFWL2, Precision::Confusion()))
1170                 {
1171                   ExtendFirst(aWLine2, aPOn2S);
1172                 }
1173                 else
1174                 {
1175                   aWLine2->Curve()->Value(1, aPOn2S);
1176                 }
1177               }
1178             }
1179           }
1180         }//if(aVec3.SquareMagnitude() > aSqToler) cond.
1181       }//if(!(aCheckResult & 0x08)) cond.
1182
1183       if(!(aCheckResult & IntPatchWT_DisFirstLast))
1184       {// First/Last
1185         aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
1186         aVec2.SetXYZ(aPntLWL2.Value().XYZ() - aPntLm1WL2.Value().XYZ());
1187         aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntLWL2.Value().XYZ());
1188
1189         if(aVec3.SquareMagnitude() > aSqToler)
1190         {
1191           if((aVec1.Angle(aVec2) < aMaxAngle) &&
1192              (aVec1.Angle(aVec3) < aMaxAngle) &&
1193              (aVec2.Angle(aVec3) < aMaxAngle))
1194           {
1195             aPmid.SetXYZ(0.5*(aPntFWL1.Value().XYZ()+aPntLWL2.Value().XYZ()));
1196             if(IsIntersectionPoint(aPmid, theS1, theS2, aPntFWL1, theToler3D,
1197                                    theU1Period, theU2Period, theV1Period, theV2Period,
1198                                    aU1, aV1, aU2, aV2))
1199             {
1200               IntSurf_PntOn2S aPOn2S;
1201               aPOn2S.SetValue(aPmid, aU1, aV1, aU2, aV2);
1202
1203               Standard_Real aU11 = 0.0, aV11 = 0.0, aU21 = 0.0, aV21 = 0.0,
1204                             aU12 = 0.0, aV12 = 0.0, aU22 = 0.0, aV22 = 0.0;
1205               aPntFWL1.Parameters(aU11, aV11, aU21, aV21);
1206               aPntLWL2.Parameters(aU12, aV12, aU22, aV22);
1207
1208               if(!IsSeam(aU11, aU12, theU1Period) &&
1209                  !IsSeam(aV11, aV12, theV1Period) &&
1210                  !IsSeam(aU21, aU22, theU2Period) &&
1211                  !IsSeam(aV21, aV22, theV2Period))
1212               {
1213                 aCheckResult |= IntPatchWT_DisLastLast;
1214
1215                 if(!aPOn2S.IsSame(aPntFWL1, Precision::Confusion()))
1216                 {
1217                   ExtendFirst(aWLine1, aPOn2S);
1218                 }
1219                 else
1220                 {
1221                   aWLine1->Curve()->Value(1, aPOn2S);
1222                 }
1223
1224                 if(!aPOn2S.IsSame(aPntLWL2, Precision::Confusion()))
1225                 {
1226                   ExtendLast(aWLine2, aPOn2S);
1227                 }
1228                 else
1229                 {
1230                   aWLine2->Curve()->Value(aWLine2->NbPnts(), aPOn2S);
1231                 }
1232               }
1233             }
1234           }
1235         }//if(aVec3.SquareMagnitude() > aSqToler) cond.
1236       }//if(!(aCheckResult & 0x04)) cond.
1237
1238       if(!(aCheckResult & IntPatchWT_DisLastFirst))
1239       {// Last/First
1240         aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
1241         aVec2.SetXYZ(aPntFp1WL2.Value().XYZ() - aPntFWL2.Value().XYZ());
1242         aVec3.SetXYZ(aPntFWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
1243
1244         if(aVec3.SquareMagnitude() > aSqToler)
1245         {
1246           if((aVec1.Angle(aVec2) < aMaxAngle) &&
1247              (aVec1.Angle(aVec3) < aMaxAngle) &&
1248              (aVec2.Angle(aVec3) < aMaxAngle))
1249           {
1250             aPmid.SetXYZ(0.5*(aPntLWL1.Value().XYZ()+aPntFWL2.Value().XYZ()));
1251             if(IsIntersectionPoint(aPmid, theS1, theS2, aPntLWL1, theToler3D,
1252                                    theU1Period, theU2Period, theV1Period, theV2Period,
1253                                    aU1, aV1, aU2, aV2))
1254             {
1255               IntSurf_PntOn2S aPOn2S;
1256               aPOn2S.SetValue(aPmid, aU1, aV1, aU2, aV2);
1257
1258               Standard_Real aU11 = 0.0, aV11 = 0.0, aU21 = 0.0, aV21 = 0.0,
1259                             aU12 = 0.0, aV12 = 0.0, aU22 = 0.0, aV22 = 0.0;
1260               aPntLWL1.Parameters(aU11, aV11, aU21, aV21);
1261               aPntFWL2.Parameters(aU12, aV12, aU22, aV22);
1262
1263               if(!IsSeam(aU11, aU12, theU1Period) &&
1264                  !IsSeam(aV11, aV12, theV1Period) &&
1265                  !IsSeam(aU21, aU22, theU2Period) &&
1266                  !IsSeam(aV21, aV22, theV2Period))
1267               {
1268                 aCheckResult |= IntPatchWT_DisLastLast;
1269
1270                 if(!aPOn2S.IsSame(aPntLWL1, Precision::Confusion()))
1271                 {
1272                   ExtendLast(aWLine1, aPOn2S);
1273                 }
1274                 else
1275                 {
1276                   aWLine1->Curve()->Value(aWLine1->NbPnts(), aPOn2S);
1277                 }
1278
1279                 if(!aPOn2S.IsSame(aPntFWL2, Precision::Confusion()))
1280                 {
1281                   ExtendFirst(aWLine2, aPOn2S);
1282                 }
1283                 else
1284                 {
1285                   aWLine2->Curve()->Value(1, aPOn2S);
1286                 }
1287               }
1288             }
1289           }
1290         }//if(aVec3.SquareMagnitude() > aSqToler) cond.
1291       }//if(!(aCheckResult & 0x02)) cond.
1292
1293       if(!(aCheckResult & IntPatchWT_DisLastLast))
1294       {// Last/Last
1295         aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
1296         aVec2.SetXYZ(aPntLm1WL2.Value().XYZ() - aPntLWL2.Value().XYZ());
1297         aVec3.SetXYZ(aPntLWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
1298
1299         if(aVec3.SquareMagnitude() > aSqToler)
1300         {
1301           if((aVec1.Angle(aVec2) < aMaxAngle) &&
1302              (aVec1.Angle(aVec3) < aMaxAngle) &&
1303              (aVec2.Angle(aVec3) < aMaxAngle))
1304           {
1305             aPmid.SetXYZ(0.5*(aPntLWL1.Value().XYZ()+aPntLWL2.Value().XYZ()));
1306             if(IsIntersectionPoint(aPmid, theS1, theS2, aPntLWL1, theToler3D,
1307                                    theU1Period, theU2Period, theV1Period, theV2Period,
1308                                    aU1, aV1, aU2, aV2))
1309             {
1310               IntSurf_PntOn2S aPOn2S;
1311               aPOn2S.SetValue(aPmid, aU1, aV1, aU2, aV2);
1312
1313               Standard_Real aU11 = 0.0, aV11 = 0.0, aU21 = 0.0, aV21 = 0.0,
1314                             aU12 = 0.0, aV12 = 0.0, aU22 = 0.0, aV22 = 0.0;
1315               aPntLWL1.Parameters(aU11, aV11, aU21, aV21);
1316               aPntLWL2.Parameters(aU12, aV12, aU22, aV22);
1317
1318               if(!IsSeam(aU11, aU12, theU1Period) &&
1319                  !IsSeam(aV11, aV12, theV1Period) &&
1320                  !IsSeam(aU21, aU22, theU2Period) &&
1321                  !IsSeam(aV21, aV22, theV2Period))
1322               {
1323                 if(!aPOn2S.IsSame(aPntLWL1, Precision::Confusion()))
1324                 {
1325                   ExtendLast(aWLine1, aPOn2S);
1326                 }
1327                 else
1328                 {
1329                   aWLine1->Curve()->Value(aWLine1->NbPnts(), aPOn2S);
1330                 }
1331
1332                 if(!aPOn2S.IsSame(aPntLWL2, Precision::Confusion()))
1333                 {
1334                   ExtendLast(aWLine2, aPOn2S);
1335                 }
1336                 else
1337                 {
1338                   aWLine2->Curve()->Value(aWLine2->NbPnts(), aPOn2S);
1339                 }
1340               }
1341             }
1342           }
1343         }//if(aVec3.SquareMagnitude() > aSqToler) cond.
1344       }//if(!(aCheckResult & 0x01)) cond.
1345     }
1346   }
1347 }