0023746: IGES wheel model fails to load when OCCT unit is meters
[occt.git] / src / ShapeAnalysis / ShapeAnalysis_WireOrder.cxx
CommitLineData
b311480e 1// Copyright (c) 1999-2012 OPEN CASCADE SAS
2//
3// The content of this file is subject to the Open CASCADE Technology Public
4// License Version 6.5 (the "License"). You may not use the content of this file
5// except in compliance with the License. Please obtain a copy of the License
6// at http://www.opencascade.org and read it completely before using this file.
7//
8// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
10//
11// The Original Code and all software distributed under the License is
12// distributed on an "AS IS" basis, without warranty of any kind, and the
13// Initial Developer hereby disclaims all such warranties, including without
14// limitation, any warranties of merchantability, fitness for a particular
15// purpose or non-infringement. Please see the License for the specific terms
16// and conditions governing the rights and limitations under the License.
17
7fd59977 18//:o4 abv 17.02.99: r0301_db.stp #53082: treatment of open wires implemented
19// pdn 11.03.99 S4135 changing reordering algorithm in order to make it independent on tolerance
20//szv#4 S4163
21// pdn 09.05.99: S4174: preserve order of edges for complete torus
22#include <ShapeAnalysis_WireOrder.ixx>
23
24#include <Precision.hxx>
25
26#include <Standard_TypeMismatch.hxx>
27
28#include <TColgp_Array1OfXYZ.hxx>
29#include <TColStd_Array1OfInteger.hxx>
30#include <TColStd_SequenceOfInteger.hxx>
31#include <TColStd_Array1OfBoolean.hxx>
32#include <TColStd_SequenceOfInteger.hxx>
33#include <gp_Pnt.hxx>
34#include <TColStd_SequenceOfTransient.hxx>
35#include <TColStd_HSequenceOfInteger.hxx>
36
37//=======================================================================
38//function : ShapeAnalysis_WireOrder
39//purpose :
40//=======================================================================
41
42ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder()
43 : myKeepLoops(Standard_False) , myGap (0.) , myStat (0) , myMode (Standard_True)
44{
45 myTol = Precision::Confusion();
46 Clear();
47}
48
49//=======================================================================
50//function : ShapeAnalysis_WireOrder
51//purpose :
52//=======================================================================
53
54ShapeAnalysis_WireOrder::ShapeAnalysis_WireOrder(const Standard_Boolean mode3d,
55 const Standard_Real tol)
56 : myKeepLoops(Standard_False), myTol (tol), myGap (0.), myStat (0), myMode (mode3d)
57{
58 Clear();
59}
60
61//=======================================================================
62//function : SetMode
63//purpose :
64//=======================================================================
65
66void ShapeAnalysis_WireOrder::SetMode(const Standard_Boolean mode3d,const Standard_Real tol)
67{
68 if (mode3d != myMode) Clear();
69 myOrd.Nullify(); myStat = 0; myGap = 0.;
70 myMode = mode3d;
71 myTol = (tol > 0.)? tol : 1.e-08; //szv#4:S4163:12Mar99 optimized
72}
73
74//=======================================================================
75//function : Tolerance
76//purpose :
77//=======================================================================
78
79Standard_Real ShapeAnalysis_WireOrder::Tolerance() const
80{
81 return myTol;
82}
83
84//=======================================================================
85//function : Clear
86//purpose :
87//=======================================================================
88
89void ShapeAnalysis_WireOrder::Clear()
90{
91 myXYZ = new TColgp_HSequenceOfXYZ();
92 myStat = 0;
93 myGap = 0.;
94}
95
96//=======================================================================
97//function : Add
98//purpose :
99//=======================================================================
100
101void ShapeAnalysis_WireOrder::Add(const gp_XYZ& start3d,const gp_XYZ& end3d)
102{
103 //szv#4:S4163:12Mar99 waste raise
104 //if (!myMode)
105 //Standard_TypeMismatch::Raise("ShapeAnalysis_WireOrder : AddXYZ");
106 if (myMode) {
107 myXYZ->Append (start3d); myXYZ->Append (end3d);
108 }
109}
110
111//=======================================================================
112//function : Add
113//purpose :
114//=======================================================================
115
116void ShapeAnalysis_WireOrder::Add(const gp_XY& start2d,const gp_XY& end2d)
117{
118 //szv#4:S4163:12Mar99 waste raise
119 //if ( myMode)
120 //Standard_TypeMismatch::Raise("ShapeAnalysis_WireOrder : AddXY");
121 if (!myMode) {
122 gp_XYZ val;
123 val.SetCoord (start2d.X(),start2d.Y(),0.);
124 myXYZ->Append (val);
125 val.SetCoord (end2d.X(),end2d.Y(),0.);
126 myXYZ->Append (val);
127 }
128}
129
130//=======================================================================
131//function : NbEdges
132//purpose :
133//=======================================================================
134
135Standard_Integer ShapeAnalysis_WireOrder::NbEdges() const
136{
137 return myXYZ->Length() / 2;
138}
139
140
141static Standard_Real DISTABS (const gp_XYZ& v1, const gp_XYZ& v2)
142{
143 return Abs (v1.X() - v2.X()) + Abs (v1.Y() - v2.Y()) + Abs (v1.Z() - v2.Z());
144}
145
146// La routine qui suit gere les boucles internes a un wire. Questce a dire ?
147// Un wire normalement chaine (meme pas dans l ordre et avec des inverses)
148// balaie toutes ses edges au moins une fois dans une seule liste
149// En 3D il peut y avoir des COUTURES ... une, mais evt plusieurs ...
150// En ce cas le critere fin-debut peut definir des sous-parties fermees du
151// wire, ce sont les boucles en question
152// Exemple (cylindre gentil) : la couture (balayee deux fois) : 1 boucle
153// chaque limite (haute et basse) definit aussi une boucle (1 edge ou +)
154
155// En cours de chainage, il faut donc :
156// 1/ sauter la boucle, pour ne pas la rebalayer 36 fois : NextFree y pourvoit
157// en notant les tetes de boucles, on n a pas le droit de les revoir
158// NB: ca marche car en cours de constitution de liste, on s interdit de
159// repasser plus d une fois sur chaque edge (test fol-pre non nul)
160// 2/ reprendre les boucles pour les fusionner : pas encore fait
161// (pour l instant, on imprime un petit message, c est tout)
162
163static Standard_Integer NextFree
164 (const Standard_Integer i, const Standard_Integer nb,
165 Standard_Integer& nbloops, TColStd_Array1OfInteger& loops,
166 TColStd_Array1OfInteger& loopord,
167 const Handle(TColStd_HArray1OfInteger)& ord)
168{
169 if (i < 0) return -NextFree (-i, nb,nbloops,loops,loopord,ord);
170
171 //szv#4:S4163:12Mar99 optimized
172 Standard_Integer j; // svv Jan11 2000 : porting on DEC
173 for (j = 1; j <= nbloops; j ++) if (i == loops(j)) break;
174 if ( j > nbloops ) return i; // OK
175
176 // sinon, une boucle de plus, et chercher le prochain libre
177 nbloops ++;
178 for (j = 1; j <= nb; j ++)
179 if (loopord.Value(j) == 0) { loops(nbloops) = j; return j; }
180 nbloops --; // finalement il n ya plus rien
181 return 0;
182}
183
184//=======================================================================
185//function : KeepLoopsMode
186//purpose :
187//=======================================================================
188
189Standard_Boolean& ShapeAnalysis_WireOrder::KeepLoopsMode()
190{
191 return myKeepLoops;
192}
193
194//=======================================================================
195//function : Perform
196//purpose :
197//=======================================================================
198
199static Standard_Boolean IsBetter(const Standard_Integer first,
200 const Standard_Integer second)
201{
202 //rln 23.03.99 bm4_al_eye.stp, entity 5281
203 //Order in the file is better even if another order has the same distance
204 //Lexicograhical order of preference: 0 > 2 > 1 > 3
205 if (first == 0 && second > 0 ) return Standard_True;
206 if (first == 2 && (second == 1 || second == 3)) return Standard_True;
207 if (first == 1 && second == 3 ) return Standard_True;
208 return Standard_False;
209}
210
211void ShapeAnalysis_WireOrder::Perform(const Standard_Boolean /*closed*/)
212{
213 Standard_Integer i, nb = myXYZ->Length() / 2;
214 myOrd = new TColStd_HArray1OfInteger(1,nb); myOrd->Init(0);
215
216 Handle(TColStd_HSequenceOfInteger) seq = new TColStd_HSequenceOfInteger;
217 TColStd_SequenceOfTransient loops;
218
219 TColgp_Array1OfXYZ debs(0,nb);
220 TColgp_Array1OfXYZ fins(0,nb);
221
222 TColStd_Array1OfBoolean idone (1, nb);
223 idone.Init (Standard_False);
224
225// Calcul des precedents-suivants
226 for (i = 1; i <= nb; i ++) {
227 debs(i) = myXYZ->Value(2*i-1);
228 fins(i) = myXYZ->Value(2*i);
229 }
230
08cd2f6b 231 Standard_Real tol2 = Precision::SquareConfusion();
7fd59977 232 idone(1) = Standard_True;
233 gp_Pnt wireFirst = debs(1);
234 gp_Pnt wireLast = fins(1);
235 seq->Append(1);
236 Standard_Boolean done = Standard_False;
237
238 //pdn 11.03.99 S4135 constructing closed loops of edges
239 while(!done) {
240 Standard_Integer resultType = 3;
241 Standard_Real distmin = RealLast();
242 Standard_Integer ledge;
243 Standard_Boolean found = Standard_False;
244 Standard_Real closeDist = wireFirst.SquareDistance(wireLast);
245
246 for(Standard_Integer iedge = 1; (iedge <= nb) && (distmin||resultType||(resultType!=2)); iedge++)
247 if(!idone(iedge)) {
248 Standard_Real tailhead = wireLast.SquareDistance(debs(iedge));
249 Standard_Real tailtail = wireLast.SquareDistance(fins(iedge));
250 Standard_Real headtail = wireFirst.SquareDistance(fins(iedge));
251 Standard_Real headhead = wireFirst.SquareDistance(debs(iedge));
252 Standard_Real dm1 = tailhead, dm2 = headtail;
253 Standard_Integer res1 = 0, res2 = 2;
254
255 if (tailhead > tailtail) {res1 = 1; dm1 = tailtail;}
256 if (headtail > headhead) {res2 = 3; dm2 = headhead;}
257 Standard_Integer result =0;
258 Standard_Real myMin3d = Min (dm1, dm2);
259 if(fabs(dm1 - dm2) < tol2 ) {
260 Standard_Boolean isB = IsBetter(res1,res2);
261 result = (isB ? res1 : res2);
262 }
263 else
264 result = ((dm1 > dm2) ? res2 : res1); // 0 > 2 > 1 > 3
265
266 if (distmin > tol2 || IsBetter(result,resultType))
267 if (myMin3d < distmin || ((myMin3d == distmin || myMin3d < tol2) && IsBetter(result,resultType))) {
268 found = Standard_True;
269 distmin = myMin3d;
270 ledge = iedge;
271 resultType = result;
272 }
273 }
274 if(found) {
275 if (distmin == 0 || distmin < closeDist) {
276 switch(resultType){
277 case 0: seq->Append(ledge); wireLast = fins(ledge); break;
278 case 1: seq->Append(-ledge); wireLast = debs(ledge); break;
279 case 2: seq->Prepend(ledge); wireFirst = debs(ledge); break;
280 case 3: seq->Prepend(-ledge); wireFirst = fins(ledge); break;
281 }
282 } else {
283 //pdn 11.03.99 S4135 closing loop and creating new one
284 loops.Append(seq);
285 seq = new TColStd_HSequenceOfInteger;
286 wireFirst = debs(ledge);
287 wireLast = fins(ledge);
288 seq->Append(ledge);
289 }
290 idone(ledge) = Standard_True;
291 } else {
292 ledge = -1;
293 for (i = 1 ; i <= nb && ledge == -1; i++)
294 ledge = idone(i) ? ledge : i;
295 if (ledge == -1)
296 done = 1;
297 else {
298 wireFirst = debs(ledge);
299 wireLast = fins(ledge);
300 seq->Append(ledge);
301 idone(ledge) = Standard_True;
302 }
303 }
304 }
305 loops.Append(seq);
306
307 Handle(TColStd_HSequenceOfInteger) mainSeq;
308 if (myKeepLoops) {
309
310 //pdn Keeping the loops, adding one after another.
311 mainSeq = new TColStd_HSequenceOfInteger;
312 for (Standard_Integer ii = 1; ii <= loops.Length(); ii++) {
313 Handle(TColStd_HSequenceOfInteger) subLoop =
314 Handle(TColStd_HSequenceOfInteger)::DownCast(loops(ii));
315 for (Standard_Integer j = 1; j<= subLoop->Length(); j++)
316 mainSeq->Append(subLoop->Value(j));
317 }
318 }
319 else {
320 //pdn 11.03.99 S4135 connecting loops.
321 mainSeq = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.First());
322 loops.Remove(1);
323 while(loops.Length()) {
324 Standard_Real minLoopDist = RealLast();
325 Standard_Integer loopNum=0;
326 Standard_Integer loopShift=0;
327 Standard_Boolean loopDirect=0;
328 Standard_Integer numInLoop=0;
329 for(i = 1; i <= loops.Length(); i++) {
330 Handle(TColStd_HSequenceOfInteger) loop = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.Value(i));
331 Standard_Integer num = loop->Length();
332 Standard_Integer LocShift=0;
333 Standard_Integer LocNumInLoop=0;
334 Standard_Boolean LocDirect = Standard_False;
335 Standard_Real minLocDist = RealLast();
336 for(Standard_Integer ibegin = 1; ibegin <= loop->Length(); ibegin++) {
337 Standard_Integer iend = (ibegin==1 ? num : ibegin -1);
338 gp_Pnt loopFirst = (loop->Value(ibegin) > 0 ? debs(loop->Value(ibegin)) : fins(-loop->Value(ibegin)));
339 gp_Pnt loopLast = (loop->Value(iend) > 0 ? fins(loop->Value(iend)) : debs(-loop->Value(iend)));
340 Standard_Real distmin = RealLast();
341 Standard_Integer lloop=0;
342 Standard_Boolean direct = Standard_False;
343 for(Standard_Integer j = 1; (j <= mainSeq->Length())&& distmin; j++) {
344 Standard_Integer k = (j == mainSeq->Length()? 1 : j+1);
345 gp_Pnt first = (mainSeq->Value(j) > 0 ? fins(mainSeq->Value(j)) : debs(-mainSeq->Value(j)));
346 gp_Pnt last = (mainSeq->Value(k) > 0 ? debs(mainSeq->Value(k)) : fins(-mainSeq->Value(k)));
347 Standard_Real dirDist = loopFirst.SquareDistance(first)+loopLast.SquareDistance(last);
348 Standard_Real revDist = loopFirst.SquareDistance(last)+loopLast.SquareDistance(first);
349 Standard_Real minDist;
350 if((dirDist<tol2)||(dirDist < 2.*revDist)) {
351 minDist = dirDist;
352 revDist = dirDist;
353 }
354 else
355 minDist = revDist;
fdabc211 356 if(minDist < distmin && Abs(distmin - minDist) > tol2) {
7fd59977 357 distmin = minDist;
358 direct = (dirDist <= revDist);
359 lloop = j;
360 }
361 }
fdabc211 362 if(distmin < minLocDist && Abs(minLocDist - distmin) > tol2) {
7fd59977 363 minLocDist = distmin;
364 LocDirect = direct;
365 LocNumInLoop = lloop;
366 LocShift = ibegin;
367 }
368
369 }
fdabc211 370 if(minLocDist < minLoopDist && Abs(minLoopDist - minLocDist) > tol2) {
7fd59977 371 minLoopDist = minLocDist;
372 loopNum = i;
373 loopDirect = LocDirect;
374 numInLoop = LocNumInLoop;
375 loopShift = LocShift;
376 }
377 }
378
379 Handle(TColStd_HSequenceOfInteger) loop = Handle(TColStd_HSequenceOfInteger)::DownCast(loops.Value(loopNum));
380 Standard_Integer factor = (loopDirect ? 1: -1);
381 // skl : in the next block for{} I change "i" to "ii"
382 for(Standard_Integer ii = 1; ii <= loop->Length(); ii++) {
383 Standard_Integer num = (ii+loopShift-1>loop->Length() ? ii+loopShift-1-loop->Length() : ii+loopShift-1);
384 mainSeq->InsertAfter(numInLoop+ii-1,loop->Value(num)*factor);
385 }
386 loops.Remove(loopNum);
387 }
388 }
389
390 Standard_Integer stTmp=0;
391 for(i = 1; i <= mainSeq->Length(); i++) {
392 if(i!=mainSeq->Value(i))
393 if(stTmp>=0) stTmp = (mainSeq->Value(i) > 0 ? 1 : -1);
394 myOrd->SetValue(i,mainSeq->Value(i));
395 }
396 myStat = stTmp;
397 return;
398}
399
400//=======================================================================
401//function : IsDone
402//purpose :
403//=======================================================================
404
405 Standard_Boolean ShapeAnalysis_WireOrder::IsDone() const
406{
407 return !myOrd.IsNull();
408}
409
410//=======================================================================
411//function : Status
412//purpose :
413//=======================================================================
414
415 Standard_Integer ShapeAnalysis_WireOrder::Status() const
416{
417 return myStat;
418}
419
420//=======================================================================
421//function : Ordered
422//purpose :
423//=======================================================================
424
425 Standard_Integer ShapeAnalysis_WireOrder::Ordered(const Standard_Integer n) const
426{
427 if (myOrd.IsNull() || myOrd->Upper() < n) return n;
428 Standard_Integer ord = myOrd->Value(n);
429 return (ord == 0 ? n : ord);
430}
431
432//=======================================================================
433//function : XYZ
434//purpose :
435//=======================================================================
436
437 void ShapeAnalysis_WireOrder::XYZ(const Standard_Integer num,gp_XYZ& start3d,gp_XYZ& end3d) const
438{
439 if (num > 0) {
440 start3d = myXYZ->Value (2*num-1);
441 end3d = myXYZ->Value (2*num);
442 } else {
443 start3d = myXYZ->Value (-2*num);
444 end3d = myXYZ->Value (-2*num-1);
445 }
446}
447
448//=======================================================================
449//function : XY
450//purpose :
451//=======================================================================
452
453 void ShapeAnalysis_WireOrder::XY(const Standard_Integer num,gp_XY& start2d,gp_XY& end2d) const
454{
455 const gp_XYZ& st2d = myXYZ->Value ( (num > 0 ? 2*num-1 : -2*num) );
456 start2d.SetCoord (st2d.X(),st2d.Y());
457 const gp_XYZ& en2d = myXYZ->Value ( (num > 0 ? 2*num : -2*num -1) );
458 end2d.SetCoord (en2d.X(),en2d.Y());
459}
460
461//=======================================================================
462//function : Gap
463//purpose :
464//=======================================================================
465
466 Standard_Real ShapeAnalysis_WireOrder::Gap(const Standard_Integer num) const
467{
468 if (num == 0) return myGap;
469 Standard_Integer n1 = Ordered (num);
470 Standard_Integer n0 = Ordered (num == 1 ? NbEdges() : num-1);
471// Distance entre fin (n0) et debut (n1)
472 return DISTABS (myXYZ->Value( (n0 > 0 ? 2*n0 : -2*n0 -1) ) ,
473 myXYZ->Value( (n1 > 0 ? 2*n1-1 : -2*n1 ) ) );
474//// return (myXYZ->Value(2*n0)).Distance (myXYZ->Value(2*n1-1));
475}
476
477//=======================================================================
478//function : SetChains
479//purpose :
480//=======================================================================
481
482void ShapeAnalysis_WireOrder::SetChains(const Standard_Real gap)
483{
484 Standard_Integer n0 = 0, n1, n2, nb = NbEdges(); //szv#4:S4163:12Mar99 o0,o1,o2 not needed
485 if (nb == 0) return;
486 TColStd_SequenceOfInteger chain;
487 n0 = 0;
488 chain.Append (1); // On demarre la partie
489 gp_XYZ f3d, l3d, f13d, l13d; //szv#4:S4163:12Mar99 f03d,l03d unused
490 for (n1 = 1; n1 <= nb; n1 ++) {
491 if (n0 == 0) { // nouvelle boucle
492 n0 = n1;
493 //szv#4:S4163:12Mar99 optimized
494 XYZ ( Ordered(n0), f13d, l13d );
495 }
496 //szv#4:S4163:12Mar99 optimized
497 n2 = (n1 == nb)? n0 : (n1 + 1);
498 XYZ ( Ordered(n2), f3d, l3d );
499 if (!f3d.IsEqual (l13d,gap)) { chain.Append (n2); n0 = 0; }
500 f13d = f3d; l13d = l3d;
501 }
502 nb = chain.Length();
503 if (nb == 0) return;
504 myChains = new TColStd_HArray1OfInteger (1,nb);
505 for (n1 = 1; n1 <= nb; n1 ++) myChains->SetValue (n1,chain.Value(n1));
506}
507
508//=======================================================================
509//function : NbChains
510//purpose :
511//=======================================================================
512
513 Standard_Integer ShapeAnalysis_WireOrder::NbChains() const
514{
515 return (myChains.IsNull() ? 0 : myChains->Length());
516}
517
518//=======================================================================
519//function : Chain
520//purpose :
521//=======================================================================
522
523 void ShapeAnalysis_WireOrder::Chain(const Standard_Integer num,Standard_Integer& n1,Standard_Integer& n2) const
524{
525 n1 = n2 = 0;
526 if (myChains.IsNull()) return;
527 Standard_Integer nb = myChains->Upper();
528 if (num == 0 || num > nb) return;
529 n1 = myChains->Value (num);
530 if (num == nb) n2 = NbEdges();
531 else n2 = myChains->Value (num+1) - 1;
532}
533
534//=======================================================================
535//function : SetCouples
536//purpose :
537//=======================================================================
538
539 void ShapeAnalysis_WireOrder::SetCouples(const Standard_Real /*gap*/)
540{
541 cout<<"ShapeAnalysis_WireOrder:SetCouple not yet implemented"<<endl;
542}
543
544//=======================================================================
545//function : NbCouples
546//purpose :
547//=======================================================================
548
549 Standard_Integer ShapeAnalysis_WireOrder::NbCouples() const
550{
551 return (myCouples.IsNull() ? 0 : myCouples->Length());
552}
553
554//=======================================================================
555//function : Couple
556//purpose :
557//=======================================================================
558
559 void ShapeAnalysis_WireOrder::Couple(const Standard_Integer num,Standard_Integer& n1,Standard_Integer& n2) const
560{
561 n1 = n2 = 0;
562 if (myCouples.IsNull()) return;
563 Standard_Integer nb = myCouples->Upper();
564 if (num == 0 || num*2 > nb) return;
565 n1 = myCouples->Value (2*num-1);
566 n2 = myCouples->Value (2*num);
567}
568