0031035: Coding - uninitialized class fields reported by Visual Studio Code Analysis
[occt.git] / src / BRepMesh / BRepMesh_NURBSRangeSplitter.cxx
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>
17
18 #include <algorithm>
19 #include <BRepMesh_GeomTool.hxx>
20 #include <GeomAdaptor_Curve.hxx>
21 #include <GeomLib.hxx>
22 #include <IMeshData_Edge.hxx>
23 #include <IMeshData_Wire.hxx>
24 #include <NCollection_Handle.hxx>
25
26 namespace
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),
40         mySurface(myDFace->GetSurface()->ChangeSurface().Surface().Surface()),
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)),
47         myControlParamsToRemove(new IMeshData::MapOfReal(1, myAllocator)),
48         myCurrParam(0.0),
49         myCurrControlParam(0.0),
50         myPrevControlParam(0.0)
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
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
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)) &&
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.
128         if (((aSqDist < aSqMaxDeflection) || (anAngle < myParameters.AngleInterior)) &&
129             myControlParams->Length() > 3 && theIndex < myControlParams->Length())
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() ||
169             myPrevControlVec.Angle(aTmpVec)    < myParameters.AngleInterior)
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.
220   inline Standard_Boolean addParam(
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.
236   inline Standard_Boolean initParamsFromIntervals(
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   }
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);
275       if (Precision::IsInfinite (aParamU))
276         continue;
277
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);
283         if (Precision::IsInfinite (aParamV))
284           continue;
285
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   }
296 }
297
298 //=======================================================================
299 // Function: AdjustRange
300 // Purpose : 
301 //=======================================================================
302 void 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 //=======================================================================
323 Handle(IMeshData::ListOfPnt2d) BRepMesh_NURBSRangeSplitter::GenerateSurfaceNodes(
324   const IMeshTools_Parameters& theParameters) const
325 {
326   if (!initParameters())
327   {
328     return Handle(IMeshData::ListOfPnt2d)();
329   }
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();
336   const Handle(BRepAdaptor_HSurface)& gFace    = GetSurface();
337   Handle(Geom_Surface)                aSurface = gFace->ChangeSurface().Surface().Surface();
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
395 //=======================================================================
396 // Function: initParameters
397 // Purpose : 
398 //=======================================================================
399 Standard_Boolean BRepMesh_NURBSRangeSplitter::initParameters() const
400 {
401   const Handle(BRepAdaptor_HSurface)& aSurface = GetSurface();
402
403   const GeomAbs_Shape aContinuity = GeomAbs_CN;
404   const std::pair<Standard_Integer, Standard_Integer> aIntervalsNb(
405     aSurface->NbUIntervals(aContinuity),
406     aSurface->NbVIntervals(aContinuity)
407   );
408
409   TColStd_Array1OfReal aIntervals[2] = {
410     TColStd_Array1OfReal(1, aIntervalsNb.first  + 1),
411     TColStd_Array1OfReal(1, aIntervalsNb.second + 1)
412   };
413
414   aSurface->UIntervals(aIntervals[0], aContinuity);
415   aSurface->VIntervals(aIntervals[1], aContinuity);
416
417   const Standard_Boolean isSplitIntervals = toSplitIntervals (
418     aSurface->ChangeSurface().Surface().Surface(), aIntervals);
419
420   if (!initParamsFromIntervals(aIntervals[0], GetRangeU(), isSplitIntervals,
421                                const_cast<IMeshData::IMapOfReal&>(GetParametersU())))
422   {
423     //if (!grabParamsOfEdges (Edge_Frontier, Param_U))
424     {
425       return Standard_False;
426     }
427   }
428
429   if (!initParamsFromIntervals(aIntervals[1], GetRangeV(), isSplitIntervals,
430                                const_cast<IMeshData::IMapOfReal&>(GetParametersV())))
431   {
432     //if (!grabParamsOfEdges (Edge_Frontier, Param_V))
433     {
434       return Standard_False;
435     }
436   }
437
438   return grabParamsOfEdges(Edge_Internal, Param_U | Param_V);
439 }
440
441 //=======================================================================
442 //function : grabParamsOfInternalEdges
443 //purpose  : 
444 //=======================================================================
445 Standard_Boolean BRepMesh_NURBSRangeSplitter::grabParamsOfEdges (
446   const EdgeType         theEdgeType,
447   const Standard_Integer theParamDimensionFlag) const
448 {
449   if ((theParamDimensionFlag & (Param_U | Param_V)) == 0)
450   {
451     return Standard_False;
452   }
453
454   const IMeshData::IFaceHandle& aDFace = GetDFace ();
455   for (Standard_Integer aWireIt = 0; aWireIt < aDFace->WiresNb (); ++aWireIt)
456   {
457     const IMeshData::IWireHandle& aDWire = aDFace->GetWire (aWireIt);
458     for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb (); ++aEdgeIt)
459     {
460       const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIt);
461       for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb (); ++aPCurveIt)
462       {
463         const IMeshData::IPCurveHandle& aDPCurve = aDEdge->GetPCurve (aPCurveIt);
464         if (aDPCurve->GetFace () == aDFace)
465         {
466           if (theEdgeType == Edge_Internal && !aDPCurve->IsInternal ())
467           {
468             continue;
469           }
470
471           for (Standard_Integer aPointIt = 0; aPointIt < aDPCurve->ParametersNb (); ++aPointIt)
472           {
473             const gp_Pnt2d& aPnt2d = aDPCurve->GetPoint (aPointIt);
474             if (theParamDimensionFlag & Param_U)
475             {
476               const_cast<IMeshData::IMapOfReal&>(GetParametersU ()).Add (aPnt2d.X ());
477             }
478
479             if (theParamDimensionFlag & Param_V)
480             {
481               const_cast<IMeshData::IMapOfReal&>(GetParametersV ()).Add (aPnt2d.Y ());
482             }
483           }
484         }
485       }
486     }
487   }
488
489   return Standard_True;
490 }
491
492 //=======================================================================
493 //function : computeGrainAndFilterParameters
494 //purpose  : 
495 //=======================================================================
496 Handle(IMeshData::SequenceOfReal) BRepMesh_NURBSRangeSplitter::computeGrainAndFilterParameters(
497   const IMeshData::IMapOfReal&            theSourceParams,
498   const Standard_Real                     theTol2d,
499   const Standard_Real                     theRangeDiff,
500   const Standard_Real                     theDelta,
501   const IMeshTools_Parameters&            theParameters,
502   const Handle(NCollection_IncAllocator)& theAllocator) const
503 {
504   // Sort and filter sequence of parameters
505   Standard_Real aMinDiff = Precision::PConfusion();
506   if (theDelta < 1.)
507   {
508     aMinDiff /= theDelta;
509   }
510
511   aMinDiff = Max(theParameters.MinSize, aMinDiff);
512
513   const Standard_Real aDiffMaxLim = 0.1 * theRangeDiff;
514   const Standard_Real aDiffMinLim = Max(0.005 * theRangeDiff,
515                                         2. * theTol2d);
516   const Standard_Real aDiff = Max(theParameters.MinSize,
517                                   Min(aDiffMaxLim, aDiffMinLim));
518   return filterParameters(theSourceParams, aMinDiff, aDiff, theAllocator);
519 }
520
521 //=======================================================================
522 //function : filterParameters
523 //purpose  : 
524 //=======================================================================
525 Handle(IMeshData::SequenceOfReal) BRepMesh_NURBSRangeSplitter::filterParameters(
526   const IMeshData::IMapOfReal&            theParams,
527   const Standard_Real                     theMinDist,
528   const Standard_Real                     theFilterDist,
529   const Handle(NCollection_IncAllocator)& theAllocator) const
530 {
531   Handle(IMeshData::SequenceOfReal) aResult = new IMeshData::SequenceOfReal(theAllocator);
532
533   // Sort sequence of parameters
534   const Standard_Integer anInitLen = theParams.Extent();
535
536   if (anInitLen < 1)
537   {
538     return aResult;
539   }
540
541   TColStd_Array1OfReal aParamArray(1, anInitLen);
542   Standard_Integer j;
543   for (j = 1; j <= anInitLen; j++)
544     aParamArray(j) = theParams(j);
545
546   std::sort(aParamArray.begin(), aParamArray.end());
547
548   // mandatory pre-filtering using the first (minimal) filter value
549   Standard_Integer aParamLength = 1;
550   for (j = 2; j <= anInitLen; j++)
551   {
552     if ((aParamArray(j) - aParamArray(aParamLength)) > theMinDist)
553     {
554       if (++aParamLength < j)
555         aParamArray(aParamLength) = aParamArray(j);
556     }
557   }
558
559   //perform filtering on series
560   Standard_Real aLastAdded, aLastCandidate;
561   Standard_Boolean isCandidateDefined = Standard_False;
562   aLastAdded = aParamArray(1);
563   aLastCandidate = aLastAdded;
564   aResult->Append(aLastAdded);
565
566   for (j = 2; j < aParamLength; j++)
567   {
568     Standard_Real aVal = aParamArray(j);
569     if (aVal - aLastAdded > theFilterDist)
570     {
571       //adds the parameter
572       if (isCandidateDefined)
573       {
574         aLastAdded = aLastCandidate;
575         isCandidateDefined = Standard_False;
576         j--;
577       }
578       else
579       {
580         aLastAdded = aVal;
581       }
582       aResult->Append(aLastAdded);
583       continue;
584     }
585
586     aLastCandidate = aVal;
587     isCandidateDefined = Standard_True;
588   }
589   aResult->Append(aParamArray(aParamLength));
590
591   return aResult;
592 }