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