Salome HOME
f69cd48b54ebe71c270fb2df7885fe7582747948
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_GeoExtensions.cpp
1 // Copyright (C) 2019-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <PlaneGCSSolver_GeoExtensions.h>
21 #include <PlaneGCSSolver_Tools.h>
22
23 #include <GeomAPI_BSpline2d.h>
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_XY.h>
26
27 #include <cmath>
28
29 namespace GCS
30 {
31
32 DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam)
33 {
34   if (!isCacheValid())
35     rebuildCache();
36
37   std::shared_ptr<GeomAPI_Pnt2d> aValue;
38   std::shared_ptr<GeomAPI_XY> aDeriv;
39   myCurve->D1(u, aValue, aDeriv);
40
41   // calculate the derivative on solver's parameter
42   std::shared_ptr<GeomAPI_Pnt2d> aValueDeriv(new GeomAPI_Pnt2d(0.0, 0.0));
43   bool hasParam = false;
44   std::list<GeomPnt2dPtr> aPolesDeriv;
45   for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt) {
46     double x = 0.0, y = 0.0;
47     if (anIt->x == derivparam) {
48       x = 1.0;
49       hasParam = true;
50     }
51     else if (anIt->y == derivparam) {
52       y = 1.0;
53       hasParam = true;
54     }
55           aPolesDeriv.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(x, y)));
56   }
57   if (hasParam) {
58     // use non-periodic curve, because the most of B-spline coefficients are 0,
59     // thus, it is not necessary to keep original knots and multiplicities to get correct value
60     std::shared_ptr<GeomAPI_BSpline2d> aCurveDeriv(
61         new GeomAPI_BSpline2d(degree, aPolesDeriv, myCachedWeights));
62     aCurveDeriv->D0(u, aValueDeriv);
63   }
64
65   return DeriVector2(aValue->x(), aValue->y(),
66                      aValueDeriv->x() + aDeriv->x() * du, aValueDeriv->y() + aDeriv->y() * du);
67 }
68
69 DeriVector2 BSplineImpl::CalculateNormal(Point &p, double* derivparam)
70 {
71   if (!isCacheValid())
72     rebuildCache();
73
74   double u = 0.0;
75   if (!myCurve->parameter(GeomPnt2dPtr(new GeomAPI_Pnt2d(*p.x, *p.y)), 1e100, u))
76     return DeriVector2();
77
78   std::shared_ptr<GeomAPI_Pnt2d> aValue;
79   std::shared_ptr<GeomAPI_XY> aDeriv;
80   myCurve->D1(u, aValue, aDeriv);
81
82   DeriVector2 norm(aDeriv->x(), aDeriv->y(), 0.0, 0.0);
83   return norm.rotate90ccw();
84 }
85
86 BSplineImpl* BSplineImpl::Copy()
87 {
88   return new BSplineImpl(*this);
89 }
90
91
92 bool BSplineImpl::isCacheValid() const
93 {
94   // curve has to be initialized
95   bool isValid = myCurve.get() && !myCurve->isNull();
96
97   static const double THE_TOLERANCE = 1.e-7;
98   // compare poles
99   isValid = isValid && poles.size() == myCachedPoles.size();
100   std::list<GeomPnt2dPtr>::const_iterator aCachePIt = myCachedPoles.begin();
101   GCS::VEC_P::const_iterator aPolesIt = poles.begin();
102   for (; isValid && aPolesIt != poles.end(); ++aPolesIt, ++aCachePIt) {
103     isValid = isValid && fabs((*aCachePIt)->x() - *aPolesIt->x) < THE_TOLERANCE
104                       && fabs((*aCachePIt)->y() - *aPolesIt->y) < THE_TOLERANCE;
105   }
106
107   // compare weights
108   isValid = isValid && weights.size() == myCachedWeights.size();
109   std::list<double>::const_iterator aCacheWIt = myCachedWeights.begin();
110   GCS::VEC_pD::const_iterator aWeightsIt = weights.begin();
111   for (; isValid && aWeightsIt != weights.end(); ++aWeightsIt, ++aCacheWIt)
112     isValid = isValid && fabs(*aCacheWIt - **aWeightsIt) < THE_TOLERANCE;
113
114   return isValid;
115 }
116
117 void BSplineImpl::rebuildCache()
118 {
119   myCachedPoles.clear();
120   myCachedWeights.clear();
121   myCachedKnots.clear();
122   myCachedMultiplicities.clear();
123
124   for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt)
125     myCachedPoles.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(*anIt->x, *anIt->y)));
126   for (GCS::VEC_pD::iterator anIt = weights.begin(); anIt != weights.end(); ++anIt)
127     myCachedWeights.push_back(**anIt);
128   for (GCS::VEC_pD::iterator anIt = knots.begin(); anIt != knots.end(); ++anIt)
129     myCachedKnots.push_back(**anIt);
130   myCachedMultiplicities.assign(mult.begin(), mult.end());
131
132   myCurve.reset(new GeomAPI_BSpline2d(degree, myCachedPoles, myCachedWeights,
133                                       myCachedKnots, myCachedMultiplicities, periodic));
134 }
135
136 } // namespace GCS