Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 1998-01-22 |
2 | // Created by: Philippe MANGIN/Roman BORISOV | |
3 | // Copyright (c) 1998-1999 Matra Datavision | |
973c2be1 | 4 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e | 5 | // |
973c2be1 | 6 | // This file is part of Open CASCADE Technology software library. |
b311480e | 7 | // |
d5f74e42 | 8 | // This library is free software; you can redistribute it and/or modify it under |
9 | // the terms of the GNU Lesser General Public License version 2.1 as published | |
973c2be1 | 10 | // by the Free Software Foundation, with special exception defined in the file |
11 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT | |
12 | // distribution for complete text of the license and disclaimer of any warranty. | |
b311480e | 13 | // |
973c2be1 | 14 | // Alternatively, this file may be used under the terms of Open CASCADE |
15 | // commercial license or contractual agreement. | |
7fd59977 | 16 | |
17 | #include <GeomFill_Frenet.ixx> | |
18 | #include <GeomAbs_CurveType.hxx> | |
19 | #include <Adaptor3d_HCurve.hxx> | |
20 | #include <Precision.hxx> | |
21 | #include <GeomLib.hxx> | |
22 | #include <GeomFill_SnglrFunc.hxx> | |
23 | #include <Extrema_ExtPC.hxx> | |
24 | #include <TColStd_HArray1OfBoolean.hxx> | |
7fd59977 | 25 | #include <TColgp_SequenceOfPnt2d.hxx> |
79a35943 | 26 | #include <NCollection_Array1.hxx> |
27 | #include <algorithm> | |
7fd59977 | 28 | |
32ca7a51 | 29 | static const Standard_Real NullTol = 1.e-10; |
30 | static const Standard_Real MaxSingular = 1.e-5; | |
31 | ||
32 | static const Standard_Integer maxDerivOrder = 3; | |
33 | ||
7fd59977 | 34 | |
35 | //======================================================================= | |
36 | //function : FDeriv | |
37 | //purpose : computes (F/|F|)' | |
38 | //======================================================================= | |
39 | static gp_Vec FDeriv(const gp_Vec& F, const gp_Vec& DF) | |
40 | { | |
41 | Standard_Real Norma = F.Magnitude(); | |
42 | gp_Vec Result = (DF - F*(F*DF)/(Norma*Norma))/Norma; | |
43 | return Result; | |
44 | } | |
45 | ||
46 | ||
47 | //======================================================================= | |
48 | //function : DDeriv | |
49 | //purpose : computes (F/|F|)'' | |
50 | //======================================================================= | |
51 | static gp_Vec DDeriv(const gp_Vec& F, const gp_Vec& DF, const gp_Vec& D2F) | |
52 | { | |
53 | Standard_Real Norma = F.Magnitude(); | |
54 | gp_Vec Result = (D2F - 2*DF*(F*DF)/(Norma*Norma))/Norma - | |
55 | F*((DF.SquareMagnitude() + F*D2F | |
56 | - 3*(F*DF)*(F*DF)/(Norma*Norma))/(Norma*Norma*Norma)); | |
57 | return Result; | |
58 | } | |
59 | ||
32ca7a51 | 60 | //======================================================================= |
61 | //function : CosAngle | |
62 | //purpose : Return a cosine between vectors theV1 and theV2. | |
63 | //======================================================================= | |
64 | static Standard_Real CosAngle(const gp_Vec& theV1, const gp_Vec& theV2) | |
65 | { | |
66 | const Standard_Real aTol = gp::Resolution(); | |
67 | ||
68 | const Standard_Real m1 = theV1.Magnitude(), m2 = theV2.Magnitude(); | |
69 | if((m1 <= aTol) || (m2 <= aTol)) //Vectors are codirectional | |
70 | return 1.0; | |
71 | ||
72 | Standard_Real aCAng = theV1.Dot(theV2)/(m1*m2); | |
73 | ||
74 | if(aCAng > 1.0) | |
75 | aCAng = 1.0; | |
76 | ||
77 | if(aCAng < -1.0) | |
78 | aCAng = -1.0; | |
79 | ||
80 | ||
81 | return aCAng; | |
82 | } | |
83 | ||
7fd59977 | 84 | //======================================================================= |
85 | //function : GeomFill_Frenet | |
86 | //purpose : | |
87 | //======================================================================= | |
88 | ||
89 | GeomFill_Frenet::GeomFill_Frenet() | |
90 | { | |
91 | } | |
92 | ||
93 | ||
94 | //======================================================================= | |
95 | //function : Copy | |
96 | //purpose : | |
97 | //======================================================================= | |
98 | ||
99 | Handle(GeomFill_TrihedronLaw) GeomFill_Frenet::Copy() const | |
100 | { | |
101 | Handle(GeomFill_Frenet) copy = new (GeomFill_Frenet)(); | |
102 | if (!myCurve.IsNull()) copy->SetCurve(myCurve); | |
103 | return copy; | |
104 | } | |
105 | ||
106 | //======================================================================= | |
107 | //function : SetCurve | |
108 | //purpose : | |
109 | //======================================================================= | |
110 | ||
111 | void GeomFill_Frenet::SetCurve(const Handle(Adaptor3d_HCurve)& C) | |
112 | { | |
113 | GeomFill_TrihedronLaw::SetCurve(C); | |
114 | if (! C.IsNull()) { | |
115 | GeomAbs_CurveType type; | |
116 | type = C->GetType(); | |
117 | switch (type) { | |
118 | case GeomAbs_Circle: | |
119 | case GeomAbs_Ellipse: | |
120 | case GeomAbs_Hyperbola: | |
121 | case GeomAbs_Parabola: | |
122 | case GeomAbs_Line: | |
123 | { | |
124 | // No probleme | |
125 | isSngl = Standard_False; | |
126 | } | |
127 | default : | |
128 | { | |
129 | // We have to search singulaties | |
130 | Init(); | |
131 | } | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | //======================================================================= | |
137 | //function : Init | |
138 | //purpose : | |
139 | //======================================================================= | |
140 | ||
141 | void GeomFill_Frenet::Init() | |
142 | { | |
143 | Standard_Integer i, j; | |
144 | GeomFill_SnglrFunc Func(myCurve); | |
145 | Standard_Real TolF = 1.0e-10, Tol = 10*TolF, Tol2 = Tol * Tol, | |
146 | PTol = Precision::PConfusion(); | |
147 | ||
148 | // We want to determine if the curve has linear segments | |
149 | Standard_Integer NbIntC2 = myCurve->NbIntervals(GeomAbs_C2); | |
150 | Handle(TColStd_HArray1OfReal) myC2Disc = | |
151 | new TColStd_HArray1OfReal(1, NbIntC2 + 1); | |
152 | Handle(TColStd_HArray1OfBoolean) IsLin = | |
153 | new TColStd_HArray1OfBoolean(1, NbIntC2); | |
154 | Handle(TColStd_HArray1OfBoolean) IsConst = | |
155 | new TColStd_HArray1OfBoolean(1, NbIntC2); | |
156 | TColStd_Array1OfReal AveFunc(1, NbIntC2); | |
157 | myCurve->Intervals(myC2Disc->ChangeArray1(), GeomAbs_C2); | |
158 | Standard_Integer NbControl = 10; | |
159 | Standard_Real Step, Average = 0, modulus; | |
160 | gp_Pnt C, C1; | |
161 | for(i = 1; i <= NbIntC2; i++) { | |
162 | Step = (myC2Disc->Value(i+1) - myC2Disc->Value(i))/NbControl; | |
163 | IsLin->ChangeValue(i) = Standard_True; | |
164 | IsConst->ChangeValue(i) = Standard_True; | |
165 | for(j = 1; j <= NbControl; j++) { | |
166 | Func.D0(myC2Disc->Value(i) + (j-1)*Step, C); | |
167 | if(j == 1) C1 = C; | |
168 | modulus = C.XYZ().Modulus(); | |
169 | if(modulus > Tol) { | |
170 | IsLin->ChangeValue(i) = Standard_False; | |
171 | } | |
172 | Average += modulus; | |
173 | ||
174 | if(IsConst->Value(i)) { | |
175 | if(Abs(C.X() - C1.X()) > Tol || | |
176 | Abs(C.Y() - C1.Y()) > Tol || | |
177 | Abs(C.Z() - C1.Z()) > Tol) { | |
178 | IsConst->ChangeValue(i) = Standard_False; | |
179 | } | |
180 | } | |
181 | ||
182 | } | |
183 | AveFunc(i) = Average/NbControl; | |
184 | } | |
185 | ||
186 | // Here we are looking for singularities | |
187 | TColStd_SequenceOfReal * SeqArray = new TColStd_SequenceOfReal[ NbIntC2 ]; | |
188 | TColStd_SequenceOfReal SnglSeq; | |
189 | // Standard_Real Value2, preValue=1.e200, t; | |
190 | Standard_Real Value2, t; | |
191 | Extrema_ExtPC Ext; | |
192 | gp_Pnt Origin(0, 0, 0); | |
193 | ||
194 | for(i = 1; i <= NbIntC2; i++) { | |
195 | if (!IsLin->Value(i) && !IsConst->Value(i)) | |
196 | { | |
197 | Func.SetRatio(1./AveFunc(i)); // Normalization | |
198 | Ext.Initialize(Func, myC2Disc->Value(i), myC2Disc->Value(i+1), TolF); | |
199 | Ext.Perform(Origin); | |
200 | if(Ext.IsDone() && Ext.NbExt() != 0) | |
201 | { | |
202 | for(j = 1; j <= Ext.NbExt(); j++) | |
203 | { | |
204 | Value2 = Ext.SquareDistance(j); | |
205 | if(Value2 < Tol2) | |
206 | { | |
207 | t = Ext.Point(j).Parameter(); | |
208 | SeqArray[i-1].Append(t); | |
209 | } | |
210 | } | |
211 | } | |
212 | // sorting | |
213 | if(SeqArray[i-1].Length() != 0) { | |
79a35943 | 214 | NCollection_Array1<Standard_Real> anArray( 1, SeqArray[i-1].Length() ); |
7fd59977 | 215 | for (j = 1; j <= anArray.Length(); j++) |
216 | anArray(j) = SeqArray[i-1](j); | |
79a35943 | 217 | std::sort (anArray.begin(), anArray.end()); |
7fd59977 | 218 | for (j = 1; j <= anArray.Length(); j++) |
219 | SeqArray[i-1](j) = anArray(j); | |
220 | } | |
221 | } | |
222 | } | |
223 | //Filling SnglSeq by first sets of roots | |
224 | for(i = 0; i < NbIntC2; i++) | |
225 | for (j = 1; j <= SeqArray[i].Length(); j++) | |
226 | SnglSeq.Append( SeqArray[i](j) ); | |
227 | ||
228 | //Extrema works bad, need to pass second time | |
229 | for(i = 0; i < NbIntC2; i++) | |
230 | if (! SeqArray[i].IsEmpty()) | |
231 | { | |
232 | SeqArray[i].Prepend( myC2Disc->Value(i+1) ); | |
233 | SeqArray[i].Append( myC2Disc->Value(i+2) ); | |
234 | Func.SetRatio(1./AveFunc(i+1)); // Normalization | |
235 | for (j = 1; j < SeqArray[i].Length(); j++) | |
236 | if (SeqArray[i](j+1) - SeqArray[i](j) > PTol) | |
237 | { | |
238 | Ext.Initialize(Func, SeqArray[i](j), SeqArray[i](j+1), TolF); | |
239 | Ext.Perform(Origin); | |
240 | if(Ext.IsDone()) | |
241 | { | |
242 | for(Standard_Integer k = 1; k <= Ext.NbExt(); k++) | |
243 | { | |
244 | Value2 = Ext.SquareDistance(k); | |
245 | if(Value2 < Tol2) | |
246 | { | |
247 | t = Ext.Point(k).Parameter(); | |
248 | if (t-SeqArray[i](j) > PTol && SeqArray[i](j+1)-t > PTol) | |
249 | SnglSeq.Append(t); | |
250 | } | |
251 | } | |
252 | } | |
253 | } | |
254 | } | |
255 | ||
256 | delete [] SeqArray; | |
257 | ||
258 | if(SnglSeq.Length() > 0) { | |
259 | // sorting | |
79a35943 | 260 | NCollection_Array1<Standard_Real> anArray( 1, SnglSeq.Length() ); |
7fd59977 | 261 | for (i = 1; i <= SnglSeq.Length(); i++) |
262 | anArray(i) = SnglSeq(i); | |
79a35943 | 263 | std::sort (anArray.begin(), anArray.end()); |
7fd59977 | 264 | for (i = 1; i <= SnglSeq.Length(); i++) |
265 | SnglSeq(i) = anArray(i); | |
266 | ||
267 | // discard repeating elements | |
268 | Standard_Boolean found = Standard_True; | |
269 | j = 1; | |
270 | while (found) | |
271 | { | |
272 | found = Standard_False; | |
273 | for (i = j; i < SnglSeq.Length(); i++) | |
274 | if (SnglSeq(i+1) - SnglSeq(i) <= PTol) | |
275 | { | |
276 | SnglSeq.Remove(i+1); | |
277 | j = i; | |
278 | found = Standard_True; | |
279 | break; | |
280 | } | |
281 | } | |
282 | ||
283 | mySngl = new TColStd_HArray1OfReal(1, SnglSeq.Length()); | |
284 | for(i = 1; i <= mySngl->Length(); i++) | |
285 | mySngl->ChangeValue(i) = SnglSeq(i); | |
286 | ||
287 | // computation of length of singular interval | |
288 | mySnglLen = new TColStd_HArray1OfReal(1, mySngl->Length()); | |
289 | gp_Vec SnglDer, SnglDer2; | |
290 | Standard_Real norm; | |
291 | for(i = 1; i <= mySngl->Length(); i++) { | |
292 | Func.D2(mySngl->Value(i), C, SnglDer, SnglDer2); | |
293 | if ((norm = SnglDer.Magnitude()) > gp::Resolution()) | |
294 | mySnglLen->ChangeValue(i) = Min(NullTol/norm, MaxSingular); | |
295 | else if ((norm = SnglDer2.Magnitude()) > gp::Resolution()) | |
296 | mySnglLen->ChangeValue(i) = Min(Sqrt(2*NullTol/norm), MaxSingular); | |
297 | else mySnglLen->ChangeValue(i) = MaxSingular; | |
298 | } | |
299 | #if DEB | |
300 | for(i = 1; i <= mySngl->Length(); i++) { | |
301 | cout<<"Sngl("<<i<<") = "<<mySngl->Value(i)<<" Length = "<<mySnglLen->Value(i)<<endl; | |
302 | } | |
303 | #endif | |
304 | if(mySngl->Length() > 1) { | |
305 | // we have to merge singular points that have common parts of singular intervals | |
306 | TColgp_SequenceOfPnt2d tmpSeq; | |
307 | tmpSeq.Append(gp_Pnt2d(mySngl->Value(1), mySnglLen->Value(1))); | |
308 | Standard_Real U11, U12, U21, U22; | |
309 | for(i = 2; i<= mySngl->Length(); i++) { | |
310 | U12 = tmpSeq.Last().X() + tmpSeq.Last().Y(); | |
311 | U21 = mySngl->Value(i) - mySnglLen->Value(i); | |
312 | if(U12 >= U21) { | |
313 | U11 = tmpSeq.Last().X() - tmpSeq.Last().Y(); | |
314 | U22 = mySngl->Value(i) + mySnglLen->Value(i); | |
315 | tmpSeq.ChangeValue(tmpSeq.Length()) = gp_Pnt2d((U11 + U22)/2, (U22 - U11)/2); | |
316 | } | |
317 | else tmpSeq.Append(gp_Pnt2d(mySngl->Value(i), mySnglLen->Value(i))); | |
318 | } | |
319 | mySngl = new TColStd_HArray1OfReal(1, tmpSeq.Length()); | |
320 | mySnglLen = new TColStd_HArray1OfReal(1, tmpSeq.Length()); | |
321 | for(i = 1; i <= mySngl->Length(); i++) { | |
322 | mySngl->ChangeValue(i) = tmpSeq(i).X(); | |
323 | mySnglLen->ChangeValue(i) = tmpSeq(i).Y(); | |
324 | } | |
325 | } | |
326 | #if DEB | |
327 | cout<<"After merging"<<endl; | |
328 | for(i = 1; i <= mySngl->Length(); i++) { | |
329 | cout<<"Sngl("<<i<<") = "<<mySngl->Value(i)<<" Length = "<<mySnglLen->Value(i)<<endl; | |
330 | } | |
331 | #endif | |
332 | isSngl = Standard_True; | |
333 | } | |
334 | else isSngl = Standard_False; | |
335 | } | |
336 | ||
32ca7a51 | 337 | //======================================================================= |
338 | //function : RotateTrihedron | |
339 | //purpose : This function revolves the trihedron (which is determined of | |
340 | // given "Tangent", "Normal" and "BiNormal" vectors) | |
341 | // to coincide "Tangent" and "NewTangent" axes. | |
342 | //======================================================================= | |
343 | Standard_Boolean | |
344 | GeomFill_Frenet::RotateTrihedron( gp_Vec& Tangent, | |
345 | gp_Vec& Normal, | |
346 | gp_Vec& BiNormal, | |
347 | const gp_Vec& NewTangent) const | |
348 | { | |
349 | const Standard_Real anInfCOS = cos(Precision::Angular()); //0.99999995 | |
350 | const Standard_Real aTol = gp::Resolution(); | |
351 | ||
352 | gp_Vec anAxis = Tangent.Crossed(NewTangent); | |
353 | const Standard_Real NT = anAxis.Magnitude(); | |
354 | if(NT <= aTol) | |
355 | //No rotation required | |
356 | return Standard_True; | |
357 | else | |
358 | anAxis /= NT; //Normalization | |
359 | ||
360 | const Standard_Real aPx = anAxis.X(), aPy = anAxis.Y(), aPz = anAxis.Z(); | |
361 | const Standard_Real aCAng = CosAngle(Tangent,NewTangent); //cosine | |
362 | ||
363 | const Standard_Real anAddCAng = 1.0 - aCAng; | |
364 | const Standard_Real aSAng = sqrt(1.0 - aCAng*aCAng); //sine | |
365 | ||
366 | //According to rotate direction, sine of rotation angle might be | |
367 | //positive or negative. | |
368 | //We can research to choose necessary sign. But I think, it is more | |
369 | //effectively, to rotate "Tangent" vector in both direction. After that | |
370 | //we can choose necessary rotation direction in depend of results. | |
371 | ||
372 | const gp_Vec aV11(anAddCAng*aPx*aPx+aCAng, anAddCAng*aPx*aPy-aPz*aSAng, anAddCAng*aPx*aPz+aPy*aSAng); | |
373 | const gp_Vec aV12(anAddCAng*aPx*aPx+aCAng, anAddCAng*aPx*aPy+aPz*aSAng, anAddCAng*aPx*aPz-aPy*aSAng); | |
374 | const gp_Vec aV21(anAddCAng*aPx*aPy+aPz*aSAng, anAddCAng*aPy*aPy+aCAng, anAddCAng*aPy*aPz-aPx*aSAng); | |
375 | const gp_Vec aV22(anAddCAng*aPx*aPy-aPz*aSAng, anAddCAng*aPy*aPy+aCAng, anAddCAng*aPy*aPz+aPx*aSAng); | |
376 | const gp_Vec aV31(anAddCAng*aPx*aPz-aPy*aSAng, anAddCAng*aPy*aPz+aPx*aSAng, anAddCAng*aPz*aPz+aCAng); | |
377 | const gp_Vec aV32(anAddCAng*aPx*aPz+aPy*aSAng, anAddCAng*aPy*aPz-aPx*aSAng, anAddCAng*aPz*aPz+aCAng); | |
378 | ||
379 | gp_Vec aT1(Tangent.Dot(aV11), Tangent.Dot(aV21), Tangent.Dot(aV31)); | |
380 | gp_Vec aT2(Tangent.Dot(aV12), Tangent.Dot(aV22), Tangent.Dot(aV32)); | |
381 | ||
382 | if(CosAngle(aT1,NewTangent) >= CosAngle(aT2,NewTangent)) | |
383 | { | |
384 | Tangent = aT1; | |
385 | Normal = gp_Vec(Normal.Dot(aV11), Normal.Dot(aV21), Normal.Dot(aV31)); | |
386 | BiNormal = gp_Vec(BiNormal.Dot(aV11), BiNormal.Dot(aV21), BiNormal.Dot(aV31)); | |
387 | } | |
388 | else | |
389 | { | |
390 | Tangent = aT2; | |
391 | Normal = gp_Vec(Normal.Dot(aV12), Normal.Dot(aV22), Normal.Dot(aV32)); | |
392 | BiNormal = gp_Vec(BiNormal.Dot(aV12), BiNormal.Dot(aV22), BiNormal.Dot(aV32)); | |
393 | } | |
394 | ||
395 | return CosAngle(Tangent,NewTangent) >= anInfCOS; | |
396 | } | |
397 | ||
398 | ||
7fd59977 | 399 | //======================================================================= |
400 | //function : D0 | |
401 | //purpose : | |
402 | //======================================================================= | |
403 | ||
32ca7a51 | 404 | Standard_Boolean GeomFill_Frenet::D0(const Standard_Real theParam, |
7fd59977 | 405 | gp_Vec& Tangent, |
406 | gp_Vec& Normal, | |
407 | gp_Vec& BiNormal) | |
408 | { | |
32ca7a51 | 409 | const Standard_Real aTol = gp::Resolution(); |
410 | ||
7fd59977 | 411 | Standard_Real norm; |
412 | Standard_Integer Index; | |
a31abc03 | 413 | Standard_Real Delta = 0.; |
32ca7a51 | 414 | if(IsSingular(theParam, Index)) |
415 | if (SingularD0(theParam, Index, Tangent, Normal, BiNormal, Delta)) | |
7fd59977 | 416 | return Standard_True; |
417 | ||
32ca7a51 | 418 | Standard_Real aParam = theParam + Delta; |
419 | myTrimmed->D2(aParam, P, Tangent, BiNormal); | |
420 | ||
421 | const Standard_Real DivisionFactor = 1.e-3; | |
422 | const Standard_Real anUinfium = myTrimmed->FirstParameter(); | |
423 | const Standard_Real anUsupremum = myTrimmed->LastParameter(); | |
424 | const Standard_Real aDelta = (anUsupremum - anUinfium)*DivisionFactor; | |
425 | Standard_Real Ndu = Tangent.Magnitude(); | |
426 | ||
427 | ////////////////////////////////////////////////////////////////////////////////////////////////////// | |
428 | if(Ndu <= aTol) | |
429 | { | |
430 | gp_Vec aTn; | |
431 | //Derivative is approximated by Taylor-series | |
432 | ||
433 | Standard_Integer anIndex = 1; //Derivative order | |
434 | Standard_Boolean isDeriveFound = Standard_False; | |
435 | ||
436 | do | |
437 | { | |
438 | aTn = myTrimmed->DN(theParam,++anIndex); | |
439 | Ndu = aTn.Magnitude(); | |
440 | isDeriveFound = Ndu > aTol; | |
441 | } | |
442 | while(!isDeriveFound && anIndex < maxDerivOrder); | |
7fd59977 | 443 | |
32ca7a51 | 444 | if(isDeriveFound) |
445 | { | |
446 | Standard_Real u; | |
447 | ||
448 | if(theParam-anUinfium < aDelta) | |
449 | u = theParam+aDelta; | |
450 | else | |
451 | u = theParam-aDelta; | |
452 | ||
453 | gp_Pnt P1, P2; | |
454 | myTrimmed->D0(Min(theParam, u),P1); | |
455 | myTrimmed->D0(Max(theParam, u),P2); | |
456 | ||
457 | gp_Vec V1(P1,P2); | |
458 | Standard_Real aDirFactor = aTn.Dot(V1); | |
459 | ||
460 | if(aDirFactor < 0.0) | |
461 | aTn = -aTn; | |
462 | }//if(IsDeriveFound) | |
463 | else | |
464 | { | |
465 | //Derivative is approximated by three points | |
466 | ||
467 | gp_Pnt Ptemp(0.0,0.0,0.0); //(0,0,0)-coordinate | |
468 | gp_Pnt P1, P2, P3; | |
469 | Standard_Boolean IsParameterGrown; | |
470 | ||
471 | if(theParam-anUinfium < 2*aDelta) | |
472 | { | |
473 | myTrimmed->D0(theParam,P1); | |
474 | myTrimmed->D0(theParam+aDelta,P2); | |
475 | myTrimmed->D0(theParam+2*aDelta,P3); | |
476 | IsParameterGrown = Standard_True; | |
477 | } | |
478 | else | |
479 | { | |
480 | myTrimmed->D0(theParam-2*aDelta,P1); | |
481 | myTrimmed->D0(theParam-aDelta,P2); | |
482 | myTrimmed->D0(theParam,P3); | |
483 | IsParameterGrown = Standard_False; | |
484 | } | |
485 | ||
486 | gp_Vec V1(Ptemp,P1), V2(Ptemp,P2), V3(Ptemp,P3); | |
487 | ||
488 | if(IsParameterGrown) | |
489 | aTn=-3*V1+4*V2-V3; | |
490 | else | |
491 | aTn=V1-4*V2+3*V3; | |
492 | }//else of "if(IsDeriveFound)" condition | |
493 | Ndu = aTn.Magnitude(); | |
494 | gp_Pnt Pt = P; | |
495 | Standard_Real dPar = 10.0*aDelta; | |
496 | ||
497 | //Recursive calling is used for determine of trihedron for | |
498 | //point, which is near to given. | |
499 | if(theParam-anUinfium < dPar) | |
500 | { | |
501 | if(D0(aParam+dPar,Tangent,Normal,BiNormal) == Standard_False) | |
502 | return Standard_False; | |
503 | } | |
504 | else | |
505 | { | |
506 | if(D0(aParam-dPar,Tangent,Normal,BiNormal) == Standard_False) | |
507 | return Standard_False; | |
508 | } | |
509 | ||
510 | P = Pt; | |
511 | ||
512 | if(RotateTrihedron(Tangent,Normal,BiNormal,aTn) == Standard_False) | |
513 | { | |
514 | #ifdef DEB | |
515 | cout << "Cannot coincide two tangents." << endl; | |
516 | #endif | |
517 | return Standard_False; | |
518 | } | |
519 | }//if(Ndu <= aTol) | |
520 | else | |
521 | { | |
522 | Tangent = Tangent/Ndu; | |
523 | BiNormal = Tangent.Crossed(BiNormal); | |
524 | norm = BiNormal.Magnitude(); | |
525 | if (norm <= gp::Resolution()) | |
526 | { | |
527 | gp_Ax2 Axe (gp_Pnt(0,0,0), Tangent); | |
528 | BiNormal.SetXYZ(Axe.YDirection().XYZ()); | |
529 | } | |
530 | else | |
531 | BiNormal.Normalize(); | |
532 | ||
533 | Normal = BiNormal; | |
534 | Normal.Cross(Tangent); | |
535 | } | |
7fd59977 | 536 | |
537 | return Standard_True; | |
538 | } | |
539 | ||
540 | //======================================================================= | |
541 | //function : D1 | |
542 | //purpose : | |
543 | //======================================================================= | |
544 | ||
545 | Standard_Boolean GeomFill_Frenet::D1(const Standard_Real Param, | |
546 | gp_Vec& Tangent, | |
547 | gp_Vec& DTangent, | |
548 | gp_Vec& Normal, | |
549 | gp_Vec& DNormal, | |
550 | gp_Vec& BiNormal, | |
551 | gp_Vec& DBiNormal) | |
552 | { | |
553 | Standard_Integer Index; | |
a31abc03 | 554 | Standard_Real Delta = 0.; |
7fd59977 | 555 | if(IsSingular(Param, Index)) |
a31abc03 | 556 | if (SingularD1(Param, Index, Tangent, DTangent, Normal, DNormal, BiNormal, DBiNormal, Delta)) |
7fd59977 | 557 | return Standard_True; |
558 | ||
559 | // Standard_Real Norma; | |
a31abc03 | 560 | Standard_Real theParam = Param + Delta; |
7fd59977 | 561 | gp_Vec DC1, DC2, DC3; |
a31abc03 | 562 | myTrimmed->D3(theParam, P, DC1, DC2, DC3); |
7fd59977 | 563 | Tangent = DC1.Normalized(); |
564 | ||
565 | //if (DC2.Magnitude() <= NullTol || Tangent.Crossed(DC2).Magnitude() <= NullTol) { | |
566 | if (Tangent.Crossed(DC2).Magnitude() <= gp::Resolution()) { | |
567 | gp_Ax2 Axe (gp_Pnt(0,0,0), Tangent); | |
568 | Normal.SetXYZ(Axe.XDirection().XYZ()); | |
569 | BiNormal.SetXYZ(Axe.YDirection().XYZ()); | |
570 | DTangent.SetCoord(0,0,0); | |
571 | DNormal.SetCoord(0,0,0); | |
572 | DBiNormal.SetCoord(0,0,0); | |
573 | return Standard_True; | |
574 | } | |
575 | else | |
576 | BiNormal = Tangent.Crossed(DC2).Normalized(); | |
577 | ||
578 | Normal = BiNormal.Crossed(Tangent); | |
579 | ||
580 | DTangent = FDeriv(DC1, DC2); | |
581 | ||
582 | gp_Vec instead_DC1, instead_DC2; | |
583 | instead_DC1 = Tangent.Crossed(DC2); | |
584 | instead_DC2 = DTangent.Crossed(DC2) + Tangent.Crossed(DC3); | |
585 | DBiNormal = FDeriv(instead_DC1, instead_DC2); | |
586 | ||
587 | DNormal = DBiNormal.Crossed(Tangent) + BiNormal.Crossed(DTangent); | |
588 | return Standard_True; | |
589 | } | |
590 | ||
591 | //======================================================================= | |
592 | //function : D2 | |
593 | //purpose : | |
594 | //======================================================================= | |
595 | ||
596 | Standard_Boolean GeomFill_Frenet::D2(const Standard_Real Param, | |
597 | gp_Vec& Tangent, | |
598 | gp_Vec& DTangent, | |
599 | gp_Vec& D2Tangent, | |
600 | gp_Vec& Normal, | |
601 | gp_Vec& DNormal, | |
602 | gp_Vec& D2Normal, | |
603 | gp_Vec& BiNormal, | |
604 | gp_Vec& DBiNormal, | |
605 | gp_Vec& D2BiNormal) | |
606 | { | |
607 | Standard_Integer Index; | |
a31abc03 | 608 | Standard_Real Delta = 0.; |
7fd59977 | 609 | if(IsSingular(Param, Index)) |
610 | if(SingularD2(Param, Index, Tangent, DTangent, D2Tangent, | |
611 | Normal, DNormal, D2Normal, | |
a31abc03 | 612 | BiNormal, DBiNormal, D2BiNormal, |
613 | Delta)) | |
7fd59977 | 614 | return Standard_True; |
615 | ||
616 | // Standard_Real Norma; | |
a31abc03 | 617 | Standard_Real theParam = Param + Delta; |
7fd59977 | 618 | gp_Vec DC1, DC2, DC3, DC4; |
a31abc03 | 619 | myTrimmed->D3(theParam, P, DC1, DC2, DC3); |
620 | DC4 = myTrimmed->DN(theParam, 4); | |
7fd59977 | 621 | |
622 | Tangent = DC1.Normalized(); | |
623 | ||
624 | //if (DC2.Magnitude() <= NullTol || Tangent.Crossed(DC2).Magnitude() <= NullTol) { | |
625 | if (Tangent.Crossed(DC2).Magnitude() <= gp::Resolution()) { | |
626 | gp_Ax2 Axe (gp_Pnt(0,0,0), Tangent); | |
627 | Normal.SetXYZ(Axe.XDirection().XYZ()); | |
628 | BiNormal.SetXYZ(Axe.YDirection().XYZ()); | |
629 | DTangent.SetCoord(0,0,0); | |
630 | DNormal.SetCoord(0,0,0); | |
631 | DBiNormal.SetCoord(0,0,0); | |
632 | D2Tangent.SetCoord(0,0,0); | |
633 | D2Normal.SetCoord(0,0,0); | |
634 | D2BiNormal.SetCoord(0,0,0); | |
635 | return Standard_True; | |
636 | } | |
637 | else | |
638 | BiNormal = Tangent.Crossed(DC2).Normalized(); | |
639 | ||
640 | Normal = BiNormal.Crossed(Tangent); | |
641 | ||
642 | DTangent = FDeriv(DC1, DC2); | |
643 | D2Tangent = DDeriv(DC1, DC2, DC3); | |
644 | ||
645 | gp_Vec instead_DC1, instead_DC2, instead_DC3; | |
646 | instead_DC1 = Tangent.Crossed(DC2); | |
647 | instead_DC2 = DTangent.Crossed(DC2) + Tangent.Crossed(DC3); | |
648 | instead_DC3 = D2Tangent.Crossed(DC2) + 2*DTangent.Crossed(DC3) + Tangent.Crossed(DC4); | |
649 | DBiNormal = FDeriv(instead_DC1, instead_DC2); | |
650 | D2BiNormal = DDeriv(instead_DC1, instead_DC2, instead_DC3); | |
651 | ||
652 | DNormal = DBiNormal.Crossed(Tangent) + BiNormal.Crossed(DTangent); | |
653 | ||
654 | D2Normal = D2BiNormal.Crossed(Tangent) + 2*DBiNormal.Crossed(DTangent) + BiNormal.Crossed(D2Tangent); | |
655 | ||
656 | return Standard_True; | |
657 | } | |
658 | ||
659 | //======================================================================= | |
660 | //function : NbIntervals | |
661 | //purpose : | |
662 | //======================================================================= | |
663 | ||
664 | Standard_Integer GeomFill_Frenet::NbIntervals(const GeomAbs_Shape S) const | |
665 | { | |
666 | GeomAbs_Shape tmpS = GeomAbs_C0; | |
667 | Standard_Integer NbTrimmed; | |
668 | switch (S) { | |
669 | case GeomAbs_C0: tmpS = GeomAbs_C2; break; | |
670 | case GeomAbs_C1: tmpS = GeomAbs_C3; break; | |
671 | case GeomAbs_C2: | |
672 | case GeomAbs_C3: | |
673 | case GeomAbs_CN: tmpS = GeomAbs_CN; break; | |
674 | default: Standard_OutOfRange::Raise(); | |
675 | } | |
676 | ||
677 | NbTrimmed = myCurve->NbIntervals(tmpS); | |
678 | ||
679 | if (!isSngl) return NbTrimmed; | |
680 | ||
681 | TColStd_Array1OfReal TrimInt(1, NbTrimmed + 1); | |
682 | myCurve->Intervals(TrimInt, tmpS); | |
683 | ||
684 | TColStd_SequenceOfReal Fusion; | |
685 | GeomLib::FuseIntervals(TrimInt, mySngl->Array1(), Fusion); | |
686 | ||
687 | return Fusion.Length() - 1; | |
688 | } | |
689 | ||
690 | //======================================================================= | |
691 | //function : Intervals | |
692 | //purpose : | |
693 | //======================================================================= | |
694 | ||
695 | void GeomFill_Frenet::Intervals(TColStd_Array1OfReal& T, | |
696 | const GeomAbs_Shape S) const | |
697 | { | |
698 | GeomAbs_Shape tmpS = GeomAbs_C0; | |
699 | Standard_Integer NbTrimmed; | |
700 | switch (S) { | |
701 | case GeomAbs_C0: tmpS = GeomAbs_C2; break; | |
702 | case GeomAbs_C1: tmpS = GeomAbs_C3; break; | |
703 | case GeomAbs_C2: | |
704 | case GeomAbs_C3: | |
705 | case GeomAbs_CN: tmpS = GeomAbs_CN; break; | |
706 | default: Standard_OutOfRange::Raise(); | |
707 | } | |
708 | ||
709 | if (!isSngl) { | |
710 | myCurve->Intervals(T, tmpS); | |
711 | return; | |
712 | } | |
713 | ||
714 | NbTrimmed = myCurve->NbIntervals(tmpS); | |
715 | TColStd_Array1OfReal TrimInt(1, NbTrimmed + 1); | |
716 | myCurve->Intervals(TrimInt, tmpS); | |
717 | ||
718 | TColStd_SequenceOfReal Fusion; | |
719 | GeomLib::FuseIntervals(TrimInt, mySngl->Array1(), Fusion); | |
720 | ||
721 | for (Standard_Integer i = 1; i <= Fusion.Length(); i++) | |
722 | T.ChangeValue(i) = Fusion.Value(i); | |
723 | } | |
724 | ||
725 | void GeomFill_Frenet::GetAverageLaw(gp_Vec& ATangent, | |
726 | gp_Vec& ANormal, | |
727 | gp_Vec& ABiNormal) | |
728 | { | |
729 | Standard_Integer Num = 20; //order of digitalization | |
730 | gp_Vec T, N, BN; | |
731 | ATangent = gp_Vec(0, 0, 0); | |
732 | ANormal = gp_Vec(0, 0, 0); | |
733 | ABiNormal = gp_Vec(0, 0, 0); | |
734 | Standard_Real Step = (myTrimmed->LastParameter() - | |
735 | myTrimmed->FirstParameter()) / Num; | |
736 | Standard_Real Param; | |
737 | for (Standard_Integer i = 0; i <= Num; i++) { | |
738 | Param = myTrimmed->FirstParameter() + i*Step; | |
739 | if (Param > myTrimmed->LastParameter()) Param = myTrimmed->LastParameter(); | |
740 | D0(Param, T, N, BN); | |
741 | ATangent += T; | |
742 | ANormal += N; | |
743 | ABiNormal += BN; | |
744 | } | |
745 | ATangent /= Num + 1; | |
746 | ANormal /= Num + 1; | |
747 | ||
748 | ATangent.Normalize(); | |
749 | ABiNormal = ATangent.Crossed(ANormal).Normalized(); | |
750 | ANormal = ABiNormal.Crossed(ATangent); | |
751 | } | |
752 | ||
753 | //======================================================================= | |
754 | //function : IsConstant | |
755 | //purpose : | |
756 | //======================================================================= | |
757 | ||
758 | Standard_Boolean GeomFill_Frenet::IsConstant() const | |
759 | { | |
760 | return (myCurve->GetType() == GeomAbs_Line); | |
761 | } | |
762 | ||
763 | //======================================================================= | |
764 | //function : IsOnlyBy3dCurve | |
765 | //purpose : | |
766 | //======================================================================= | |
767 | ||
768 | Standard_Boolean GeomFill_Frenet::IsOnlyBy3dCurve() const | |
769 | { | |
770 | return Standard_True; | |
771 | } | |
772 | ||
773 | //======================================================================= | |
774 | //function : IsSingular | |
775 | //purpose : | |
776 | //======================================================================= | |
777 | ||
778 | Standard_Boolean GeomFill_Frenet::IsSingular(const Standard_Real U, Standard_Integer& Index) const | |
779 | { | |
780 | Standard_Integer i; | |
781 | if(!isSngl) return Standard_False; | |
782 | for(i = 1; i <= mySngl->Length(); i++) { | |
783 | if (Abs(U - mySngl->Value(i)) < mySnglLen->Value(i)) { | |
784 | Index = i; | |
785 | return Standard_True; | |
786 | } | |
787 | } | |
788 | return Standard_False; | |
789 | } | |
790 | ||
791 | //======================================================================= | |
792 | //function : DoSingular | |
793 | //purpose : | |
794 | //======================================================================= | |
795 | ||
796 | Standard_Boolean GeomFill_Frenet::DoSingular(const Standard_Real U, | |
797 | const Standard_Integer Index, | |
798 | gp_Vec& Tangent, | |
799 | gp_Vec& BiNormal, | |
800 | Standard_Integer& n, | |
801 | Standard_Integer& k, | |
802 | Standard_Integer& TFlag, | |
a31abc03 | 803 | Standard_Integer& BNFlag, |
804 | Standard_Real& Delta) | |
7fd59977 | 805 | { |
806 | Standard_Integer i, MaxN = 20; | |
a31abc03 | 807 | Delta = 0.; |
7fd59977 | 808 | Standard_Real h; |
809 | h = 2*mySnglLen->Value(Index); | |
810 | ||
811 | Standard_Real A, B; | |
812 | gp_Vec T, N, BN; | |
813 | TFlag = 1; | |
814 | BNFlag = 1; | |
815 | GetInterval(A, B); | |
a31abc03 | 816 | if (U >= (A + B)/2) |
817 | h = -h; | |
7fd59977 | 818 | for(i = 1; i <= MaxN; i++) { |
819 | Tangent = myTrimmed->DN(U, i); | |
820 | if(Tangent.Magnitude() > Precision::Confusion()) break; | |
821 | } | |
822 | if (i > MaxN) return Standard_False; | |
823 | Tangent.Normalize(); | |
824 | n = i; | |
825 | ||
826 | i++; | |
827 | for(; i <= MaxN; i++) { | |
828 | BiNormal = Tangent.Crossed(myTrimmed->DN(U, i)); | |
829 | Standard_Real magn = BiNormal.Magnitude(); | |
830 | if (magn > Precision::Confusion()) | |
831 | { | |
832 | //modified by jgv, 12.08.03 for OCC605 //// | |
833 | gp_Vec NextBiNormal = Tangent.Crossed(myTrimmed->DN(U, i+1)); | |
834 | if (NextBiNormal.Magnitude() > magn) | |
835 | { | |
836 | i++; | |
837 | BiNormal = NextBiNormal; | |
838 | } | |
839 | /////////////////////////////////////////// | |
840 | break; | |
841 | } | |
842 | } | |
a31abc03 | 843 | if (i > MaxN) |
844 | { | |
845 | Delta = h; | |
846 | return Standard_False; | |
847 | } | |
848 | ||
7fd59977 | 849 | BiNormal.Normalize(); |
850 | k = i; | |
851 | ||
852 | D0(U + h, T, N, BN); | |
853 | ||
c6541a0c D |
854 | if(Tangent.Angle(T) > M_PI/2) TFlag = -1; |
855 | if(BiNormal.Angle(BN) > M_PI/2) BNFlag = -1; | |
7fd59977 | 856 | |
857 | return Standard_True; | |
858 | } | |
859 | ||
860 | Standard_Boolean GeomFill_Frenet::SingularD0(const Standard_Real Param, | |
861 | const Standard_Integer Index, | |
862 | gp_Vec& Tangent, | |
863 | gp_Vec& Normal, | |
a31abc03 | 864 | gp_Vec& BiNormal, |
865 | Standard_Real& Delta) | |
7fd59977 | 866 | { |
867 | Standard_Integer n, k, TFlag, BNFlag; | |
868 | if(!DoSingular(Param, Index, Tangent, BiNormal, | |
a31abc03 | 869 | n, k, TFlag, BNFlag, Delta)) |
870 | return Standard_False; | |
871 | ||
7fd59977 | 872 | Tangent *= TFlag; |
873 | BiNormal *= BNFlag; | |
874 | Normal = BiNormal; | |
875 | Normal.Cross(Tangent); | |
876 | ||
877 | return Standard_True; | |
878 | } | |
879 | ||
880 | Standard_Boolean GeomFill_Frenet::SingularD1(const Standard_Real Param, | |
881 | const Standard_Integer Index, | |
882 | gp_Vec& Tangent,gp_Vec& DTangent, | |
883 | gp_Vec& Normal,gp_Vec& DNormal, | |
a31abc03 | 884 | gp_Vec& BiNormal,gp_Vec& DBiNormal, |
885 | Standard_Real& Delta) | |
7fd59977 | 886 | { |
887 | Standard_Integer n, k, TFlag, BNFlag; | |
a31abc03 | 888 | if(!DoSingular(Param, Index, Tangent, BiNormal, n, k, TFlag, BNFlag, Delta)) |
889 | return Standard_False; | |
7fd59977 | 890 | |
891 | gp_Vec F, DF, Dtmp; | |
892 | F = myTrimmed->DN(Param, n); | |
893 | DF = myTrimmed->DN(Param, n+1); | |
894 | DTangent = FDeriv(F, DF); | |
895 | ||
896 | Dtmp = myTrimmed->DN(Param, k); | |
897 | F = Tangent.Crossed(Dtmp); | |
898 | DF = DTangent.Crossed(Dtmp) + Tangent.Crossed(myTrimmed->DN(Param, k+1)); | |
899 | DBiNormal = FDeriv(F, DF); | |
900 | ||
901 | if(TFlag < 0) { | |
902 | Tangent = -Tangent; | |
903 | DTangent = -DTangent; | |
904 | } | |
905 | ||
906 | if(BNFlag < 0) { | |
907 | BiNormal = -BiNormal; | |
908 | DBiNormal = -DBiNormal; | |
909 | } | |
910 | ||
911 | Normal = BiNormal.Crossed(Tangent); | |
912 | DNormal = DBiNormal.Crossed(Tangent) + BiNormal.Crossed(DTangent); | |
913 | ||
914 | return Standard_True; | |
915 | } | |
916 | ||
917 | Standard_Boolean GeomFill_Frenet::SingularD2(const Standard_Real Param, | |
918 | const Standard_Integer Index, | |
919 | gp_Vec& Tangent, | |
920 | gp_Vec& DTangent, | |
921 | gp_Vec& D2Tangent, | |
922 | gp_Vec& Normal, | |
923 | gp_Vec& DNormal, | |
924 | gp_Vec& D2Normal, | |
925 | gp_Vec& BiNormal, | |
926 | gp_Vec& DBiNormal, | |
a31abc03 | 927 | gp_Vec& D2BiNormal, |
928 | Standard_Real& Delta) | |
7fd59977 | 929 | { |
930 | Standard_Integer n, k, TFlag, BNFlag; | |
a31abc03 | 931 | if(!DoSingular(Param, Index, Tangent, BiNormal, n, k, TFlag, BNFlag, Delta)) |
7fd59977 | 932 | return Standard_False; |
933 | ||
934 | gp_Vec F, DF, D2F, Dtmp1, Dtmp2; | |
935 | F = myTrimmed->DN(Param, n); | |
936 | DF = myTrimmed->DN(Param, n+1); | |
937 | D2F = myTrimmed->DN(Param, n+2); | |
938 | DTangent = FDeriv(F, DF); | |
939 | D2Tangent = DDeriv(F, DF, D2F); | |
940 | ||
941 | Dtmp1 = myTrimmed->DN(Param, k); | |
942 | Dtmp2 = myTrimmed->DN(Param, k+1); | |
943 | F = Tangent.Crossed(Dtmp1); | |
944 | DF = DTangent.Crossed(Dtmp1) + Tangent.Crossed(Dtmp2); | |
945 | D2F = D2Tangent.Crossed(Dtmp1) + 2*DTangent.Crossed(Dtmp2) + | |
946 | Tangent.Crossed(myTrimmed->DN(Param, k+2)); | |
947 | DBiNormal = FDeriv(F, DF); | |
948 | D2BiNormal = DDeriv(F, DF, D2F); | |
949 | ||
950 | if(TFlag < 0) { | |
951 | Tangent = -Tangent; | |
952 | DTangent = -DTangent; | |
953 | D2Tangent = -D2Tangent; | |
954 | } | |
955 | ||
956 | if(BNFlag < 0) { | |
957 | BiNormal = -BiNormal; | |
958 | DBiNormal = -DBiNormal; | |
959 | D2BiNormal = -D2BiNormal; | |
960 | } | |
961 | ||
962 | Normal = BiNormal.Crossed(Tangent); | |
963 | DNormal = DBiNormal.Crossed(Tangent) + BiNormal.Crossed(DTangent); | |
964 | D2Normal = D2BiNormal.Crossed(Tangent) + 2*DBiNormal.Crossed(DTangent) + BiNormal.Crossed(D2Tangent); | |
965 | ||
966 | return Standard_True; | |
967 | } |