1 // Copyright (C) 2007-2008 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 #include "QuadraticPolygon.hxx"
20 #include "ElementaryEdge.hxx"
21 #include "EdgeArcCircle.hxx"
22 #include "AbstractEdge.hxx"
23 #include "EdgeLin.hxx"
31 using namespace INTERP_KERNEL;
33 namespace INTERP_KERNEL
35 const unsigned MAX_SIZE_OF_LINE_XFIG_FILE=1024;
38 QuadraticPolygon::QuadraticPolygon(const char *file)
40 char currentLine[MAX_SIZE_OF_LINE_XFIG_FILE];
41 ifstream stream(file);
42 stream.exceptions(ios_base::eofbit);
46 stream.getline(currentLine,MAX_SIZE_OF_LINE_XFIG_FILE);
47 while(strcmp(currentLine,"1200 2")!=0);
50 Edge *newEdge=Edge::buildFromXfigLine(stream);
52 newEdge->changeStartNodeWith(back()->getEndNode());
57 catch(ifstream::failure& e)
60 front()->changeStartNodeWith(back()->getEndNode());
63 QuadraticPolygon::~QuadraticPolygon()
67 QuadraticPolygon *QuadraticPolygon::buildLinearPolygon(std::vector<Node *>& nodes)
69 QuadraticPolygon *ret=new QuadraticPolygon;
70 int size=nodes.size();
71 for(int i=0;i<size;i++)
73 ret->pushBack(new EdgeLin(nodes[i],nodes[(i+1)%size]));
79 QuadraticPolygon *QuadraticPolygon::buildArcCirclePolygon(std::vector<Node *>& nodes)
81 QuadraticPolygon *ret=new QuadraticPolygon;
82 int size=nodes.size();
83 for(int i=0;i<size/2;i++)
86 e1=new EdgeLin(nodes[i],nodes[i+size/2]);
87 e2=new EdgeLin(nodes[i+size/2],nodes[(i+1)%(size/2)]);
88 SegSegIntersector inters(*e1,*e2);
89 bool colinearity=inters.areColinears();
92 ret->pushBack(new EdgeLin(nodes[i],nodes[(i+1)%(size/2)]));
94 ret->pushBack(new EdgeArcCircle(nodes[i],nodes[i+size/2],nodes[(i+1)%(size/2)]));
95 nodes[i]->decrRef(); nodes[i+size/2]->decrRef();
100 void QuadraticPolygon::buildDbgFile(const std::vector<Node *>& nodes, const char *fileName)
102 ofstream file(fileName);
103 file << setprecision(16);
104 file << " double coords[]=" << endl << " { ";
105 for(vector<Node *>::const_iterator iter=nodes.begin();iter!=nodes.end();iter++)
107 if(iter!=nodes.begin())
108 file << "," << endl << " ";
109 file << (*(*iter))[0] << ", " << (*(*iter))[1];
111 file << "};" << endl;
114 void QuadraticPolygon::closeMe() const
116 if(!front()->changeStartNodeWith(back()->getEndNode()))
117 throw(Exception("big error: not closed polygon..."));
120 void QuadraticPolygon::circularPermute()
122 if(_sub_edges.size()>1)
124 ElementaryEdge *first=_sub_edges.front();
125 _sub_edges.pop_front();
126 _sub_edges.push_back(first);
130 void QuadraticPolygon::dumpInXfigFileWithOther(const ComposedEdge& other, const char *fileName) const
132 ofstream file(fileName);
133 const int resolution=1200;
135 box.prepareForAggregation();
137 other.fillBounds(box);
138 dumpInXfigFile(file,resolution,box);
139 other.ComposedEdge::dumpInXfigFile(file,resolution,box);
142 void QuadraticPolygon::dumpInXfigFile(const char *fileName) const
144 ofstream file(fileName);
145 const int resolution=1200;
147 box.prepareForAggregation();
149 dumpInXfigFile(file,resolution,box);
152 void QuadraticPolygon::dumpInXfigFile(std::ostream& stream, int resolution, const Bounds& box) const
154 stream << "#FIG 3.2 Produced by xfig version 3.2.5-alpha5" << endl;
155 stream << "Landscape" << endl;
156 stream << "Center" << endl;
157 stream << "Metric" << endl;
158 stream << "Letter" << endl;
159 stream << "100.00" << endl;
160 stream << "Single" << endl;
161 stream << "-2" << endl;
162 stream << resolution << " 2" << endl;
163 ComposedEdge::dumpInXfigFile(stream,resolution,box);
167 * Warning contrary to intersectWith method this method is \b NOT const. 'this' and 'other' are modified after call of this method.
169 double QuadraticPolygon::intersectWithAbs(QuadraticPolygon& other)
172 double fact=normalize(&other);
173 vector<QuadraticPolygon *> polygs=intersectMySelfWith(other);
174 for(vector<QuadraticPolygon *>::iterator iter=polygs.begin();iter!=polygs.end();iter++)
176 ret+=fabs((*iter)->getArea());
179 return ret*fact*fact;
183 * \b WARNING this method is const and other is const too. \b BUT location of Edges in 'this' and 'other' are nevertheless modified.
184 * This is possible because loc attribute in Edge class is mutable.
185 * This implies that if 'this' or/and 'other' are reused for intersect* method initLocations has to be called on each of this/them.
187 double QuadraticPolygon::intersectWith(const QuadraticPolygon& other) const
190 vector<QuadraticPolygon *> polygs=intersectMySelfWith(other);
191 for(vector<QuadraticPolygon *>::iterator iter=polygs.begin();iter!=polygs.end();iter++)
193 ret+=fabs((*iter)->getArea());
200 * \b WARNING this method is const and other is const too. \b BUT location of Edges in 'this' and 'other' are nevertheless modified.
201 * This is possible because loc attribute in Edge class is mutable.
202 * This implies that if 'this' or/and 'other' are reused for intersect* method initLocations has to be called on each of this/them.
204 void QuadraticPolygon::intersectForPerimeter(const QuadraticPolygon& other, double& perimeterThisPart, double& perimeterOtherPart, double& perimeterCommonPart) const
206 perimeterThisPart=0.; perimeterOtherPart=0.; perimeterCommonPart=0.;
207 QuadraticPolygon cpyOfThis(*this);
208 QuadraticPolygon cpyOfOther(other); int nbOfSplits=0;
209 splitPolygonsEachOther(cpyOfThis,cpyOfOther,nbOfSplits);
210 performLocatingOperation(cpyOfOther);
211 other.performLocatingOperation(cpyOfThis);
212 cpyOfThis.dispatchPerimeterExcl(perimeterThisPart,perimeterCommonPart);
213 cpyOfOther.dispatchPerimeterExcl(perimeterOtherPart,perimeterCommonPart);
214 perimeterCommonPart/=2.;
218 * \b WARNING this method is const and other is const too. \b BUT location of Edges in 'this' and 'other' are nevertheless modified.
219 * This is possible because loc attribute in Edge class is mutable.
220 * This implies that if 'this' or/and 'other' are reused for intersect* method initLocations has to be called on each of this/them.
222 * polThis.size()==this->size() and polOther.size()==other.size().
223 * For each ElementaryEdge of 'this', the corresponding contribution in resulting polygon is in 'polThis'.
224 * For each ElementaryEdge of 'other', the corresponding contribution in resulting polygon is in 'polOther'.
225 * As consequence common part are counted twice (in polThis \b and in polOther).
227 void QuadraticPolygon::intersectForPerimeterAdvanced(const QuadraticPolygon& other, std::vector< double >& polThis, std::vector< double >& polOther) const
229 polThis.resize(size());
230 polOther.resize(other.size());
231 IteratorOnComposedEdge it1((QuadraticPolygon *)this);
233 for(it1.first();!it1.finished();it1.next(),edgeId++)
235 ElementaryEdge* curE1=it1.current();
236 QuadraticPolygon cpyOfOther(other);
237 QuadraticPolygon tmp;
238 tmp.pushBack(curE1->clone());
240 splitPolygonsEachOther(tmp,cpyOfOther,tmp2);
241 other.performLocatingOperation(tmp);
242 tmp.dispatchPerimeter(polThis[edgeId]);
245 IteratorOnComposedEdge it2((QuadraticPolygon *)&other);
247 for(it2.first();!it2.finished();it2.next(),edgeId++)
249 ElementaryEdge* curE2=it2.current();
250 QuadraticPolygon cpyOfThis(*this);
251 QuadraticPolygon tmp;
252 tmp.pushBack(curE2->clone());
254 splitPolygonsEachOther(tmp,cpyOfThis,tmp2);
255 performLocatingOperation(tmp);
256 tmp.dispatchPerimeter(polOther[edgeId]);
262 * numberOfCreatedPointsPerEdge is resized to the number of edges of 'this'.
263 * This method returns in ordered maner the number of newly created points per edge.
264 * This method performs a split process between 'this' and 'other' that gives the result PThis.
265 * Then for each edges of 'this' this method counts how many edges in Pthis have the same id.
267 void QuadraticPolygon::intersectForPoint(const QuadraticPolygon& other, std::vector< int >& numberOfCreatedPointsPerEdge) const
269 numberOfCreatedPointsPerEdge.resize(size());
270 IteratorOnComposedEdge it1((QuadraticPolygon *)this);
272 for(it1.first();!it1.finished();it1.next(),edgeId++)
274 ElementaryEdge* curE1=it1.current();
275 QuadraticPolygon cpyOfOther(other);
276 QuadraticPolygon tmp;
277 tmp.pushBack(curE1->clone());
279 splitPolygonsEachOther(tmp,cpyOfOther,tmp2);
280 numberOfCreatedPointsPerEdge[edgeId]=tmp.recursiveSize()-1;
285 * \b WARNING this method is const and other is const too. \b BUT location of Edges in 'this' and 'other' are nevertheless modified.
286 * This is possible because loc attribute in Edge class is mutable.
287 * This implies that if 'this' or/and 'other' are reused for intersect* method initLocations has to be called on each of this/them.
289 std::vector<QuadraticPolygon *> QuadraticPolygon::intersectMySelfWith(const QuadraticPolygon& other) const
291 QuadraticPolygon cpyOfThis(*this);
292 QuadraticPolygon cpyOfOther(other); int nbOfSplits=0;
293 splitPolygonsEachOther(cpyOfThis,cpyOfOther,nbOfSplits);
294 //At this point cpyOfThis and cpyOfOther have been splited at maximum edge so that in/out can been done.
295 performLocatingOperation(cpyOfOther);
296 return other.buildIntersectionPolygons(cpyOfThis,cpyOfOther);
300 * This method is typically the first step of boolean operations between pol1 and pol2.
301 * This method perform the minimal splitting so that at the end each edges constituting pol1 are fully either IN or OUT or ON.
302 * @param pol1 IN/OUT param that is equal to 'this' when called.
304 void QuadraticPolygon::splitPolygonsEachOther(QuadraticPolygon& pol1, QuadraticPolygon& pol2, int& nbOfSplits)
306 IteratorOnComposedEdge it1(&pol1),it2(&pol2);
308 ComposedEdge *c1=new ComposedEdge;
309 ComposedEdge *c2=new ComposedEdge;
310 for(it2.first();!it2.finished();it2.next())
312 ElementaryEdge* curE2=it2.current();
313 if(!curE2->isThereStartPoint())
316 it1=curE2->getIterator();
317 for(;!it1.finished();)
320 ElementaryEdge* curE1=it1.current();
321 merge.clear(); nbOfSplits++;
322 if(curE1->getPtr()->intersectWith(curE2->getPtr(),merge,*c1,*c2))
324 if(!curE1->getDirection()) c1->reverse();
325 if(!curE2->getDirection()) c2->reverse();
326 updateNeighbours(merge,it1,it2,c1,c2);
327 //Substitution of simple edge by sub-edges.
328 delete curE1; // <-- destroying simple edge coming from pol1
329 delete curE2; // <-- destroying simple edge coming from pol2
330 it1.insertElemEdges(c1,true);// <-- 2nd param is true to go next.
331 it2.insertElemEdges(c2,false);// <-- 2nd param is false to avoid to go next.
334 it1.assignMySelfToAllElems(c2);//To avoid that others
342 updateNeighbours(merge,it1,it2,curE1,curE2);
351 void QuadraticPolygon::performLocatingOperation(QuadraticPolygon& pol2) const
353 IteratorOnComposedEdge it(&pol2);
354 TypeOfEdgeLocInPolygon loc=FULL_ON_1;
355 for(it.first();!it.finished();it.next())
357 ElementaryEdge *cur=it.current();
358 loc=cur->locateFullyMySelf(*this,loc);
363 * Given 2 polygons 'pol1' and 'pol2' (localized) the resulting polygons are returned.
365 * this : pol2 simplified.
366 * @param pol1 pol1 split.
367 * @param pol2 pol2 split.
369 std::vector<QuadraticPolygon *> QuadraticPolygon::buildIntersectionPolygons(const QuadraticPolygon& pol1, const QuadraticPolygon& pol2) const
371 vector<QuadraticPolygon *> ret;
372 list<QuadraticPolygon *> pol2Zip=pol2.zipConsecutiveInSegments();
374 closePolygons(pol2Zip,pol1,ret);
376 {//borders of pol2 do not cross pol1,and pol2 borders are outside of pol1. That is to say, either pol2 and pol1
377 //do not overlap or pol1 is fully inside pol2. So in the first case no intersection, in the other case
378 //the intersection is pol1.
379 ElementaryEdge *e1FromPol1=pol1[0];
380 TypeOfEdgeLocInPolygon loc=FULL_ON_1;
381 loc=e1FromPol1->locateFullyMySelf(*this,loc);
383 ret.push_back(new QuadraticPolygon(pol1));
389 * Returns parts of potentially non closed-polygons. Each returned polygons are not mergeable.
390 * this : pol2 split and locallized.
392 std::list<QuadraticPolygon *> QuadraticPolygon::zipConsecutiveInSegments() const
394 list<QuadraticPolygon *> ret;
395 IteratorOnComposedEdge it((ComposedEdge *)this);
396 int nbOfTurns=recursiveSize();
398 if(!it.goToNextInOn(false,i,nbOfTurns))
404 QuadraticPolygon *tmp1=new QuadraticPolygon;
405 TypeOfEdgeLocInPolygon loc=it.current()->getLoc();
406 while(loc!=FULL_OUT_1 && i<nbOfTurns)
408 ElementaryEdge *tmp3=it.current()->clone();
409 tmp1->pushBack(tmp3);
411 loc=it.current()->getLoc();
419 it.goToNextInOn(true,i,nbOfTurns);
425 * 'this' should be considered as pol2Simplified.
426 * @param pol2zip is a list of set of edges (openned polygon) coming from split polygon 2.
427 * @param pol1 is split pol1.
428 * @param results the resulting \b CLOSED polygons.
430 void QuadraticPolygon::closePolygons(std::list<QuadraticPolygon *>& pol2Zip, const QuadraticPolygon& pol1,
431 std::vector<QuadraticPolygon *>& results) const
433 bool directionKnownInPol1=false;
434 bool directionInPol1;
435 for(list<QuadraticPolygon *>::iterator iter=pol2Zip.begin();iter!=pol2Zip.end();)
437 if((*iter)->completed())
439 results.push_back(*iter);
440 directionKnownInPol1=false;
441 iter=pol2Zip.erase(iter);
444 if(!directionKnownInPol1)
445 if(!(*iter)->amIAChanceToBeCompletedBy(pol1,*this,directionInPol1))
446 { delete *iter; iter=pol2Zip.erase(iter); continue; }
448 directionKnownInPol1=true;
449 list<QuadraticPolygon *>::iterator iter2=iter; iter2++;
450 list<QuadraticPolygon *>::iterator iter3=(*iter)->fillAsMuchAsPossibleWith(pol1,iter2,pol2Zip.end(),directionInPol1);
451 if(iter3!=pol2Zip.end())
453 (*iter)->pushBack(*iter3);
455 pol2Zip.erase(iter3);
461 * 'this' is expected to be set of edges (not closed) of pol2 split.
463 bool QuadraticPolygon::amIAChanceToBeCompletedBy(const QuadraticPolygon& pol1Splitted,const QuadraticPolygon& pol2NotSplitted, bool& direction)
465 IteratorOnComposedEdge it((QuadraticPolygon *)&pol1Splitted);
467 Node *n=getEndNode();
468 ElementaryEdge *cur=it.current();
469 for(it.first();!it.finished() && !found;)
472 found=(cur->getStartNode()==n);
477 throw Exception("Internal error : polygons uncompatible each others. Should never happend");
478 //Ok we found correspondance between this and pol1. Searching for right direction to close polygon.
479 ElementaryEdge *e=_sub_edges.back();
480 if(e->getLoc()==FULL_ON_1)
482 if(e->getPtr()==cur->getPtr())
487 Node *repr=cur->getPtr()->buildRepresentantOfMySelf();
488 bool ret=pol2NotSplitted.isInOrOut(repr);
495 Node *repr=cur->getPtr()->buildRepresentantOfMySelf();
496 bool ret=pol2NotSplitted.isInOrOut(repr);
502 direction=cur->locateFullyMySelfAbsolute(pol2NotSplitted)==FULL_IN_1;
507 * This method fills as much as possible 'this' (part of pol2 split) with edges of 'pol1Splitted'.
509 std::list<QuadraticPolygon *>::iterator QuadraticPolygon::fillAsMuchAsPossibleWith(const QuadraticPolygon& pol1Splitted,
510 std::list<QuadraticPolygon *>::iterator iStart,
511 std::list<QuadraticPolygon *>::iterator iEnd,
514 IteratorOnComposedEdge it((QuadraticPolygon *)&pol1Splitted);
516 Node *n=getEndNode();
518 for(it.first();!it.finished() && !found;)
521 found=(cur->getStartNode()==n);
528 std::list<QuadraticPolygon *>::iterator ret;
532 ElementaryEdge *tmp=cur->clone();
536 nodeToTest=tmp->getEndNode();
537 direction?it.nextLoop():it.previousLoop();
538 ret=checkInList(nodeToTest,iStart,iEnd);
546 std::list<QuadraticPolygon *>::iterator QuadraticPolygon::checkInList(Node *n, std::list<QuadraticPolygon *>::iterator iStart,
547 std::list<QuadraticPolygon *>::iterator iEnd)
549 for(list<QuadraticPolygon *>::iterator iter=iStart;iter!=iEnd;iter++)
550 if((*iter)->isNodeIn(n))