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//26-04-1997 modified by pmn : Initialisation plus fine de la resolution
16
17Standard_Integer Blend_Walking::ArcToRecadre(const Standard_Boolean OnFirst,
18					     const math_Vector& theSol,
19					     const Standard_Integer PrevIndex,
20					     gp_Pnt2d& lastpt2d,
21					     gp_Pnt2d& pt2d,
22					     Standard_Real& ponarc)
23{
24  Standard_Integer IndexSol = 0,  nbarc = 0;
25  Standard_Boolean ok = Standard_False;
26  Standard_Boolean byinter = (line->NbPoints() != 0), okinter = 0;
27  Standard_Real distmin = RealLast();
28  Standard_Real uprev = 0.,vprev = 0., prm = 0., dist = 0.;
29  Handle(TheTopolTool) Iter;
30
31  if (OnFirst) {
32    if(byinter) previousP.ParametersOnS1(uprev,vprev);
33    pt2d.SetCoord(theSol(1),theSol(2));
34    Iter = recdomain1;
35  }
36  else {
37    if(byinter) previousP.ParametersOnS2(uprev,vprev);
38    pt2d.SetCoord(theSol(3),theSol(4));
39    Iter = recdomain2;
40  }
41  lastpt2d.SetCoord(uprev,vprev);
42  Iter->Init();
43  while (Iter->More()) {
44    nbarc++; ok = 0;
45    if (OnFirst) {
46      if(byinter) {
47	ok = okinter = TheBlendTool::Inters(pt2d,lastpt2d,
48					    surf1,Iter->Value(),prm,dist);
49      }
50      if(!ok) ok = TheBlendTool::Project(pt2d,surf1,Iter->Value(),prm,dist);
51    }
52    else {
53      if(byinter) {
54	ok = okinter = TheBlendTool::Inters(pt2d,lastpt2d,
55					    surf2,Iter->Value(),prm,dist);
56      }
57      if(!ok) ok = TheBlendTool::Project(pt2d,surf2,Iter->Value(),prm,dist);
58    }
59    if (ok && (nbarc != PrevIndex) ) {
60      if (dist<distmin || okinter) {
61	distmin = dist;
62	ponarc = prm;
63	IndexSol = nbarc;
64	if(okinter && (PrevIndex==0)) break;
65      }
66    }
67    Iter->Next();
68  }
69  return IndexSol;
70}
71
72Standard_Boolean Blend_Walking::Recadre(Blend_FuncInv& FuncInv,
73					const Standard_Boolean OnFirst,
74					const math_Vector& theSol,
75					math_Vector& solrst,
76					Standard_Integer& Indexsol,
77					Standard_Boolean& IsVtx,
78					TheVertex& Vtx,
79					const Standard_Real Extrap)
80
81{
82  Standard_Boolean jalons_Trouve = Standard_False;
83  Standard_Boolean recadre = Standard_True, ok;
84  Standard_Boolean byinter = (line->NbPoints() != 0);
85  Standard_Integer LeJalon = 0;
86
87  Standard_Integer nbarc;
88  Standard_Real dist,prm,pmin, vtol;
89  gp_Pnt2d pt2d, lastpt2d;
90
91  math_Vector toler(1,4),infb(1,4),supb(1,4),valsol(1,4);
92
93  Handle(Adaptor2d_HCurve2d) thecur;
94  Handle(TheTopolTool) Iter;
95
96  if (OnFirst) Iter = recdomain1;
97  else         Iter = recdomain2;
98
99  Indexsol = ArcToRecadre(OnFirst, theSol, 0,
100			  lastpt2d, pt2d, pmin);
101  IsVtx = Standard_False;
102  if (Indexsol == 0) {
103    return Standard_False;
104  }
105
106  Iter->Init();
107  nbarc = 1;
108  while (nbarc < Indexsol) {
109    nbarc++;
110    Iter->Next();
111  }
112
113  TheArc thearc = Iter->Value();
114
115  if (OnFirst) {
116    thecur = TheBlendTool::CurveOnSurf(thearc,surf1);
117  }
118  else {
119    thecur = TheBlendTool::CurveOnSurf(thearc,surf2);
120  }
121
122// Le probleme a resoudre
123  FuncInv.Set(OnFirst,thecur);
124  FuncInv.GetBounds(infb,supb);
125  infb(2) -= Extrap;
126  supb(2) += Extrap;
127
128  FuncInv.GetTolerance(toler,tolesp/10);//Il vaut mieux garder un peu de marge
129  math_FunctionSetRoot rsnld(FuncInv,toler,35);
130  toler *= 10; // Mais on fait les tests correctements
131
132// Calcul d'un point d'init
133  Standard_Real ufirst,ulast;
134  TheBlendTool::Bounds(thecur, ufirst,ulast);
135  // Pour aider a trouver les coins singuliers on recadre eventuelement le paramtere
136  if (Abs(pmin-ufirst) < Abs(ulast-ufirst)/1000) {
137    pmin = ufirst;
138  }
139  if (Abs(pmin-ulast) < Abs(ulast-ufirst)/1000) {
140    pmin = ulast;
141  }
142
143  if (byinter) {
144    Standard_Real lastParam = previousP.Parameter();
145    // Verifie que le recadrage n'est pas un jalons
146    if (jalons.Length()!=0) {
147      Standard_Real t1, t2, t;
148      Standard_Boolean Cherche=Standard_True;
149      Standard_Integer ii;
150      if (lastParam < param) {
151	t1 = lastParam; t2 = param;
152      }
153      else {
154	t1 = param; t2 = lastParam;
155      }
156      for (ii=1; ii<=jalons.Length() && Cherche; ii++) {
157	t = jalons.Value(ii).Parameter();
158        if  (((t1 < t) && (t2 > t)) || (t==param)) {
159	 jalons_Trouve = Standard_True;
160	 LeJalon = ii;
161	 Cherche = Standard_False; //Ne marche que si l'on sort simultanement
162       }
163	else Cherche = t < t2; // On s'arrete si t>=t2;
164      }
165    }
166    if (!jalons_Trouve) {
167      //Initialisation par Interpolation
168      Standard_Real lambda, u, v;
169      gp_Pnt2d Pnt, Pnt1, Pnt2;//,  POnC;
170      thecur->D0(pmin, Pnt);
171      if (OnFirst) {
172	previousP.ParametersOnS2(u,v);
173	Pnt1.SetCoord(u, v);
174	Pnt2.SetCoord(theSol(3), theSol(4));
175      }
176      else {
177	previousP.ParametersOnS1(u,v);
178	Pnt1.SetCoord(u, v);
179	Pnt2.SetCoord(theSol(1), theSol(2));
180      }
181
182      lambda = Pnt.Distance(lastpt2d);
183      if (lambda > 1.e-12) lambda /=  Pnt.Distance(lastpt2d) + Pnt.Distance(pt2d);
184      else lambda = 0;
185      solrst(1) = pmin;
186      solrst(2) = (1-lambda)*lastParam + lambda*param;
187      solrst(3) = (1-lambda)*Pnt1.X()  + lambda*Pnt2.X();
188      solrst(4) = (1-lambda)*Pnt1.Y()  + lambda*Pnt2.Y();
189    }
190  }
191  else { // sinon on initialise par le dernier point calcule
192    solrst(1) = pmin;
193    solrst(2) = param;
194    if (OnFirst) {
195      solrst(3) = theSol(3);
196      solrst(4) = theSol(4);
197    }
198    else {
199      solrst(3) = theSol(1);
200      solrst(4) = theSol(2);
201    }
202  }
203
204  if (jalons_Trouve) { // On recupere le jalon
205    Blend_Point MonJalon;
206    Standard_Boolean periodic;
207    Standard_Real uperiod = 0, vperiod = 0;
208    gp_Pnt2d Pnt;
209    Standard_Real distaux;
210    MonJalon = jalons.Value(LeJalon);
211    solrst(2) =  MonJalon.Parameter();
212    if (OnFirst) {
213      MonJalon.ParametersOnS2(solrst(3), solrst(4));
214      periodic = (surf2->IsUPeriodic() || surf2->IsVPeriodic());
215    }
216    else  {
217       MonJalon.ParametersOnS1(solrst(3), solrst(4));
218       periodic = (surf1->IsUPeriodic() || surf1->IsVPeriodic());
219     }
220
221    // Recadrage eventuelle pour le cas periodique
222    if (periodic) {
223      Handle(Adaptor3d_HSurface) surf;
224      if (OnFirst) surf = surf2;
225      else surf = surf1;
226
227      lastpt2d = thecur->Value(pmin);
228
229      if (surf->IsUPeriodic()) {
230	uperiod =  surf->UPeriod();
231	if (solrst(3)-lastpt2d.X() >  uperiod*0.6) solrst(3) -= uperiod;
232	if (solrst(3)-lastpt2d.X() < -uperiod*0.6) solrst(3) += uperiod;
233      }
234      if (surf->IsVPeriodic()) {
235	vperiod =  surf->VPeriod();
236	if (solrst(4)-lastpt2d.Y() >  vperiod*0.6) solrst(4) -= vperiod;
237	if (solrst(4)-lastpt2d.Y() < -vperiod*0.6) solrst(4) += vperiod;
238      }
239    }
240
241    // Pour le parametre sur arc il faut projeter...
242    pt2d.SetCoord(solrst(3), solrst(4));
243    Pnt = thecur->Value(ufirst);
244    dist = pt2d.Distance(Pnt);
245    solrst(1) = ufirst;
246    Pnt = thecur->Value(ulast);
247    distaux = pt2d.Distance(Pnt);
248    if ( distaux < dist) {
249      solrst(1) = ulast;
250      dist = distaux;
251    }
252
253    if (dist>Precision::PConfusion()) {
254      prm = pmin;
255      if (OnFirst) {
256	ok = TheBlendTool::Project(pt2d,surf1,thearc,prm,distaux);
257      }
258      else {
259	ok = TheBlendTool::Project(pt2d,surf2,thearc,prm,distaux);
260      }
261      if (ok && (pt2d.Distance(thecur->Value(prm)) < dist)) solrst(1) = prm;
262      else solrst(1) = pmin;
263    }
264    // On verifie le jalon
265    jalons_Trouve = (FuncInv.IsSolution(solrst,tolesp));
266  }
267
268  if (!jalons_Trouve) {
269    // Resolution...
270    rsnld.Perform(FuncInv,solrst,infb,supb);
271    if (!rsnld.IsDone()) {
272#ifdef OCCT_DEBUG
273      std::cout << "Walking::Recadre : RSNLD not done " << std::endl;
274#endif
275      recadre = Standard_False;
276    }
277    else {
278      rsnld.Root(solrst);
279      recadre = FuncInv.IsSolution(solrst,tolesp);
280    }
281  }
282
283  // En cas d'echecs, on regarde si un autre arc
284  // peut faire l'affaire (cas des sorties a proximite d'un vertex)
285  dist = (ulast - ufirst)/100;
286  if ((!recadre) &&
287      ((Abs(pmin-ulast) < dist) || (Abs(pmin-ufirst) < dist)) ) {
288
289    Indexsol =  ArcToRecadre(OnFirst, theSol, Indexsol,
290			     lastpt2d, pt2d, pmin);
291    if (Indexsol == 0) {
292      return Standard_False;
293    }
294
295    Iter->Init();
296    nbarc = 1;
297    while (nbarc < Indexsol) {
298      nbarc++;
299      Iter->Next();
300    }
301    thearc = Iter->Value();
302
303    if (OnFirst) {
304      thecur = TheBlendTool::CurveOnSurf(thearc,surf1);
305    }
306    else {
307      thecur = TheBlendTool::CurveOnSurf(thearc,surf2);
308    }
309    solrst(1) = pmin;
310    // Le probleme a resoudre
311    FuncInv.Set(OnFirst,thecur);
312    FuncInv.GetBounds(infb,supb);
313    FuncInv.GetTolerance(toler,tolesp/10);//Il vaut mieux garder un peu de marge
314    math_FunctionSetRoot aRsnld(FuncInv,toler,35);
315    toler *= 10; // Mais on fait les tests correctements
316    // Resolution...
317    aRsnld.Perform(FuncInv,solrst,infb,supb);
318
319    if (!aRsnld.IsDone()) {
320#ifdef OCCT_DEBUG
321      std::cout << "Walking::Recadre : RSNLD not done " << std::endl;
322#endif
323      recadre = Standard_False;
324    }
325    else {
326      aRsnld.Root(solrst);
327      recadre = FuncInv.IsSolution(solrst,tolesp);
328    }
329  }
330
331  if (recadre) {
332    // Classification topologique
333    if (OnFirst) {
334      thecur = TheBlendTool::CurveOnSurf(thearc,surf1);
335    }
336    else {
337      thecur = TheBlendTool::CurveOnSurf(thearc,surf2);
338    }
339    TheBlendTool::Bounds(thecur, ufirst,ulast);
340
341    Iter->Initialize(thearc);
342    Iter->InitVertexIterator();
343    IsVtx = !Iter->MoreVertex();
344    while (!IsVtx) {
345      Vtx = Iter->Vertex();
346      vtol = 0.4*Abs(ulast-ufirst); // Un majorant de la tolerance
347      if (vtol > Max(TheBlendTool::Tolerance(Vtx,thearc), toler(1)))
348	vtol = Max(TheBlendTool::Tolerance(Vtx,thearc), toler(1));
349      if (Abs(TheBlendTool::Parameter(Vtx,thearc)-solrst(1)) <= vtol) {
350	IsVtx = Standard_True; // On est dans la boule du vertex ou
351	                       // le vertex est dans la "boule" du recadrage
352      }
353      else {
354	Iter->NextVertex();
355	IsVtx = !Iter->MoreVertex();
356      }
357    }
358    if (!Iter->MoreVertex()) {
359      IsVtx = Standard_False;
360    }
361    return Standard_True;
362  }
363  return Standard_False;
364}
365
366
367void Blend_Walking::Transition(const Standard_Boolean OnFirst,
368			       const TheArc& A,
369			       const Standard_Real Param,
370			       IntSurf_Transition& TLine,
371			       IntSurf_Transition& TArc)
372{
373  Standard_Boolean computetranstionaveclacorde = 0;
374  gp_Vec tgline;
375  Blend_Point prevprev;
376
377  if(previousP.IsTangencyPoint()){
378    if(line->NbPoints() < 2) return;
379    computetranstionaveclacorde = 1;
380    if(sens < 0){
381      prevprev = line->Point(2);
382    }
383    else {
384      prevprev = line->Point(line->NbPoints() - 1);
385    }
386  }
387  gp_Pnt2d p2d;
388  gp_Vec2d dp2d;
389
390  gp_Pnt pbid;
391  gp_Vec d1u,d1v,normale,tgrst;
392  gp_Dir thenormal;
393  CSLib_NormalStatus stat;
394
395  TheArcTool::D1(A,Param,p2d,dp2d);
396  if (OnFirst) {
397    TheSurfaceTool::D1(surf1,p2d.X(),p2d.Y(),pbid,d1u,d1v);
398    if(!computetranstionaveclacorde) tgline = previousP.TangentOnS1();
399    else tgline = gp_Vec(prevprev.PointOnS1(),previousP.PointOnS1());
400  }
401  else {
402    TheSurfaceTool::D1(surf2,p2d.X(),p2d.Y(),pbid,d1u,d1v);
403    if(!computetranstionaveclacorde) tgline = previousP.TangentOnS2();
404    else tgline = gp_Vec(prevprev.PointOnS2(),previousP.PointOnS2());
405  }
406
407  tgrst.SetLinearForm(dp2d.X(),d1u,dp2d.Y(),d1v);
408
409  CSLib::Normal(d1u, d1v, 1.e-9, stat, thenormal);
410  if (stat ==  CSLib_Defined) normale.SetXYZ(thenormal.XYZ());
411  else {
412    Handle(Adaptor3d_HSurface) surf;
413    if (OnFirst) surf = surf1;
414    else         surf = surf2;
415    Standard_Integer iu, iv;
416    TColgp_Array2OfVec Der(0, 2 , 0, 2);
417    TheSurfaceTool::D2(surf,p2d.X(),p2d.Y(),pbid, Der(1,0), Der(0,1),
418		       Der(2,0), Der(0,2), Der(1,1));
419    Der(2,1) = TheSurfaceTool::DN(surf, p2d.X(), p2d.Y(), 2,1);
420    Der(1,2) = TheSurfaceTool::DN(surf,p2d.X(),p2d.Y(), 1,2);
421    Der(2,2) = TheSurfaceTool::DN(surf,p2d.X(),p2d.Y(), 2,2);
422    CSLib::Normal(2, Der, 1.e-9,
423		  p2d.X(), p2d.Y(),
424		  TheSurfaceTool::FirstUParameter(surf),
425		  TheSurfaceTool::LastUParameter(surf),
426		  TheSurfaceTool::FirstVParameter(surf),
427		  TheSurfaceTool::LastVParameter(surf),
428		  stat, thenormal, iu, iv);
429    normale.SetXYZ(thenormal.XYZ());
430#ifdef OCCT_DEBUG
431    if (stat == CSLib_InfinityOfSolutions)
432      std::cout << "Blend_Walking::Transition : Infinite de Normal" << std::endl;
433#endif
434  }
435
436  IntSurf::MakeTransition(tgline,tgrst,normale,TLine,TArc);
437
438}
439
440
441void Blend_Walking::MakeExtremity(TheExtremity& Extrem,
442				  const Standard_Boolean OnFirst,
443				  const Standard_Integer Index,
444				  const Standard_Real Param,
445				  const Standard_Boolean IsVtx,
446				  const TheVertex& Vtx)
447{
448
449  IntSurf_Transition Tline,Tarc;
450  Standard_Integer nbarc;
451  Handle(TheTopolTool) Iter;
452
453  if (OnFirst) {
454    Extrem.SetValue(previousP.PointOnS1(),
455		    sol(1),sol(2),
456		    previousP.Parameter(), tolesp);
457    if (!previousP.IsTangencyPoint())
458      Extrem.SetTangent(previousP.TangentOnS1());
459    Iter = recdomain1;
460  }
461  else {
462    Extrem.SetValue(previousP.PointOnS2(),
463		    sol(3),sol(4),
464		    previousP.Parameter(), tolesp);
465    if (!previousP.IsTangencyPoint())
466      Extrem.SetTangent(previousP.TangentOnS2());
467    Iter = recdomain2;
468  }
469
470  Iter->Init();
471  nbarc = 1;
472
473  while (nbarc < Index) {
474    nbarc++;
475    Iter->Next();
476  }
477
478  Transition(OnFirst,Iter->Value(),Param,Tline,Tarc);
479  Extrem.AddArc(Iter->Value(),Param,Tline,Tarc);
480  if (IsVtx) Extrem.SetVertex(Vtx);
481}
482
483void  Blend_Walking::MakeSingularExtremity( TheExtremity& Extrem,
484					   const Standard_Boolean OnFirst,
485					   const TheVertex& Vtx)
486{
487  IntSurf_Transition Tline,Tarc;
488  Handle(TheTopolTool) Iter;
489  Standard_Real prm;
490
491  if (OnFirst) {
492    Iter = recdomain1;
493    if (!previousP.IsTangencyPoint())
494      Extrem.SetTangent(previousP.TangentOnS1());
495  }
496  else {
497    if (!previousP.IsTangencyPoint())
498      Extrem.SetTangent(previousP.TangentOnS2());
499    Iter = recdomain2;
500  }
501
502  Iter->Init();
503  Extrem.SetVertex(Vtx);
504  while (Iter->More()) {
505    TheArc arc = Iter->Value();
506    Iter->Initialize(arc);
507    Iter->InitVertexIterator();
508    while (Iter->MoreVertex()) {
509      if (Iter->Identical(Vtx,Iter->Vertex())) {
510	prm = TheBlendTool::Parameter(Vtx,arc);
511	Transition(OnFirst,arc,prm,Tline,Tarc);
512	Extrem.AddArc(arc,prm,Tline,Tarc);
513      }
514      Iter->NextVertex();
515    }
516    Iter->Next();
517  }
518}
519
520
521
522
523
524
525
526
527
528
529
530