b311480e |
1 | // Created on: 1996-06-07 |
2 | // Created by: Philippe MANGIN |
3 | // Copyright (c) 1996-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 | |
7fd59977 |
17 | |
7fd59977 |
18 | #include <Geom_BezierSurface.hxx> |
42cf5bc1 |
19 | #include <Geom_BSplineSurface.hxx> |
7fd59977 |
20 | #include <Geom_Curve.hxx> |
42cf5bc1 |
21 | #include <GeomConvert_CompBezierSurfacesToBSplineSurface.hxx> |
7fd59977 |
22 | #include <gp_Pnt.hxx> |
23 | #include <gp_Vec.hxx> |
42cf5bc1 |
24 | #include <gp_XYZ.hxx> |
7fd59977 |
25 | #include <Precision.hxx> |
42cf5bc1 |
26 | #include <Standard_ConstructionError.hxx> |
27 | #include <Standard_DimensionError.hxx> |
28 | #include <Standard_NotImplemented.hxx> |
29 | #include <TColGeom_Array2OfBezierSurface.hxx> |
30 | #include <TColgp_HArray2OfPnt.hxx> |
31 | #include <TColStd_HArray1OfReal.hxx> |
7fd59977 |
32 | |
33 | // ============================================================================ |
34 | GeomConvert_CompBezierSurfacesToBSplineSurface:: |
35 | GeomConvert_CompBezierSurfacesToBSplineSurface(const TColGeom_Array2OfBezierSurface& Beziers) |
36 | // ============================================================================ |
37 | { |
38 | Standard_Integer ii; |
39 | myDone = Standard_True; |
40 | // Choix des noeuds |
41 | myUKnots = new (TColStd_HArray1OfReal) (1, Beziers.ColLength()+1); |
42 | for (ii=0; ii<myUKnots->Length(); ii++) { myUKnots->SetValue(ii+1, ii); } |
43 | |
44 | myVKnots = new (TColStd_HArray1OfReal) (1, Beziers.RowLength()+1); |
45 | for (ii=0; ii<myVKnots->Length(); ii++) { myVKnots->SetValue(ii+1, ii); } |
46 | |
47 | // Calcul des Poles |
48 | Perform(Beziers); |
49 | } |
50 | |
51 | |
52 | // ============================================================================ |
53 | GeomConvert_CompBezierSurfacesToBSplineSurface:: |
54 | GeomConvert_CompBezierSurfacesToBSplineSurface( |
55 | const TColGeom_Array2OfBezierSurface& Beziers, |
56 | const Standard_Real Tolerance, |
57 | const Standard_Boolean RemoveKnots) |
58 | // ============================================================================ |
59 | { |
60 | Standard_Integer ii, jj, multU=0, multV, minus; |
61 | Standard_Boolean Ok; |
62 | gp_Vec vec; |
63 | Standard_Real V1, V2, V3, Ratio, L1, L2, Tol, val; |
64 | gp_Pnt P1, P2, P3; |
65 | Handle(Geom_Curve) FirstCurve, SecondCurve; |
66 | |
67 | myDone = Standard_True; |
68 | |
69 | // Choix des noeuds |
70 | |
71 | myUKnots = new (TColStd_HArray1OfReal) (1, Beziers.ColLength()+1); |
72 | myVKnots = new (TColStd_HArray1OfReal) (1, Beziers.RowLength()+1); |
73 | |
74 | // --> en U |
75 | myUKnots->SetValue(1, 0); |
76 | jj = myVKnots->Length()/2; |
77 | FirstCurve = Beziers(1, jj)->VIso(0.3); |
78 | FirstCurve->D0(0, P1); |
79 | FirstCurve->D0(0.5, P2); |
80 | FirstCurve->D1(1, P3, vec); |
81 | |
82 | L1 = P1.Distance(P2) + P2.Distance(P3); |
83 | myUKnots->SetValue(2, L1); |
84 | |
85 | V1 = vec.Magnitude(); |
86 | // si la Parametrisation est trop bizzare on garde la pseudo-longueur |
87 | if ((V1 > 1000 * L1) || (V1 < L1 * 1.e-3)) V1 = L1; |
88 | |
89 | for (ii=2; ii<myUKnots->Length(); ii++) { |
90 | |
91 | SecondCurve = Beziers(ii, jj)->VIso(0.3); |
92 | SecondCurve->D1(0, P1, vec); |
93 | V2 = vec.Magnitude(); |
94 | SecondCurve->D0(0.5, P2); |
95 | SecondCurve->D1(1, P3, vec); |
96 | V3 = vec.Magnitude(); |
97 | L2 = P1.Distance(P2) + P2.Distance(P3); |
98 | |
99 | // On calcul le ratio, en evitant les cas tordus... |
100 | if ((V2 > 1000 * L2) || (V2 < L2 * 1.e-3)) V2 = L2; |
101 | if ((V3 > 1000 * L2) || (V3 < L2 * 1.e-3)) V3 = L2; |
102 | |
103 | Ratio = 1; |
104 | if ( (V1 > Precision::Confusion()) && (V2 > Precision::Confusion()) ) { |
105 | Ratio = V2 / V1; |
106 | } |
107 | if ( (Ratio < Precision::Confusion()) |
108 | || (Ratio > 1/Precision::Confusion()) ) {Ratio = 1;} |
109 | |
110 | // On en deduit un nouveau noeud |
111 | val = myUKnots->Value(ii); |
112 | myUKnots->SetValue(ii+1, val + Ratio*(val- myUKnots->Value(ii-1)) ); |
113 | |
114 | // Et c'est reparti, pour un tour |
115 | L1 = L2; |
116 | V1 = V3; |
117 | FirstCurve = SecondCurve; |
118 | } |
119 | |
120 | // --> en V |
121 | myVKnots->SetValue(1, 0); |
122 | ii = myUKnots->Length()/2; |
123 | FirstCurve = Beziers(ii, 1)->UIso(0.3); |
124 | FirstCurve->D0(0, P1); |
125 | FirstCurve->D0(0.5, P2); |
126 | FirstCurve->D1(1, P3, vec); |
127 | |
128 | L1 = P1.Distance(P2) + P2.Distance(P3); |
129 | myVKnots->SetValue(2, L1); |
130 | |
131 | V1 = vec.Magnitude(); |
132 | // si la Parametrisation est trop bizzare on garde la pseudo-longueur |
133 | if ((V1 > 1000 * L1) || (V1 < L1 * 1.e-3)) V1 = L1; |
134 | |
135 | for (jj=2; jj<myVKnots->Length(); jj++) { |
136 | |
137 | SecondCurve = Beziers(ii, jj)->UIso(0.3); |
138 | SecondCurve->D1(0, P1, vec); |
139 | V2 = vec.Magnitude(); |
140 | SecondCurve->D0(0.5, P2); |
141 | SecondCurve->D1(1, P3, vec); |
142 | V3 = vec.Magnitude(); |
143 | L2 = P1.Distance(P2) + P2.Distance(P3); |
144 | |
145 | // On calcul le ratio, en evitant les cas tordus... |
146 | if ((V2 > 1000 * L2) || (V2 < L2 * 1.e-3)) V2 = L2; |
147 | if ((V3 > 1000 * L2) || (V3 < L2 * 1.e-3)) V3 = L2; |
148 | |
149 | Ratio = 1; |
150 | if ( (V1 > Precision::Confusion()) && (V2 > Precision::Confusion()) ) { |
151 | Ratio = V2 / V1; |
152 | } |
153 | if ( (Ratio < Precision::Confusion()) |
154 | || (Ratio > 1/Precision::Confusion()) ) {Ratio = 1;} |
155 | |
156 | // On en deduit un nouveau noeud |
157 | val = myVKnots->Value(jj); |
158 | myVKnots->SetValue(jj+1, val + Ratio*(val-myVKnots->Value(jj-1)) ); |
159 | |
160 | // Et c'est reparti, pour un tour |
161 | L1 = L2; |
162 | V1 = V3; |
163 | FirstCurve = SecondCurve; |
164 | } |
165 | |
166 | // Calcul des Poles |
167 | Perform(Beziers); |
168 | |
169 | // Reduction de la multiplicite |
170 | Handle(Geom_BSplineSurface) Surface = new (Geom_BSplineSurface) |
171 | (myPoles->Array2(), |
172 | myUKnots->Array1(), |
173 | myVKnots->Array1(), |
174 | myUMults->Array1(), |
175 | myVMults->Array1(), |
176 | myUDegree, |
177 | myVDegree); |
178 | |
179 | if (RemoveKnots) minus = 0; |
180 | else minus = 1; |
181 | |
182 | for (ii=myUKnots->Length()-1; ii>1; ii--) { |
183 | Ok=Standard_True; |
184 | Tol = Tolerance/2; |
185 | multU = myUMults->Value(ii)-1; |
186 | for ( ; Ok && multU > minus; multU--, Tol/=2) { |
187 | Ok = Surface->RemoveUKnot(ii, multU, Tol); |
188 | } |
189 | } |
190 | |
191 | for (ii=myVKnots->Length()-1; ii>1; ii--) { |
192 | Ok=Standard_True; |
193 | Tol = Tolerance/2; |
194 | multV = myVMults->Value(ii)-1; |
195 | for ( ; Ok && multU > minus; multV--, Tol/=2) { |
196 | Ok = Surface->RemoveVKnot(ii, multV, Tol); |
197 | } |
198 | } |
199 | |
200 | // Les nouveaux champs sont arrivees .... |
201 | myPoles = new (TColgp_HArray2OfPnt) (1, Surface->NbUPoles(), 1, Surface->NbVPoles()); |
202 | Surface->Poles( myPoles->ChangeArray2()); |
203 | |
204 | myUMults = new (TColStd_HArray1OfInteger) (1, Surface->NbUKnots()); |
205 | myVMults = new (TColStd_HArray1OfInteger) (1, Surface->NbVKnots()); |
206 | myUKnots = new (TColStd_HArray1OfReal) (1, Surface->NbUKnots()); |
207 | myVKnots = new (TColStd_HArray1OfReal) (1, Surface->NbVKnots()); |
208 | |
209 | |
210 | Surface->UMultiplicities( myUMults->ChangeArray1()); |
211 | Surface->VMultiplicities( myVMults->ChangeArray1()); |
212 | Surface->UKnots( myUKnots->ChangeArray1()); |
213 | Surface->VKnots( myVKnots->ChangeArray1()); |
214 | } |
215 | |
216 | // ============================================================================ |
217 | GeomConvert_CompBezierSurfacesToBSplineSurface:: |
218 | GeomConvert_CompBezierSurfacesToBSplineSurface( |
219 | const TColGeom_Array2OfBezierSurface& Beziers, |
220 | const TColStd_Array1OfReal& UKnots, |
221 | const TColStd_Array1OfReal& VKnots, |
222 | const GeomAbs_Shape UContinuity, |
223 | const GeomAbs_Shape VContinuity, |
224 | const Standard_Real Tolerance) |
225 | // ============================================================================ |
226 | { |
227 | Standard_Integer decu=0, decv=0; |
228 | Standard_Boolean Ok; |
229 | |
230 | myDone = Standard_True; |
231 | |
232 | // Recuperation des noeuds |
233 | myUKnots = new (TColStd_HArray1OfReal) (1, Beziers.ColLength()+1); |
234 | myUKnots->ChangeArray1() = UKnots; |
235 | |
236 | myVKnots = new (TColStd_HArray1OfReal) (1, Beziers.RowLength()+1); |
237 | myVKnots->ChangeArray1() = VKnots; |
238 | |
239 | // Calcul des Poles |
240 | Perform(Beziers); |
241 | |
242 | // Obtention des bonne continuitee |
243 | |
244 | switch ( UContinuity ) { |
245 | case GeomAbs_C0 : |
246 | decu = 0; |
247 | break; |
248 | case GeomAbs_C1 : |
249 | decu = 1; |
250 | break; |
251 | case GeomAbs_C2 : |
252 | decu = 2; |
253 | break; |
254 | case GeomAbs_C3 : |
255 | decu = 3; |
256 | break; |
257 | default: |
258 | Standard_ConstructionError::Raise( |
259 | "GeomConvert_CompBezierSurfacesToBSpl:: UContinuity error"); |
260 | } |
261 | |
262 | switch ( VContinuity ) { |
263 | case GeomAbs_C0 : |
264 | decv = 0; |
265 | break; |
266 | case GeomAbs_C1 : |
267 | decv = 1; |
268 | break; |
269 | case GeomAbs_C2 : |
270 | decv = 2; |
271 | break; |
272 | case GeomAbs_C3 : |
273 | decv = 3; |
274 | break; |
275 | default: |
276 | Standard_ConstructionError::Raise( |
277 | "GeomConvert_CompBezierSurfacesToBSpl:: VContinuity error"); |
278 | } |
279 | |
280 | |
281 | if ( (decu>0) || (decv>0) ) { |
282 | |
283 | Standard_Integer ii; |
284 | Standard_Integer multU = myUDegree - decu; |
285 | Standard_ConstructionError_Raise_if( |
286 | ((multU <= 0) && (myUKnots->Length()>2)) , |
287 | "GeomConvert_CompBezierSurfacesToBSpl:: UContinuity or Udeg error"); |
288 | |
289 | Standard_Integer multV = myVDegree - decv; |
290 | Standard_ConstructionError_Raise_if( |
291 | ((multV <= 0) && (myVKnots->Length()>2)) , |
292 | "GeomConvert_CompBezierSurfacesToBSpl:: VContinuity or Vdeg error"); |
293 | |
294 | Handle(Geom_BSplineSurface) Surface = new (Geom_BSplineSurface) |
295 | (myPoles->Array2(), |
296 | myUKnots->Array1(), |
297 | myVKnots->Array1(), |
298 | myUMults->Array1(), |
299 | myVMults->Array1(), |
300 | myUDegree, |
301 | myVDegree); |
302 | |
303 | |
304 | if (decu>0) { |
305 | for (ii=2; ii<myUKnots->Length(); ii++) { |
306 | Ok = Surface->RemoveUKnot(ii, multU, Tolerance); |
307 | if (!Ok) {myDone = Ok;} |
308 | } |
309 | } |
310 | |
311 | if (decv>0) { |
312 | for (ii=2; ii<myVKnots->Length(); ii++) { |
313 | Ok = Surface->RemoveVKnot(ii, multV, Tolerance); |
314 | if (!Ok) {myDone = Ok;} |
315 | } |
316 | } |
317 | |
318 | // Les nouveaux champs sont arrivees .... |
319 | myPoles = new (TColgp_HArray2OfPnt) (1, Surface->NbUPoles(), 1, Surface->NbVPoles()); |
320 | Surface->Poles( myPoles->ChangeArray2()); |
321 | Surface->UMultiplicities( myUMults->ChangeArray1()); |
322 | Surface->VMultiplicities( myVMults->ChangeArray1()); |
323 | } |
324 | } |
325 | |
326 | |
327 | // ================================================================================ |
328 | void GeomConvert_CompBezierSurfacesToBSplineSurface::Perform( |
329 | const TColGeom_Array2OfBezierSurface& Beziers) |
330 | // ================================================================================ |
331 | { |
332 | Standard_Integer IU, IV; |
333 | |
334 | // (1) Determination des degrees et si le resultat est rationnel. |
335 | isrational = Standard_False; |
336 | myUDegree = 1; |
337 | myVDegree = 1; |
338 | |
339 | for (IU=Beziers.LowerRow(); IU <=Beziers.UpperRow(); IU++) { |
340 | for (IV=Beziers.LowerCol(); IV <=Beziers.UpperCol(); IV++) { |
341 | if ( Beziers(IU, IV)-> IsURational() |
342 | || Beziers(IU, IV)-> IsVRational()) { isrational = Standard_True;} |
343 | |
344 | myUDegree = ( Beziers(IU, IV)->UDegree() > myUDegree ) ? |
345 | Beziers(IU, IV)->UDegree() : myUDegree; |
346 | |
347 | myVDegree = ( Beziers(IU, IV)->VDegree() > myVDegree ) ? |
348 | Beziers(IU, IV)->VDegree() : myVDegree; |
349 | } |
350 | } |
351 | |
352 | Standard_NotImplemented_Raise_if(isrational, |
353 | "CompBezierSurfacesToBSpl : rational !"); |
354 | |
355 | |
356 | // (2) Boucle sur les carreaux ----------------------------- |
357 | |
358 | Handle(Geom_BezierSurface) Patch; |
359 | Standard_Integer UIndex, VIndex, uindex, vindex, udeb, vdeb; |
360 | Standard_Integer upol, vpol, ii; |
361 | |
362 | |
363 | myPoles = new (TColgp_HArray2OfPnt) |
364 | ( 1, (myUDegree+1)*Beziers.ColLength() - myUKnots->Length() + 2 , |
365 | 1, (myVDegree+1)*Beziers.RowLength() - myVKnots->Length() + 2 ); |
366 | |
367 | for (IU=Beziers.LowerRow(); IU <=Beziers.UpperRow(); IU++) { |
368 | UIndex = (IU-1)*myUDegree + 1; |
369 | for (IV=Beziers.LowerCol(); IV <=Beziers.UpperCol(); IV++) { |
370 | |
371 | Patch = Beziers(IU, IV); |
372 | VIndex = (IV-1)*myVDegree + 1; |
373 | |
374 | // (2.1) Augmentation du degree |
375 | Patch->Increase(myUDegree, myVDegree); |
376 | |
377 | // (2.2) Poles a recopier |
378 | if (IU==1) {udeb = 1;} |
379 | else {udeb = 2;} |
380 | if (IV==1) {vdeb = 1;} |
381 | else {vdeb = 2;} |
382 | |
383 | uindex = UIndex + udeb -1; |
384 | |
385 | for (upol = udeb; upol <= myUDegree+1; upol++, uindex++ ) { |
386 | vindex = VIndex + vdeb - 1; |
387 | for (vpol = vdeb; vpol <= myVDegree+1; vpol++, vindex++) { |
388 | myPoles->ChangeValue(uindex, vindex) = Patch->Pole(upol, vpol); |
389 | } |
390 | } |
391 | |
392 | // (2.3) Poles a sommer |
393 | if (udeb==2) { |
394 | vindex = VIndex + vdeb - 1; |
395 | for (vpol = vdeb; vpol <= myVDegree+1; vpol++, vindex++) { |
396 | myPoles->ChangeValue(UIndex, vindex).ChangeCoord() += |
397 | Patch->Pole(1, vpol).Coord(); |
398 | } |
399 | } |
400 | |
401 | if (vdeb==2) { |
402 | uindex = UIndex + udeb - 1; |
403 | for (upol = udeb; upol <= myUDegree+1; upol++, uindex++) { |
404 | myPoles->ChangeValue(uindex, VIndex).ChangeCoord() += |
405 | Patch->Pole(upol, 1).Coord(); |
406 | } |
407 | } |
408 | |
409 | if (udeb==2 && vdeb==2) { |
410 | myPoles->ChangeValue(UIndex, VIndex).ChangeCoord() += |
411 | Patch->Pole(1, 1).Coord(); |
412 | } |
413 | } |
414 | } |
415 | |
416 | // (3) Elimination des redondances |
417 | // car dans la boucle precedente on compte : |
418 | // - 2 fois les poles associes aux noeuds simples |
419 | // - 4 fois les poles associes aux doubles noeuds (en U et V) |
420 | |
421 | // (3.1) Elimination en U |
422 | for ( UIndex = myUDegree+1, ii=2; |
423 | ii< myUKnots->Length(); |
424 | ii++, UIndex+=myUDegree) { |
425 | for (vpol = 1; vpol<=myPoles->UpperCol(); vpol++) { |
426 | myPoles->ChangeValue(UIndex, vpol).ChangeCoord() *= 0.5; |
427 | } |
428 | } |
429 | |
430 | // (3.2) Elimination en V |
431 | for ( VIndex = myVDegree+1, ii=2; |
432 | ii< myVKnots->Length(); |
433 | ii++, VIndex += myVDegree) { |
434 | for (upol = 1; upol<=myPoles->UpperRow(); upol++) { |
435 | myPoles->ChangeValue(upol, VIndex).ChangeCoord() *= 0.5; |
436 | } |
437 | } |
438 | |
439 | // (4) Init des multiplicites |
440 | myUMults = new (TColStd_HArray1OfInteger) (1, myUKnots->Length()); |
441 | myUMults->Init( myUDegree); |
442 | myUMults->SetValue(1, myUDegree+1); |
443 | myUMults->SetValue( myUMults->Upper(), myUDegree+1); |
444 | |
445 | myVMults = new (TColStd_HArray1OfInteger) (1, myVKnots->Length()); |
446 | myVMults->Init( myVDegree); |
447 | myVMults->SetValue(1, myVDegree+1); |
448 | myVMults->SetValue(myVMults->Upper(), myVDegree+1); |
449 | } |
450 | |
451 | // ======================================================================== |
452 | Standard_Boolean GeomConvert_CompBezierSurfacesToBSplineSurface::IsDone() const |
453 | // ======================================================================== |
454 | { |
455 | return myDone; |
456 | } |
457 | |