abfe5b04159053c485309e51f9a24b26b155fc45
[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 #include <Bnd_Range.hxx>
19 #include <ElCLib.hxx>
20 #include <ElSLib.hxx>
21 #include <IntPatch_SpecialPoints.hxx>
22 #include <NCollection_IncAllocator.hxx>
23 #include <TopAbs_State.hxx>
24
25 // It is pure empirical value.
26 const Standard_Real IntPatch_WLineTool::myMaxConcatAngle = M_PI/6;
27
28 //Bit-mask is used for information about 
29 //the operation made in
30 //IntPatch_WLineTool::ExtendTwoWLines(...) method.
31 enum
32 {
33   IntPatchWT_EnAll = 0x00,
34   IntPatchWT_DisLastLast = 0x01,
35   IntPatchWT_DisLastFirst = 0x02,
36   IntPatchWT_DisFirstLast = 0x04,
37   IntPatchWT_DisFirstFirst = 0x08
38 };
39
40 enum IntPatchWT_WLsConnectionType
41 {
42   IntPatchWT_NotConnected,
43   IntPatchWT_Singular,
44   IntPatchWT_EachOther
45 };
46
47 //=======================================================================
48 //function : MinMax
49 //purpose  : Replaces theParMIN = MIN(theParMIN, theParMAX),
50 //                    theParMAX = MAX(theParMIN, theParMAX).
51 //
52 //           Static subfunction in IsSeamOrBound.
53 //=======================================================================
54 static inline void MinMax(Standard_Real& theParMIN, Standard_Real& theParMAX)
55 {
56   if(theParMIN > theParMAX)
57   {
58     const Standard_Real aTmp = theParMAX;
59     theParMAX = theParMIN;
60     theParMIN = aTmp;
61   }
62 }
63
64 //=========================================================================
65 // function : FillPointsHash
66 // purpose  : Fill points hash by input data.
67 //            Static subfunction in ComputePurgedWLine.
68 //=========================================================================
69 static void FillPointsHash(const Handle(IntPatch_WLine)         &theWLine,
70                            NCollection_Array1<Standard_Integer> &thePointsHash)
71 {
72   // 1 - Delete point.
73   // 0 - Store point.
74   // -1 - Vertex point (not delete).
75   Standard_Integer i, v;
76
77   for(i = 1; i <= theWLine->NbPnts(); i++)
78     thePointsHash.SetValue(i, 0);
79
80   for(v = 1; v <= theWLine->NbVertex(); v++) 
81   {
82     IntPatch_Point aVertex = theWLine->Vertex(v);
83     Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
84     thePointsHash.SetValue(avertexindex, -1);
85   }
86 }
87
88 //=========================================================================
89 // function : MakeNewWLine
90 // purpose  : Makes new walking line according to the points hash
91 //            Static subfunction in ComputePurgedWLine and DeleteOuter.
92 //=========================================================================
93 static Handle(IntPatch_WLine) MakeNewWLine(const Handle(IntPatch_WLine)         &theWLine,
94                                            NCollection_Array1<Standard_Integer> &thePointsHash,
95                                            const Standard_Boolean theIsOuter)
96 {
97   Standard_Integer i;
98
99   Handle(IntSurf_LineOn2S) aPurgedLineOn2S = new IntSurf_LineOn2S();
100   Handle(IntPatch_WLine) aLocalWLine = new IntPatch_WLine(aPurgedLineOn2S, Standard_False);
101   Standard_Integer anOldLineIdx = 1, aVertexIdx = 1, anIndexPrev = -1, anIdxOld = -1;
102   gp_Pnt aPPrev, aPOld;
103   for(i = 1; i <= thePointsHash.Upper(); i++)
104   {
105     if (thePointsHash(i) == 0)
106     {
107       // Point has to be added
108
109       const gp_Pnt aP = theWLine->Point(i).Value();
110       const Standard_Real aSqDistPrev = aPPrev.SquareDistance(aPOld);
111       const Standard_Real aSqDist = aPPrev.SquareDistance(aP);
112
113       const Standard_Real aRatio = (aSqDistPrev < gp::Resolution()) ? 0.0 : 9.0*aSqDist / aSqDistPrev;
114
115       if(theIsOuter ||
116          (aRatio < gp::Resolution()) ||
117          ((1.0 < aRatio) && (aRatio < 81.0)) ||
118          (i - anIndexPrev <= 1) ||
119          (i - anIdxOld <= 1))
120       {
121         // difference in distances is satisfactory
122         // (1/9 < aSqDist/aSqDistPrev < 9)
123
124         // Store this point.
125         aPurgedLineOn2S->Add(theWLine->Point(i));
126         anOldLineIdx++;
127         aPOld = aPPrev;
128         aPPrev = aP;
129         anIdxOld = anIndexPrev;
130         anIndexPrev = i;
131       }
132       else if(aSqDist >= aSqDistPrev*9.0)
133       {
134         // current segment is much more longer
135         // (aSqDist/aSqDistPrev >= 9)
136
137         i = (i + anIndexPrev)/2;
138         thePointsHash(i) = 0;
139         i--;
140       }
141       else
142       {
143         //previous segment is much more longer
144         //(aSqDist/aSqDistPrev <= 1/9)
145
146         if(anIndexPrev - anIdxOld > 1)
147         {
148           //Delete aPPrev from WL
149           aPurgedLineOn2S->RemovePoint(aPurgedLineOn2S->NbPoints());
150           anOldLineIdx--;
151
152           // Insert point between aPOld and aPPrev 
153           i = (anIdxOld + anIndexPrev) / 2;
154           thePointsHash(i) = 0;
155
156           aPPrev = aPOld;
157           anIndexPrev = anIdxOld;
158         }
159         else
160         {
161           aPOld = aPPrev;
162           anIdxOld = anIndexPrev;
163         }
164
165         //Next iterations will start from this inserted point.
166         i--;
167       }
168     }
169     else if (thePointsHash(i) == -1)
170     {
171       // Add vertex.
172       IntPatch_Point aVertex = theWLine->Vertex(aVertexIdx++);
173       aVertex.SetParameter(anOldLineIdx++);
174       aLocalWLine->AddVertex(aVertex);
175       aPurgedLineOn2S->Add(theWLine->Point(i));
176       aPPrev = aPOld = theWLine->Point(i).Value();
177       anIndexPrev = anIdxOld = i;
178     }
179
180     //Other points will be rejected by purger.
181   }
182
183   return aLocalWLine;
184 }
185
186 //=========================================================================
187 // function : MovePoint
188 // purpose  : Move point into surface param space. No interpolation used 
189 //            because walking algorithm should care for closeness to the param space.
190 //            Static subfunction in ComputePurgedWLine.
191 //=========================================================================
192 static void MovePoint(const Handle(Adaptor3d_HSurface)   &theS1,
193                       Standard_Real &U1, Standard_Real &V1)
194 {
195   if (U1 < theS1->FirstUParameter())
196     U1 = theS1->FirstUParameter();
197
198   if (U1 > theS1->LastUParameter())
199     U1 = theS1->LastUParameter();
200
201   if (V1 < theS1->FirstVParameter())
202     V1 = theS1->FirstVParameter();
203
204   if (V1 > theS1->LastVParameter())
205    V1 = theS1->LastVParameter();
206 }
207
208 //=========================================================================
209 // function : DeleteOuterPoints
210 // purpose  : Check and delete out of bounds points on walking line.
211 //            Static subfunction in ComputePurgedWLine.
212 //=========================================================================
213 static Handle(IntPatch_WLine)
214   DeleteOuterPoints(const Handle(IntPatch_WLine)       &theWLine,
215                     const Handle(Adaptor3d_HSurface)   &theS1,
216                     const Handle(Adaptor3d_HSurface)   &theS2,
217                     const Handle(Adaptor3d_TopolTool)  &theDom1,
218                     const Handle(Adaptor3d_TopolTool)  &theDom2)
219 {
220   Standard_Integer i;
221
222   NCollection_Array1<Standard_Integer> aDelOuterPointsHash(1, theWLine->NbPnts());
223   FillPointsHash(theWLine, aDelOuterPointsHash);
224
225   if (theS1->IsUPeriodic() || theS1->IsVPeriodic() ||
226       theS2->IsUPeriodic() || theS2->IsVPeriodic() )
227       return theWLine;
228
229   gp_Pnt2d aPntOnF1, aPntOnF2;
230   Standard_Real aX1, aY1, aX2, aY2;
231
232   // Iterate over points in walking line and delete which are out of bounds.
233   // Forward.
234   Standard_Boolean isAllDeleted = Standard_True;
235   Standard_Boolean aChangedFirst = Standard_False;
236   Standard_Integer aFirstGeomIdx = 1;
237   for(i = 1; i <= theWLine->NbPnts(); i++)
238   {
239     theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
240     aPntOnF1.SetCoord(aX1, aY1);
241     aPntOnF2.SetCoord(aX2, aY2);
242
243     TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
244     TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
245
246     if (aState1 == TopAbs_OUT ||
247         aState2 == TopAbs_OUT )
248     {
249       aDelOuterPointsHash(i) = 1;
250       aChangedFirst = Standard_True;
251     }
252     else
253     {
254       isAllDeleted = Standard_False;
255
256       aFirstGeomIdx = Max (i - 1, 1);
257       if (aDelOuterPointsHash(i) == -1)
258         aFirstGeomIdx = i; // Use data what lies in (i) point / vertex.
259
260       aDelOuterPointsHash(i) = -1;
261       break;
262     }
263   }
264
265   if (isAllDeleted)
266   {
267     // ALL points are out of bounds:
268     // case boolean bcut_complex F5 and similar.
269     return theWLine;
270   }
271
272   // Backward.
273   Standard_Boolean aChangedLast = Standard_False;
274   Standard_Integer aLastGeomIdx = theWLine->NbPnts();
275   for(i = theWLine->NbPnts(); i >= 1; i--)
276   {
277     theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
278     aPntOnF1.SetCoord(aX1, aY1);
279     aPntOnF2.SetCoord(aX2, aY2);
280
281     TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
282     TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
283
284     if (aState1 == TopAbs_OUT ||
285         aState2 == TopAbs_OUT )
286     {
287       aDelOuterPointsHash(i) = 1;
288       aChangedLast = Standard_True; // Move vertex to first good point
289     }
290     else
291     {
292       aLastGeomIdx = Min (i + 1, theWLine->NbPnts());
293       if (aDelOuterPointsHash(i) == -1)
294         aLastGeomIdx = i; // Use data what lies in (i) point / vertex.
295
296       aDelOuterPointsHash(i) = -1;
297       break;
298     }
299   }
300
301   if (!aChangedFirst && !aChangedLast)
302   {
303     // Nothing is done, return input.
304     return theWLine;
305   }
306
307   // Build new line and modify geometry of necessary vertexes.
308   Handle(IntPatch_WLine) aLocalWLine = MakeNewWLine(theWLine, aDelOuterPointsHash, Standard_True);
309
310   if (aChangedFirst)
311   {
312     // Vertex geometry.
313     IntPatch_Point aVertex = aLocalWLine->Vertex(1);
314     aVertex.SetValue(theWLine->Point(aFirstGeomIdx).Value());
315     Standard_Real aU1, aU2, aV1, aV2;
316     theWLine->Point(aFirstGeomIdx).Parameters(aU1, aV1, aU2, aV2);
317     MovePoint(theS1, aU1, aV1);
318     MovePoint(theS2, aU2, aV2);
319     aVertex.SetParameters(aU1, aV1, aU2, aV2);
320     aLocalWLine->Replace(1, aVertex);
321     // Change point in walking line.
322     aLocalWLine->SetPoint(1, aVertex);
323   }
324
325   if (aChangedLast)
326   {
327     // Vertex geometry.
328     IntPatch_Point aVertex = aLocalWLine->Vertex(aLocalWLine->NbVertex());
329     aVertex.SetValue(theWLine->Point(aLastGeomIdx).Value());
330     Standard_Real aU1, aU2, aV1, aV2;
331     theWLine->Point(aLastGeomIdx).Parameters(aU1, aV1, aU2, aV2);
332     MovePoint(theS1, aU1, aV1);
333     MovePoint(theS2, aU2, aV2);
334     aVertex.SetParameters(aU1, aV1, aU2, aV2);
335     aLocalWLine->Replace(aLocalWLine->NbVertex(), aVertex);
336     // Change point in walking line.
337     aLocalWLine->SetPoint(aLocalWLine->NbPnts(), aVertex);
338   }
339
340
341   return aLocalWLine;
342 }
343
344 //=========================================================================
345 // function : IsInsideIn2d
346 // purpose  : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
347 //            In 2d space. Static subfunction in DeleteByTube.
348 //=========================================================================
349 static Standard_Boolean IsInsideIn2d(const gp_Pnt2d& aBasePnt,
350                                      const gp_Vec2d& aBaseVec,
351                                      const gp_Pnt2d& aNextPnt,
352                                      const Standard_Real aSquareMaxDist)
353 {
354   gp_Vec2d aVec2d(aBasePnt, aNextPnt);
355
356   //d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
357   Standard_Real aCross = aVec2d.Crossed(aBaseVec);
358   Standard_Real aSquareDist = aCross * aCross
359                             / aBaseVec.SquareMagnitude();
360
361   return (aSquareDist <= aSquareMaxDist);
362 }
363
364 //=========================================================================
365 // function : IsInsideIn3d
366 // purpose  : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
367 //            In 3d space. Static subfunction in DeleteByTube.
368 //=========================================================================
369 static Standard_Boolean IsInsideIn3d(const gp_Pnt& aBasePnt,
370                                      const gp_Vec& aBaseVec,
371                                      const gp_Pnt& aNextPnt,
372                                      const Standard_Real aSquareMaxDist)
373 {
374   gp_Vec aVec(aBasePnt, aNextPnt);
375
376   //d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
377   Standard_Real aSquareDist = aVec.CrossSquareMagnitude(aBaseVec)
378                             / aBaseVec.SquareMagnitude();
379
380   return (aSquareDist <= aSquareMaxDist);
381 }
382
383 static const Standard_Integer aMinNbBadDistr = 15;
384 static const Standard_Integer aNbSingleBezier = 30;
385
386 //=========================================================================
387 // function : DeleteByTube
388 // purpose  : Check and delete points using tube criteria.
389 //            Static subfunction in ComputePurgedWLine.
390 //=========================================================================
391 static Handle(IntPatch_WLine)
392   DeleteByTube(const Handle(IntPatch_WLine)       &theWLine,
393                const Handle(Adaptor3d_HSurface)   &theS1,
394                const Handle(Adaptor3d_HSurface)   &theS2)
395 {
396   // III: Check points for tube criteria:
397   // Workaround to handle case of small amount points after purge.
398   // Test "boolean boptuc_complex B5" and similar.
399   Standard_Integer aNbPnt = 0 , i;
400
401   if (theWLine->NbPnts() <= 2)
402     return theWLine;
403
404   NCollection_Array1<Standard_Integer> aNewPointsHash(1, theWLine->NbPnts());
405   FillPointsHash(theWLine, aNewPointsHash);
406   
407   // Inital computations.
408   Standard_Real UonS1[3], VonS1[3], UonS2[3], VonS2[3];
409   theWLine->Point(1).ParametersOnS1(UonS1[0], VonS1[0]);
410   theWLine->Point(2).ParametersOnS1(UonS1[1], VonS1[1]);
411   theWLine->Point(1).ParametersOnS2(UonS2[0], VonS2[0]);
412   theWLine->Point(2).ParametersOnS2(UonS2[1], VonS2[1]);
413
414   gp_Pnt2d aBase2dPnt1(UonS1[0], VonS1[0]);
415   gp_Pnt2d aBase2dPnt2(UonS2[0], VonS2[0]);
416   gp_Vec2d aBase2dVec1(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
417   gp_Vec2d aBase2dVec2(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
418   gp_Pnt   aBase3dPnt = theWLine->Point(1).Value();
419   gp_Vec   aBase3dVec(theWLine->Point(1).Value(), theWLine->Point(2).Value());
420
421   // Choose base tolerance and scale it to pipe algorithm.
422   const Standard_Real aBaseTolerance = Precision::Approximation();
423   Standard_Real aResS1Tol = Min(theS1->UResolution(aBaseTolerance),
424                                 theS1->VResolution(aBaseTolerance));
425   Standard_Real aResS2Tol = Min(theS2->UResolution(aBaseTolerance),
426                                 theS2->VResolution(aBaseTolerance));
427   Standard_Real aTol1 = aResS1Tol * aResS1Tol;
428   Standard_Real aTol2 = aResS2Tol * aResS2Tol;
429   Standard_Real aTol3d = aBaseTolerance * aBaseTolerance;
430
431   const Standard_Real aLimitCoeff = 0.99 * 0.99;
432   for(i = 3; i <= theWLine->NbPnts(); i++)
433   {
434     Standard_Boolean isDeleteState = Standard_False;
435
436     theWLine->Point(i).ParametersOnS1(UonS1[2], VonS1[2]);
437     theWLine->Point(i).ParametersOnS2(UonS2[2], VonS2[2]);
438     gp_Pnt2d aPnt2dOnS1(UonS1[2], VonS1[2]);
439     gp_Pnt2d aPnt2dOnS2(UonS2[2], VonS2[2]);
440     const gp_Pnt& aPnt3d = theWLine->Point(i).Value();
441
442     if (aNewPointsHash(i - 1) != - 1 &&
443         IsInsideIn2d(aBase2dPnt1, aBase2dVec1, aPnt2dOnS1, aTol1) &&
444         IsInsideIn2d(aBase2dPnt2, aBase2dVec2, aPnt2dOnS2, aTol2) &&
445         IsInsideIn3d(aBase3dPnt, aBase3dVec, aPnt3d, aTol3d) )
446     {
447       // Handle possible uneven parametrization on one of 2d subspaces.
448       // Delete point only when expected lengths are close to each other (aLimitCoeff).
449       // Example:
450       // c2d1 - line
451       // c3d - line
452       // c2d2 - geometrically line, but have uneven parametrization -> c2d2 is bspline.
453       gp_XY aPntOnS1[2]= { gp_XY(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0])
454                          , gp_XY(UonS1[2] - UonS1[1], VonS1[2] - VonS1[1])};
455       gp_XY aPntOnS2[2]= { gp_XY(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0])
456                          , gp_XY(UonS2[2] - UonS2[1], VonS2[2] - VonS2[1])};
457
458       Standard_Real aStepOnS1 = aPntOnS1[0].SquareModulus() / aPntOnS1[1].SquareModulus();
459       Standard_Real aStepOnS2 = aPntOnS2[0].SquareModulus() / aPntOnS2[1].SquareModulus();
460
461       // Check very rare case when wline fluctuates nearly one point and some of them may be equal.
462       // Middle point will be deleted when such situation occurs.
463       // bugs moddata_2 bug469.
464       if (Min(aStepOnS1, aStepOnS2) >= aLimitCoeff * Max(aStepOnS1, aStepOnS2))
465       {
466         // Set hash flag to "Delete" state.
467         isDeleteState = Standard_True;
468         aNewPointsHash.SetValue(i - 1, 1);
469
470         // Change middle point.
471         UonS1[1] = UonS1[2];
472         UonS2[1] = UonS2[2];
473         VonS1[1] = VonS1[2];
474         VonS2[1] = VonS2[2];
475       }
476     }
477
478     if (!isDeleteState)
479     {
480       // Compute new pipe parameters.
481       UonS1[0] = UonS1[1];
482       VonS1[0] = VonS1[1];
483       UonS2[0] = UonS2[1];
484       VonS2[0] = VonS2[1];
485
486       UonS1[1] = UonS1[2];
487       VonS1[1] = VonS1[2];
488       UonS2[1] = UonS2[2];
489       VonS2[1] = VonS2[2];
490
491       aBase2dPnt1.SetCoord(UonS1[0], VonS1[0]);
492       aBase2dPnt2.SetCoord(UonS2[0], VonS2[0]);
493       aBase2dVec1.SetCoord(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
494       aBase2dVec2.SetCoord(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
495       aBase3dPnt = theWLine->Point(i - 1).Value();
496       aBase3dVec = gp_Vec(theWLine->Point(i - 1).Value(), theWLine->Point(i).Value());
497
498       aNbPnt++;
499     }
500   }
501
502   // Workaround to handle case of small amount of points after purge.
503   // Test "boolean boptuc_complex B5" and similar.
504   // This is possible since there are at least two points.
505   if (aNewPointsHash(1) == -1 &&
506       aNewPointsHash(2) == -1 &&
507       aNbPnt <= 3)
508   {
509     // Delete first.
510     aNewPointsHash(1) = 1;
511   }
512   if (aNewPointsHash(theWLine->NbPnts() - 1) == -1 &&
513       aNewPointsHash(theWLine->NbPnts()    ) == -1 &&
514       aNbPnt <= 3)
515   {
516     // Delete last.
517     aNewPointsHash(theWLine->NbPnts()) = 1;
518   }
519
520   // Purgre when too small amount of points left.
521   if (aNbPnt <= 2)
522   {
523     for(i = aNewPointsHash.Lower(); i <= aNewPointsHash.Upper(); i++)
524     {
525       if (aNewPointsHash(i) != -1)
526       {
527         aNewPointsHash(i) = 1;
528       }
529     }
530   }
531
532   // Handle possible bad distribution of points, 
533   // which are will converted into one single bezier curve (less than 30 points).
534   // Make distribution more even:
535   // max step will be nearly to 0.1 of param distance.
536   if (aNbPnt + 2 > aMinNbBadDistr &&
537       aNbPnt + 2 < aNbSingleBezier )
538   {
539     for(Standard_Integer anIdx = 1; anIdx <= 8; anIdx++)
540     {
541       Standard_Integer aHashIdx = 
542         Standard_Integer(anIdx * theWLine->NbPnts() / 9);
543
544       //Vertex must be stored as VERTEX (HASH = -1)
545       if (aNewPointsHash(aHashIdx) != -1)
546         aNewPointsHash(aHashIdx) = 0;
547     }
548   }
549
550   return MakeNewWLine(theWLine, aNewPointsHash, Standard_False);
551 }
552
553 //=======================================================================
554 //function : IsSeamOrBound
555 //purpose  : Returns TRUE if segment [thePtf, thePtl] intersects "seam-edge"
556 //            (if it exist) or surface boundaries and both thePtf and thePtl do
557 //            not match "seam-edge" or boundaries.
558 //           Point thePtmid lies in this segment (in both 3D and 2D-space).
559 //           If thePtmid match "seam-edge" or boundaries strictly 
560 //            (without any tolerance) then the function will return TRUE.
561 //            See comments in function body for detail information.
562 //
563 //          Arrays theArrPeriods, theFBound and theLBound must be filled
564 //            as follows:
565 //          [0] - U-parameter of 1st surface;
566 //          [1] - V-parameter of 1st surface;
567 //          [2] - U-parameter of 2nd surface;
568 //          [3] - V-parameter of 2nd surface.
569 //=======================================================================
570 static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
571                                       const IntSurf_PntOn2S& thePtl,
572                                       const IntSurf_PntOn2S& thePtmid,
573                                       const Standard_Real theArrPeriods[4],
574                                       const Standard_Real theFBound[4],
575                                       const Standard_Real theLBound[4])
576 {
577   Standard_Real aParF[4] = { 0.0, 0.0, 0.0, 0.0 };
578   Standard_Real aParL[4] = { 0.0, 0.0, 0.0, 0.0 };
579   thePtf.Parameters(aParF[0], aParF[1], aParF[2], aParF[3]);
580   thePtl.Parameters(aParL[0], aParL[1], aParL[2], aParL[3]);
581
582   Bnd_Range aBndR[4];
583
584   for (Standard_Integer i = 0; i < 4; i++)
585   {
586     aBndR[i].Add(aParF[i]);
587     aBndR[i].Add(aParL[i]);
588
589     if (aBndR[i].IsIntersected(theFBound[i], theArrPeriods[i]) == 1)
590       return Standard_True;
591
592     if (aBndR[i].IsIntersected(theLBound[i], theArrPeriods[i]) == 1)
593       return Standard_True;
594   }
595
596   for (Standard_Integer i = 0; i < 4; i++)
597   {
598     if (theArrPeriods[i] == 0.0)
599     {
600       //Strictly equal
601       continue;
602     }
603
604     const Standard_Real aDelta = Abs(aParL[i] - aParF[i]);
605     if (2.0*aDelta > theArrPeriods[i])
606     {
607       //Most likely, seam is intersected.
608       return Standard_True;
609     }
610
611     if (aBndR[i].IsIntersected(0.0, theArrPeriods[i]) == 1)
612       return Standard_True;
613   }
614
615   //The segment [thePtf, thePtl] does not intersect the boundaries and
616   //the seam-edge of the surfaces.
617   //Nevertheless, following situation is possible:
618
619   //              seam or
620   //               bound
621   //                 |
622   //    thePtf  *    |
623   //                 |
624   //                 * thePtmid
625   //      thePtl  *  |
626   //                 |
627
628   //This case must be processed, too.
629
630   Standard_Real aMPar[4] = { 0.0, 0.0, 0.0, 0.0 };
631   thePtmid.Parameters(aMPar[0], aMPar[1], aMPar[2], aMPar[3]);
632
633   for (Standard_Integer i = 0; i < 4; i++)
634   {
635     const Bnd_Range aBR(aMPar[i], aMPar[i]);
636     if (aBR.IsIntersected(theFBound[i], theArrPeriods[i]))
637       return Standard_True;
638
639     if (aBR.IsIntersected(theLBound[i], theArrPeriods[i]))
640       return Standard_True;
641
642     if (aBR.IsIntersected(0.0, theArrPeriods[i]))
643       return Standard_True;
644   }
645
646   return Standard_False;
647 }
648
649 //=======================================================================
650 //function : IsIntersectionPoint
651 //purpose  : Returns True if thePmid is intersection point
652 //            between theS1 and theS2 with given tolerance.
653 //           In this case, parameters of thePmid on every quadric
654 //            will be recomputed and returned.
655 //=======================================================================
656 static Standard_Boolean IsIntersectionPoint(const gp_Pnt& thePmid,
657                                             const Handle(Adaptor3d_HSurface)& theS1,
658                                             const Handle(Adaptor3d_HSurface)& theS2,
659                                             const IntSurf_PntOn2S& theRefPt,
660                                             const Standard_Real theTol,
661                                             const Standard_Real* const theArrPeriods,
662                                             IntSurf_PntOn2S& theNewPt)
663 {
664   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
665   
666   switch(theS1->GetType())
667   {
668   case GeomAbs_Plane:
669     ElSLib::Parameters(theS1->Plane(), thePmid, aU1, aV1);
670     break;
671
672   case GeomAbs_Cylinder:
673     ElSLib::Parameters(theS1->Cylinder(), thePmid, aU1, aV1);
674     break;
675
676   case GeomAbs_Sphere:
677     ElSLib::Parameters(theS1->Sphere(), thePmid, aU1, aV1);
678     break;
679
680   case GeomAbs_Cone:
681     ElSLib::Parameters(theS1->Cone(), thePmid, aU1, aV1);
682     break;
683
684   case GeomAbs_Torus:
685     ElSLib::Parameters(theS1->Torus(), thePmid, aU1, aV1);
686     break;
687
688   default:
689     return Standard_False;
690   }
691
692   switch(theS2->GetType())
693   {
694   case GeomAbs_Plane:
695     ElSLib::Parameters(theS2->Plane(), thePmid, aU2, aV2);
696     break;
697
698   case GeomAbs_Cylinder:
699     ElSLib::Parameters(theS2->Cylinder(), thePmid, aU2, aV2);
700     break;
701
702   case GeomAbs_Sphere:
703     ElSLib::Parameters(theS2->Sphere(), thePmid, aU2, aV2);
704     break;
705
706   case GeomAbs_Cone:
707     ElSLib::Parameters(theS2->Cone(), thePmid, aU2, aV2);
708     break;
709
710   case GeomAbs_Torus:
711     ElSLib::Parameters(theS2->Torus(), thePmid, aU2, aV2);
712     break;
713
714   default:
715     return Standard_False;
716   }
717
718   theNewPt.SetValue(thePmid, aU1, aV1, aU2, aV2);
719
720   IntPatch_SpecialPoints::AdjustPointAndVertex(theRefPt, theArrPeriods, theNewPt);
721
722   const gp_Pnt aP1(theS1->Value(aU1, aV1));
723   const gp_Pnt aP2(theS2->Value(aU2, aV2));
724
725   return (aP1.SquareDistance(aP2) <= theTol*theTol);
726 }
727
728 //=======================================================================
729 //function : ExtendFirst
730 //purpose  : Adds thePOn2S to the begin of theWline
731 //=======================================================================
732 static void ExtendFirst(const Handle(IntPatch_WLine)& theWline,
733                         const IntSurf_PntOn2S& theAddedPt)
734 {
735   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
736   theAddedPt.Parameters(aU1, aV1, aU2, aV2);
737
738   if(theAddedPt.IsSame(theWline->Point(1), Precision::Confusion()))
739   {
740     theWline->Curve()->Value(1, theAddedPt);
741     for(Standard_Integer i = 1; i <= theWline->NbVertex(); i++)
742     {
743       IntPatch_Point &aVert = theWline->ChangeVertex(i);
744       if(aVert.ParameterOnLine() != 1)
745         break;
746
747       aVert.SetParameters(aU1, aV1, aU2, aV2);
748       aVert.SetValue(theAddedPt.Value());
749     }
750
751     return;
752   }
753
754   theWline->Curve()->InsertBefore(1, theAddedPt);
755
756   for(Standard_Integer i = 1; i <= theWline->NbVertex(); i++)
757   {
758     IntPatch_Point &aVert = theWline->ChangeVertex(i);
759
760     if(aVert.ParameterOnLine() == 1)
761     {
762       aVert.SetParameters(aU1, aV1, aU2, aV2);
763       aVert.SetValue(theAddedPt.Value());
764     }
765     else
766     {
767       aVert.SetParameter(aVert.ParameterOnLine()+1);
768     }
769   }
770 }
771
772 //=======================================================================
773 //function : ExtendLast
774 //purpose  : Adds thePOn2S to the end of theWline
775 //=======================================================================
776 static void ExtendLast(const Handle(IntPatch_WLine)& theWline,
777                         const IntSurf_PntOn2S& theAddedPt)
778 {
779   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
780   theAddedPt.Parameters(aU1, aV1, aU2, aV2);
781
782   const Standard_Integer aNbPnts = theWline->NbPnts();
783   if(theAddedPt.IsSame(theWline->Point(aNbPnts), Precision::Confusion()))
784   {
785     theWline->Curve()->Value(aNbPnts, theAddedPt);
786   }
787   else
788   {
789     theWline->Curve()->Add(theAddedPt);
790   }
791
792   for(Standard_Integer i = theWline->NbVertex(); i >= 1; i--)
793   {
794     IntPatch_Point &aVert = theWline->ChangeVertex(i);
795     if(aVert.ParameterOnLine() != aNbPnts)
796       break;
797
798     aVert.SetParameters(aU1, aV1, aU2, aV2);
799     aVert.SetValue(theAddedPt.Value());
800     aVert.SetParameter(theWline->NbPnts());
801   }
802 }
803
804 //=========================================================================
805 // function: IsOutOfDomain
806 // purpose : Checks, if 2D-representation of thePOn2S is in surfaces domain,
807 //            defined by bounding-boxes theBoxS1 and theBoxS2
808 //=========================================================================
809 static Standard_Boolean IsOutOfDomain(const Bnd_Box2d& theBoxS1,
810                                       const Bnd_Box2d& theBoxS2,
811                                       const IntSurf_PntOn2S &thePOn2S,
812                                       const Standard_Real* const theArrPeriods)
813 {
814   Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
815   Standard_Real aU1min = 0.0, aU1max = 0.0, aV1min = 0.0, aV1max = 0.0;
816   Standard_Real aU2min = 0.0, aU2max = 0.0, aV2min = 0.0, aV2max = 0.0;
817
818   thePOn2S.Parameters(aU1, aV1, aU2, aV2);
819
820   theBoxS1.Get(aU1min, aV1min, aU1max, aV1max);
821   theBoxS2.Get(aU2min, aV2min, aU2max, aV2max);
822
823   aU1 = ElCLib::InPeriod(aU1, aU1min, aU1min + theArrPeriods[0]);
824   aV1 = ElCLib::InPeriod(aV1, aV1min, aV1min + theArrPeriods[1]);
825   aU2 = ElCLib::InPeriod(aU2, aU2min, aU2min + theArrPeriods[2]);
826   aV2 = ElCLib::InPeriod(aV2, aV2min, aV2min + theArrPeriods[3]);
827
828   return (theBoxS1.IsOut(gp_Pnt2d(aU1, aV1)) ||
829           theBoxS2.IsOut(gp_Pnt2d(aU2, aV2)));
830 }
831
832 //=======================================================================
833 //function : CheckArgumentsToExtend
834 //purpose  : Check if extending is possible
835 //            (see IntPatch_WLineTool::ExtendTwoWLines)
836 //=======================================================================
837 static IntPatchWT_WLsConnectionType
838                     CheckArgumentsToExtend(const Handle(Adaptor3d_HSurface)& theS1,
839                                            const Handle(Adaptor3d_HSurface)& theS2,
840                                            const IntSurf_PntOn2S& thePtWL1,
841                                            const IntSurf_PntOn2S& thePtWL2,
842                                            IntSurf_PntOn2S& theNewPoint,
843                                            const gp_Vec& theVec1,
844                                            const gp_Vec& theVec2,
845                                            const gp_Vec& theVec3,
846                                            const Bnd_Box2d& theBoxS1,
847                                            const Bnd_Box2d& theBoxS2,
848                                            const Standard_Real theToler3D,
849                                            const Standard_Real* const theArrPeriods)
850 {
851   const Standard_Real aSqToler = theToler3D*theToler3D;
852
853   if(theVec3.SquareMagnitude() <= aSqToler)
854   {
855     return IntPatchWT_NotConnected;
856   }
857
858   if((theVec1.Angle(theVec2) > IntPatch_WLineTool::myMaxConcatAngle) ||
859      (theVec1.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle) ||
860      (theVec2.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle))
861   {
862     return IntPatchWT_NotConnected;
863   }
864
865   const gp_Pnt aPmid(0.5*(thePtWL1.Value().XYZ()+thePtWL2.Value().XYZ()));
866
867   Standard_Real aNewPar[4] = {0.0, 0.0, 0.0, 0.0};
868
869   //Left-bottom corner
870   Standard_Real aParLBC[4] = {0.0, 0.0, 0.0, 0.0};
871   theBoxS1.Get(aParLBC[0], aParLBC[1], aNewPar[0], aNewPar[0]);  
872   theBoxS2.Get(aParLBC[2], aParLBC[3], aNewPar[0], aNewPar[0]);
873
874   if(!IsIntersectionPoint(aPmid, theS1, theS2, thePtWL1, theToler3D,
875                           theArrPeriods, theNewPoint))
876   {
877     return IntPatchWT_NotConnected;
878   }
879
880   if(IsOutOfDomain(theBoxS1, theBoxS2, theNewPoint, theArrPeriods))
881   {
882     return IntPatchWT_NotConnected;
883   }
884
885   Standard_Real aParWL1[4] = {0.0, 0.0, 0.0, 0.0},
886                 aParWL2[4] = {0.0, 0.0, 0.0, 0.0};
887   
888   thePtWL1.Parameters(aParWL1[0], aParWL1[1], aParWL1[2], aParWL1[3]);
889   thePtWL2.Parameters(aParWL2[0], aParWL2[1], aParWL2[2], aParWL2[3]);
890   theNewPoint.Parameters(aNewPar[0], aNewPar[1], aNewPar[2], aNewPar[3]);
891
892   Bnd_Range aR1, aR2;
893
894   Standard_Boolean isOnBoundary = Standard_False;
895   for(Standard_Integer i = 0; i < 4; i++)
896   {
897     if (theArrPeriods[i] == 0.0)
898     {
899       //Strictly equal
900       continue;
901     }
902
903     aR1.SetVoid();
904     aR1.Add(aParWL1[i]);
905     aR1.Add(aParWL2[i]);
906
907     if (aR1.IsIntersected(aParLBC[i],theArrPeriods[i]))
908     {
909       //Check, if we intersect surface boundary when we will extend Wline1 or Wline2
910       //to theNewPoint
911       MinMax(aParWL1[i], aParWL2[i]);
912       if(aNewPar[i] > aParWL2[i])
913       {
914         //Source situation:
915         //
916         //---*---------------*------------*-----
917         // aParWL1[i]   aParWL2[i]    aNewPar[i]
918         //
919         //After possible adjusting:
920         //
921         //---*---------------*------------*-----
922         // aParWL1[i]   aNewPar[i]    aParWL2[i]
923         //
924         //Now we will be able to extend every WLine to
925         //aNewPar[i] to make them close to each other.
926         //However, it is necessary to add check if we
927         //intersect boundary.
928         const Standard_Real aPar = aParWL1[i] +
929                 theArrPeriods[i]*Ceiling((aNewPar[i]-aParWL1[i])/theArrPeriods[i]);
930         aParWL1[i] = aParWL2[i];
931         aParWL2[i] = aPar;
932       }
933       else if(aNewPar[i] < aParWL1[i])
934       {
935         //See comments to main "if".
936         //Source situation:
937         //
938         //---*---------------*------------*-----
939         // aNewPar[i]    aParWL1[i]   aParWL2[i]    
940         //
941         //After possible adjusting:
942         //
943         //---*---------------*------------*-----
944         // aParWL1[i]   aNewPar[i]    aParWL2[i]
945           
946         const Standard_Real aPar = aParWL2[i] - 
947                 theArrPeriods[i]*Ceiling((aParWL2[i]-aNewPar[i])/theArrPeriods[i]);
948         aParWL2[i] = aParWL1[i];
949         aParWL1[i] = aPar;
950       }
951
952       aR1.SetVoid();
953       aR2.SetVoid();
954       aR1.Add(aParWL1[i]);
955       aR1.Add(aNewPar[i]);
956       aR2.Add(aNewPar[i]);
957       aR2.Add(aParWL2[i]);
958
959       if (aR1.IsIntersected(aParLBC[i], theArrPeriods[i]) ||
960           aR2.IsIntersected(aParLBC[i], theArrPeriods[i]))
961       {
962         return IntPatchWT_NotConnected;
963       }
964       else
965       {
966         isOnBoundary = Standard_True;
967       }
968     }
969   }
970
971   if(isOnBoundary)
972   {
973     return IntPatchWT_Singular;
974   }
975
976   return IntPatchWT_EachOther;
977 }
978
979 //=======================================================================
980 //function : CheckArgumentsToJoin
981 //purpose  : Check if joining is possible
982 //            (see IntPatch_WLineTool::JoinWLines(...))
983 //=======================================================================
984 Standard_Boolean CheckArgumentsToJoin(const Handle(Adaptor3d_HSurface)& theS1,
985                                       const Handle(Adaptor3d_HSurface)& theS2,
986                                       const IntSurf_PntOn2S& thePnt,
987                                       const Standard_Real theMinRad)
988 {
989   const Standard_Real aRad = 
990         IntPatch_PointLine::CurvatureRadiusOfIntersLine(theS1, theS2, thePnt);
991
992   return (aRad > theMinRad);
993 }
994
995 //=======================================================================
996 //function : ExtendTwoWLFirstFirst
997 //purpose  : Performs extending theWLine1 and theWLine2 through their
998 //            respecting start point.
999 //=======================================================================
1000 static void ExtendTwoWLFirstFirst(const Handle(Adaptor3d_HSurface)& theS1,
1001                                   const Handle(Adaptor3d_HSurface)& theS2,
1002                                   const Handle(IntPatch_WLine)& theWLine1,
1003                                   const Handle(IntPatch_WLine)& theWLine2,
1004                                   const IntSurf_PntOn2S& thePtWL1,
1005                                   const IntSurf_PntOn2S& thePtWL2,
1006                                   const gp_Vec& theVec1,
1007                                   const gp_Vec& theVec2,
1008                                   const gp_Vec& theVec3,
1009                                   const Bnd_Box2d& theBoxS1,
1010                                   const Bnd_Box2d& theBoxS2,
1011                                   const Standard_Real theToler3D,
1012                                   const Standard_Real* const theArrPeriods,
1013                                   unsigned int &theCheckResult,
1014                                   Standard_Boolean &theHasBeenJoined)
1015 {
1016   IntSurf_PntOn2S aPOn2S;
1017   const IntPatchWT_WLsConnectionType aCheckRes = 
1018                       CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
1019                                              theVec1, theVec2, theVec3,
1020                                              theBoxS1, theBoxS2,
1021                                              theToler3D, theArrPeriods);
1022
1023   if(aCheckRes != IntPatchWT_NotConnected)
1024     theCheckResult |= (IntPatchWT_DisFirstLast | IntPatchWT_DisLastFirst);
1025   else
1026     return;
1027
1028   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
1029   ExtendFirst(theWLine1, aPOn2S);
1030   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
1031   ExtendFirst(theWLine2, aPOn2S);
1032
1033   if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
1034     return;
1035
1036   Standard_Real aPrm = theWLine1->Vertex(1).ParameterOnLine();
1037   while(theWLine1->Vertex(1).ParameterOnLine() == aPrm)
1038     theWLine1->RemoveVertex(1);
1039
1040   aPrm = theWLine2->Vertex(1).ParameterOnLine();
1041   while(theWLine2->Vertex(1).ParameterOnLine() == aPrm)
1042     theWLine2->RemoveVertex(1);
1043
1044   const Standard_Integer aNbPts = theWLine2->NbPnts();
1045   for(Standard_Integer aNPt = 2; aNPt <= aNbPts; aNPt++)
1046   {
1047     const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
1048     theWLine1->Curve()->InsertBefore(1, aPt);
1049   }
1050
1051   for(Standard_Integer aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
1052   {
1053     IntPatch_Point &aVert = theWLine1->ChangeVertex(aNVtx);
1054     const Standard_Real aCurParam = aVert.ParameterOnLine();
1055     aVert.SetParameter(aNbPts+aCurParam-1);
1056   }
1057
1058   for(Standard_Integer aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
1059   {
1060     IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
1061     const Standard_Real aCurParam = aVert.ParameterOnLine();
1062     aVert.SetParameter(aNbPts-aCurParam+1);
1063     theWLine1->AddVertex(aVert, Standard_True);
1064   }
1065
1066   theHasBeenJoined = Standard_True;
1067 }
1068
1069 //=======================================================================
1070 //function : ExtendTwoWLFirstLast
1071 //purpose  : Performs extending theWLine1 through its start point and theWLine2
1072 //            through its end point.
1073 //=======================================================================
1074 static void ExtendTwoWLFirstLast(const Handle(Adaptor3d_HSurface)& theS1,
1075                                  const Handle(Adaptor3d_HSurface)& theS2,
1076                                  const Handle(IntPatch_WLine)& theWLine1,
1077                                  const Handle(IntPatch_WLine)& theWLine2,
1078                                  const IntSurf_PntOn2S& thePtWL1,
1079                                  const IntSurf_PntOn2S& thePtWL2,
1080                                  const gp_Vec& theVec1,
1081                                  const gp_Vec& theVec2,
1082                                  const gp_Vec& theVec3,
1083                                  const Bnd_Box2d& theBoxS1,
1084                                  const Bnd_Box2d& theBoxS2,
1085                                  const Standard_Real theToler3D,
1086                                  const Standard_Real* const theArrPeriods,
1087                                  unsigned int &theCheckResult,
1088                                  Standard_Boolean &theHasBeenJoined)
1089 {
1090   IntSurf_PntOn2S aPOn2S;
1091   const IntPatchWT_WLsConnectionType aCheckRes = 
1092                       CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
1093                                              theVec1, theVec2, theVec3,
1094                                              theBoxS1, theBoxS2,
1095                                              theToler3D, theArrPeriods);
1096
1097   if(aCheckRes != IntPatchWT_NotConnected)
1098     theCheckResult |= IntPatchWT_DisLastLast;
1099   else
1100     return;
1101
1102   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
1103   ExtendFirst(theWLine1, aPOn2S);
1104   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
1105   ExtendLast (theWLine2, aPOn2S);
1106
1107   if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
1108     return;
1109
1110   Standard_Real aPrm = theWLine1->Vertex(1).ParameterOnLine();
1111   while(theWLine1->Vertex(1).ParameterOnLine() == aPrm)
1112     theWLine1->RemoveVertex(1);
1113
1114   aPrm = theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine();
1115   while(theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine() == aPrm)
1116     theWLine2->RemoveVertex(theWLine2->NbVertex());
1117
1118   const Standard_Integer aNbPts = theWLine2->NbPnts();
1119   for(Standard_Integer aNPt = aNbPts - 1; aNPt >= 1; aNPt--)
1120   {
1121     const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
1122     theWLine1->Curve()->InsertBefore(1, aPt);
1123   }
1124
1125   for(Standard_Integer aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
1126   {
1127     IntPatch_Point &aVert = theWLine1->ChangeVertex(aNVtx);
1128     const Standard_Real aCurParam = aVert.ParameterOnLine();
1129     aVert.SetParameter(aNbPts+aCurParam-1);
1130   }
1131
1132   for(Standard_Integer aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
1133   {
1134     const IntPatch_Point &aVert = theWLine2->Vertex(aNVtx);
1135     theWLine1->AddVertex(aVert, Standard_True);
1136   }
1137
1138   theHasBeenJoined = Standard_True;
1139 }
1140
1141 //=======================================================================
1142 //function : ExtendTwoWLLastFirst
1143 //purpose  : Performs extending theWLine1 through its end point and theWLine2
1144 //            through its start point.
1145 //=======================================================================
1146 static void ExtendTwoWLLastFirst(const Handle(Adaptor3d_HSurface)& theS1,
1147                                  const Handle(Adaptor3d_HSurface)& theS2,
1148                                  const Handle(IntPatch_WLine)& theWLine1,
1149                                  const Handle(IntPatch_WLine)& theWLine2,
1150                                  const IntSurf_PntOn2S& thePtWL1,
1151                                  const IntSurf_PntOn2S& thePtWL2,
1152                                  const gp_Vec& theVec1,
1153                                  const gp_Vec& theVec2,
1154                                  const gp_Vec& theVec3,
1155                                  const Bnd_Box2d& theBoxS1,
1156                                  const Bnd_Box2d& theBoxS2,
1157                                  const Standard_Real theToler3D,
1158                                  const Standard_Real* const theArrPeriods,
1159                                  unsigned int &theCheckResult,
1160                                  Standard_Boolean &theHasBeenJoined)
1161 {
1162   IntSurf_PntOn2S aPOn2S;
1163   const IntPatchWT_WLsConnectionType aCheckRes = 
1164                       CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
1165                                              theVec1, theVec2, theVec3,
1166                                              theBoxS1, theBoxS2,
1167                                              theToler3D, theArrPeriods);
1168
1169   if(aCheckRes != IntPatchWT_NotConnected)
1170     theCheckResult |= IntPatchWT_DisLastLast;
1171   else
1172     return;
1173
1174   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
1175   ExtendLast (theWLine1, aPOn2S);
1176   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
1177   ExtendFirst(theWLine2, aPOn2S);
1178
1179   if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
1180   {
1181     return;
1182   }
1183
1184   Standard_Real aPrm = theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine();
1185   while(theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine() == aPrm)
1186     theWLine1->RemoveVertex(theWLine1->NbVertex());
1187
1188   aPrm = theWLine2->Vertex(1).ParameterOnLine();
1189   while(theWLine2->Vertex(1).ParameterOnLine() == aPrm)
1190     theWLine2->RemoveVertex(1);
1191
1192   const Standard_Integer aNbPts = theWLine1->NbPnts();
1193   for(Standard_Integer aNPt = 2; aNPt <= theWLine2->NbPnts(); aNPt++)
1194   {
1195     const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
1196     theWLine1->Curve()->Add(aPt);
1197   }
1198
1199   for(Standard_Integer aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
1200   {
1201     IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
1202     const Standard_Real aCurParam = aVert.ParameterOnLine();
1203     aVert.SetParameter(aNbPts+aCurParam-1);
1204     theWLine1->AddVertex(aVert, Standard_False);
1205   }
1206
1207   theHasBeenJoined = Standard_True;
1208 }
1209
1210 //=======================================================================
1211 //function : ExtendTwoWLLastLast
1212 //purpose  : 
1213 //=======================================================================
1214 static void ExtendTwoWLLastLast(const Handle(Adaptor3d_HSurface)& theS1,
1215                                 const Handle(Adaptor3d_HSurface)& theS2,
1216                                 const Handle(IntPatch_WLine)& theWLine1,
1217                                 const Handle(IntPatch_WLine)& theWLine2,
1218                                 const IntSurf_PntOn2S& thePtWL1,
1219                                 const IntSurf_PntOn2S& thePtWL2,
1220                                 const gp_Vec& theVec1,
1221                                 const gp_Vec& theVec2,
1222                                 const gp_Vec& theVec3,
1223                                 const Bnd_Box2d& theBoxS1,
1224                                 const Bnd_Box2d& theBoxS2,
1225                                 const Standard_Real theToler3D,
1226                                 const Standard_Real* const theArrPeriods,
1227                                 unsigned int &theCheckResult,
1228                                 Standard_Boolean &theHasBeenJoined)
1229 {
1230   IntSurf_PntOn2S aPOn2S;
1231   const IntPatchWT_WLsConnectionType aCheckRes = 
1232                       CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
1233                                              theVec1, theVec2, theVec3,
1234                                              theBoxS1, theBoxS2,
1235                                              theToler3D, theArrPeriods);
1236   
1237   if(aCheckRes != IntPatchWT_NotConnected)
1238     theCheckResult |= IntPatchWT_DisLastLast;
1239   else
1240     return;
1241
1242   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
1243   ExtendLast(theWLine1, aPOn2S);
1244   IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
1245   ExtendLast(theWLine2, aPOn2S);
1246
1247   if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
1248     return;
1249
1250   Standard_Real aPrm = theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine();
1251   while(theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine() == aPrm)
1252     theWLine1->RemoveVertex(theWLine1->NbVertex());
1253
1254   aPrm = theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine();
1255   while(theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine() == aPrm)
1256     theWLine2->RemoveVertex(theWLine2->NbVertex());
1257
1258   const Standard_Integer aNbPts = theWLine1->NbPnts() + theWLine2->NbPnts();
1259   for(Standard_Integer aNPt = theWLine2->NbPnts()-1; aNPt >= 1; aNPt--)
1260   {
1261     const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
1262     theWLine1->Curve()->Add(aPt);
1263   }
1264
1265   for(Standard_Integer aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
1266   {
1267     IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
1268     const Standard_Real aCurParam = aVert.ParameterOnLine();
1269     aVert.SetParameter(aNbPts - aCurParam);
1270     theWLine1->AddVertex(aVert, Standard_False);
1271   }
1272
1273   theHasBeenJoined = Standard_True;
1274 }
1275
1276 //=========================================================================
1277 // function : ComputePurgedWLine
1278 // purpose  :
1279 //=========================================================================
1280 Handle(IntPatch_WLine) IntPatch_WLineTool::
1281   ComputePurgedWLine(const Handle(IntPatch_WLine)       &theWLine,
1282                      const Handle(Adaptor3d_HSurface)   &theS1,
1283                      const Handle(Adaptor3d_HSurface)   &theS2,
1284                      const Handle(Adaptor3d_TopolTool)  &theDom1,
1285                      const Handle(Adaptor3d_TopolTool)  &theDom2)
1286 {
1287   Standard_Integer i, k, v, nb, nbvtx;
1288   Handle(IntPatch_WLine) aResult;
1289   nbvtx = theWLine->NbVertex();
1290   nb = theWLine->NbPnts();
1291   if (nb==2)
1292   {
1293     const IntSurf_PntOn2S& p1 = theWLine->Point(1);
1294     const IntSurf_PntOn2S& p2 = theWLine->Point(2);
1295     if(p1.Value().IsEqual(p2.Value(), gp::Resolution()))
1296       return aResult;
1297   }
1298
1299   Handle(IntPatch_WLine) aLocalWLine;
1300   Handle(IntPatch_WLine) aTmpWLine = theWLine;
1301   Handle(IntSurf_LineOn2S) aLineOn2S = new IntSurf_LineOn2S();
1302   aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
1303   for(i = 1; i <= nb; i++)
1304     aLineOn2S->Add(theWLine->Point(i));
1305
1306   for(v = 1; v <= nbvtx; v++)
1307     aLocalWLine->AddVertex(theWLine->Vertex(v));
1308
1309   // I: Delete equal points
1310   for(i = 1; i <= aLineOn2S->NbPoints(); i++)
1311   {
1312     Standard_Integer aStartIndex = i + 1;
1313     Standard_Integer anEndIndex = i + 5;
1314     nb = aLineOn2S->NbPoints();
1315     anEndIndex = (anEndIndex > nb) ? nb : anEndIndex;
1316
1317     if((aStartIndex > nb) || (anEndIndex <= 1))
1318       continue;
1319
1320     k = aStartIndex;
1321
1322     while(k <= anEndIndex)
1323     {
1324       if(i != k)
1325       {
1326         IntSurf_PntOn2S p1 = aLineOn2S->Value(i);
1327         IntSurf_PntOn2S p2 = aLineOn2S->Value(k);
1328         
1329         Standard_Real UV[8];
1330         p1.Parameters(UV[0], UV[1], UV[2], UV[3]);
1331         p2.Parameters(UV[4], UV[5], UV[6], UV[7]);
1332
1333         Standard_Real aMax = Abs(UV[0]);
1334         for(Standard_Integer anIdx = 1; anIdx < 8; anIdx++)
1335         {
1336           if (aMax < Abs(UV[anIdx]))
1337             aMax = Abs(UV[anIdx]);
1338         }
1339
1340         if(p1.Value().IsEqual(p2.Value(), gp::Resolution()) ||
1341            Abs(UV[0] - UV[4]) + Abs(UV[1] - UV[5]) < 1.0e-16 * aMax ||
1342            Abs(UV[2] - UV[6]) + Abs(UV[3] - UV[7]) < 1.0e-16 * aMax )
1343         {
1344           aTmpWLine = aLocalWLine;
1345           aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
1346           
1347           for(v = 1; v <= aTmpWLine->NbVertex(); v++)
1348           {
1349             IntPatch_Point aVertex = aTmpWLine->Vertex(v);
1350             Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
1351
1352             if(avertexindex >= k)
1353             {
1354               aVertex.SetParameter(aVertex.ParameterOnLine() - 1.);
1355             }
1356             aLocalWLine->AddVertex(aVertex);
1357           }
1358           aLineOn2S->RemovePoint(k);
1359           anEndIndex--;
1360           continue;
1361         }
1362       }
1363       k++;
1364     }
1365   }
1366
1367   if (aLineOn2S->NbPoints() <= 2)
1368   {
1369     if (aLineOn2S->NbPoints() == 2)
1370       return aLocalWLine;
1371     else
1372       return aResult;
1373   }
1374
1375   // Avoid purge in case of C0 continuity:
1376   // Intersection approximator may produce invalid curve after purge, example:
1377   // bugs modalg_5 bug24731.
1378   // Do not run purger when base number of points is too small.
1379   if (theS1->UContinuity() == GeomAbs_C0 ||
1380       theS1->VContinuity() == GeomAbs_C0 ||
1381       theS2->UContinuity() == GeomAbs_C0 ||
1382       theS2->VContinuity() == GeomAbs_C0 ||
1383       nb < aNbSingleBezier)
1384   {
1385     return aLocalWLine;
1386   }
1387
1388   // II: Delete out of borders points.
1389   aLocalWLine = DeleteOuterPoints(aLocalWLine, theS1, theS2, theDom1, theDom2);
1390
1391   // III: Delete points by tube criteria.
1392   Handle(IntPatch_WLine) aLocalWLineTube = 
1393     DeleteByTube(aLocalWLine, theS1, theS2);
1394
1395   if(aLocalWLineTube->NbPnts() > 1)
1396   {
1397     aResult = aLocalWLineTube;
1398   }
1399   return aResult;
1400 }
1401
1402 //=======================================================================
1403 //function : JoinWLines
1404 //purpose  :
1405 //=======================================================================
1406 void IntPatch_WLineTool::JoinWLines(IntPatch_SequenceOfLine& theSlin,
1407                                     IntPatch_SequenceOfPoint& theSPnt,
1408                                     Handle(Adaptor3d_HSurface) theS1,
1409                                     Handle(Adaptor3d_HSurface) theS2,
1410                                     const Standard_Real theTol3D)
1411 {
1412   if(theSlin.Length() == 0)
1413     return;
1414
1415   // For two cylindrical surfaces only
1416   const Standard_Real aMinRad = 1.0e-3*Min(theS1->Cylinder().Radius(),
1417                                               theS2->Cylinder().Radius());
1418
1419   const Standard_Real anArrPeriods[4] = {theS1->IsUPeriodic() ? theS1->UPeriod() : 0.0,
1420                                          theS1->IsVPeriodic() ? theS1->VPeriod() : 0.0,
1421                                          theS2->IsUPeriodic() ? theS2->UPeriod() : 0.0,
1422                                          theS2->IsVPeriodic() ? theS2->VPeriod() : 0.0};
1423
1424   const Standard_Real anArrFBonds[4] = {theS1->FirstUParameter(), theS1->FirstVParameter(),
1425                                         theS2->FirstUParameter(), theS2->FirstVParameter()};
1426   const Standard_Real anArrLBonds[4] = {theS1->LastUParameter(), theS1->LastVParameter(),
1427                                         theS2->LastUParameter(), theS2->LastVParameter()};
1428
1429   Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator();
1430
1431   for(Standard_Integer aN1 = 1; aN1 <= theSlin.Length(); aN1++)
1432   {
1433     Handle(IntPatch_WLine) aWLine1(Handle(IntPatch_WLine)::DownCast(theSlin.Value(aN1)));
1434
1435     if(aWLine1.IsNull())
1436     {//We must have failed to join not-point-lines
1437       continue;
1438     }
1439
1440     const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
1441     const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
1442     const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
1443
1444     for(Standard_Integer aNPt = 1; aNPt <= theSPnt.Length(); aNPt++)
1445     {
1446       const IntSurf_PntOn2S aPntCur = theSPnt.Value(aNPt).PntOn2S();
1447
1448       if( aPntCur.IsSame(aPntFWL1, Precision::Confusion()) ||
1449         aPntCur.IsSame(aPntLWL1, Precision::Confusion()))
1450       {
1451         theSPnt.Remove(aNPt);
1452         aNPt--;
1453       }
1454     }
1455
1456     anAlloc->Reset();
1457     NCollection_List<Standard_Integer> aListFC(anAlloc),
1458                                        aListLC(anAlloc);
1459     
1460     Standard_Boolean isFirstConnected = Standard_False, isLastConnected = Standard_False;
1461
1462     for (Standard_Integer aN2 = 1; aN2 <= theSlin.Length(); aN2++)
1463     {
1464       if (aN2 == aN1)
1465         continue;
1466
1467       Handle(IntPatch_WLine) aWLine2(Handle(IntPatch_WLine)::DownCast(theSlin.Value(aN2)));
1468
1469       if (aWLine2.IsNull())
1470         continue;
1471
1472       isFirstConnected = isLastConnected = Standard_False;
1473
1474       const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
1475
1476       const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
1477       const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
1478
1479       Standard_Real aSqDistF = aPntFWL1.Value().SquareDistance(aPntFWL2.Value());
1480       Standard_Real aSqDistL = aPntFWL1.Value().SquareDistance(aPntLWL2.Value());
1481
1482       const Standard_Real aSqMinFDist = Min(aSqDistF, aSqDistL);
1483       if (aSqMinFDist < Precision::SquareConfusion())
1484       {
1485         if (CheckArgumentsToJoin(theS1, theS2, aPntFWL1, aMinRad))
1486         {
1487           const Standard_Boolean isFM = (aSqDistF < aSqDistL);
1488           const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2);
1489           const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) :
1490                                                       aWLine2->Point(aNbPntsWL2 - 1);
1491
1492           if (!IsSeamOrBound(aPt1, aPt2, aPntFWL1,
1493                               anArrPeriods, anArrFBonds, anArrLBonds))
1494           {
1495             isFirstConnected = Standard_True;
1496           }
1497         }
1498       }
1499
1500       aSqDistF = aPntLWL1.Value().SquareDistance(aPntFWL2.Value());
1501       aSqDistL = aPntLWL1.Value().SquareDistance(aPntLWL2.Value());
1502
1503       const Standard_Real aSqMinLDist = Min(aSqDistF, aSqDistL);
1504       if (aSqMinLDist < Precision::SquareConfusion())
1505       {
1506         if (CheckArgumentsToJoin(theS1, theS2, aPntLWL1, aMinRad))
1507         {
1508           const Standard_Boolean isFM = (aSqDistF < aSqDistL);
1509           const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1 - 1);
1510           const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) :
1511                                                aWLine2->Point(aNbPntsWL2 - 1);
1512
1513           if (!IsSeamOrBound(aPt1, aPt2, aPntLWL1,
1514                               anArrPeriods, anArrFBonds, anArrLBonds))
1515           {
1516             isLastConnected = Standard_True;
1517           }
1518         }
1519       }
1520
1521       if (isFirstConnected && isLastConnected)
1522       {
1523         if (aSqMinFDist < aSqMinLDist)
1524         {
1525           aListFC.Append(aN2);
1526         }
1527         else
1528         {
1529           aListLC.Append(aN2);
1530         }
1531       }
1532       else if (isFirstConnected)
1533       {
1534         aListFC.Append(aN2);
1535       }
1536       else if (isLastConnected)
1537       {
1538         aListLC.Append(aN2);
1539       }
1540     }
1541
1542     isFirstConnected = (aListFC.Extent() == 1);
1543     isLastConnected = (aListLC.Extent() == 1);
1544
1545     if (!(isFirstConnected || isLastConnected))
1546     {
1547       continue;
1548     }
1549
1550     const Standard_Integer anIndexWL2 = isFirstConnected ? aListFC.First() : aListLC.First();
1551     Handle(IntPatch_WLine) aWLine2(Handle(IntPatch_WLine)::DownCast(theSlin.Value(anIndexWL2)));
1552     
1553     const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
1554     const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
1555
1556     aWLine1->ClearVertexes();
1557
1558     if (isFirstConnected)
1559     {
1560       if (aPntFWL1.IsSame(aPntFWL2, Precision::Confusion()))
1561       {
1562         //First-First-connection
1563         for (Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
1564         {
1565           const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1566           aWLine1->Curve()->InsertBefore(1, aPt);
1567         }
1568       }
1569       else
1570       {
1571         //First-Last-connection
1572         for (Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
1573         {
1574           const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1575           aWLine1->Curve()->InsertBefore(1, aPt);
1576         }
1577       }
1578     }
1579     else //if (isLastConnected)
1580     {
1581       if (aPntLWL1.IsSame(aPntFWL2, Precision::Confusion()))
1582       {
1583         //Last-First connection
1584         for(Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
1585         {
1586           const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1587           aWLine1->Curve()->Add(aPt);
1588         }
1589       }
1590       else
1591       {
1592         //Last-Last connection
1593         for (Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
1594         {
1595           const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
1596           aWLine1->Curve()->Add(aPt);
1597         }
1598       }
1599     }
1600
1601     aWLine1->ComputeVertexParameters(theTol3D);
1602     theSlin.Remove(anIndexWL2);
1603     aN1--;
1604   }
1605 }
1606
1607 //=======================================================================
1608 //function : ExtendTwoWLines
1609 //purpose  : Performs extending theWLine1 and theWLine2 through their
1610 //            respecting end point.
1611 //=======================================================================
1612 void IntPatch_WLineTool::ExtendTwoWLines(IntPatch_SequenceOfLine& theSlin,
1613                                          const Handle(Adaptor3d_HSurface)& theS1,
1614                                          const Handle(Adaptor3d_HSurface)& theS2,
1615                                          const Standard_Real theToler3D,
1616                                          const Standard_Real* const theArrPeriods,
1617                                          const Bnd_Box2d& theBoxS1,
1618                                          const Bnd_Box2d& theBoxS2)
1619 {
1620   if(theSlin.Length() < 2)
1621     return;
1622
1623   gp_Vec aVec1, aVec2, aVec3;
1624
1625   for(Standard_Integer aNumOfLine1 = 1; aNumOfLine1 <= theSlin.Length(); aNumOfLine1++)
1626   {
1627     Handle(IntPatch_WLine) aWLine1 (Handle(IntPatch_WLine)::
1628                                     DownCast(theSlin.Value(aNumOfLine1)));
1629
1630     if(aWLine1.IsNull())
1631     {//We must have failed to join not-point-lines
1632       continue;
1633     }
1634     
1635     const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
1636
1637     if(aWLine1->Vertex(1).ParameterOnLine() != 1)
1638       continue;
1639
1640     if(aWLine1->Vertex(aWLine1->NbVertex()).ParameterOnLine() != aWLine1->NbPnts())
1641       continue;
1642
1643     const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
1644     const IntSurf_PntOn2S& aPntFp1WL1 = aWLine1->Point(2);
1645
1646     const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
1647     const IntSurf_PntOn2S& aPntLm1WL1 = aWLine1->Point(aNbPntsWL1-1);
1648
1649     //Enable/Disable of some ckeck. Bit-mask is used for it.
1650     //E.g. if 1st point of aWLine1 matches with
1651     //1st point of aWLine2 then we do not need in check
1652     //1st point of aWLine1 and last point of aWLine2 etc.
1653     unsigned int aCheckResult = IntPatchWT_EnAll;
1654
1655     //If aWLine1 is already connected with another Wline then
1656     //there is no point in extending.
1657     for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1;
1658         aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
1659     {
1660       Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::
1661                                     DownCast(theSlin.Value(aNumOfLine2)));
1662
1663       if(aWLine2.IsNull())
1664         continue;
1665
1666       const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
1667       const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aWLine2->NbPnts());
1668
1669       if( aPntFWL1.IsSame(aPntFWL2, theToler3D) ||
1670           aPntFWL1.IsSame(aPntLWL2, theToler3D) )
1671       {
1672         aCheckResult |= IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast;
1673       }
1674
1675       if( aPntLWL1.IsSame(aPntFWL2, theToler3D) ||
1676           aPntLWL1.IsSame(aPntFWL2, theToler3D))
1677       {
1678         aCheckResult |= IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast;
1679       }
1680     }
1681
1682     if(aCheckResult == (IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast |
1683                         IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast))
1684       continue;
1685
1686     for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1;
1687         aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
1688     {
1689       Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::
1690                                     DownCast(theSlin.Value(aNumOfLine2)));
1691
1692       if(aWLine2.IsNull())
1693         continue;
1694
1695       if(aWLine2->Vertex(1).ParameterOnLine() != 1)
1696         continue;
1697
1698       if(aWLine2->Vertex(aWLine2->NbVertex()).ParameterOnLine() != aWLine2->NbPnts())
1699         continue;
1700
1701       Standard_Boolean hasBeenJoined = Standard_False;
1702
1703       const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
1704
1705       const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
1706       const IntSurf_PntOn2S& aPntFp1WL2 = aWLine2->Point(2);
1707
1708       const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
1709       const IntSurf_PntOn2S& aPntLm1WL2 = aWLine2->Point(aNbPntsWL2-1);
1710       
1711       //if(!(aCheckResult & IntPatchWT_DisFirstFirst))
1712       {// First/First
1713         aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
1714         aVec2.SetXYZ(aPntFWL2.Value().XYZ() - aPntFp1WL2.Value().XYZ());
1715         aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntFWL2.Value().XYZ());
1716
1717         ExtendTwoWLFirstFirst(theS1, theS2, aWLine1, aWLine2, aPntFWL1, aPntFWL2,
1718                               aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
1719                               theArrPeriods, aCheckResult, hasBeenJoined);
1720       }
1721
1722       if(!(aCheckResult & IntPatchWT_DisFirstLast))
1723       {// First/Last
1724         aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
1725         aVec2.SetXYZ(aPntLWL2.Value().XYZ() - aPntLm1WL2.Value().XYZ());
1726         aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntLWL2.Value().XYZ());
1727
1728         ExtendTwoWLFirstLast(theS1, theS2, aWLine1, aWLine2, aPntFWL1, aPntLWL2,
1729                              aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
1730                              theArrPeriods, aCheckResult, hasBeenJoined);
1731       }
1732
1733       if(!(aCheckResult & IntPatchWT_DisLastFirst))
1734       {// Last/First
1735         aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
1736         aVec2.SetXYZ(aPntFp1WL2.Value().XYZ() - aPntFWL2.Value().XYZ());
1737         aVec3.SetXYZ(aPntFWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
1738
1739         ExtendTwoWLLastFirst(theS1, theS2, aWLine1, aWLine2, aPntLWL1, aPntFWL2,
1740                              aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
1741                              theArrPeriods, aCheckResult, hasBeenJoined);
1742       }
1743
1744       if(!(aCheckResult & IntPatchWT_DisLastLast))
1745       {// Last/Last
1746         aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
1747         aVec2.SetXYZ(aPntLm1WL2.Value().XYZ() - aPntLWL2.Value().XYZ());
1748         aVec3.SetXYZ(aPntLWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
1749
1750         ExtendTwoWLLastLast(theS1, theS2, aWLine1, aWLine2, aPntLWL1, aPntLWL2,
1751                             aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
1752                             theArrPeriods, aCheckResult, hasBeenJoined);
1753       }
1754
1755       if(hasBeenJoined)
1756       {
1757         theSlin.Remove(aNumOfLine2);
1758         aNumOfLine2--;
1759       }
1760     }
1761   }
1762 }