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