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