1 // Copyright (C) 2007-2013 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
19 // Author : Anthony Geay (CEA/DEN)
21 #include "InterpKernelGeo2DComposedEdge.hxx"
22 #include "InterpKernelGeo2DElementaryEdge.hxx"
23 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
24 #include "InterpKernelGeo2DEdgeInfLin.hxx"
25 #include "InterpKernelException.hxx"
32 using namespace INTERP_KERNEL;
34 ComposedEdge::ComposedEdge(const ComposedEdge& other)
36 for(std::list<ElementaryEdge *>::const_iterator iter=other._sub_edges.begin();iter!=other._sub_edges.end();iter++)
37 _sub_edges.push_back((*iter)->clone());
40 ComposedEdge::~ComposedEdge()
42 clearAll(_sub_edges.begin());
45 void ComposedEdge::setValueAt(int i, Edge *e, bool direction)
47 std::list<ElementaryEdge*>::iterator it=_sub_edges.begin();
51 *it=new ElementaryEdge(e,direction);
56 AbsEdgeCmp(ElementaryEdge *b):_b1(b) { }
57 bool operator()(ElementaryEdge *a) { return a->getPtr()==_b1->getPtr();}
62 double ComposedEdge::getCommonLengthWith(const ComposedEdge& other) const
65 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
67 if(find_if(other._sub_edges.begin(),other._sub_edges.end(),AbsEdgeCmp(*iter))!=other._sub_edges.end())
69 const ElementaryEdge *tmp=static_cast<const ElementaryEdge *>(*iter);
70 ret+=tmp->getCurveLength();
76 void ComposedEdge::clear()
78 clearAll(_sub_edges.begin());
82 void ComposedEdge::pushBack(Edge *edge, bool direction)
84 _sub_edges.push_back(new ElementaryEdge(edge,direction));
87 void ComposedEdge::pushBack(ElementaryEdge *elem)
89 _sub_edges.push_back(elem);
92 void ComposedEdge::pushBack(ComposedEdge *elem)
94 std::list<ElementaryEdge *> *elemsOfElem=elem->getListBehind();
95 _sub_edges.insert(_sub_edges.end(),elemsOfElem->begin(),elemsOfElem->end());
98 ElementaryEdge *ComposedEdge::operator[](int i) const
100 std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
101 for(int ii=0;ii<i;ii++)
106 void ComposedEdge::reverse()
108 _sub_edges.reverse();
109 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
113 bool ComposedEdge::presenceOfOn() const
116 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
117 ret=((*iter)->getLoc()==FULL_ON_1);
121 bool ComposedEdge::presenceOfQuadraticEdge() const
124 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
126 Edge *e=(*iter)->getPtr();
128 ret=dynamic_cast<EdgeArcCircle*>(e)!=0;
133 void ComposedEdge::initLocations() const
135 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
136 (*iter)->initLocations();
140 * Reset the status of all edges (OUT, IN, ON) because they were potentially assignated
141 * by the previous candidate processing.
143 void ComposedEdge::initLocationsWithOther(const ComposedEdge& other) const
145 std::set<Edge *> s1,s2;
146 for(std::list<ElementaryEdge *>::const_iterator it1=_sub_edges.begin();it1!=_sub_edges.end();it1++)
147 s1.insert((*it1)->getPtr());
148 for(std::list<ElementaryEdge *>::const_iterator it2=other._sub_edges.begin();it2!=other._sub_edges.end();it2++)
149 s2.insert((*it2)->getPtr());
151 other.initLocations();
152 std::vector<Edge *> s3;
153 std::set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(),std::back_insert_iterator< std::vector<Edge *> >(s3));
154 for(std::vector<Edge *>::const_iterator it3=s3.begin();it3!=s3.end();it3++)
158 ComposedEdge *ComposedEdge::clone() const
160 return new ComposedEdge(*this);
163 bool ComposedEdge::isNodeIn(Node *n) const
166 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
167 ret=(*iter)->isNodeIn(n);
172 * This method computes the area of 'this'.
175 * Area=\int_{Polygon} dS
177 * Thanks to Green's theorem we have.
179 * \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}}
181 * Where \f$ AreaOfZone_{i} \f$ is computed virtually by INTERP_KERNEL::Edge::getAreaOfZone with following formula :
183 * AreaOfZone_{i}=\int_{Edge_{i}} -ydx
186 double ComposedEdge::getArea() const
189 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
190 ret+=(*iter)->getAreaOfZone();
194 double ComposedEdge::getPerimeter() const
197 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
198 ret+=(*iter)->getCurveLength();
202 double ComposedEdge::getHydraulicDiameter() const
204 return 4*fabs(getArea())/getPerimeter();
208 * This method computes barycenter of 'this' by returning xG in bary[0] and yG in bary[1].
211 * Area \cdot x_{G}=\int_{Polygon} x \cdot dS
214 * Area \cdot y_{G}=\int_{Polygon} y \cdot dS
216 * Thanks to Green's theorem we have.
218 * \int_{Polygon} x \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}yxdx
221 * \int_{Polygon} y \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}\frac{y^{2}}{2}dx
223 * Area is computed using the same principle than described in INTERP_KERNEL::ComposedEdge::getArea method.
224 * \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.
226 void ComposedEdge::getBarycenter(double *bary) const
231 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
233 (*iter)->getBarycenterOfZone(bary);
234 area+=(*iter)->getAreaOfZone();
241 * Idem ComposedEdge::getBarycenter except that the special case where _sub_edges==1 is dealt here.
243 void ComposedEdge::getBarycenterGeneral(double *bary) const
245 if(_sub_edges.empty())
246 throw INTERP_KERNEL::Exception("ComposedEdge::getBarycenterGeneral called on an empty polygon !");
247 if(_sub_edges.size()>2)
248 return getBarycenter(bary);
250 _sub_edges.back()->getBarycenter(bary,w);
253 double ComposedEdge::normalizeMe(double& xBary, double& yBary)
256 b.prepareForAggregation();
258 double dimChar=b.getCaracteristicDim();
259 b.getBarycenter(xBary,yBary);
260 applyGlobalSimilarity(xBary,yBary,dimChar);
264 double ComposedEdge::normalize(ComposedEdge *other, double& xBary, double& yBary)
267 b.prepareForAggregation();
269 other->fillBounds(b);
270 double dimChar=b.getCaracteristicDim();
271 b.getBarycenter(xBary,yBary);
272 applyGlobalSimilarity(xBary,yBary,dimChar);
273 other->applyGlobalSimilarity(xBary,yBary,dimChar);
278 * This method operates the opposite operation than ComposedEdge::applyGlobalSimilarity.
280 void ComposedEdge::unApplyGlobalSimilarityExt(ComposedEdge& other, double xBary, double yBary, double fact)
282 std::set<Node *> allNodes;
283 getAllNodes(allNodes);
284 other.getAllNodes(allNodes);
285 for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
286 (*iter)->unApplySimilarity(xBary,yBary,fact);
288 // [Adrien] - same issue as in applyGlobalSimilarity() - see comments there
289 std::set<Edge *> allEdges;
290 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
291 allEdges.insert((*iter)->getPtr());
292 for(std::list<ElementaryEdge *>::iterator iter=other._sub_edges.begin();iter!=other._sub_edges.end();iter++)
293 allEdges.insert((*iter)->getPtr());
294 for(std::set<Edge *>::iterator iter = allEdges.begin();iter != allEdges.end();iter++)
295 (*iter)->unApplySimilarity(xBary,yBary,fact);
298 double ComposedEdge::normalizeExt(ComposedEdge *other, double& xBary, double& yBary)
301 b.prepareForAggregation();
303 other->fillBounds(b);
304 double dimChar=b.getCaracteristicDim();
305 b.getBarycenter(xBary,yBary);
306 applyGlobalSimilarity2(other,xBary,yBary,dimChar);
310 void ComposedEdge::dumpInXfigFile(std::ostream& stream, int resolution, const Bounds& box) const
312 stream.precision(10);
313 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
314 (*iter)->dumpInXfigFile(stream,resolution,box);
317 Node *ComposedEdge::getEndNode() const
319 return _sub_edges.back()->getEndNode();
322 Node *ComposedEdge::getStartNode() const
324 return _sub_edges.front()->getStartNode();
327 bool ComposedEdge::changeEndNodeWith(Node *node) const
329 return _sub_edges.back()->changeEndNodeWith(node);
332 bool ComposedEdge::changeStartNodeWith(Node *node) const
334 return _sub_edges.front()->changeStartNodeWith(node);
337 void ComposedEdge::fillBounds(Bounds& output) const
339 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
340 (*iter)->fillBounds(output);
344 * \b WARNING : applies similarity \b ONLY on edges without any change on Nodes. To perform a global similarity call applyGlobalSimilarity.
346 void ComposedEdge::applySimilarity(double xBary, double yBary, double dimChar)
348 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
349 (*iter)->applySimilarity(xBary,yBary,dimChar);
353 * Perform Similarity transformation on all elements of this Nodes and Edges.
355 void ComposedEdge::applyGlobalSimilarity(double xBary, double yBary, double dimChar)
357 std::set<Node *> allNodes;
358 getAllNodes(allNodes);
359 for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
360 (*iter)->applySimilarity(xBary,yBary,dimChar);
361 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
362 (*iter)->applySimilarity(xBary,yBary,dimChar);
366 * Perform Similarity transformation on all elements of this Nodes and Edges on 'this' and 'other'.
367 * Nodes can be shared between 'this' and 'other'.
369 void ComposedEdge::applyGlobalSimilarity2(ComposedEdge *other, double xBary, double yBary, double dimChar)
371 std::set<Node *> allNodes;
372 getAllNodes(allNodes);
373 std::set<Node *> allNodes2;
374 other->getAllNodes(allNodes2);
375 for(std::set<Node *>::const_iterator it=allNodes2.begin();it!=allNodes2.end();it++)
376 if(allNodes.find(*it)!=allNodes.end())
378 allNodes.insert(allNodes2.begin(),allNodes2.end());
379 for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
380 (*iter)->applySimilarity(xBary,yBary,dimChar);
381 // [Adrien] many ElementaryEdge might reference the same Edge* - ensure we don'y scale twice!
382 std::set<Edge *> allEdges;
383 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
384 allEdges.insert((*iter)->getPtr());
385 for(std::list<ElementaryEdge *>::iterator iter=other->_sub_edges.begin();iter!=other->_sub_edges.end();iter++)
386 allEdges.insert((*iter)->getPtr());
387 // Similarity only on set of unique underlying edges:
388 for(std::set<Edge *>::iterator iter = allEdges.begin();iter != allEdges.end();iter++)
389 (*iter)->applySimilarity(xBary,yBary,dimChar);
393 * This method append to param 'partConsidered' the part of length of subedges IN or ON.
394 * @param partConsidered INOUT param.
396 void ComposedEdge::dispatchPerimeter(double& partConsidered) const
398 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
400 TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
401 if(loc==FULL_IN_1 || loc==FULL_ON_1)
402 partConsidered+=(*iter)->getCurveLength();
407 * Idem dispatchPerimeterExcl except that when a subedge is declared as ON this subedge is counted in commonPart.
409 void ComposedEdge::dispatchPerimeterExcl(double& partConsidered, double& commonPart) const
411 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
413 TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
415 partConsidered+=(*iter)->getCurveLength();
417 commonPart+=(*iter)->getCurveLength();
421 void ComposedEdge::getAllNodes(std::set<Node *>& output) const
423 std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
424 for(;iter!=_sub_edges.end();iter++)
425 (*iter)->getAllNodes(output);
428 void ComposedEdge::getBarycenter(double *bary, double& weigh) const
430 weigh=0.; bary[0]=0.; bary[1]=0.;
432 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
434 (*iter)->getBarycenter(tmp2,tmp1);
436 bary[0]+=tmp1*tmp2[0];
437 bary[1]+=tmp1*tmp2[1];
444 * \sa ComposedEdge::isInOrOut2
446 bool ComposedEdge::isInOrOut(Node *nodeToTest) const
448 std::set< IntersectElement > inOutSwitch;
449 double ref(isInOrOutAlg(nodeToTest,inOutSwitch));
451 for(std::set< IntersectElement >::iterator iter4=inOutSwitch.begin();iter4!=inOutSwitch.end();iter4++)
453 if((*iter4).getVal1()<ref)
455 if((*iter4).getNodeOnly()->getLoc()==ON_1)
465 * This method is close to ComposedEdge::isInOrOut behaviour except that here EPSILON is taken into account to detect if it is IN or OUT.
466 * If \a nodeToTest is close to an edge in \a this, true will be returned even if it is outside informatically from \a this.
467 * This method makes the hypothesis that
469 * \sa ComposedEdge::isInOrOut
471 bool ComposedEdge::isInOrOut2(Node *nodeToTest) const
473 std::set< IntersectElement > inOutSwitch;
474 double ref(isInOrOutAlg(nodeToTest,inOutSwitch));
476 for(std::set< IntersectElement >::iterator iter4=inOutSwitch.begin();iter4!=inOutSwitch.end();iter4++)
478 double val((*iter4).getVal1());
479 if(fabs(val-ref)>=QUADRATIC_PLANAR::_precision)
483 if((*iter4).getNodeOnly()->getLoc()==ON_1)
495 double ComposedEdge::isInOrOutAlg(Node *nodeToTest, std::set< IntersectElement >& inOutSwitch) const
497 Bounds b; b.prepareForAggregation();
499 //if(b.nearlyWhere((*nodeToTest)[0],(*nodeToTest)[1])==OUT)
502 std::set<Node *> nodes;
504 std::set<double> radialDistributionOfNodes;
505 std::set<Node *>::const_iterator iter;
506 for(iter=nodes.begin();iter!=nodes.end();iter++)
507 radialDistributionOfNodes.insert(nodeToTest->getSlope(*(*iter)));
508 std::vector<double> radialDistrib(radialDistributionOfNodes.begin(),radialDistributionOfNodes.end());
509 radialDistributionOfNodes.clear();
510 std::vector<double> radialDistrib2(radialDistrib.size());
511 copy(radialDistrib.begin()+1,radialDistrib.end(),radialDistrib2.begin());
512 radialDistrib2.back()=M_PI+radialDistrib.front();
513 std::vector<double> radialDistrib3(radialDistrib.size());
514 std::transform(radialDistrib2.begin(),radialDistrib2.end(),radialDistrib.begin(),radialDistrib3.begin(),std::minus<double>());
515 std::vector<double>::iterator iter3=max_element(radialDistrib3.begin(),radialDistrib3.end());
516 int i=iter3-radialDistrib3.begin();
517 // ok for e1 - Let's go.
518 EdgeInfLin *e1=new EdgeInfLin(nodeToTest,radialDistrib[i]+radialDistrib3[i]/2.);
519 double ref=e1->getCharactValue(*nodeToTest);
520 for(std::list<ElementaryEdge *>::const_iterator iter4=_sub_edges.begin();iter4!=_sub_edges.end();iter4++)
522 ElementaryEdge *val=(*iter4);
525 Edge *e=val->getPtr();
526 std::auto_ptr<EdgeIntersector> intersc(Edge::BuildIntersectorWith(e1,e));
527 bool obviousNoIntersection,areOverlapped;
528 intersc->areOverlappedOrOnlyColinears(0,obviousNoIntersection,areOverlapped); // first parameter never used
529 if(obviousNoIntersection)
535 std::list< IntersectElement > listOfIntesc=intersc->getIntersectionsCharacteristicVal();
536 for(std::list< IntersectElement >::iterator iter2=listOfIntesc.begin();iter2!=listOfIntesc.end();iter2++)
537 if((*iter2).isIncludedByBoth())
538 inOutSwitch.insert(*iter2);
540 //if overlapped we can forget
543 throw Exception("Invalid use of ComposedEdge::isInOrOutAlg : only one level supported !");
549 /*bool ComposedEdge::isInOrOut(Node *aNodeOn, Node *nodeToTest) const
552 EdgeInfLin *e1=new EdgeInfLin(aNodeOn,nodeToTest);
553 double ref=e1->getCharactValue(*nodeToTest);
554 set< IntersectElement > inOutSwitch;
555 for(vector<AbstractEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
557 ElementaryEdge *val=dynamic_cast<ElementaryEdge *>(*iter);
560 Edge *e=val->getPtr();
561 auto_ptr<Intersector> intersc(Edge::buildIntersectorWith(e1,e));
562 bool obviousNoIntersection,areOverlapped;
563 intersc->areOverlappedOrOnlyColinears(0,obviousNoIntersection,areOverlapped);
564 if(obviousNoIntersection)
570 list< IntersectElement > listOfIntesc=intersc->getIntersectionsCharacteristicVal();
571 for(list< IntersectElement >::iterator iter2=listOfIntesc.begin();iter2!=listOfIntesc.end();iter2++)
572 if((*iter2).isIncludedByBoth())
573 inOutSwitch.insert(*iter2);
575 //if overlapped we can forget
578 throw Exception("Invalid use of ComposedEdge::isInOrOut : only one level supported !");
582 for(set< IntersectElement >::iterator iter=inOutSwitch.begin();iter!=inOutSwitch.end();iter++)
584 if((*iter).getVal1()<ref)
586 if((*iter).getNodeOnly()->getLoc()==ON_1)
595 bool ComposedEdge::getDirection() const
597 throw Exception("ComposedEdge::getDirection : no sense");
600 bool ComposedEdge::intresincEqCoarse(const Edge *other) const
602 if(_sub_edges.size()!=1)
604 return _sub_edges.front()->intresincEqCoarse(other);
607 void ComposedEdge::clearAll(std::list<ElementaryEdge *>::iterator startToDel)
609 for(std::list<ElementaryEdge *>::iterator iter=startToDel;iter!=_sub_edges.end();iter++)