Salome HOME
c57210de9e049d6b22169eaa9c78f5d4d0c7cb98
[modules/med.git] / src / INTERP_KERNEL / Geometric2D / InterpKernelGeo2DComposedEdge.cxx
1 // Copyright (C) 2007-2012  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.
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 "InterpKernelGeo2DComposedEdge.hxx"
21 #include "InterpKernelGeo2DElementaryEdge.hxx"
22 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
23 #include "InterpKernelGeo2DEdgeInfLin.hxx"
24 #include "InterpKernelException.hxx"
25
26 #include <algorithm>
27 #include <memory>
28 #include <iterator>
29 #include <set>
30
31 using namespace INTERP_KERNEL;
32
33 ComposedEdge::ComposedEdge(const ComposedEdge& other)
34 {
35   for(std::list<ElementaryEdge *>::const_iterator iter=other._sub_edges.begin();iter!=other._sub_edges.end();iter++)
36     _sub_edges.push_back((*iter)->clone());
37 }
38
39 ComposedEdge::~ComposedEdge()
40 {
41   clearAll(_sub_edges.begin());
42 }
43
44 void ComposedEdge::setValueAt(int i, Edge *e, bool direction)
45 {
46   std::list<ElementaryEdge*>::iterator it=_sub_edges.begin();
47   for(int j=0;j<i;j++)
48     it++;
49   delete *it;
50   *it=new ElementaryEdge(e,direction);
51 }
52
53 struct AbsEdgeCmp
54 {
55   AbsEdgeCmp(ElementaryEdge *b):_b1(b) { }
56   bool operator()(ElementaryEdge *a) { return a->getPtr()==_b1->getPtr();}
57
58   ElementaryEdge *_b1;
59 };
60
61 double ComposedEdge::getCommonLengthWith(const ComposedEdge& other) const
62 {
63   double ret=0.;
64   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
65     {
66       if(find_if(other._sub_edges.begin(),other._sub_edges.end(),AbsEdgeCmp(*iter))!=other._sub_edges.end())
67         {
68           const ElementaryEdge *tmp=static_cast<const ElementaryEdge *>(*iter);
69           ret+=tmp->getCurveLength();
70         }
71     }
72   return ret;
73 }
74
75 void ComposedEdge::clear()
76 {
77   clearAll(_sub_edges.begin());
78   _sub_edges.clear();
79 }
80
81 void ComposedEdge::pushBack(Edge *edge, bool direction)
82 {
83   _sub_edges.push_back(new ElementaryEdge(edge,direction));
84 }
85
86 void ComposedEdge::pushBack(ElementaryEdge *elem)
87 {
88   _sub_edges.push_back(elem);
89 }
90
91 void ComposedEdge::pushBack(ComposedEdge *elem)
92 {
93   std::list<ElementaryEdge *> *elemsOfElem=elem->getListBehind();
94   _sub_edges.insert(_sub_edges.end(),elemsOfElem->begin(),elemsOfElem->end());
95 }
96
97 ElementaryEdge *ComposedEdge::operator[](int i) const
98 {
99   std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
100   for(int ii=0;ii<i;ii++)
101     iter++;
102   return *iter;
103 }
104
105 void ComposedEdge::reverse()
106 {
107   _sub_edges.reverse();
108   for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
109     (*iter)->reverse();
110 }
111
112 bool ComposedEdge::presenceOfOn() const
113 {
114   bool ret=false;
115   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
116     ret=((*iter)->getLoc()==FULL_ON_1);
117   return ret;
118 }
119
120 bool ComposedEdge::presenceOfQuadraticEdge() const
121 {
122   bool ret=false;
123   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
124     {
125       Edge *e=(*iter)->getPtr();
126       if(e)
127         ret=dynamic_cast<EdgeArcCircle*>(e)!=0;
128     }
129   return ret;
130 }
131
132 void ComposedEdge::initLocations() const
133 {
134   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
135     (*iter)->initLocations();
136 }
137
138 ComposedEdge *ComposedEdge::clone() const
139 {
140   return new ComposedEdge(*this);
141 }
142
143 bool ComposedEdge::isNodeIn(Node *n) const
144 {
145   bool ret=false;
146   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
147     ret=(*iter)->isNodeIn(n);
148   return ret;
149 }
150
151 /*!
152  * This method computes the area of 'this'.
153  * By definition :
154  * \f[
155  * Area=\int_{Polygon} dS
156  * \f]
157  * Thanks to Green's theorem we have.
158  * \f[
159  * \int_{Polygon} x \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}ydx=\sum_{0 \leq i < nb of edges} AreaOfZone_{Edge_{i}}
160  * \f]
161  * Where \f$ AreaOfZone_{i} \f$ is computed virtually by INTERP_KERNEL::Edge::getAreaOfZone with following formula :
162  * \f[
163  * AreaOfZone_{i}=\int_{Edge_{i}} -ydx
164  * \f]
165  */
166 double ComposedEdge::getArea() const
167 {
168   double ret=0.;
169   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
170     ret+=(*iter)->getAreaOfZone();
171   return ret;
172 }
173
174 double ComposedEdge::getPerimeter() const
175 {
176   double ret=0.;
177   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
178     ret+=(*iter)->getCurveLength();
179   return ret;
180 }
181
182 double ComposedEdge::getHydraulicDiameter() const
183 {
184   return 4*fabs(getArea())/getPerimeter();
185 }
186
187 /*!
188  * This method computes barycenter of 'this' by returning xG in bary[0] and yG in bary[1].
189  * By definition :
190  * \f[
191  * Area \cdot x_{G}=\int_{Polygon} x \cdot dS
192  * \f]
193  * \f[
194  * Area \cdot y_{G}=\int_{Polygon} y \cdot dS
195  * \f]
196  * Thanks to Green's theorem we have.
197  * \f[
198  * \int_{Polygon} x \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}yxdx
199  * \f]
200  * \f[
201  * \int_{Polygon} y \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}\frac{y^{2}}{2}dx
202  * \f]
203  * Area is computed using the same principle than described in INTERP_KERNEL::ComposedEdge::getArea method.
204  * \f$ -\int_{Edge_{i}}yxdx \f$ and \f$ -\int_{Edge_{i}}\frac{y^{2}}{2}dx \f$ are computed virtually with INTERP_KERNEL::Edge::getBarycenterOfZone.
205  */
206 void ComposedEdge::getBarycenter(double *bary) const
207 {
208   bary[0]=0.;
209   bary[1]=0.;
210   double area=0.;
211   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
212     {
213       (*iter)->getBarycenterOfZone(bary);
214       area+=(*iter)->getAreaOfZone();
215     }
216   bary[0]/=area;
217   bary[1]/=area;
218 }
219
220 /*!
221  * Idem ComposedEdge::getBarycenter except that the special case where _sub_edges==1 is dealt here.
222  */
223 void ComposedEdge::getBarycenterGeneral(double *bary) const
224 {
225   if(_sub_edges.empty())
226     throw INTERP_KERNEL::Exception("ComposedEdge::getBarycenterGeneral called on an empty polygon !");
227   if(_sub_edges.size()>2)
228     return getBarycenter(bary);
229   double w;
230   _sub_edges.back()->getBarycenter(bary,w);
231 }
232
233 double ComposedEdge::normalize(ComposedEdge *other, double& xBary, double& yBary)
234 {
235   Bounds b;
236   b.prepareForAggregation();
237   fillBounds(b); 
238   other->fillBounds(b);
239   double dimChar=b.getCaracteristicDim();
240   b.getBarycenter(xBary,yBary);
241   applyGlobalSimilarity(xBary,yBary,dimChar);
242   other->applyGlobalSimilarity(xBary,yBary,dimChar);
243   return dimChar;
244 }
245
246 /*!
247  * This method operates the opposite operation than ComposedEdge::applyGlobalSimilarity.
248  */
249 void ComposedEdge::unApplyGlobalSimilarityExt(ComposedEdge& other, double xBary, double yBary, double fact)
250 {
251   std::set<Node *> allNodes;
252   getAllNodes(allNodes);
253   other.getAllNodes(allNodes);
254   for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
255     (*iter)->unApplySimilarity(xBary,yBary,fact);
256   for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
257     (*iter)->unApplySimilarity(xBary,yBary,fact);
258 }
259
260 double ComposedEdge::normalizeExt(ComposedEdge *other, double& xBary, double& yBary)
261 {
262   Bounds b;
263   b.prepareForAggregation();
264   fillBounds(b); 
265   other->fillBounds(b);
266   double dimChar=b.getCaracteristicDim();
267   b.getBarycenter(xBary,yBary);
268   applyGlobalSimilarity2(other,xBary,yBary,dimChar);
269   return dimChar;
270 }
271
272 void ComposedEdge::dumpInXfigFile(std::ostream& stream, int resolution, const Bounds& box) const
273 {
274   stream.precision(10);
275   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
276     (*iter)->dumpInXfigFile(stream,resolution,box);
277 }
278
279 Node *ComposedEdge::getEndNode() const
280 {
281   return _sub_edges.back()->getEndNode();
282 }
283
284 Node *ComposedEdge::getStartNode() const
285 {
286   return _sub_edges.front()->getStartNode();
287 }
288
289 bool ComposedEdge::changeEndNodeWith(Node *node) const
290 {
291   return _sub_edges.back()->changeEndNodeWith(node);
292 }
293
294 bool ComposedEdge::changeStartNodeWith(Node *node) const
295 {
296   return _sub_edges.front()->changeStartNodeWith(node);
297 }
298
299 void ComposedEdge::fillBounds(Bounds& output) const
300 {
301   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
302     (*iter)->fillBounds(output);
303 }
304
305 /*!
306  * \b WARNING : applies similarity \b ONLY on edges without any change on Nodes. To perform a global similarity call applyGlobalSimilarity.
307  */
308 void ComposedEdge::applySimilarity(double xBary, double yBary, double dimChar)
309 {
310   for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
311     (*iter)->applySimilarity(xBary,yBary,dimChar);
312 }
313
314 /*!
315  * Perform Similarity transformation on all elements of this Nodes and Edges.
316  */
317 void ComposedEdge::applyGlobalSimilarity(double xBary, double yBary, double dimChar)
318 {
319   std::set<Node *> allNodes;
320   getAllNodes(allNodes);
321   for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
322     (*iter)->applySimilarity(xBary,yBary,dimChar);
323   for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
324     (*iter)->applySimilarity(xBary,yBary,dimChar);
325 }
326
327 /*!
328  * Perform Similarity transformation on all elements of this Nodes and Edges on 'this' and 'other'.
329  * Nodes can be shared between 'this' and 'other'.
330  */
331 void ComposedEdge::applyGlobalSimilarity2(ComposedEdge *other, double xBary, double yBary, double dimChar)
332 {
333   std::set<Node *> allNodes;
334   getAllNodes(allNodes);
335   std::set<Node *> allNodes2;
336   other->getAllNodes(allNodes2);
337   for(std::set<Node *>::const_iterator it=allNodes2.begin();it!=allNodes2.end();it++)
338     if(allNodes.find(*it)!=allNodes.end())
339       (*it)->declareOn();
340   allNodes.insert(allNodes2.begin(),allNodes2.end());
341   for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
342     (*iter)->applySimilarity(xBary,yBary,dimChar);
343   for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
344     (*iter)->applySimilarity(xBary,yBary,dimChar);
345   for(std::list<ElementaryEdge *>::iterator iter=other->_sub_edges.begin();iter!=other->_sub_edges.end();iter++)
346     (*iter)->applySimilarity(xBary,yBary,dimChar);
347 }
348
349 /*!
350  * This method append to param 'partConsidered' the part of length of subedges IN or ON.
351  * @param partConsidered INOUT param.
352  */
353 void ComposedEdge::dispatchPerimeter(double& partConsidered) const
354 {
355   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
356     {
357       TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
358       if(loc==FULL_IN_1 || loc==FULL_ON_1)
359         partConsidered+=(*iter)->getCurveLength();
360     }
361 }
362
363 /*!
364  * Idem dispatchPerimeterExcl except that when a subedge is declared as ON this subedge is counted in commonPart.
365  */
366 void ComposedEdge::dispatchPerimeterExcl(double& partConsidered, double& commonPart) const
367 {
368   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
369     {
370       TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
371       if(loc==FULL_IN_1)
372         partConsidered+=(*iter)->getCurveLength();
373       if(loc==FULL_ON_1)
374         commonPart+=(*iter)->getCurveLength();
375     }
376 }
377
378 void ComposedEdge::getAllNodes(std::set<Node *>& output) const
379 {
380   std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
381   for(;iter!=_sub_edges.end();iter++)
382     (*iter)->getAllNodes(output);
383 }
384
385 void ComposedEdge::getBarycenter(double *bary, double& weigh) const
386 {
387   weigh=0.; bary[0]=0.; bary[1]=0.;
388   double tmp1,tmp2[2];
389   for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
390     {
391       (*iter)->getBarycenter(tmp2,tmp1);
392       weigh+=tmp1;
393       bary[0]+=tmp1*tmp2[0];
394       bary[1]+=tmp1*tmp2[1];
395     }
396   bary[0]/=weigh;
397   bary[1]/=weigh;
398 }
399
400 bool ComposedEdge::isInOrOut(Node *nodeToTest) const
401 {
402   Bounds b; b.prepareForAggregation();
403   fillBounds(b);
404   if(b.nearlyWhere((*nodeToTest)[0],(*nodeToTest)[1])==OUT)
405     return false;
406   // searching for e1
407   std::set<Node *> nodes;
408   getAllNodes(nodes);
409   std::set<double> radialDistributionOfNodes;
410   std::set<Node *>::const_iterator iter;
411   for(iter=nodes.begin();iter!=nodes.end();iter++)
412     radialDistributionOfNodes.insert(nodeToTest->getSlope(*(*iter)));
413   std::vector<double> radialDistrib(radialDistributionOfNodes.begin(),radialDistributionOfNodes.end());
414   radialDistributionOfNodes.clear();
415   std::vector<double> radialDistrib2(radialDistrib.size());
416   copy(radialDistrib.begin()+1,radialDistrib.end(),radialDistrib2.begin());
417   radialDistrib2.back()=M_PI+radialDistrib.front();
418   std::vector<double> radialDistrib3(radialDistrib.size());
419   std::transform(radialDistrib2.begin(),radialDistrib2.end(),radialDistrib.begin(),radialDistrib3.begin(),std::minus<double>());
420   std::vector<double>::iterator iter3=max_element(radialDistrib3.begin(),radialDistrib3.end());
421   int i=iter3-radialDistrib3.begin();
422   // ok for e1 - Let's go.
423   EdgeInfLin *e1=new EdgeInfLin(nodeToTest,radialDistrib[i]+radialDistrib3[i]/2.);
424   double ref=e1->getCharactValue(*nodeToTest);
425   std::set< IntersectElement > inOutSwitch;
426   for(std::list<ElementaryEdge *>::const_iterator iter4=_sub_edges.begin();iter4!=_sub_edges.end();iter4++)
427     {
428       ElementaryEdge *val=(*iter4);
429       if(val)
430         {
431           Edge *e=val->getPtr();
432           std::auto_ptr<EdgeIntersector> intersc(Edge::BuildIntersectorWith(e1,e));
433           bool obviousNoIntersection,areOverlapped;
434           intersc->areOverlappedOrOnlyColinears(0,obviousNoIntersection,areOverlapped);
435           if(obviousNoIntersection)
436             {
437               continue;
438             }
439           if(!areOverlapped)
440             {
441               std::list< IntersectElement > listOfIntesc=intersc->getIntersectionsCharacteristicVal();
442               for(std::list< IntersectElement >::iterator iter2=listOfIntesc.begin();iter2!=listOfIntesc.end();iter2++)
443                 if((*iter2).isIncludedByBoth())
444                   inOutSwitch.insert(*iter2);
445               }
446           //if overlapped we can forget
447         }
448       else
449         throw Exception("Invalid use of ComposedEdge::isInOrOut : only one level supported !");
450     }
451   e1->decrRef();
452   bool ret=false;
453   for(std::set< IntersectElement >::iterator iter4=inOutSwitch.begin();iter4!=inOutSwitch.end();iter4++)
454     {
455       if((*iter4).getVal1()<ref)
456         {
457           if((*iter4).getNodeOnly()->getLoc()==ON_1)
458             ret=!ret;
459         }
460       else
461         break;
462     }
463   return ret;
464 }
465
466 /*bool ComposedEdge::isInOrOut(Node *aNodeOn, Node *nodeToTest) const
467 {
468   
469   EdgeInfLin *e1=new EdgeInfLin(aNodeOn,nodeToTest);
470   double ref=e1->getCharactValue(*nodeToTest);
471   set< IntersectElement > inOutSwitch;
472   for(vector<AbstractEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
473     {
474       ElementaryEdge *val=dynamic_cast<ElementaryEdge *>(*iter);
475       if(val)
476         {
477           Edge *e=val->getPtr();
478           auto_ptr<Intersector> intersc(Edge::buildIntersectorWith(e1,e));
479           bool obviousNoIntersection,areOverlapped;
480           intersc->areOverlappedOrOnlyColinears(0,obviousNoIntersection,areOverlapped);
481           if(obviousNoIntersection)
482             {
483               continue;
484             }
485           if(!areOverlapped)
486             {
487               list< IntersectElement > listOfIntesc=intersc->getIntersectionsCharacteristicVal();
488               for(list< IntersectElement >::iterator iter2=listOfIntesc.begin();iter2!=listOfIntesc.end();iter2++)
489                 if((*iter2).isIncludedByBoth())
490                   inOutSwitch.insert(*iter2);
491               }
492           //if overlapped we can forget
493         }
494       else
495         throw Exception("Invalid use of ComposedEdge::isInOrOut : only one level supported !");
496     }
497   e1->decrRef();
498   bool ret=false;
499   for(set< IntersectElement >::iterator iter=inOutSwitch.begin();iter!=inOutSwitch.end();iter++)
500     {
501       if((*iter).getVal1()<ref)
502         {
503           if((*iter).getNodeOnly()->getLoc()==ON_1)
504             ret=!ret;
505         }
506       else
507         break;
508     }
509   return ret;
510 }*/
511
512 bool ComposedEdge::getDirection() const
513 {
514   throw Exception("ComposedEdge::getDirection : no sense");
515 }
516
517 bool ComposedEdge::intresincEqCoarse(const Edge *other) const
518 {
519   if(_sub_edges.size()!=1)
520     return false;
521   return _sub_edges.front()->intresincEqCoarse(other);
522 }
523
524 void ComposedEdge::clearAll(std::list<ElementaryEdge *>::iterator startToDel)
525 {
526   for(std::list<ElementaryEdge *>::iterator iter=startToDel;iter!=_sub_edges.end();iter++)
527     delete (*iter);
528 }