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