1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 // File : BLSURFPlugin_Attractor.cxx
22 // Authors : Renaud Nédélec (OCC)
25 // The idea of the algorithm used to calculate the distance on a
26 // non-euclidian parametric surface has been found in the ref. below:
28 // Ref:"Accurate Anisotropic Fast Marching for Diffusion-Based Geodesic Tractography"
29 // S. Jbabdi, P. Bellec, R. Toro, Daunizeau, M. Pélégrini-Issac, and H. Benali1
32 #include "BLSURFPlugin_Attractor.hxx"
33 #include <utilities.h>
38 #include "ShapeAnalysis.hxx"
39 #include "ShapeConstruct_ProjectCurveOnSurface.hxx"
40 #include <Precision.hxx>
42 BLSURFPlugin_Attractor::BLSURFPlugin_Attractor ()
63 _isEmpty(true){ MESSAGE("construction of a void attractor"); }
65 BLSURFPlugin_Attractor::BLSURFPlugin_Attractor (const TopoDS_Face& Face, const TopoDS_Shape& Attractor, const std::string& attEntry)
89 _attractorShape = Attractor;
94 bool BLSURFPlugin_Attractor::init(){
99 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(_face);
101 // Calculation of the bounds of the face
102 ShapeAnalysis::GetFaceUVBounds(_face,_u1,_u2,_v1,_v2);
103 MESSAGE("u1 = "<<_u1<<" ,u2 = "<<_u2);
104 MESSAGE("v1 = "<<_v1<<" ,v2 = "<<_v2);
105 // _gridU = floor (_u2 - _u1) / _step;
106 // _gridV = floor (_v2 - _v1) / _step;
111 for (i=0; i<=_gridU; i++){
112 _vectU.push_back(_u1+i*(_u2-_u1)/_gridU) ;
114 for (j=0; j<=_gridV; j++){
115 _vectV.push_back(_v1+j*(_v2-_v1)/_gridV) ;
118 // Initialization of _DMap and _known
119 std::vector<double> temp(_gridV+1,std::numeric_limits<double>::infinity()); // Set distance of all "far" points to Infinity
120 for (i=0; i<=_gridU; i++){
121 _DMap.push_back(temp);
123 std::vector<bool> temp2(_gridV+1,false);
124 for (i=0; i<=_gridU; i++){
125 _known.push_back(temp2);
129 // Determination of the starting points
130 TopExp_Explorer anEdgeExp(_attractorShape, TopAbs_EDGE, TopAbs_FACE);
131 TopExp_Explorer aVertExp(_attractorShape, TopAbs_VERTEX, TopAbs_EDGE);
133 for(; anEdgeExp.More(); anEdgeExp.Next()){
134 const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current());
135 edgeInit(aSurf, anEdge);
138 for(; aVertExp.More(); aVertExp.Next()){
139 const TopoDS_Vertex& aVertex = TopoDS::Vertex(aVertExp.Current());
141 gp_Pnt P = BRep_Tool::Pnt(aVertex);
142 GeomAPI_ProjectPointOnSurf projector( P, aSurf );
143 projector.LowerDistanceParameters(u0,v0);
144 MESSAGE("u0 = "<<u0<<" ,v0 = "<<v0);
145 i0 = floor ( (u0 - _u1) * _gridU / (_u2 - _u1) + 0.5 );
146 j0 = floor ( (v0 - _v1) * _gridV / (_v2 - _v1) + 0.5 );
147 TPnt[0]=0.; // Set the distance of the starting point to 0.
151 _trial.insert(TPnt); // Move starting point to _trial
156 void BLSURFPlugin_Attractor::edgeInit(Handle(Geom_Surface) theSurf, const TopoDS_Edge& anEdge){
162 Handle(Geom2d_Curve) aCurve2d;
163 Handle(Geom_Curve) aCurve3d = BRep_Tool::Curve (anEdge, first, last);
164 ShapeConstruct_ProjectCurveOnSurface curveProjector;
165 curveProjector.Init(theSurf, Precision::Confusion());
166 curveProjector.PerformAdvanced (aCurve3d, first, last, aCurve2d);
167 //int N = 20 * (last - first) / _step; // If the edge is a circle : 4>Pi so the number of points on the edge should be good -> 5 for ellipses
169 MESSAGE("Initialization of the starting points")
170 for (i=0; i<=N; i++){
171 P2 = aCurve2d->Value(first + i * (last-first) / N);
172 i0 = floor( (P2.X() - _u1) * _gridU / (_u2 - _u1) + 0.5 );
173 j0 = floor( (P2.Y() - _v1) * _gridV / (_v2 - _v1) + 0.5 );
174 // MESSAGE("i0 = "<<i0<<" , j0 = "<<j0)
181 MESSAGE("_trial.size() = "<<_trial.size())
185 void BLSURFPlugin_Attractor::SetParameters(double Start_Size, double End_Size, double Action_Radius, double Constant_Radius){
186 MESSAGE("BLSURFPlugin_Attractor::SetParameters")
187 _startSize = Start_Size;
189 _actionRadius = Action_Radius;
190 _constantRadius = Constant_Radius;
193 double BLSURFPlugin_Attractor::_distance(double u, double v){
195 // // calcul des coins du carre
196 // double stepU = (_u2 - _u1) / _gridU ;
197 // double stepV = (_v2 - _v1) / _gridV ;
199 // int i_sup = floor ( fabs(u - _u1) / stepU ) + 1;
200 // int j_sup = floor ( fabs(v - _v1) / stepV ) + 1;
201 // i_sup = std::min( i_sup, _gridU);
202 // j_sup = std::min( j_sup, _gridV);
205 // // int i_inf = floor ( (u - _u1) * _mapGrid / (_u2 - _u1) );
206 // // int j_inf = floor ( (v - _v1) * _mapGrid / (_v2 - _v1) );
207 // int i_inf = i_sup - 1;
208 // int j_inf = j_sup - 1;
210 // double u_sup = _vectU[i_sup];
211 // double v_sup = _vectV[j_sup];
213 // double u_inf = _vectU[i_inf];
214 // double v_inf = _vectV[j_inf];
216 // // // MESSAGE("i_inf , i_sup, j_inf, j_sup = "<<i_inf<<" , "<<i_sup<<" , "<<j_inf<<" , "<<j_sup)
217 // // // MESSAGE("u = "<<u<<", _u1 ="<<_u1)
218 // // // MESSAGE("(u - _u1) / stepU = "<< (u - _u1) / stepU)
219 // double d1 = _DMap[i_sup][j_sup];
220 // double d2 = _DMap[i_sup][j_inf];
221 // double d3 = _DMap[i_inf][j_sup];
222 // double d4 = _DMap[i_inf][j_inf];
224 // // double d = 0.25 * (d1 + d2 + d3 + d4);
225 // // //double d = d1;
227 // // // if (fabs(v_inf-v_sup) < 1e-14 || fabs(u_inf-u_sup) < 1e-14 ){
228 // // // MESSAGE("division par zero v_inf-v_sup = "<< fabs(v_inf-v_sup)<<" , u_inf-u_sup"<<fabs(u_inf-u_sup))
229 // // // MESSAGE("v_inf = "<< v_inf<<" , v_sup"<<v_sup)
230 // // // MESSAGE("u_inf = "<< u_inf<<" , u_sup"<<u_sup)
232 // double P_inf = d4 * ( 1 + (u_inf - u) / stepU + (v_inf - v) / stepV )
233 // + d3 * ( (v - v_inf) / stepV )
234 // + d2 * ( (u - u_inf) / stepU ) ;
236 // double P_sup = d1 * ( 1 + (u - u_sup) / stepU + (v - v_sup) / stepV )
237 // + d3 * ( (u_sup - u) / stepU )
238 // + d2 * ( (v_sup - v) / stepV ) ;
240 // // calcul de la distance (interpolation lineaire)
241 // bool P_switch = (u+v > u_sup+v_sup);
252 // BLSURF seems to perform a linear interpolation so it's sufficient to give it a non-continuous distance map
253 int i = floor ( (u - _u1) * _gridU / (_u2 - _u1) + 0.5 );
254 int j = floor ( (v - _v1) * _gridV / (_v2 - _v1) + 0.5 );
260 double BLSURFPlugin_Attractor::GetSize(double u, double v){
261 double myDist = 0.5 * (_distance(u,v) - _constantRadius + fabs(_distance(u,v) - _constantRadius));
263 // MESSAGE("Warning myDist<0 : myDist= "<<myDist)
268 if (fabs(_actionRadius) <= std::numeric_limits<double>::epsilon()){
269 if (myDist <= std::numeric_limits<double>::epsilon()){
277 return _endSize - (_endSize - _startSize) * exp(- myDist * myDist / (_actionRadius * _actionRadius) );
281 return _startSize + ( 0.5 * (_distance(u,v) - _constantRadius + abs(_distance(u,v) - _constantRadius)) ) ;
287 void BLSURFPlugin_Attractor::BuildMap(){
289 MESSAGE("building the map");
296 double Guu, Gvv, Guv; // Components of the local metric tensor
301 IJ_Pnt Current_Pnt(2,0);
303 TTrialSet::iterator min;
304 TTrialSet::iterator found;
305 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(_face);
307 // While there are points in "Trial" (representing a kind of advancing front), loop on them -----------------------------------------------------------
308 while (_trial.size() > 0 ){
309 min = _trial.begin(); // Get trial point with min distance from start
312 _known[i0][j0] = true; // Move it to "Known"
313 // MESSAGE("_DMap["<<i0<<"]["<<j0<<"] = "<<_DMap[i0][j0])
314 _trial.erase(min); // Remove it from "Trial"
315 // Loop on neighbours of the trial min --------------------------------------------------------------------------------------------------------------
316 for (i=i0 - 1 ; i <= i0 + 1 ; i++){
317 if (!aSurf->IsUPeriodic()){ // Periodic conditions in U
323 ip = (i + _gridU + 1) % (_gridU+1); // We get a periodic index :
324 for (j=j0 - 1 ; j <= j0 + 1 ; j++){ // ip=modulo(i,N+2) so that i=-1->ip=N; i=0 -> ip=0 ; ... ; i=N+1 -> ip=0;
325 if (!aSurf->IsVPeriodic()){ // Periodic conditions in V .
332 jp = (j + _gridV + 1) % (_gridV+1);
334 if (!_known[ip][jp]){ // If the distance is not known yet
335 aSurf->D1(_vectU[ip],_vectV[jp],P,D1U,D1V); // Calculate the metric at (i,j)
336 // G(i,j) = | ||dS/du||**2 * |
337 // | <dS/du,dS/dv> ||dS/dv||**2 |
338 Guu = D1U.X()*D1U.X() + D1U.Y()*D1U.Y() + D1U.Z()*D1U.Z(); // Guu = ||dS/du||**2
339 Gvv = D1V.X()*D1V.X() + D1V.Y()*D1V.Y() + D1V.Z()*D1V.Z(); // Gvv = ||dS/dv||**2
340 Guv = D1U.X()*D1V.X() + D1U.Y()*D1V.Y() + D1U.Z()*D1V.Z(); // Guv = Gvu = < dS/du,dS/dv >
341 D_Ref = _DMap[ip][jp]; // Set a ref. distance of the point to its value in _DMap
342 TPnt[0] = D_Ref; // (may be infinite or uncertain)
345 Dist_changed = false;
346 // Loop on neighbours to calculate the min distance from them ---------------------------------------------------------------------------------
347 for (k=i - 1 ; k <= i + 1 ; k++){
348 if (!aSurf->IsUPeriodic()){ // Periodic conditions in U
355 kp = (k + _gridU + 1) % (_gridU+1); // periodic index
356 for (n=j - 1 ; n <= j + 1 ; n++){
357 if (!aSurf->IsVPeriodic()){ // Periodic conditions in V
364 np = (n + _gridV + 1) % (_gridV+1);
365 if (_known[kp][np]){ // If the distance of the neighbour is known
366 // Calculate the distance from (k,n)
367 du = (k-i) * (_u2 - _u1) / _gridU;
368 dv = (n-j) * (_v2 - _v1) / _gridV;
369 Dist = _DMap[kp][np] + sqrt( Guu * du*du + 2*Guv * du*dv + Gvv * dv*dv ); // ds**2 = du'Gdu + 2*du'Gdv + dv'Gdv (G is always symetrical)
370 if (Dist < D_Ref) { // If smaller than ref. distance -> update ref. distance
376 } // End of the loop on neighbours --------------------------------------------------------------------------------------------------------------
377 if (Dist_changed) { // If distance has been updated, update _trial
378 found=_trial.find(TPnt);
379 if (found != _trial.end()){
380 _trial.erase(found); // Erase the point if it was already in _trial
385 _DMap[ip][jp] = D_Ref; // Set it distance to the minimum distance found during the loop above
386 _trial.insert(TPnt); // Insert it (or reinsert it) in _trial
388 } // end if (!_known[ip][jp])
395 MESSAGE("_gridU = "<<_gridU<<" , _gridV = "<<_gridV)
396 } // end of BuildMap()