]> SALOME platform Git repositories - tools/medcoupling.git/blob - src/INTERP_KERNEL/Geometric2D/InterpKernelGeo2DEdgeLin.cxx
Salome HOME
Bug fix: SegSegIntersector::areColinears() was too tolerant.
[tools/medcoupling.git] / src / INTERP_KERNEL / Geometric2D / InterpKernelGeo2DEdgeLin.cxx
1 // Copyright (C) 2007-2016  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, or (at your option) any later version.
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 // Author : Anthony Geay (CEA/DEN)
20
21 #include "InterpKernelGeo2DEdgeLin.hxx"
22 #include "InterpKernelGeo2DNode.hxx"
23 #include "InterpKernelException.hxx"
24 #include "NormalizedUnstructuredMesh.hxx"
25
26 using namespace INTERP_KERNEL;
27
28 namespace INTERP_KERNEL
29 {
30   extern const unsigned MAX_SIZE_OF_LINE_XFIG_FILE=1024;
31 }
32
33 SegSegIntersector::SegSegIntersector(const EdgeLin& e1, const EdgeLin& e2):SameTypeEdgeIntersector(e1,e2)
34 {
35   _matrix[0]=(*(e2.getStartNode()))[0]-(*(e2.getEndNode()))[0];
36   _matrix[1]=(*(e1.getEndNode()))[0]-(*(e1.getStartNode()))[0];
37   _matrix[2]=(*(e2.getStartNode()))[1]-(*(e2.getEndNode()))[1];
38   _matrix[3]=(*(e1.getEndNode()))[1]-(*(e1.getStartNode()))[1];
39   _col[0]=_matrix[3]*(*(e1.getStartNode()))[0]-_matrix[1]*(*(e1.getStartNode()))[1];
40   _col[1]=-_matrix[2]*(*(e2.getStartNode()))[0]+_matrix[0]*(*(e2.getStartNode()))[1];
41   //Little trick to avoid problems if 'e1' and 'e2' are colinears and along Ox or Oy axes.
42   if(fabs(_matrix[3])>fabs(_matrix[1]))
43     _ind=0;
44   else
45     _ind=1;
46 }
47
48 /*!
49  * Must be called when 'this' and 'other' have been detected to be at least colinear. Typically they are overlapped.
50  * Must be called after call of areOverlappedOrOnlyColinears.
51  */
52 bool SegSegIntersector::haveTheySameDirection() const
53 {
54   return (_matrix[3]*_matrix[1]+_matrix[2]*_matrix[0])>0.;
55   //return (_matrix[_ind?1:0]>0. && _matrix[_ind?3:2]>0.) || (_matrix[_ind?1:0]<0. && _matrix[_ind?3:2]<0.);
56 }
57
58 /*!
59  * Precondition start and end must be so that there predecessor was in the same direction than 'e1'
60  */
61 void SegSegIntersector::getPlacements(Node *start, Node *end, TypeOfLocInEdge& whereStart, TypeOfLocInEdge& whereEnd, MergePoints& commonNode) const
62 {
63   getCurveAbscisse(start,whereStart,commonNode);
64   getCurveAbscisse(end,whereEnd,commonNode);
65 }
66
67 void SegSegIntersector::getCurveAbscisse(Node *node, TypeOfLocInEdge& where, MergePoints& commonNode) const
68 {
69   bool obvious;
70   obviousCaseForCurvAbscisse(node,where,commonNode,obvious);
71   if(obvious)
72     return ;
73   double ret=((*node)[!_ind]-(*_e1.getStartNode())[!_ind])/((*_e1.getEndNode())[!_ind]-(*_e1.getStartNode())[!_ind]);
74   if(ret>0. && ret <1.)
75     where=INSIDE;
76   else if(ret<0.)
77     where=OUT_BEFORE;
78   else
79     where=OUT_AFTER;
80 }
81
82 /*!
83  * areColinears method should be called before with a returned colinearity equal to false to avoid bad news.
84  */
85 std::list< IntersectElement > SegSegIntersector::getIntersectionsCharacteristicVal() const
86 {
87   std::list< IntersectElement > ret;
88   double x=_matrix[0]*_col[0]+_matrix[1]*_col[1];
89   double y=_matrix[2]*_col[0]+_matrix[3]*_col[1];
90   //Only one intersect point possible
91   Node *node=new Node(x,y);
92   node->declareOn();
93   bool i_1S=_e1.getStartNode()->isEqual(*node);
94   bool i_1E=_e1.getEndNode()->isEqual(*node);
95   bool i_2S=_e2.getStartNode()->isEqual(*node);
96   bool i_2E=_e2.getEndNode()->isEqual(*node);
97   ret.push_back(IntersectElement(_e1.getCharactValue(*node),
98       _e2.getCharactValue(*node),
99       i_1S,i_1E,i_2S,i_2E,node,_e1,_e2,keepOrder()));
100   return ret;
101 }
102
103 /*!
104  * retrieves if segs are colinears.
105  * WARNING !!! Contrary to areOverlappedOrOnlyColinears method, this method use an
106  * another precision to detect colinearity !
107  */
108 bool SegSegIntersector::areColinears() const
109 {
110   Bounds b;
111   b.prepareForAggregation();
112   b.aggregate(_e1.getBounds());
113   b.aggregate(_e2.getBounds());
114   double determinant=_matrix[0]*_matrix[3]-_matrix[1]*_matrix[2];
115   double dimChar=b.getCaracteristicDim();
116
117   return fabs(determinant)< dimChar*QuadraticPlanarArcDetectionPrecision::getArcDetectionPrecision();  // TODO [ABN]: should be QuadraticPlanarPrecision::getPrecision() ...
118 }
119
120 /*!
121  * Should be called \b once ! non const method.
122  * \param whereToFind specifies the box where final seek should be done. Essentially it is used for caracteristic reason.
123  * \param colinearity returns if regarding QuadraticPlanarPrecision::getPrecision() ; e1 and e2 are colinears
124  *                    If true 'this' is modified ! So this method be called once above all if true is returned for this parameter.
125  * \param areOverlapped if colinearity if true, this parameter looks if e1 and e2 are overlapped.
126  */
127 void SegSegIntersector::areOverlappedOrOnlyColinears(const Bounds *whereToFind, bool& colinearity, bool& areOverlapped)
128 {
129   double determinant=_matrix[0]*_matrix[3]-_matrix[1]*_matrix[2];
130   if(fabs(determinant)>2.*QuadraticPlanarPrecision::getPrecision())//2*_precision due to max of offset on _start and _end
131     {
132       colinearity=false; areOverlapped=false;
133       _matrix[0]/=determinant; _matrix[1]/=determinant; _matrix[2]/=determinant; _matrix[3]/=determinant;
134     }
135   else
136     {
137       colinearity=true;
138       //retrieving initial matrix
139       double tmp=_matrix[0]; _matrix[0]=_matrix[3]; _matrix[3]=tmp;
140       _matrix[1]=-_matrix[1]; _matrix[2]=-_matrix[2];
141       //
142       double deno=sqrt(_matrix[0]*_matrix[0]+_matrix[1]*_matrix[1]);
143       double x=(*(_e1.getStartNode()))[0]-(*(_e2.getStartNode()))[0];
144       double y=(*(_e1.getStartNode()))[1]-(*(_e2.getStartNode()))[1];
145       areOverlapped=fabs((_matrix[1]*y+_matrix[0]*x)/deno)<QuadraticPlanarPrecision::getPrecision();
146     }
147 }
148
149 EdgeLin::EdgeLin(std::istream& lineInXfig)
150 {
151   char currentLine[MAX_SIZE_OF_LINE_XFIG_FILE];
152   lineInXfig.getline(currentLine,MAX_SIZE_OF_LINE_XFIG_FILE);
153   _start=new Node(lineInXfig);
154   _end=new Node(lineInXfig);
155   updateBounds();
156 }
157
158 EdgeLin::EdgeLin(Node *start, Node *end, bool direction):Edge(start,end,direction)
159 {
160   updateBounds();
161 }
162
163 EdgeLin::EdgeLin(double sX, double sY, double eX, double eY):Edge(sX,sY,eX,eY)
164 {
165   updateBounds();
166 }
167
168 EdgeLin::~EdgeLin()
169 {
170 }
171
172 /*!
173  * Characteristic for edges is relative position btw 0.;1.
174  */
175 bool EdgeLin::isIn(double characterVal) const
176 {
177   return characterVal>0. && characterVal<1.;
178 }
179
180 Node *EdgeLin::buildRepresentantOfMySelf() const
181 {
182   return new Node(((*(_start))[0]+(*(_end))[0])/2.,((*(_start))[1]+(*(_end))[1])/2.);
183 }
184
185 double EdgeLin::getCharactValue(const Node& node) const
186 {
187   return getCharactValueEng(node);
188 }
189
190 double EdgeLin::getCharactValueBtw0And1(const Node& node) const
191 {
192   return getCharactValueEng(node);
193 }
194
195 double EdgeLin::getDistanceToPoint(const double *pt) const
196 {
197   double loc=getCharactValueEng(pt);
198   if(loc>0. && loc<1.)
199     {
200       double tmp[2];
201       tmp[0]=(*_start)[0]*(1-loc)+loc*(*_end)[0];
202       tmp[1]=(*_start)[1]*(1-loc)+loc*(*_end)[1];
203       return Node::distanceBtw2Pt(pt,tmp);
204     }
205   else
206     {
207       double dist1=Node::distanceBtw2Pt(*_start,pt);
208       double dist2=Node::distanceBtw2Pt(*_end,pt);
209       return std::min(dist1,dist2);
210     }
211 }
212
213 bool EdgeLin::isNodeLyingOn(const double *coordOfNode) const
214 {
215   double dBase=sqrt(_start->distanceWithSq(*_end));
216   double d1=Node::distanceBtw2Pt(*_start,coordOfNode);
217   d1+=Node::distanceBtw2Pt(*_end,coordOfNode);
218   return Node::areDoubleEquals(dBase,d1);
219 }
220
221 void EdgeLin::dumpInXfigFile(std::ostream& stream, bool direction, int resolution, const Bounds& box) const
222 {
223   stream << "2 1 0 1 ";
224   fillXfigStreamForLoc(stream);
225   stream << " 7 50 -1 -1 0.000 0 0 -1 1 0 2" << std::endl << "1 1 1.00 60.00 120.00" << std::endl;
226   direction?_start->dumpInXfigFile(stream,resolution,box):_end->dumpInXfigFile(stream,resolution,box);
227   direction?_end->dumpInXfigFile(stream,resolution,box):_start->dumpInXfigFile(stream,resolution,box);
228   stream << std::endl;
229 }
230
231 void EdgeLin::update(Node *m)
232 {
233   updateBounds();
234 }
235
236 double EdgeLin::getNormSq() const
237 {
238   return _start->distanceWithSq(*_end);
239 }
240
241 /*!
242  * This methods computes :
243  * \f[
244  * \int_{Current Edge} -ydx
245  * \f]
246  */
247 double EdgeLin::getAreaOfZone() const
248 {
249   return ((*_start)[0]-(*_end)[0])*((*_start)[1]+(*_end)[1])/2.;
250 }
251
252 void EdgeLin::getBarycenter(double *bary) const
253 {
254   bary[0]=((*_start)[0]+(*_end)[0])/2.;
255   bary[1]=((*_start)[1]+(*_end)[1])/2.;
256 }
257
258 /*!
259  * \f[
260  * bary[0]=\int_{Current Edge} -yxdx
261  * \f]
262  * \f[
263  * bary[1]=\int_{Current Edge} -\frac{y^{2}}{2}dx
264  * \f]
265  * To compute these 2 expressions in this class we have :
266  * \f[
267  * y=y_{1}+\frac{y_{2}-y_{1}}{x_{2}-x_{1}}(x-x_{1})
268  * \f]
269  */
270 void EdgeLin::getBarycenterOfZone(double *bary) const
271 {
272   double x1=(*_start)[0];
273   double y1=(*_start)[1];
274   double x2=(*_end)[0];
275   double y2=(*_end)[1];
276   bary[0]=(x1-x2)*(y1*(2.*x1+x2)+y2*(2.*x2+x1))/6.;
277   //bary[0]+=(y1-y2)*(x2*x2/3.-(x1*x2+x1*x1)/6.)+y1*(x1*x1-x2*x2)/2.;
278   //bary[0]+=(y1-y2)*((x2*x2+x1*x2+x1*x1)/3.-(x2+x1)*x1/2.)+y1*(x1*x1-x2*x2)/2.;
279   bary[1]=(x1-x2)*(y1*(y1+y2)+y2*y2)/6.;
280 }
281
282 /*!
283  * Here \a this is not used (contrary to EdgeArcCircle class).
284  */
285 void EdgeLin::getMiddleOfPoints(const double *p1, const double *p2, double *mid) const
286 {
287   mid[0]=(p1[0]+p2[0])/2.;
288   mid[1]=(p1[1]+p2[1])/2.;
289 }
290
291 double EdgeLin::getCurveLength() const
292 {
293   double x=(*_start)[0]-(*_end)[0];
294   double y=(*_start)[1]-(*_end)[1];
295   return sqrt(x*x+y*y);
296 }
297
298 Edge *EdgeLin::buildEdgeLyingOnMe(Node *start, Node *end, bool direction) const
299 {
300   return new EdgeLin(start,end,direction);
301 }
302
303 /*!
304  * No precision should be introduced here. Just think as if precision was perfect.
305  */
306 void EdgeLin::updateBounds()
307 {
308   _bounds.setValues(std::min((*_start)[0],(*_end)[0]),std::max((*_start)[0],(*_end)[0]),std::min((*_start)[1],(*_end)[1]),std::max((*_start)[1],(*_end)[1]));
309 }
310
311 double EdgeLin::getCharactValueEng(const double *node) const
312 {
313   double car1_1x=node[0]-(*(_start))[0]; double car1_2x=(*(_end))[0]-(*(_start))[0];
314   double car1_1y=node[1]-(*(_start))[1]; double car1_2y=(*(_end))[1]-(*(_start))[1];
315   return (car1_1x*car1_2x+car1_1y*car1_2y)/(car1_2x*car1_2x+car1_2y*car1_2y);
316 }
317
318 void EdgeLin::fillGlobalInfoAbs(bool direction, const std::map<INTERP_KERNEL::Node *,int>& mapThis, const std::map<INTERP_KERNEL::Node *,int>& mapOther, int offset1, int offset2, double fact, double baryX, double baryY,
319                                 std::vector<int>& edgesThis, std::vector<double>& addCoo, std::map<INTERP_KERNEL::Node *,int> mapAddCoo) const
320 {
321   int tmp[2];
322   _start->fillGlobalInfoAbs(mapThis,mapOther,offset1,offset2,fact,baryX,baryY,addCoo,mapAddCoo,tmp);
323   _end->fillGlobalInfoAbs(mapThis,mapOther,offset1,offset2,fact,baryX,baryY,addCoo,mapAddCoo,tmp+1);
324   if(direction)
325     {
326       edgesThis.push_back(tmp[0]);
327       edgesThis.push_back(tmp[1]);
328     }
329   else
330     {
331       edgesThis.push_back(tmp[1]);
332       edgesThis.push_back(tmp[0]);
333     }
334 }
335
336 void EdgeLin::fillGlobalInfoAbs2(const std::map<INTERP_KERNEL::Node *,int>& mapThis, const std::map<INTERP_KERNEL::Node *,int>& mapOther, int offset1, int offset2, double fact, double baryX, double baryY,
337                                  std::vector<int>& edgesOther, std::vector<double>& addCoo, std::map<INTERP_KERNEL::Node *,int>& mapAddCoo) const
338 {
339   _start->fillGlobalInfoAbs2(mapThis,mapOther,offset1,offset2,fact,baryX,baryY,addCoo,mapAddCoo,edgesOther);
340   _end->fillGlobalInfoAbs2(mapThis,mapOther,offset1,offset2,fact,baryX,baryY,addCoo,mapAddCoo,edgesOther);
341 }