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