1// Created on: 2005-09-08
2// Created by: Alexander GRIGORIEV
3// Copyright (c) 2005-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16inline Standard_Boolean _compareDist  (const RealType aHSize[2],
17                                       const RealType aDist[2])
18{
19  return (Abs(aDist[0]) > aHSize[0] || Abs(aDist[1]) > aHSize[1]);
20}
21
22inline Standard_Boolean _compareDistD (const gp_XY& aHSize, const gp_XY& aDist)
23{
24  return (Abs(aDist.X()) > aHSize.X() || Abs(aDist.Y()) > aHSize.Y());
25}
26
27//=======================================================================
28//function : Add
29//purpose  : Update the box by a point
30//=======================================================================
31
32void Bnd_B2x::Add (const gp_XY& thePnt) {
33  if (IsVoid()) {
34    myCenter[0] = RealType(thePnt.X());
35    myCenter[1] = RealType(thePnt.Y());
36    myHSize [0] = 0.;
37    myHSize [1] = 0.;
38  } else {
39    const RealType aDiff[2] = {
40      RealType(thePnt.X()) - myCenter[0],
41      RealType(thePnt.Y()) - myCenter[1]
42    };
43    if (aDiff[0] > myHSize[0]) {
44      const RealType aShift = (aDiff[0] - myHSize[0]) / 2;
45      myCenter[0] += aShift;
46      myHSize [0] += aShift;
47    } else if (aDiff[0] < -myHSize[0]) {
48      const RealType aShift = (aDiff[0] + myHSize[0]) / 2;
49      myCenter[0] += aShift;
50      myHSize [0] -= aShift;
51    }
52    if (aDiff[1] > myHSize[1]) {
53      const RealType aShift = (aDiff[1] - myHSize[1]) / 2;
54      myCenter[1] += aShift;
55      myHSize [1] += aShift;
56    } else if (aDiff[1] < -myHSize[1]) {
57      const RealType aShift = (aDiff[1] + myHSize[1]) / 2;
58      myCenter[1] += aShift;
59      myHSize [1] -= aShift;
60    }
61  }
62}
63
64//=======================================================================
65//function : Limit
66//purpose  : limit the current box with the internals of theBox
67//=======================================================================
68
69Standard_Boolean Bnd_B2x::Limit (const Bnd_B2x& theBox)
70{
71  Standard_Boolean aResult (Standard_False);
72  const RealType diffC[2] = {
73    theBox.myCenter[0] - myCenter[0],
74    theBox.myCenter[1] - myCenter[1]
75  };
76  const RealType sumH[2] = {
77    theBox.myHSize[0] + myHSize[0],
78    theBox.myHSize[1] + myHSize[1]
79  };
80  // check the condition IsOut
81  if (_compareDist (sumH, diffC) == Standard_False) {
82    const RealType diffH[2] = {
83      theBox.myHSize[0] - myHSize[0],
84      theBox.myHSize[1] - myHSize[1]
85    };
86    if (diffC[0] - diffH[0] > 0.) {
87      const RealType aShift = (diffC[0] - diffH[0]) / 2; // positive
88      myCenter[0] += aShift;
89      myHSize [0] -= aShift;
90    } else if (diffC[0] + diffH[0] < 0.) {
91      const RealType aShift = (diffC[0] + diffH[0]) / 2; // negative
92      myCenter[0] += aShift;
93      myHSize [0] += aShift;
94    }
95    if (diffC[1] - diffH[1] > 0.) {
96      const RealType aShift = (diffC[1] - diffH[1]) / 2; // positive
97      myCenter[1] += aShift;
98      myHSize [1] -= aShift;
99    } else if (diffC[1] + diffH[1] < 0.) {
100      const RealType aShift = (diffC[1] + diffH[1]) / 2; // negative
101      myCenter[1] += aShift;
102      myHSize [1] += aShift;
103    }
104    aResult = Standard_True;
105  }
106  return aResult;
107}
108
109//=======================================================================
110//function : Transformed
111//purpose  :
112//=======================================================================
113
114Bnd_B2x Bnd_B2x::Transformed (const gp_Trsf2d& theTrsf) const
115{
116  Bnd_B2x aResult;
117  const gp_TrsfForm aForm = theTrsf.Form();
118  const Standard_Real aScale = theTrsf.ScaleFactor();
119  const Standard_Real aScaleAbs = Abs(aScale);
120  if (aForm == gp_Identity)
121    aResult = * this;
122  else if (aForm== gp_Translation || aForm== gp_PntMirror || aForm== gp_Scale)
123  {
124    aResult.myCenter[0] =
125      (RealType)(myCenter[0] * aScale + theTrsf.TranslationPart().X());
126    aResult.myCenter[1] =
127      (RealType)(myCenter[1] * aScale + theTrsf.TranslationPart().Y());
128    aResult.myHSize[0] = (RealType)(myHSize[0] * aScaleAbs);
129    aResult.myHSize[1] = (RealType)(myHSize[1] * aScaleAbs);
130  } else {
131    gp_XY aCenter ((Standard_Real)myCenter[0],
132                   (Standard_Real)myCenter[1]);
133    theTrsf.Transforms (aCenter);
134    aResult.myCenter[0] = (RealType)aCenter.X();
135    aResult.myCenter[1] = (RealType)aCenter.Y();
136
137    const Standard_Real * aMat = &theTrsf.HVectorialPart().Value(1,1);
138    aResult.myHSize[0] = (RealType)(aScaleAbs * (Abs(aMat[0]) * myHSize[0]+
139                                                 Abs(aMat[1]) * myHSize[1]));
140    aResult.myHSize[1] = (RealType)(aScaleAbs * (Abs(aMat[2]) * myHSize[0]+
141                                                 Abs(aMat[3]) * myHSize[1]));
142  }
143  return aResult;
144}
145
146//=======================================================================
147//function : IsOut
148//purpose  : Intersection Box - Circle
149//=======================================================================
150
151Standard_Boolean Bnd_B2x::IsOut (const gp_XY&           theCenter,
152                                 const Standard_Real    theRadius,
153                                 const Standard_Boolean isCircleHollow) const
154{
155  Standard_Boolean aResult (Standard_True);
156  if (isCircleHollow == Standard_False) {
157    // vector from the center of the circle to the nearest box face
158    const Standard_Real aDist[2] = {
159      Abs(theCenter.X()-Standard_Real(myCenter[0])) - Standard_Real(myHSize[0]),
160      Abs(theCenter.Y()-Standard_Real(myCenter[1])) - Standard_Real(myHSize[1])
161    };
162    Standard_Real aD (0.);
163    if (aDist[0] > 0.)
164      aD  = aDist[0]*aDist[0];
165    if (aDist[1] > 0.)
166      aD += aDist[1]*aDist[1];
167    aResult = (aD > theRadius*theRadius);
168  } else {
169    const Standard_Real aDistC[2] = {
170      Abs(theCenter.X()-Standard_Real(myCenter[0])),
171      Abs(theCenter.Y()-Standard_Real(myCenter[1]))
172    };
173    // vector from the center of the circle to the nearest box face
174    Standard_Real aDist[2] = {
175      aDistC[0] - Standard_Real(myHSize[0]),
176      aDistC[1] - Standard_Real(myHSize[1])
177    };
178    Standard_Real aD (0.);
179    if (aDist[0] > 0.)
180      aD  = aDist[0]*aDist[0];
181    if (aDist[1] > 0.)
182      aD += aDist[1]*aDist[1];
183    if (aD < theRadius*theRadius) {
184      // the box intersects the solid circle; check if it is completely
185      // inside the circle (in such case return isOut==True)
186      aDist[0] = aDistC[0] + Standard_Real(myHSize[0]);
187      aDist[1] = aDistC[1] + Standard_Real(myHSize[1]);
188      if (aDist[0]*aDist[0]+aDist[1]*aDist[1] > theRadius*theRadius)
189        aResult = Standard_False;
190    }
191  }
192  return aResult;
193}
194
195//=======================================================================
196//function : IsOut
197//purpose  : Intersection Box - transformed Box
198//=======================================================================
199
200Standard_Boolean Bnd_B2x::IsOut (const Bnd_B2x&   theBox,
201                                 const gp_Trsf2d& theTrsf) const
202{
203  Standard_Boolean aResult (Standard_False);
204  const gp_TrsfForm aForm = theTrsf.Form();
205  const Standard_Real aScale = theTrsf.ScaleFactor();
206  const Standard_Real aScaleAbs = Abs(aScale);
207  if (aForm == gp_Translation || aForm == gp_Identity ||
208      aForm == gp_PntMirror   || aForm == gp_Scale)
209  {
210    aResult =
211      (Abs (RealType(theBox.myCenter[0]*aScale + theTrsf.TranslationPart().X())
212            - myCenter[0])
213         > RealType (theBox.myHSize[0]*aScaleAbs) + myHSize[0] ||
214       Abs (RealType(theBox.myCenter[1]*aScale + theTrsf.TranslationPart().Y())
215            - myCenter[1])
216         > RealType (theBox.myHSize[1]*aScaleAbs) + myHSize[1]);
217
218  }
219  else {
220    // theBox is transformed and we check the resulting (enlarged) box against
221    // 'this' box.
222    const Standard_Real * aMat = &theTrsf.HVectorialPart().Value(1,1);
223
224    gp_XY aCenter ((Standard_Real)theBox.myCenter[0],
225                   (Standard_Real)theBox.myCenter[1]);
226    theTrsf.Transforms (aCenter);
227    const Standard_Real aDist[2] = {
228      aCenter.X() - (Standard_Real)myCenter[0],
229      aCenter.Y() - (Standard_Real)myCenter[1]
230    };
231    const Standard_Real aMatAbs[4] = {
232      Abs(aMat[0]), Abs(aMat[1]), Abs(aMat[2]), Abs(aMat[3])
233    };
234    if (Abs(aDist[0]) > (aScaleAbs * (aMatAbs[0]*theBox.myHSize[0]+
235                                      aMatAbs[1]*theBox.myHSize[1]) +
236                         (Standard_Real)myHSize[0])    ||
237        Abs(aDist[1]) > (aScaleAbs * (aMatAbs[2]*theBox.myHSize[0]+
238                                      aMatAbs[3]*theBox.myHSize[1]) +
239                         (Standard_Real)myHSize[1]))
240      aResult = Standard_True;
241
242    else {
243    // theBox is rotated, scaled and translated. We apply the reverse
244    // translation and scaling then check against the rotated box 'this'
245      if ((Abs(aMat[0]*aDist[0]+aMat[2]*aDist[1])
246           > theBox.myHSize[0]*aScaleAbs + (aMatAbs[0]*myHSize[0] +
247                                            aMatAbs[2]*myHSize[1])) ||
248          (Abs(aMat[1]*aDist[0]+aMat[3]*aDist[1])
249           > theBox.myHSize[1]*aScaleAbs + (aMatAbs[1]*myHSize[0] +
250                                            aMatAbs[3]*myHSize[1])))
251        aResult = Standard_True;
252    }
253  }
254  return aResult;
255}
256
257//=======================================================================
258//function : IsOut
259//purpose  : Intersection Box - Line
260//=======================================================================
261
262Standard_Boolean Bnd_B2x::IsOut (const gp_Ax2d& theLine) const
263{
264  if (IsVoid())
265    return Standard_True;
266  // Intersect the line containing the segment.
267  const Standard_Real aProd[3] = {
268    theLine.Direction().XY() ^ (gp_XY (myCenter[0] - theLine.Location().X(),
269                                       myCenter[1] - theLine.Location().Y())),
270    theLine.Direction().X() * Standard_Real(myHSize[1]),
271    theLine.Direction().Y() * Standard_Real(myHSize[0])
272  };
273  return (Abs(aProd[0]) > (Abs(aProd[1]) + Abs(aProd[2])));
274}
275
276//=======================================================================
277//function : IsOut
278//purpose  : Intersection Box - Segment
279//=======================================================================
280
281Standard_Boolean Bnd_B2x::IsOut (const gp_XY& theP0, const gp_XY& theP1) const
282{
283  Standard_Boolean aResult (Standard_True);
284  if (IsVoid() == Standard_False)
285  {
286    // Intersect the line containing the segment.
287    const gp_XY aSegDelta (theP1 - theP0);
288    const Standard_Real aProd[3] = {
289      aSegDelta ^ (gp_XY (myCenter[0], myCenter[1]) - theP0),
290      aSegDelta.X() * Standard_Real(myHSize[1]),
291      aSegDelta.Y() * Standard_Real(myHSize[0])
292    };
293    if (Abs(aProd[0]) < (Abs(aProd[1]) + Abs(aProd[2])))
294    {
295      // Intersection with line detected; check the segment as bounding box
296      const gp_XY aHSeg    (0.5 * aSegDelta.X(), 0.5 * aSegDelta.Y());
297      const gp_XY aHSegAbs (Abs(aHSeg.X()), Abs(aHSeg.Y()));
298      aResult = _compareDistD (gp_XY((Standard_Real)myHSize[0],
299                                     (Standard_Real)myHSize[1]) + aHSegAbs,
300                               theP0 + aHSeg-gp_XY((Standard_Real)myCenter[0],
301                                                   (Standard_Real)myCenter[1]));
302    }
303  }
304  return aResult;
305}
306
307//=======================================================================
308//function : IsIn
309//purpose  : Test the complete inclusion of this box in transformed theOtherBox
310//=======================================================================
311
312Standard_Boolean Bnd_B2x::IsIn (const Bnd_B2x&   theBox,
313                                const gp_Trsf2d& theTrsf) const
314{
315  Standard_Boolean aResult (Standard_False);
316  const gp_TrsfForm aForm = theTrsf.Form();
317  const Standard_Real aScale = theTrsf.ScaleFactor();
318  const Standard_Real aScaleAbs = Abs(aScale);
319  if (aForm == gp_Translation || aForm == gp_Identity ||
320      aForm == gp_PntMirror   || aForm == gp_Scale)
321  {
322    aResult =
323      (Abs (RealType(theBox.myCenter[0]*aScale + theTrsf.TranslationPart().X())
324            - myCenter[0])
325         < RealType (theBox.myHSize[0]*aScaleAbs) - myHSize[0] &&
326       Abs (RealType(theBox.myCenter[1]*aScale + theTrsf.TranslationPart().Y())
327            - myCenter[1])
328         < RealType (theBox.myHSize[1]*aScaleAbs) - myHSize[1]);
329
330  } else {
331    // theBox is rotated, scaled and translated. We apply the reverse
332    // translation and scaling then check against the rotated box 'this'
333    const Standard_Real * aMat = &theTrsf.HVectorialPart().Value(1,1);
334    gp_XY aCenter ((Standard_Real)theBox.myCenter[0],
335                   (Standard_Real)theBox.myCenter[1]);
336    theTrsf.Transforms (aCenter);
337    const Standard_Real aDist[2] = {
338      aCenter.X() - (Standard_Real)myCenter[0],
339      aCenter.Y() - (Standard_Real)myCenter[1]
340    };
341    if ((Abs(aMat[0]*aDist[0]+aMat[2]*aDist[1])
342         < theBox.myHSize[0]*aScaleAbs - (Abs(aMat[0])*myHSize[0] +
343                                          Abs(aMat[2])*myHSize[1])) &&
344        (Abs(aMat[1]*aDist[0]+aMat[3]*aDist[1])
345         < theBox.myHSize[1]*aScaleAbs - (Abs(aMat[1])*myHSize[0] +
346                                          Abs(aMat[3])*myHSize[1])))
347      aResult = Standard_True;
348  }
349  return aResult;
350}
351