0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / BRepMesh / BRepMesh_NURBSRangeSplitter.cxx
CommitLineData
7bd071ed 1// Created on: 2016-04-19
2// Copyright (c) 2016 OPEN CASCADE SAS
3// Created by: Oleg AGASHIN
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#include <BRepMesh_NURBSRangeSplitter.hxx>
46478ffe 17
18#include <algorithm>
19#include <BRepMesh_GeomTool.hxx>
7bd071ed 20#include <GeomAdaptor_Curve.hxx>
46478ffe 21#include <GeomLib.hxx>
7bd071ed 22#include <IMeshData_Edge.hxx>
46478ffe 23#include <IMeshData_Wire.hxx>
7bd071ed 24#include <NCollection_Handle.hxx>
7bd071ed 25
26namespace
27{
28 class AnalyticalFilter
29 {
30 public:
31 //! Constructor.
32 AnalyticalFilter(
33 const IMeshData::IFaceHandle& theDFace,
34 const GeomAbs_IsoType theIsoType,
35 const Handle(IMeshData::SequenceOfReal)& theParams,
36 const Handle(IMeshData::SequenceOfReal)& theControlParams,
37 const Handle(IMeshData::MapOfReal)& theParamsForbiddenToRemove,
38 const Handle(IMeshData::MapOfReal)& theControlParamsForbiddenToRemove)
39 : myDFace(theDFace),
c22b52d6 40 mySurface(myDFace->GetSurface()->Surface().Surface()),
7bd071ed 41 myIsoU(theIsoType == GeomAbs_IsoU),
42 myParams(theParams),
43 myControlParams(theControlParams),
44 myParamsForbiddenToRemove(theParamsForbiddenToRemove),
45 myControlParamsForbiddenToRemove(theControlParamsForbiddenToRemove),
46 myAllocator(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
d533dafb 47 myControlParamsToRemove(new IMeshData::MapOfReal(1, myAllocator)),
48 myCurrParam(0.0),
49 myCurrControlParam(0.0),
50 myPrevControlParam(0.0)
7bd071ed 51 {
52 }
53
54 //! Returns map of parameters supposed to be removed.
55 const Handle(IMeshData::MapOfReal)& GetControlParametersToRemove(
56 const IMeshTools_Parameters& theParameters)
57 {
58 myParameters = theParameters;
59
7bd071ed 60 Standard_Integer aStartIndex, aEndIndex;
61 if (myIsoU)
62 {
63 aStartIndex = 1;
64 aEndIndex = myParams->Length();
65 }
66 else
67 {
68 aStartIndex = 2;
69 aEndIndex = myParams->Length() - 1;
70 }
71
72 for (Standard_Integer i = aStartIndex; i <= aEndIndex; ++i)
73 {
74 myCurrParam = myParams->Value(i);
75 myIso = new GeomAdaptor_Curve(myIsoU ? mySurface->UIso(myCurrParam) : mySurface->VIso(myCurrParam));
76
77 myPrevControlParam = myControlParams->Value(1);
78 myIso->D1(myPrevControlParam, myPrevControlPnt, myPrevControlVec);
79 for (Standard_Integer j = 2; j <= myControlParams->Length();)
80 {
81 j += checkControlPointAndMoveOn(j);
82 }
83 }
84
85 return myControlParamsToRemove;
86 }
87
88 private:
89
90 //! Checks the given control point for deviation.
91 //! Returns number of steps to be used to move point iterator.
92 Standard_Integer checkControlPointAndMoveOn(const Standard_Integer theIndex)
93 {
94 Standard_Integer aMoveSteps = 0;
95 myCurrControlParam = myControlParams->Value(theIndex);
96 myIso->D1(myCurrControlParam, myCurrControlPnt, myCurrControlVec);
97
98 const Standard_Real aMidParam = 0.5 * (myPrevControlParam + myCurrControlParam);
99 const gp_Pnt aMidPnt = myIso->Value(aMidParam);
100
101 const Standard_Real aSqDist = BRepMesh_GeomTool::SquareDeflectionOfSegment(
102 myPrevControlPnt, myCurrControlPnt, aMidPnt);
103
46478ffe 104 Standard_Real anAngle = 0.0;
105
106 if ((myPrevControlVec.SquareMagnitude() > Precision::SquareConfusion()) &&
107 (myCurrControlVec.SquareMagnitude() > Precision::SquareConfusion()))
108 {
109 anAngle = myPrevControlVec.Angle(myCurrControlVec);
110 }
111
112 const Standard_Real aSqMaxDeflection = myDFace->GetDeflection() *
113 myDFace->GetDeflection();
114
115 if (((aSqDist > aSqMaxDeflection) || (anAngle > myParameters.AngleInterior)) &&
7bd071ed 116 aSqDist > myParameters.MinSize * myParameters.MinSize)
117 {
118 // insertion
119 myControlParams->InsertBefore(theIndex, aMidParam);
120 }
121 else
122 {
123 // Here we should leave at least 3 parameters as far as
124 // we must have at least one parameter related to surface
125 // internals in order to prevent movement of triangle body
126 // outside the surface in case of highly curved ones, e.g.
127 // BSpline springs.
46478ffe 128 if (((aSqDist < aSqMaxDeflection) || (anAngle < myParameters.AngleInterior)) &&
129 myControlParams->Length() > 3 && theIndex < myControlParams->Length())
7bd071ed 130 {
131 // Remove too dense points
132 const Standard_Real aTmpParam = myControlParams->Value(theIndex + 1);
133 if (checkParameterForDeflectionAndUpdateCache(aTmpParam))
134 {
135 ++aMoveSteps;
136 }
137 }
138
139 myPrevControlParam = myCurrControlParam;
140 myPrevControlPnt = myCurrControlPnt;
141 myPrevControlVec = myCurrControlVec;
142
143 ++aMoveSteps;
144 }
145
146 return aMoveSteps;
147 }
148
149 //! Checks whether the given param suits specified deflection. Updates cache.
150 Standard_Boolean checkParameterForDeflectionAndUpdateCache(const Standard_Real theParam)
151 {
152 gp_Pnt aTmpPnt;
153 gp_Vec aTmpVec;
154 myIso->D1(theParam, aTmpPnt, aTmpVec);
155
156 const Standard_Real aTmpMidParam = 0.5 * (myPrevControlParam + theParam);
157 const gp_Pnt aTmpMidPnt = myIso->Value(aTmpMidParam);
158
159 // Lets check next parameter.
160 // If it also fits deflection, we can remove previous parameter.
161 const Standard_Real aSqDist = BRepMesh_GeomTool::SquareDeflectionOfSegment(
162 myPrevControlPnt, aTmpPnt, aTmpMidPnt);
163
164 if (aSqDist < myDFace->GetDeflection() * myDFace->GetDeflection())
165 {
166 // Lets check parameters for angular deflection.
167 if (myPrevControlVec.SquareMagnitude() < gp::Resolution() ||
168 aTmpVec.SquareMagnitude() < gp::Resolution() ||
46478ffe 169 myPrevControlVec.Angle(aTmpVec) < myParameters.AngleInterior)
7bd071ed 170 {
171 // For current Iso line we can remove this parameter.
172 myControlParamsToRemove->Add(myCurrControlParam);
173 myCurrControlParam = theParam;
174 myCurrControlPnt = aTmpPnt;
175 myCurrControlVec = aTmpVec;
176 return Standard_True;
177 }
178 else
179 {
180 // We have found a place on the surface refusing
181 // removement of this parameter.
182 myParamsForbiddenToRemove ->Add(myCurrParam);
183 myControlParamsForbiddenToRemove->Add(myCurrControlParam);
184 }
185 }
186
187 return Standard_False;
188 }
189
190 private:
191
192 IMeshData::IFaceHandle myDFace;
193 Handle(Geom_Surface) mySurface;
194 Standard_Boolean myIsoU;
195 Handle(IMeshData::SequenceOfReal) myParams;
196 Handle(IMeshData::SequenceOfReal) myControlParams;
197
198 Handle(IMeshData::MapOfReal) myParamsForbiddenToRemove;
199 Handle(IMeshData::MapOfReal) myControlParamsForbiddenToRemove;
200
201 Handle(NCollection_IncAllocator) myAllocator;
202 Handle(IMeshData::MapOfReal) myControlParamsToRemove;
203
204
205 IMeshTools_Parameters myParameters;
206 NCollection_Handle<GeomAdaptor_Curve> myIso;
207
208 Standard_Real myCurrParam;
209
210 Standard_Real myCurrControlParam;
211 gp_Pnt myCurrControlPnt;
212 gp_Vec myCurrControlVec;
213
214 Standard_Real myPrevControlParam;
215 gp_Pnt myPrevControlPnt;
216 gp_Vec myPrevControlVec;
217 };
218
219 //! Adds param to map if it fits specified range.
4945e8be 220 Standard_Boolean addParam(
7bd071ed 221 const Standard_Real& theParam,
222 const std::pair<Standard_Real, Standard_Real>& theRange,
223 IMeshData::IMapOfReal& theParams)
224 {
225 if (theParam < theRange.first ||
226 theParam > theRange.second)
227 {
228 return Standard_False;
229 }
230
231 theParams.Add(theParam);
232 return Standard_True;
233 }
234
235 //! Initializes parameters map using CN intervals.
4945e8be 236 Standard_Boolean initParamsFromIntervals(
7bd071ed 237 const TColStd_Array1OfReal& theIntervals,
238 const std::pair<Standard_Real, Standard_Real>& theRange,
239 const Standard_Boolean isSplitIntervals,
240 IMeshData::IMapOfReal& theParams)
241 {
242 Standard_Boolean isAdded = Standard_False;
243
244 for (Standard_Integer i = theIntervals.Lower(); i <= theIntervals.Upper(); ++i)
245 {
246 const Standard_Real aStartParam = theIntervals.Value(i);
247 if (addParam(aStartParam, theRange, theParams))
248 {
249 isAdded = Standard_True;
250 }
251
252 if (isSplitIntervals && i < theIntervals.Upper())
253 {
254 const Standard_Real aMidParam = (aStartParam + theIntervals.Value(i + 1)) / 2.;
255 if (addParam(aMidParam, theRange, theParams))
256 {
257 isAdded = Standard_True;
258 }
259 }
260 }
261
262 return isAdded;
263 }
46478ffe 264
265 //! Checks whether intervals should be split.
266 //! Returns true in case if it is impossible to compute normal
267 //! directly on intervals, false is returned elsewhere.
268 Standard_Boolean toSplitIntervals (const Handle (Geom_Surface)& theSurf,
269 const TColStd_Array1OfReal (&theIntervals)[2])
270 {
271 Standard_Integer aIntervalU = theIntervals[0].Lower ();
272 for (; aIntervalU <= theIntervals[0].Upper (); ++aIntervalU)
273 {
274 const Standard_Real aParamU = theIntervals[0].Value(aIntervalU);
973f7d55 275 if (Precision::IsInfinite (aParamU))
276 continue;
277
46478ffe 278 Standard_Integer aIntervalV = theIntervals[1].Lower ();
279 for (; aIntervalV <= theIntervals[1].Upper (); ++aIntervalV)
280 {
281 gp_Dir aNorm;
282 const Standard_Real aParamV = theIntervals[1].Value(aIntervalV);
973f7d55 283 if (Precision::IsInfinite (aParamV))
284 continue;
285
46478ffe 286 if (GeomLib::NormEstim (theSurf, gp_Pnt2d (aParamU, aParamV), Precision::Confusion (), aNorm) != 0)
287 {
288 return Standard_True;
289 }
290 // TODO: do not split intervals if there is no normal in the middle of interval.
291 }
292 }
293
294 return Standard_False;
295 }
7bd071ed 296}
297
298//=======================================================================
299// Function: AdjustRange
300// Purpose :
301//=======================================================================
302void BRepMesh_NURBSRangeSplitter::AdjustRange()
303{
304 BRepMesh_DefaultRangeSplitter::AdjustRange();
305 mySurfaceType = GetSurface()->GetType();
306
307 if (mySurfaceType == GeomAbs_BezierSurface)
308 {
309 const std::pair<Standard_Real, Standard_Real>& aRangeU = GetRangeU();
310 const std::pair<Standard_Real, Standard_Real>& aRangeV = GetRangeV();
311
312 myIsValid = !(aRangeU.first < -0.5 ||
313 aRangeU.second > 1.5 ||
314 aRangeV.first < -0.5 ||
315 aRangeV.second > 1.5);
316 }
317}
318
319//=======================================================================
320// Function: GenerateSurfaceNodes
321// Purpose :
322//=======================================================================
323Handle(IMeshData::ListOfPnt2d) BRepMesh_NURBSRangeSplitter::GenerateSurfaceNodes(
324 const IMeshTools_Parameters& theParameters) const
325{
46478ffe 326 if (!initParameters())
327 {
328 return Handle(IMeshData::ListOfPnt2d)();
329 }
7bd071ed 330
331 const std::pair<Standard_Real, Standard_Real>& aRangeU = GetRangeU();
332 const std::pair<Standard_Real, Standard_Real>& aRangeV = GetRangeV();
333 const std::pair<Standard_Real, Standard_Real>& aDelta = GetDelta ();
334
335 const Standard_Real aDefFace = GetDFace()->GetDeflection();
c22b52d6 336 const Handle(BRepAdaptor_Surface)& gFace = GetSurface();
337 Handle(Geom_Surface) aSurface = gFace->Surface().Surface();
7bd071ed 338
339 const Handle(NCollection_IncAllocator) aTmpAlloc =
340 new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
341
342 const Handle(IMeshData::SequenceOfReal) aParams[2] = {
343 computeGrainAndFilterParameters(GetParametersU(), gFace->UResolution(aDefFace),
344 (aRangeU.second - aRangeU.first), aDelta.first, theParameters, aTmpAlloc),
345
346 computeGrainAndFilterParameters(GetParametersV(), gFace->VResolution(aDefFace),
347 (aRangeV.second - aRangeV.first), aDelta.second, theParameters, aTmpAlloc)
348 };
349
350 // check intermediate isolines
351 Handle(IMeshData::MapOfReal) aFixedParams[2] = {
352 new IMeshData::MapOfReal(1, aTmpAlloc),
353 new IMeshData::MapOfReal(1, aTmpAlloc)
354 };
355
356 const Handle(IMeshData::MapOfReal) aParamsToRemove[2] = {
357 AnalyticalFilter(GetDFace(), GeomAbs_IsoV, aParams[1], aParams[0],
358 aFixedParams[1], aFixedParams[0]).GetControlParametersToRemove(theParameters),
359
360 AnalyticalFilter(GetDFace(), GeomAbs_IsoU, aParams[0], aParams[1],
361 aFixedParams[0], aFixedParams[1]).GetControlParametersToRemove(theParameters),
362 };
363
364 aParamsToRemove[0]->Subtract(*aFixedParams[0]);
365 aParamsToRemove[1]->Subtract(*aFixedParams[1]);
366
367 // insert nodes of the regular grid
368 Handle(IMeshData::ListOfPnt2d) aNodes = new IMeshData::ListOfPnt2d(
369 new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE));
370
371 // insert nodes of the regular grid
372 for (Standard_Integer i = 1; i <= aParams[0]->Length(); ++i)
373 {
374 const Standard_Real aParam1 = aParams[0]->Value(i);
375 if (aParamsToRemove[0]->Contains(aParam1))
376 {
377 continue;
378 }
379
380 for (Standard_Integer j = 1; j <= aParams[1]->Length(); ++j)
381 {
382 const Standard_Real aParam2 = aParams[1]->Value(j);
383 if (aParamsToRemove[1]->Contains(aParam2))
384 {
385 continue;
386 }
387
388 aNodes->Append(gp_Pnt2d(aParam1, aParam2));
389 }
390 }
391
392 return aNodes;
393}
394
c4ea4ca3 395//=======================================================================
396// Function: getUndefinedIntervalNb
397// Purpose :
398//=======================================================================
399Standard_Integer BRepMesh_NURBSRangeSplitter::getUndefinedIntervalNb(
400 const Handle(Adaptor3d_Surface)& theSurface,
401 const Standard_Boolean isU,
402 const GeomAbs_Shape /*theContinuity*/) const
403{
404 return (isU ? theSurface->NbUPoles() : theSurface->NbVPoles()) - 1;
405}
406
407//=======================================================================
408// Function: getUndefinedInterval
409// Purpose :
410//=======================================================================
411void BRepMesh_NURBSRangeSplitter::getUndefinedInterval(
412 const Handle(Adaptor3d_Surface)& theSurface,
413 const Standard_Boolean isU,
414 const GeomAbs_Shape theContinuity,
415 const std::pair<Standard_Real, Standard_Real>& theRange,
416 TColStd_Array1OfReal& theIntervals) const
417{
418 Standard_Integer aIntervalsNb = isU ?
419 theSurface->NbUIntervals(theContinuity) :
420 theSurface->NbVIntervals(theContinuity);
421
422 if (aIntervalsNb == 1)
423 {
424 aIntervalsNb = getUndefinedIntervalNb(theSurface, isU, theContinuity);
425 if (aIntervalsNb > 1)
426 {
427 theIntervals = TColStd_Array1OfReal(1, aIntervalsNb - 1);
428 const Standard_Real aDiff = (theRange.second - theRange.first) / aIntervalsNb;
429 for (Standard_Integer i = theIntervals.Lower(); i <= theIntervals.Upper(); ++i)
430 {
431 theIntervals.SetValue(i, theRange.first + i * aDiff);
432 }
433 }
434 }
435
436 if (theIntervals.IsEmpty())
437 {
438 theIntervals = TColStd_Array1OfReal(1, aIntervalsNb + 1);
439 if (isU)
440 {
441 theSurface->UIntervals(theIntervals, theContinuity);
442 }
443 else
444 {
445 theSurface->VIntervals(theIntervals, theContinuity);
446 }
447 }
448}
449
7bd071ed 450//=======================================================================
451// Function: initParameters
452// Purpose :
453//=======================================================================
46478ffe 454Standard_Boolean BRepMesh_NURBSRangeSplitter::initParameters() const
7bd071ed 455{
7bd071ed 456 const GeomAbs_Shape aContinuity = GeomAbs_CN;
c4ea4ca3 457 const Handle(BRepAdaptor_Surface)& aSurface = GetSurface();
7bd071ed 458
c4ea4ca3 459 TColStd_Array1OfReal aIntervals[2];
460 getUndefinedInterval(aSurface, Standard_True, aContinuity, GetRangeU(), aIntervals[0]);
461 getUndefinedInterval(aSurface, Standard_False, aContinuity, GetRangeV(), aIntervals[1]);
7bd071ed 462
c22b52d6 463 const Standard_Boolean isSplitIntervals = toSplitIntervals (aSurface->Surface().Surface(), aIntervals);
7bd071ed 464
46478ffe 465 if (!initParamsFromIntervals(aIntervals[0], GetRangeU(), isSplitIntervals,
466 const_cast<IMeshData::IMapOfReal&>(GetParametersU())))
7bd071ed 467 {
46478ffe 468 //if (!grabParamsOfEdges (Edge_Frontier, Param_U))
469 {
470 return Standard_False;
471 }
7bd071ed 472 }
473
46478ffe 474 if (!initParamsFromIntervals(aIntervals[1], GetRangeV(), isSplitIntervals,
475 const_cast<IMeshData::IMapOfReal&>(GetParametersV())))
476 {
477 //if (!grabParamsOfEdges (Edge_Frontier, Param_V))
478 {
479 return Standard_False;
480 }
481 }
7bd071ed 482
46478ffe 483 return grabParamsOfEdges(Edge_Internal, Param_U | Param_V);
484}
485
486//=======================================================================
487//function : grabParamsOfInternalEdges
488//purpose :
489//=======================================================================
490Standard_Boolean BRepMesh_NURBSRangeSplitter::grabParamsOfEdges (
491 const EdgeType theEdgeType,
492 const Standard_Integer theParamDimensionFlag) const
493{
494 if ((theParamDimensionFlag & (Param_U | Param_V)) == 0)
495 {
496 return Standard_False;
497 }
498
499 const IMeshData::IFaceHandle& aDFace = GetDFace ();
500 for (Standard_Integer aWireIt = 0; aWireIt < aDFace->WiresNb (); ++aWireIt)
501 {
502 const IMeshData::IWireHandle& aDWire = aDFace->GetWire (aWireIt);
503 for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb (); ++aEdgeIt)
504 {
505 const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIt);
506 for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
507 {
508 const IMeshData::IPCurveHandle& aDPCurve = aDEdge->GetPCurve (aPCurveIt);
509 if (aDPCurve->GetFace () == aDFace)
510 {
511 if (theEdgeType == Edge_Internal && !aDPCurve->IsInternal ())
512 {
513 continue;
514 }
515
516 for (Standard_Integer aPointIt = 0; aPointIt < aDPCurve->ParametersNb (); ++aPointIt)
517 {
518 const gp_Pnt2d& aPnt2d = aDPCurve->GetPoint (aPointIt);
519 if (theParamDimensionFlag & Param_U)
520 {
521 const_cast<IMeshData::IMapOfReal&>(GetParametersU ()).Add (aPnt2d.X ());
522 }
523
524 if (theParamDimensionFlag & Param_V)
525 {
526 const_cast<IMeshData::IMapOfReal&>(GetParametersV ()).Add (aPnt2d.Y ());
527 }
528 }
529 }
530 }
531 }
532 }
533
534 return Standard_True;
7bd071ed 535}
536
537//=======================================================================
538//function : computeGrainAndFilterParameters
539//purpose :
540//=======================================================================
541Handle(IMeshData::SequenceOfReal) BRepMesh_NURBSRangeSplitter::computeGrainAndFilterParameters(
542 const IMeshData::IMapOfReal& theSourceParams,
543 const Standard_Real theTol2d,
544 const Standard_Real theRangeDiff,
545 const Standard_Real theDelta,
546 const IMeshTools_Parameters& theParameters,
547 const Handle(NCollection_IncAllocator)& theAllocator) const
548{
549 // Sort and filter sequence of parameters
550 Standard_Real aMinDiff = Precision::PConfusion();
551 if (theDelta < 1.)
552 {
553 aMinDiff /= theDelta;
554 }
555
a939fd40 556 const Handle(BRepAdaptor_Surface)& aSurface = GetSurface();
557 const Standard_Real aMinSize2d = Max(
558 aSurface->UResolution(theParameters.MinSize),
f55fe3b3 559 aSurface->VResolution(theParameters.MinSize));
a939fd40 560
561 aMinDiff = Max(aMinSize2d, aMinDiff);
7bd071ed 562
563 const Standard_Real aDiffMaxLim = 0.1 * theRangeDiff;
46478ffe 564 const Standard_Real aDiffMinLim = Max(0.005 * theRangeDiff,
565 2. * theTol2d);
a939fd40 566 const Standard_Real aDiff = Max(aMinSize2d,
46478ffe 567 Min(aDiffMaxLim, aDiffMinLim));
7bd071ed 568 return filterParameters(theSourceParams, aMinDiff, aDiff, theAllocator);
569}
570
571//=======================================================================
572//function : filterParameters
573//purpose :
574//=======================================================================
575Handle(IMeshData::SequenceOfReal) BRepMesh_NURBSRangeSplitter::filterParameters(
576 const IMeshData::IMapOfReal& theParams,
577 const Standard_Real theMinDist,
578 const Standard_Real theFilterDist,
579 const Handle(NCollection_IncAllocator)& theAllocator) const
580{
581 Handle(IMeshData::SequenceOfReal) aResult = new IMeshData::SequenceOfReal(theAllocator);
582
583 // Sort sequence of parameters
584 const Standard_Integer anInitLen = theParams.Extent();
585
586 if (anInitLen < 1)
587 {
588 return aResult;
589 }
590
591 TColStd_Array1OfReal aParamArray(1, anInitLen);
592 Standard_Integer j;
593 for (j = 1; j <= anInitLen; j++)
594 aParamArray(j) = theParams(j);
595
596 std::sort(aParamArray.begin(), aParamArray.end());
597
598 // mandatory pre-filtering using the first (minimal) filter value
599 Standard_Integer aParamLength = 1;
600 for (j = 2; j <= anInitLen; j++)
601 {
602 if ((aParamArray(j) - aParamArray(aParamLength)) > theMinDist)
603 {
604 if (++aParamLength < j)
605 aParamArray(aParamLength) = aParamArray(j);
606 }
607 }
608
609 //perform filtering on series
610 Standard_Real aLastAdded, aLastCandidate;
611 Standard_Boolean isCandidateDefined = Standard_False;
612 aLastAdded = aParamArray(1);
613 aLastCandidate = aLastAdded;
614 aResult->Append(aLastAdded);
615
616 for (j = 2; j < aParamLength; j++)
617 {
618 Standard_Real aVal = aParamArray(j);
619 if (aVal - aLastAdded > theFilterDist)
620 {
621 //adds the parameter
622 if (isCandidateDefined)
623 {
624 aLastAdded = aLastCandidate;
625 isCandidateDefined = Standard_False;
626 j--;
627 }
628 else
629 {
630 aLastAdded = aVal;
631 }
632 aResult->Append(aLastAdded);
633 continue;
634 }
635
636 aLastCandidate = aVal;
637 isCandidateDefined = Standard_True;
638 }
639 aResult->Append(aParamArray(aParamLength));
640
641 return aResult;
642}