1// Copyright (c) 1995-1999 Matra Datavision
2// Copyright (c) 1999-2014 OPEN CASCADE SAS
3//
4// This file is part of Open CASCADE Technology software library.
5//
6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
11//
12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
14
15#include <gce_MakePln.hxx>
16#include <Extrema_ExtPS.hxx>
17#include <Extrema_ExtPC.hxx>
18
19#ifdef DRAW
20#include <DrawTrSurf.hxx>
21#endif
22
23
24static const Standard_Real CosRef3D = 0.88;
25
26static void RecadreIfPeriodic(Standard_Real& NewU,
27                              Standard_Real& NewV,
28                              const Standard_Real OldU,
29                              const Standard_Real OldV,
30                              const Standard_Real UPeriod,
31                              const Standard_Real VPeriod)
32{
33  if (UPeriod > 0.)
34  {
35    Standard_Real sign = (NewU < OldU)? 1 : -1;
36    while (Abs(NewU - OldU) > UPeriod/2)
37      NewU += sign * UPeriod;
38  }
39  if (VPeriod > 0.)
40  {
41    Standard_Real sign = (NewV < OldV)? 1 : -1;
42    while (Abs(NewV - OldV) > VPeriod/2)
43      NewV += sign * VPeriod;
44  }
45}
46
47static void evalpinit(math_Vector& parinit,
48		      const Blend_Point& previousP,
49		      const Standard_Real parprec,
50		      const Standard_Real param,
51		      const math_Vector& infbound,
52		      const math_Vector& supbound,
53		      const Standard_Boolean classonS1,
54		      const Standard_Boolean classonS2)
55{
56  if(previousP.IsTangencyPoint()){
57    previousP.ParametersOnS1(parinit(1),parinit(2));
58    previousP.ParametersOnS2(parinit(3),parinit(4));
59  }
60  else {
61    Standard_Real u1,v1,u2,v2;
62    Standard_Real du1,dv1,du2,dv2;
63    Standard_Boolean Inside=Standard_True;
64    previousP.ParametersOnS1(u1,v1);
65    previousP.ParametersOnS2(u2,v2);
66    previousP.Tangent2dOnS1().Coord(du1,dv1);
67    previousP.Tangent2dOnS2().Coord(du2,dv2);
68    Standard_Real step = param - parprec;
69    u1+= step*du1;
70    v1+= step*dv1;
71    if ( classonS1 ) {
72      if ((u1<infbound(1)) || (u1>supbound(1))) Inside=Standard_False;
73      if ((v1<infbound(2)) || (v1>supbound(2))) Inside=Standard_False;
74    }
75    u2+= step*du2;
76    v2+= step*dv2;
77    if ( classonS2) {
78      if ((u2<infbound(3)) || (u2>supbound(3))) Inside=Standard_False;
79      if ((v2<infbound(4)) || (v2>supbound(4))) Inside=Standard_False;
80    }
81
82    if (Inside) {
83      parinit(1) = u1;
84      parinit(2) = v1;
85      parinit(3) = u2;
86      parinit(4) = v2;
87    }
88    else { // on ne joue pas au plus malin
89      previousP.ParametersOnS1(parinit(1),parinit(2));
90      previousP.ParametersOnS2(parinit(3),parinit(4));
91    }
92
93  }
94}
95
96
97
98void Blend_Walking::InternalPerform(Blend_Function& Func,
99				    Blend_FuncInv& FuncInv,
100				    const Standard_Real Bound)
101{
102  Standard_Real Cosi = 0., Cosi2 = 0.;
103
104  Standard_Real stepw = pasmax;
105  Standard_Integer nbp = line->NbPoints();
106  if(nbp >= 2){ //On reprend le dernier step s'il n est pas trop petit.
107    if(sens < 0.){
108      stepw = (line->Point(2).Parameter() - line->Point(1).Parameter());
109    }
110    else{
111      stepw = (line->Point(nbp).Parameter() - line->Point(nbp - 1).Parameter());
112    }
113    stepw = Max(stepw,100.*tolgui);
114  }
115  Standard_Real parprec = param;
116  gp_Vec TgOnGuide, PrevTgOnGuide;
117  gp_Pnt PtOnGuide;
118  hguide->D1(parprec, PtOnGuide, TgOnGuide);
119  PrevTgOnGuide = TgOnGuide;
120
121  if (sens*(parprec - Bound) >= -tolgui) {
122    return;
123  }
124  Blend_Status State = Blend_OnRst12;
125  TopAbs_State situ1 =TopAbs_IN,situ2=TopAbs_IN;
126  Standard_Real w1,w2;
127  Standard_Integer Index1 = 0, Index2 = 0, nbarc;
128  Standard_Boolean Arrive,recad1,recad2, control;
129  Standard_Boolean Isvtx1 = Standard_False, Isvtx2 = Standard_False, echecrecad;
130  gp_Pnt2d p2d;
131  math_Vector tolerance(1,4),infbound(1,4),supbound(1,4),parinit(1,4);
132  math_Vector solrst1(1,4),solrst2(1,4);
133  TheVertex Vtx1,Vtx2;
134  TheExtremity Ext1,Ext2;
135
136  //IntSurf_Transition Tline,Tarc;
137
138  Func.GetTolerance(tolerance,tolesp);
139  Func.GetBounds(infbound,supbound);
140
141  math_FunctionSetRoot rsnld(Func,tolerance,30);
142  parinit = sol;
143
144  Arrive = Standard_False;
145  param = parprec + sens*stepw;
146  if(sens *(param - Bound) > 0.) {
147    stepw = sens*(Bound - parprec)*0.5;
148    param = parprec + sens*stepw;
149  }
150
151  evalpinit(parinit,previousP,parprec,param,
152	    infbound,supbound, clasonS1, clasonS2);
153
154  while (!Arrive) {
155
156#ifdef OCCT_DEBUG
157    sectioncalculee = 0;
158    nbcomputedsection++;
159#endif
160
161    hguide->D1(param, PtOnGuide, TgOnGuide);
162    //Check deflection on guide
163    Cosi = PrevTgOnGuide * TgOnGuide;
164    if (Cosi < gp::Resolution()) //angle>=pi/2 or null magnitude
165      Cosi2 = 0.;
166    else
167      Cosi2 = Cosi * Cosi / PrevTgOnGuide.SquareMagnitude() / TgOnGuide.SquareMagnitude();
168    if (Cosi2 < CosRef3D) //angle 3d too great
169    {
170      State = Blend_StepTooLarge;
171      stepw = stepw/2.;
172      param = parprec + sens*stepw;  // on ne risque pas de depasser Bound.
173      if (Abs(stepw) < tolgui) {
174        Ext1.SetValue(previousP.PointOnS1(),
175                      sol(1),sol(2),
176                      previousP.Parameter(),tolesp);
177        Ext2.SetValue(previousP.PointOnS2(),
178                      sol(3),sol(4),
179                      previousP.Parameter(),tolesp);
180        if (!previousP.IsTangencyPoint()) {
181          Ext1.SetTangent(previousP.TangentOnS1());
182          Ext2.SetTangent(previousP.TangentOnS2());
183        }
184        Arrive = Standard_True;
185      }
186      continue;
187    }
188    PrevTgOnGuide = TgOnGuide;
189    //////////////////////////
190
191    Standard_Boolean bonpoint = 1;
192    Func.Set(param);
193    rsnld.Perform(Func,parinit,infbound,supbound);
194
195    if (!rsnld.IsDone()) {
196      State = Blend_StepTooLarge;
197      bonpoint = 0;
198    }
199    else {
200      rsnld.Root(sol);
201
202      if(clasonS1) situ1 = domain1->Classify(gp_Pnt2d(sol(1),sol(2)),
203					     Min(tolerance(1),tolerance(2)),0);
204      else situ1 = TopAbs_IN;
205      if(clasonS2) situ2 = domain2->Classify(gp_Pnt2d(sol(3),sol(4)),
206					     Min(tolerance(3),tolerance(4)),0);
207      else situ2 = TopAbs_IN;
208    }
209    if(bonpoint && line->NbPoints() == 1 && (situ1 != TopAbs_IN || situ2 != TopAbs_IN)){
210      State = Blend_StepTooLarge;
211      bonpoint = 0;
212    }
213    if(bonpoint){
214      w1 = w2 = Bound;
215      recad1 = Standard_False;
216      recad2 = Standard_False;
217      echecrecad = Standard_False;
218      control = Standard_False;
219
220      if (situ1 == TopAbs_OUT || situ1 == TopAbs_ON) {
221	// pb inverse sur surf1
222	//Si le recadrage s'effectue dans le sens de la progression a une tolerance pres,
223	//on a pris la mauvaise solution.
224	recad1 = Recadre(FuncInv,Standard_True,
225			 sol,solrst1,Index1,Isvtx1,Vtx1);
226
227	if (recad1) {
228	  Standard_Real wtemp;
229	  wtemp  = solrst1(2);
230	  if ((param - wtemp)/sens>= -10*tolesp){
231	    w1 = solrst1(2);
232	    control = Standard_True;
233	  }
234	  else {
235	    echecrecad = Standard_True;
236	    recad1 = Standard_False;
237	    State = Blend_StepTooLarge;
238	    bonpoint = 0;
239	    stepw = stepw/2.;
240	  }
241	}
242	else {
243	  echecrecad = Standard_True;
244	}
245      }
246      if (situ2 == TopAbs_OUT || situ2 == TopAbs_ON) {
247	// pb inverse sur surf2
248	//Si le recadrage s'effectue dans le sens de la progression a une tolerance pres,
249	//on a pris la mauvaise solution.
250	recad2 = Recadre(FuncInv,Standard_False,
251			 sol,solrst2,Index2,Isvtx2,Vtx2);
252
253	if (recad2) {
254	  Standard_Real wtemp;
255	  wtemp = solrst2(2);
256	  if ((param - wtemp)/sens>= -10*tolesp){
257	    w2 = solrst2(2);
258	    control = Standard_True;
259	  }
260	  else {
261	    echecrecad = Standard_True;
262	    recad2 = Standard_False;
263	    State = Blend_StepTooLarge;
264	    bonpoint = 0;
265	    stepw = stepw/2.;
266	  }
267	}
268	else {
269	  echecrecad = Standard_True;
270	}
271      }
272
273      // Que faut il controler
274      if (recad1 && recad2) {
275	  if (Abs(w1-w2) <= 10*tolgui) {
276	  // pas besoin de controler les recadrage
277	  // Le control pouvant se planter (cf model blend10)
278          // La tolerance est choisie grossse afin, de permetre au
279          // cheminement suivant, de poser quelques sections ...
280	  control = Standard_False;
281	  }
282	  else if (sens*(w1-w2) < 0.) {
283	    //sol sur 1 ?
284	    recad2 = Standard_False;
285	  }
286	  else {
287	    //sol sur 2 ?
288	    recad1 = Standard_False;
289	  }
290	}
291
292      // Controle effectif des recadrage
293      if (control) {
294	TopAbs_State situ;
295	if (recad1 && clasonS2) {
296	  situ = recdomain2->Classify(gp_Pnt2d(solrst1(3),solrst1(4)),
297			              Min(tolerance(3),tolerance(4)));
298	  if (situ == TopAbs_OUT) {
299	    recad1 = Standard_False;
300	    echecrecad = Standard_True;
301	  }
302	}
303	else if (recad2 && clasonS1) {
304	  situ = recdomain1->Classify(gp_Pnt2d(solrst2(3),solrst2(4)),
305			              Min(tolerance(1),tolerance(1)));
306	  if (situ == TopAbs_OUT) {
307	    recad2 = Standard_False;
308	    echecrecad = Standard_True;
309	  }
310	}
311      }
312
313      if(recad1 || recad2) echecrecad = Standard_False;
314
315      if (!echecrecad) {
316	if (recad1 && recad2) {
317	  //sol sur 1 et 2 a la fois
318	  // On passe par les arcs , pour ne pas avoir de probleme
319	  // avec les surfaces periodiques.
320	  State = Blend_OnRst12;
321	  param =  (w1+w2)/2;
322          gp_Pnt Pnt1, Pnt2;
323	  p2d = TheArcTool::Value(recdomain1->Value(),solrst1(1));
324	  sol(1) = p2d.X();
325	  sol(2) = p2d.Y();
326          Pnt1 = TheSurfaceTool::Value(surf1,sol(1),sol(2));
327	  p2d = TheArcTool::Value(recdomain2->Value(),solrst2(1));
328	  sol(3) = p2d.X();
329	  sol(4) = p2d.Y();
330          Pnt2 = TheSurfaceTool::Value(surf2,sol(3),sol(4));
331          const Standard_Real TolProd = 1.e-5;
332          Standard_Real SavedParams [2];
333          Standard_Boolean SameDirs [2] = {Standard_False, Standard_False};
334          ChFiDS_ElSpine& theElSpine = hguide->ChangeCurve();
335          SavedParams[0] = theElSpine.GetSavedFirstParameter();
336          SavedParams[1] = theElSpine.GetSavedLastParameter();
337          for (Standard_Integer ind = 0; ind < 2; ind++)
338          {
339            if (!Precision::IsInfinite(SavedParams[ind]))
340            {
341              //Check the original first and last parameters of guide curve
342              //for equality to found parameter <param>:
343              //check equality of tangent to guide curve and
344              //normal to plane built on 3 points:
345              //point on guide curve and points on restrictions of adjacent
346              //surfaces.
347              gp_Pnt Pnt0;
348              gp_Vec Dir0;
349              hguide->D1(SavedParams[ind], Pnt0, Dir0);
350              Standard_Real Length = Dir0.Magnitude();
351              if (Length <= gp::Resolution())
352                continue;
353              Dir0 /= Length;
354              gce_MakePln PlaneBuilder(Pnt0, Pnt1, Pnt2);
355              if (!PlaneBuilder.IsDone())
356                continue;
357              gp_Pln thePlane = PlaneBuilder.Value();
358              gp_Dir DirPlane = thePlane.Axis().Direction();
359              gp_Vec theProd = Dir0 ^ DirPlane;
360              Standard_Real ProdMod = theProd.Magnitude();
361              if (ProdMod <= TolProd)
362                SameDirs[ind] = Standard_True;
363            }
364          }
365          Standard_Real theParam = Precision::Infinite();
366          //Choose the closest parameter
367          if (SameDirs[0] && SameDirs[1])
368            theParam = (Abs(param - SavedParams[0]) < Abs(param - SavedParams[1]))?
369              SavedParams[0] : SavedParams[1];
370          else if (SameDirs[0])
371            theParam = SavedParams[0];
372          else if (SameDirs[1])
373            theParam = SavedParams[1];
374
375          Standard_Real NewU, NewV, NewParam;
376          gp_Pnt NewPnt;
377          Standard_Boolean Corrected = CorrectExtremityOnOneRst(1, sol(3), sol(4), param, Pnt1,
378                                                                NewU, NewV, NewPnt, NewParam);
379          if (Corrected)
380          {
381            if (Abs(param - NewParam) < Abs(param - theParam))
382              theParam = NewParam;
383          }
384
385          if (!Precision::IsInfinite(theParam))
386            param = theParam;
387	}
388	else if (recad1) {
389	  // sol sur 1
390	  State = Blend_OnRst1;
391	  param = w1;
392	  recdomain1->Init();
393	  nbarc = 1;
394	  while (nbarc < Index1) {
395	    nbarc++;
396	    recdomain1->Next();
397	  }
398	  p2d = TheArcTool::Value(recdomain1->Value(),solrst1(1));
399	  sol(1) = p2d.X();
400	  sol(2) = p2d.Y();
401	  sol(3) = solrst1(3);
402	  sol(4) = solrst1(4);
403          gp_Pnt thePntOnRst = TheSurfaceTool::Value(surf1,sol(1),sol(2));
404          Standard_Real NewU, NewV, NewParam;
405          gp_Pnt NewPnt;
406          Standard_Boolean Corrected = CorrectExtremityOnOneRst(1, sol(3), sol(4), param, thePntOnRst,
407                                                                NewU, NewV, NewPnt, NewParam);
408          if (Corrected)
409          {
410            param = NewParam;
411            sol(3) = NewU;
412            sol(4) = NewV;
413          }
414	}
415	else if (recad2) {
416	  //sol sur 2
417	  State = Blend_OnRst2;
418	  param = w2;
419
420	  recdomain2->Init();
421	  nbarc = 1;
422	  while (nbarc < Index2) {
423	    nbarc++;
424	    recdomain2->Next();
425	  }
426	  p2d = TheArcTool::Value(recdomain2->Value(),solrst2(1));
427	  sol(1) = solrst2(3);
428	  sol(2) = solrst2(4);
429	  sol(3) = p2d.X();
430	  sol(4) = p2d.Y();
431          gp_Pnt thePntOnRst = TheSurfaceTool::Value(surf2,sol(3),sol(4));
432          Standard_Real NewU, NewV, NewParam;
433          gp_Pnt NewPnt;
434          Standard_Boolean Corrected = CorrectExtremityOnOneRst(2, sol(1), sol(2), param, thePntOnRst,
435                                                                NewU, NewV, NewPnt, NewParam);
436          if (Corrected)
437          {
438            param = NewParam;
439            sol(1) = NewU;
440            sol(2) = NewV;
441          }
442	}
443	else {
444	  State = Blend_OK;
445	}
446
447	Standard_Boolean testdefl = 1;
448#ifdef OCCT_DEBUG
449	testdefl = !Blend_GetcontextNOTESTDEFL();
450#endif
451	if (recad1 || recad2) {
452	  Func.Set(param);
453          // Il vaut mieux un pas non orthodoxe que pas de recadrage!! PMN
454	  State = TestArret(Func, State,
455			    (testdefl && (Abs(stepw) > 3*tolgui)),
456			    Standard_False, Standard_True);
457	}
458	else {
459	  State = TestArret(Func, State, testdefl);
460	}
461      }
462      else {
463	// Ou bien le pas max est mal regle. On divise.
464//	if(line->NbPoints() == 1) State = Blend_StepTooLarge;
465	if (stepw > 2*tolgui) State = Blend_StepTooLarge;
466	// Sinon echec recadrage. On sort avec PointsConfondus
467	else {
468#ifdef OCCT_DEBUG
469	  std::cout << "Echec recadrage" << std::endl;
470#endif
471	  State = Blend_SamePoints;
472	}
473      }
474    }
475
476#ifdef OCCT_DEBUG
477    if (Blend_GettraceDRAWSECT()){
478      Drawsect(surf1,surf2,sol,param,Func, State);
479    }
480#endif
481    switch (State) {
482    case Blend_OK :
483      {
484	// Mettre a jour la ligne.
485	if (sens>0.) {
486	  line->Append(previousP);
487	}
488	else {
489	  line->Prepend(previousP);
490	}
491#ifdef DRAW
492        Standard_Integer nbpts = line->NbPoints();
493        char name [100];
494        sprintf(name, "pg%d", nbpts);
495        DrawTrSurf::Set(name, PtOnGuide);
496        sprintf(name, "p1_%d", nbpts);
497        DrawTrSurf::Set(name, previousP.PointOnS1());
498        sprintf(name, "p2_%d", nbpts);
499        DrawTrSurf::Set(name, previousP.PointOnS2());
500#endif
501
502	parprec = param;
503
504	if (param == Bound) {
505	  Arrive = Standard_True;
506	  Ext1.SetValue(previousP.PointOnS1(),
507			sol(1),sol(2),
508			previousP.Parameter(), tolesp);
509	  Ext2.SetValue(previousP.PointOnS2(),
510			sol(3),sol(4),
511			previousP.Parameter(), tolesp);
512	  if (!previousP.IsTangencyPoint()) {
513	    Ext1.SetTangent(previousP.TangentOnS1());
514	    Ext2.SetTangent(previousP.TangentOnS2());
515	  }
516
517	  // Indiquer que fin sur Bound.
518	}
519	else {
520	  param = param + sens*stepw;
521	  if (sens*(param - Bound) > - tolgui) {
522	    param = Bound;
523	  }
524	}
525	evalpinit(parinit,previousP,parprec,param,
526		  infbound,supbound, clasonS1, clasonS2);
527      }
528      break;
529
530    case Blend_StepTooLarge :
531      {
532	stepw = stepw/2.;
533	if (Abs(stepw) < tolgui) {
534	  Ext1.SetValue(previousP.PointOnS1(),
535			sol(1),sol(2),
536			previousP.Parameter(),tolesp);
537	  Ext2.SetValue(previousP.PointOnS2(),
538			sol(3),sol(4),
539			previousP.Parameter(),tolesp);
540	  if (!previousP.IsTangencyPoint()) {
541	    Ext1.SetTangent(previousP.TangentOnS1());
542	    Ext2.SetTangent(previousP.TangentOnS2());
543	  }
544	  Arrive = Standard_True;
545	  if (line->NbPoints()>=2) {
546	    // Indiquer qu on s arrete en cours de cheminement
547	  }
548//	  else {
549//	    line->Clear();
550//	  }
551	}
552	else {
553	  param = parprec + sens*stepw;  // on ne risque pas de depasser Bound.
554	  evalpinit(parinit,previousP,parprec,param,
555		    infbound,supbound, clasonS1, clasonS2);
556	}
557      }
558      break;
559
560    case Blend_StepTooSmall :
561      {
562	// Mettre a jour la ligne.
563	if (sens>0.) {
564	  line->Append(previousP);
565	}
566	else {
567	  line->Prepend(previousP);
568	}
569#ifdef DRAW
570        Standard_Integer nbpts = line->NbPoints();
571        char name [100];
572        sprintf(name, "pg%d", nbpts);
573        DrawTrSurf::Set(name, PtOnGuide);
574        sprintf(name, "p1_%d", nbpts);
575        DrawTrSurf::Set(name, previousP.PointOnS1());
576        sprintf(name, "p2_%d", nbpts);
577        DrawTrSurf::Set(name, previousP.PointOnS2());
578#endif
579
580	parprec = param;
581
582	stepw = Min(1.5*stepw,pasmax);
583	if (param == Bound) {
584	  Arrive = Standard_True;
585	  Ext1.SetValue(previousP.PointOnS1(),
586			sol(1),sol(2),
587			previousP.Parameter(),tolesp);
588	  Ext2.SetValue(previousP.PointOnS2(),
589			sol(3),sol(4),
590			previousP.Parameter(),tolesp);
591	  if (!previousP.IsTangencyPoint()) {
592	    Ext1.SetTangent(previousP.TangentOnS1());
593	    Ext2.SetTangent(previousP.TangentOnS2());
594	  }
595	  // Indiquer que fin sur Bound.
596	}
597	else {
598	  param = param + sens*stepw;
599	  if (sens*(param - Bound) > - tolgui) {
600	    param = Bound;
601	  }
602	}
603	evalpinit(parinit,previousP,parprec,param,
604		  infbound,supbound, clasonS1, clasonS2);
605      }
606      break;
607
608    case Blend_OnRst1  :
609      {
610	if (sens>0.) {
611	  line->Append(previousP);
612	}
613	else {
614	  line->Prepend(previousP);
615	}
616#ifdef DRAW
617        Standard_Integer nbpts = line->NbPoints();
618        char name [100];
619        sprintf(name, "pg%d", nbpts);
620        DrawTrSurf::Set(name, PtOnGuide);
621        sprintf(name, "p1_%d", nbpts);
622        DrawTrSurf::Set(name, previousP.PointOnS1());
623        sprintf(name, "p2_%d", nbpts);
624        DrawTrSurf::Set(name, previousP.PointOnS2());
625#endif
626
627	MakeExtremity(Ext1,Standard_True,Index1,
628		      solrst1(1),Isvtx1,Vtx1);
629        // On blinde le cas singulier ou un des recadrage a planter
630        if (previousP.PointOnS1().IsEqual(previousP.PointOnS2(), 2*tolesp)) {
631	  Ext2.SetValue(previousP.PointOnS1(),
632			sol(3),sol(4),tolesp);
633	  if (Isvtx1) MakeSingularExtremity(Ext2, Standard_False, Vtx1);
634	}
635	else {
636	  Ext2.SetValue(previousP.PointOnS2(),
637			sol(3),sol(4),
638			previousP.Parameter(),tolesp);
639	}
640	Arrive = Standard_True;
641      }
642      break;
643
644    case Blend_OnRst2  :
645      {
646	if (sens>0.) {
647	  line->Append(previousP);
648	}
649	else {
650	  line->Prepend(previousP);
651	}
652#ifdef DRAW
653        Standard_Integer nbpts = line->NbPoints();
654        char name [100];
655        sprintf(name, "pg%d", nbpts);
656        DrawTrSurf::Set(name, PtOnGuide);
657        sprintf(name, "p1_%d", nbpts);
658        DrawTrSurf::Set(name, previousP.PointOnS1());
659        sprintf(name, "p2_%d", nbpts);
660        DrawTrSurf::Set(name, previousP.PointOnS2());
661#endif
662
663        // On blinde le cas singulier ou un des recadrage a plante
664        if (previousP.PointOnS1().IsEqual(previousP.PointOnS2(), 2*tolesp)) {
665	  Ext1.SetValue(previousP.PointOnS2(),
666			sol(1),sol(2),tolesp);
667	  if (Isvtx2) MakeSingularExtremity(Ext1, Standard_True, Vtx2);
668	}
669	else {
670	  Ext1.SetValue(previousP.PointOnS1(),
671			sol(1),sol(2),
672			previousP.Parameter(),tolesp);
673	}
674	MakeExtremity(Ext2,Standard_False,Index2,
675		      solrst2(1),Isvtx2,Vtx2);
676	Arrive = Standard_True;
677      }
678      break;
679
680
681    case Blend_OnRst12 :
682      {
683	if (sens>0.) {
684	  line->Append(previousP);
685	}
686	else {
687	  line->Prepend(previousP);
688	}
689#ifdef DRAW
690        Standard_Integer nbpts = line->NbPoints();
691        char name [100];
692        sprintf(name, "pg%d", nbpts);
693        DrawTrSurf::Set(name, PtOnGuide);
694        sprintf(name, "p1_%d", nbpts);
695        DrawTrSurf::Set(name, previousP.PointOnS1());
696        sprintf(name, "p2_%d", nbpts);
697        DrawTrSurf::Set(name, previousP.PointOnS2());
698#endif
699
700	if ( (Isvtx1 != Isvtx2) &&
701	    (previousP.PointOnS1().IsEqual(previousP.PointOnS2(), 2*tolesp)) ) {
702	  // On blinde le cas singulier ou un seul recadrage
703	  // est reconnu comme vertex.
704	  if (Isvtx1) {
705	    Isvtx2 = Standard_True;
706	    Vtx2 = Vtx1;
707	  }
708	  else {
709	    Isvtx1 = Standard_True;
710	    Vtx1 = Vtx2;
711	  }
712	}
713
714	MakeExtremity(Ext1,Standard_True,Index1,
715		      solrst1(1),Isvtx1,Vtx1);
716	MakeExtremity(Ext2,Standard_False,Index2,
717		      solrst2(1),Isvtx2,Vtx2);
718	Arrive = Standard_True;
719      }
720      break;
721
722    case Blend_SamePoints :
723      {
724	// On arrete
725#ifdef OCCT_DEBUG
726	std::cout << " Points confondus dans le cheminement" << std::endl;
727#endif
728	Ext1.SetValue(previousP.PointOnS1(),
729		      sol(1),sol(2),
730		      previousP.Parameter(),tolesp);
731	Ext2.SetValue(previousP.PointOnS2(),
732		      sol(3),sol(4),
733		      previousP.Parameter(),tolesp);;
734	if (!previousP.IsTangencyPoint()) {
735	  Ext1.SetTangent(previousP.TangentOnS1());
736	  Ext2.SetTangent(previousP.TangentOnS2());
737	}
738	Arrive = Standard_True;
739      }
740      break;
741    default:
742      break;
743    }
744    if (Arrive) {
745      if (sens > 0.) {
746	line->SetEndPoints(Ext1,Ext2);
747      }
748      else {
749	line->SetStartPoints(Ext1,Ext2);
750
751      }
752    }
753
754  }
755
756}
757
758Standard_Boolean Blend_Walking::CorrectExtremityOnOneRst(const Standard_Integer IndexOfRst,
759                                                         const Standard_Real theU,
760                                                         const Standard_Real theV,
761                                                         const Standard_Real theParam,
762                                                         const gp_Pnt& thePntOnRst,
763                                                         Standard_Real& NewU,
764                                                         Standard_Real& NewV,
765                                                         gp_Pnt& NewPoint,
766                                                         Standard_Real& NewParam) const
767{
768  const Standard_Real TolAng = 0.001; //bug OCC25701
769
770  ChFiDS_ElSpine& theElSpine = hguide->ChangeCurve();
771  if (theElSpine.NbVertices() == 0)
772    return Standard_False;
773
774  Handle(TheTopolTool) DomainOfRst = (IndexOfRst == 1)? recdomain1 : recdomain2;
775  TheSurface SurfOfRst = (IndexOfRst == 1)? surf1 : surf2;
776  TheSurface AnotherSurf = (IndexOfRst == 1)? surf2 : surf1;
777
778  //Correct point on surface 2
779  //First we find right <param>
780  Standard_Real Ends [2];
781  Ends[0] = TheArcTool::FirstParameter(DomainOfRst->Value());
782  Ends[1] = TheArcTool::LastParameter(DomainOfRst->Value());
783  Standard_Real GlobalMinSqDist = Precision::Infinite();
784  Standard_Real ParamOnGuide = 0;
785  gp_Pnt PointOnGuide;
786  for (Standard_Integer k = 0; k < 2; k++)
787  {
788    gp_Pnt2d P2dOnEnd = TheArcTool::Value(DomainOfRst->Value(), Ends[k]);
789    gp_Pnt PntOnEnd = TheSurfaceTool::Value(SurfOfRst, P2dOnEnd.X(), P2dOnEnd.Y());
790    Extrema_ExtPC projoncurv(PntOnEnd, theElSpine);
791    if (!projoncurv.IsDone())
792      continue;
793    Standard_Real MinSqDist = Precision::Infinite();
794    Standard_Integer imin = 0;
795    for (Standard_Integer ind = 1; ind <= projoncurv.NbExt(); ind++)
796    {
797      Standard_Real aSqDist = projoncurv.SquareDistance(ind);
798      if (aSqDist < MinSqDist)
799      {
800        MinSqDist = aSqDist;
801        imin = ind;
802      }
803    }
804    if (MinSqDist < GlobalMinSqDist)
805    {
806      GlobalMinSqDist = MinSqDist;
807      ParamOnGuide = projoncurv.Point(imin).Parameter();
808      PointOnGuide = projoncurv.Point(imin).Value();
809    }
810  }
811  NewParam = ParamOnGuide;
812  if (hguide->IsPeriodic())
813  {
814    Standard_Real Period = hguide->Period();
815    Standard_Real sign = (NewParam < theParam)? 1 : -1;
816    while (Abs(NewParam - theParam) > Period/2)
817      NewParam += sign *Period;
818  }
819
820  //Second we find right point and tangent on guide
821  GlobalMinSqDist = Precision::Infinite();
822  gp_Ax1 theAx1;
823  for (Standard_Integer ind = 1; ind <= theElSpine.NbVertices(); ind++)
824  {
825    const gp_Ax1& anAx1 = theElSpine.VertexWithTangent(ind);
826    gp_Pnt aPnt = anAx1.Location();
827    Standard_Real aSqDist = PointOnGuide.SquareDistance(aPnt);
828    if (aSqDist < GlobalMinSqDist)
829    {
830      GlobalMinSqDist = aSqDist;
831      theAx1 = anAx1;
832    }
833  }
834  const gp_Pnt& Pnt0 = theAx1.Location();
835  const gp_Dir& Dir0 = theAx1.Direction();
836  //Check new point: is it real solution?
837  gp_Pnt OldPonGuide = hguide->Value(theParam);
838  gp_Pnt PntOnSurf2 = TheSurfaceTool::Value(AnotherSurf,theU,theV); //old point
839  gce_MakePln PlaneBuilder(thePntOnRst, OldPonGuide, PntOnSurf2);
840  if (!PlaneBuilder.IsDone())
841    return Standard_False;
842  gp_Pln OldPlane = PlaneBuilder.Value();
843  gp_Dir OldDir = OldPlane.Axis().Direction();
844  Standard_Real Angle = OldDir.Angle(Dir0);
845  if (Angle > M_PI/2)
846    Angle = M_PI - Angle;
847  if (Angle > TolAng)
848    return Standard_False;
849  ///////////////////////////////////////
850  //Project the point(theU,theV) on the plane(Pnt0,Dir0)
851  gp_Vec aVec(Pnt0, PntOnSurf2);
852  gp_Vec aTranslation( (aVec.XYZ() * Dir0.XYZ()) * Dir0.XYZ() );
853  gp_Pnt PntOnPlane = PntOnSurf2.Translated(-aTranslation);
854
855  //Check new point again: does point on restriction belong to the plane?
856  PlaneBuilder = gce_MakePln(thePntOnRst, Pnt0, PntOnPlane);
857  if (!PlaneBuilder.IsDone())
858    return Standard_False;
859  gp_Pln NewPlane = PlaneBuilder.Value();
860  const gp_Dir& DirOfNewPlane = NewPlane.Axis().Direction();
861  Angle = Dir0.Angle(DirOfNewPlane);
862  if (Angle > M_PI/2)
863    Angle = M_PI - Angle;
864  if (Angle > TolAng)
865    return Standard_False;
866  ////////////////////////////////////////////////////////////////////////
867
868  //Project the point <PntOnPlane> on the surface 2
869  Extrema_ExtPS projonsurf(PntOnPlane, AnotherSurf->Surface(),
870                           Precision::PConfusion(), Precision::PConfusion(),
871                           Extrema_ExtFlag_MIN);
872  if (projonsurf.IsDone())
873  {
874    Standard_Real MinSqDist = Precision::Infinite();
875    Standard_Integer imin = 0;
876    for (Standard_Integer ind = 1; ind <= projonsurf.NbExt(); ind++)
877    {
878      Standard_Real aSqDist = projonsurf.SquareDistance(ind);
879      if (aSqDist < MinSqDist)
880      {
881        MinSqDist = aSqDist;
882        imin = ind;
883      }
884    }
885    if (imin)
886    {
887      Extrema_POnSurf NewPOnSurf2 = projonsurf.Point(imin);
888      NewPoint = NewPOnSurf2.Value();
889      NewPOnSurf2.Parameter(NewU, NewV);
890      Standard_Real uperiod = (AnotherSurf->IsUPeriodic())? AnotherSurf->UPeriod() : 0.;
891      Standard_Real vperiod = (AnotherSurf->IsVPeriodic())? AnotherSurf->VPeriod() : 0.;
892      RecadreIfPeriodic(NewU, NewV, theU, theV,
893                        uperiod, vperiod);
894      return Standard_True;
895    }
896  }
897
898  return Standard_False;
899}
900