1 // Copyright (C) 2007-2019 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, or (at your option) any later version.
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);
54 /*! \cond HIDDEN_ITEMS */
57 AbsEdgeCmp(ElementaryEdge *b):_b1(b) { }
58 bool operator()(ElementaryEdge *a) { return a->getPtr()==_b1->getPtr();}
64 double ComposedEdge::getCommonLengthWith(const ComposedEdge& other) const
67 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
69 if(find_if(other._sub_edges.begin(),other._sub_edges.end(),AbsEdgeCmp(*iter))!=other._sub_edges.end())
71 const ElementaryEdge *tmp=static_cast<const ElementaryEdge *>(*iter);
72 ret+=tmp->getCurveLength();
78 void ComposedEdge::clear()
80 clearAll(_sub_edges.begin());
84 void ComposedEdge::pushBack(Edge *edge, bool direction)
86 _sub_edges.push_back(new ElementaryEdge(edge,direction));
89 void ComposedEdge::pushBack(ElementaryEdge *elem)
91 _sub_edges.push_back(elem);
94 void ComposedEdge::pushBack(ComposedEdge *elem)
96 std::list<ElementaryEdge *> *elemsOfElem=elem->getListBehind();
97 _sub_edges.insert(_sub_edges.end(),elemsOfElem->begin(),elemsOfElem->end());
100 ElementaryEdge *ComposedEdge::operator[](int i) const
102 std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
103 for(int ii=0;ii<i;ii++)
108 void ComposedEdge::reverse()
110 _sub_edges.reverse();
111 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
115 bool ComposedEdge::presenceOfOn() const
118 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
119 ret=((*iter)->getLoc()==FULL_ON_1);
123 bool ComposedEdge::presenceOfQuadraticEdge() const
126 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
128 Edge *e=(*iter)->getPtr();
130 ret=dynamic_cast<EdgeArcCircle*>(e)!=0;
135 void ComposedEdge::initLocations() const
137 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
138 (*iter)->initLocations();
142 * Reset the status of all edges (OUT, IN, ON) because they were potentially assigned
143 * by the previous candidate processing.
145 void ComposedEdge::InitLocationsWithOther(const ComposedEdge& first, const ComposedEdge& other)
147 std::set<Edge *> s1,s2;
148 for(std::list<ElementaryEdge *>::const_iterator it1=first._sub_edges.begin();it1!=first._sub_edges.end();it1++)
149 s1.insert((*it1)->getPtr());
150 for(std::list<ElementaryEdge *>::const_iterator it2=other._sub_edges.begin();it2!=other._sub_edges.end();it2++)
151 s2.insert((*it2)->getPtr());
152 first.initLocations();
153 other.initLocations();
154 std::vector<Edge *> s3;
155 std::set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(),std::back_insert_iterator< std::vector<Edge *> >(s3));
156 for(std::vector<Edge *>::const_iterator it3=s3.begin();it3!=s3.end();it3++)
160 ComposedEdge *ComposedEdge::clone() const
162 return new ComposedEdge(*this);
165 bool ComposedEdge::isNodeIn(Node *n) const
168 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end() && !ret;iter++)
169 ret=(*iter)->isNodeIn(n);
174 * This method computes the area of 'this'.
177 * Area=\int_{Polygon} dS
179 * Thanks to Green's theorem we have.
181 * \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}}
183 * Where \f$ AreaOfZone_{i} \f$ is computed virtually by INTERP_KERNEL::Edge::getAreaOfZone with following formula :
185 * AreaOfZone_{i}=\int_{Edge_{i}} -ydx
188 double ComposedEdge::getArea() const
191 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
192 ret+=(*iter)->getAreaOfZone();
196 double ComposedEdge::getPerimeter() const
199 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
200 ret+=(*iter)->getCurveLength();
204 double ComposedEdge::getHydraulicDiameter() const
206 return 4*fabs(getArea())/getPerimeter();
210 * This method computes barycenter of 'this' by returning xG in bary[0] and yG in bary[1].
213 * Area \cdot x_{G}=\int_{Polygon} x \cdot dS
216 * Area \cdot y_{G}=\int_{Polygon} y \cdot dS
218 * Thanks to Green's theorem we have.
220 * \int_{Polygon} x \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}yxdx
223 * \int_{Polygon} y \cdot dS=\sum_{0 \leq i < nb of edges} -\int_{Edge_{i}}\frac{y^{2}}{2}dx
225 * Area is computed using the same principle than described in INTERP_KERNEL::ComposedEdge::getArea method.
226 * \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.
228 void ComposedEdge::getBarycenter(double *bary) const
233 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
235 (*iter)->getBarycenterOfZone(bary);
236 area+=(*iter)->getAreaOfZone();
243 * Idem ComposedEdge::getBarycenter except that the special case where _sub_edges==1 is dealt here.
245 void ComposedEdge::getBarycenterGeneral(double *bary) const
247 if(_sub_edges.empty())
248 throw INTERP_KERNEL::Exception("ComposedEdge::getBarycenterGeneral called on an empty polygon !");
249 if(_sub_edges.size()>2)
250 return getBarycenter(bary);
252 _sub_edges.back()->getBarycenter(bary,w);
255 double ComposedEdge::normalizeMe(double& xBary, double& yBary)
258 b.prepareForAggregation();
260 double dimChar=b.getCaracteristicDim();
261 b.getBarycenter(xBary,yBary);
262 applyGlobalSimilarity(xBary,yBary,dimChar);
266 double ComposedEdge::normalize(ComposedEdge *other, double& xBary, double& yBary)
269 b.prepareForAggregation();
271 other->fillBounds(b);
272 double dimChar=b.getCaracteristicDim();
273 b.getBarycenter(xBary,yBary);
274 applyGlobalSimilarity(xBary,yBary,dimChar);
275 other->applyGlobalSimilarity(xBary,yBary,dimChar);
280 * This method operates the opposite operation than ComposedEdge::applyGlobalSimilarity.
282 void ComposedEdge::unApplyGlobalSimilarityExt(ComposedEdge& other, double xBary, double yBary, double fact)
285 other.initNodeHitStatus();
286 unApplySimilarityOnMyNodes(xBary,yBary,fact);
287 other.unApplySimilarityOnMyNodesIfNotAlreadyHit(xBary,yBary,fact);
289 other.initEdgeHitStatus();
290 unApplySimilarityOnMyEdges(xBary,yBary,fact);
291 other.unApplySimilarityOnMyEdgesIfNotAlreadyHit(xBary,yBary,fact);
294 double ComposedEdge::normalizeExt(ComposedEdge *other, double& xBary, double& yBary)
297 b.prepareForAggregation();
299 other->fillBounds(b);
300 double dimChar=b.getCaracteristicDim();
301 b.getBarycenter(xBary,yBary);
302 applyGlobalSimilarity2(other,xBary,yBary,dimChar);
306 void ComposedEdge::dumpInXfigFile(std::ostream& stream, int resolution, const Bounds& box) const
308 stream.precision(10);
309 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
310 (*iter)->dumpInXfigFile(stream,resolution,box);
313 void ComposedEdge::dumpToCout(const std::map<INTERP_KERNEL::Node *,int>& mapp) const
316 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++, i++)
317 (*iter)->dumpToCout(mapp, i);
318 std::cout << std::endl;
321 Node *ComposedEdge::getEndNode() const
323 return _sub_edges.back()->getEndNode();
326 Node *ComposedEdge::getStartNode() const
328 return _sub_edges.front()->getStartNode();
331 bool ComposedEdge::changeEndNodeWith(Node *node) const
333 return _sub_edges.back()->changeEndNodeWith(node);
336 bool ComposedEdge::changeStartNodeWith(Node *node) const
338 return _sub_edges.front()->changeStartNodeWith(node);
341 void ComposedEdge::fillBounds(Bounds& output) const
343 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
344 (*iter)->fillBounds(output);
348 * \b WARNING : applies similarity \b ONLY on edges without any change on Nodes. To perform a global similarity call applyGlobalSimilarity.
350 void ComposedEdge::applySimilarity(double xBary, double yBary, double dimChar)
352 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
353 (*iter)->applySimilarity(xBary,yBary,dimChar);
357 * Perform Similarity transformation on all elements of this Nodes and Edges.
359 void ComposedEdge::applyGlobalSimilarity(double xBary, double yBary, double dimChar)
361 std::set<Node *> allNodes;
362 getAllNodes(allNodes);
363 for(std::set<Node *>::iterator iter=allNodes.begin();iter!=allNodes.end();iter++)
364 (*iter)->applySimilarity(xBary,yBary,dimChar);
365 for(std::list<ElementaryEdge *>::iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
366 (*iter)->applySimilarity(xBary,yBary,dimChar);
370 * Perform Similarity transformation on all elements of this Nodes and Edges on 'this' and 'other'.
371 * Nodes can be shared between 'this' and 'other'.
373 void ComposedEdge::applyGlobalSimilarity2(ComposedEdge *other, double xBary, double yBary, double dimChar)
376 other->initNodeHitStatus();
377 applySimilarityOnMyNodes(xBary,yBary,dimChar);
378 other->applySimilarityOnMyNodesIfNotAlreadyHit(xBary,yBary,dimChar);
380 other->initEdgeHitStatus();
381 applySimilarityOnMyEdges(xBary,yBary,dimChar);
382 other->applySimilarityOnMyEdgesIfNotAlreadyHit(xBary,yBary,dimChar);
386 * This method append to param 'partConsidered' the part of length of subedges IN or ON.
387 * @param partConsidered INOUT param.
389 void ComposedEdge::dispatchPerimeter(double& partConsidered) const
391 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
393 TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
394 if(loc==FULL_IN_1 || loc==FULL_ON_1)
395 partConsidered+=(*iter)->getCurveLength();
400 * Idem dispatchPerimeterExcl except that when a subedge is declared as ON this subedge is counted in commonPart.
402 void ComposedEdge::dispatchPerimeterExcl(double& partConsidered, double& commonPart) const
404 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
406 TypeOfEdgeLocInPolygon loc=(*iter)->getLoc();
408 partConsidered+=(*iter)->getCurveLength();
410 commonPart+=(*iter)->getCurveLength();
414 void ComposedEdge::getAllNodes(std::set<Node *>& output) const
416 std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();
417 for(;iter!=_sub_edges.end();iter++)
418 (*iter)->getAllNodes(output);
421 void ComposedEdge::initNodeHitStatus() const
423 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
425 (*iter)->getStartNode()->initHitStatus();
426 (*iter)->getEndNode()->initHitStatus();
430 void ComposedEdge::applySimilarityOnMyNodes(double xBary, double yBary, double dimChar) const
432 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
434 (*iter)->getStartNode()->hitMeAlone(xBary,yBary,dimChar);
435 (*iter)->getEndNode()->hitMeAlone(xBary,yBary,dimChar);
439 void ComposedEdge::unApplySimilarityOnMyNodes(double xBary, double yBary, double dimChar) const
441 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
443 (*iter)->getStartNode()->unHitMeAlone(xBary,yBary,dimChar);
444 (*iter)->getEndNode()->unHitMeAlone(xBary,yBary,dimChar);
448 void ComposedEdge::applySimilarityOnMyNodesIfNotAlreadyHit(double xBary, double yBary, double dimChar) const
450 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
452 (*iter)->getStartNode()->hitMeAfter(xBary,yBary,dimChar);
453 (*iter)->getEndNode()->hitMeAfter(xBary,yBary,dimChar);
457 void ComposedEdge::unApplySimilarityOnMyNodesIfNotAlreadyHit(double xBary, double yBary, double dimChar) const
459 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
461 (*iter)->getStartNode()->unHitMeAfter(xBary,yBary,dimChar);
462 (*iter)->getEndNode()->unHitMeAfter(xBary,yBary,dimChar);
466 void ComposedEdge::initEdgeHitStatus() const
468 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
469 (*iter)->getPtr()->initHitStatus();
472 void ComposedEdge::applySimilarityOnMyEdges(double xBary, double yBary, double dimChar) const
474 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
475 (*iter)->getPtr()->hitMeAlone(xBary,yBary,dimChar);
478 void ComposedEdge::unApplySimilarityOnMyEdges(double xBary, double yBary, double dimChar) const
480 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
481 (*iter)->getPtr()->unHitMeAlone(xBary,yBary,dimChar);
484 void ComposedEdge::applySimilarityOnMyEdgesIfNotAlreadyHit(double xBary, double yBary, double dimChar) const
486 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
487 (*iter)->getPtr()->hitMeAfter(xBary,yBary,dimChar);
490 void ComposedEdge::unApplySimilarityOnMyEdgesIfNotAlreadyHit(double xBary, double yBary, double dimChar) const
492 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
493 (*iter)->getPtr()->unHitMeAfter(xBary,yBary,dimChar);
496 void ComposedEdge::getBarycenter(double *bary, double& weigh) const
498 weigh=0.; bary[0]=0.; bary[1]=0.;
500 for(std::list<ElementaryEdge *>::const_iterator iter=_sub_edges.begin();iter!=_sub_edges.end();iter++)
502 (*iter)->getBarycenter(tmp2,tmp1);
504 bary[0]+=tmp1*tmp2[0];
505 bary[1]+=tmp1*tmp2[1];
512 * This method makes the hypothesis that \a nodeToTest can be either IN or OUT.
514 * \sa ComposedEdge::isInOrOut2
516 bool ComposedEdge::isInOrOut(Node *nodeToTest) const
518 Bounds b; b.prepareForAggregation();
520 if(b.nearlyWhere((*nodeToTest)[0],(*nodeToTest)[1])==OUT)
522 std::set< IntersectElement > inOutSwitch;
523 std::set<Node *> nodes;
525 double ref(isInOrOutAlg(nodeToTest,nodes,inOutSwitch));
527 for(std::set< IntersectElement >::iterator iter4=inOutSwitch.begin();iter4!=inOutSwitch.end();iter4++)
529 if((*iter4).getVal1()<ref)
531 if((*iter4).getNodeOnly()->getLoc()==ON_1)
541 * This method is close to ComposedEdge::isInOrOut behaviour except that here EPSILON is taken into account to detect if it is IN or OUT.
542 * If \a nodeToTest is close to an edge in \a this, true will be returned even if it is outside informatically from \a this.
544 * \sa ComposedEdge::isInOrOut
546 bool ComposedEdge::isInOrOut2(Node *nodeToTest) const
548 std::set< IntersectElement > inOutSwitch;
549 std::set<Node *> nodes;
551 for(std::set<Node *>::const_iterator iter=nodes.begin();iter!=nodes.end();iter++)
552 if(sqrt((*iter)->distanceWithSq(*nodeToTest))<QuadraticPlanarPrecision::getPrecision())
554 double ref(isInOrOutAlg(nodeToTest,nodes,inOutSwitch));
556 for(std::set< IntersectElement >::iterator iter4=inOutSwitch.begin();iter4!=inOutSwitch.end();iter4++)
558 double val((*iter4).getVal1());
559 if(fabs(val-ref)>=QuadraticPlanarPrecision::getPrecision())
563 if((*iter4).getNodeOnly()->getLoc()==ON_1)
575 double ComposedEdge::isInOrOutAlg(Node *nodeToTest, const std::set<Node*>& nodes, std::set< IntersectElement >& inOutSwitch) const
578 std::set<double> radialDistributionOfNodes;
579 std::set<Node *>::const_iterator iter;
580 for(iter=nodes.begin();iter!=nodes.end();iter++)
581 radialDistributionOfNodes.insert(nodeToTest->getSlope(*(*iter)));
582 std::vector<double> radialDistrib(radialDistributionOfNodes.begin(),radialDistributionOfNodes.end());
583 radialDistributionOfNodes.clear();
584 std::vector<double> radialDistrib2(radialDistrib.size());
585 copy(radialDistrib.begin()+1,radialDistrib.end(),radialDistrib2.begin());
586 radialDistrib2.back()=M_PI+radialDistrib.front();
587 std::vector<double> radialDistrib3(radialDistrib.size());
588 std::transform(radialDistrib2.begin(),radialDistrib2.end(),radialDistrib.begin(),radialDistrib3.begin(),std::minus<double>());
589 std::vector<double>::iterator iter3=max_element(radialDistrib3.begin(),radialDistrib3.end());
590 int i=iter3-radialDistrib3.begin();
591 // ok for e1 - Let's go.
592 EdgeInfLin *e1=new EdgeInfLin(nodeToTest,radialDistrib[i]+radialDistrib3[i]/2.);
593 double ref=e1->getCharactValue(*nodeToTest);
594 for(std::list<ElementaryEdge *>::const_iterator iter4=_sub_edges.begin();iter4!=_sub_edges.end();iter4++)
596 ElementaryEdge *val=(*iter4);
599 Edge *e=val->getPtr();
600 std::unique_ptr<EdgeIntersector> intersc(Edge::BuildIntersectorWith(e1,e));
601 bool obviousNoIntersection,areOverlapped;
602 intersc->areOverlappedOrOnlyColinears(obviousNoIntersection,areOverlapped);
603 if(obviousNoIntersection)
609 std::list< IntersectElement > listOfIntesc=intersc->getIntersectionsCharacteristicVal();
610 for(std::list< IntersectElement >::iterator iter2=listOfIntesc.begin();iter2!=listOfIntesc.end();iter2++)
611 if((*iter2).isIncludedByBoth())
612 inOutSwitch.insert(*iter2);
614 //if overlapped we can forget
617 throw Exception("Invalid use of ComposedEdge::isInOrOutAlg : only one level supported !");
623 bool ComposedEdge::getDirection() const
625 throw Exception("ComposedEdge::getDirection : no sense");
628 bool ComposedEdge::intresincEqCoarse(const Edge *other) const
630 if(_sub_edges.size()!=1)
632 return _sub_edges.front()->intresincEqCoarse(other);
635 void ComposedEdge::clearAll(std::list<ElementaryEdge *>::iterator startToDel)
637 for(std::list<ElementaryEdge *>::iterator iter=startToDel;iter!=_sub_edges.end();iter++)