Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //  INFORMATION REGARDING THE CONTRIBUTION:
     10 //
     11 //  Author: Ovidiu Parvu
     12 //  Affiliation: Brunel University
     13 //  Created: 11.09.2013
     14 //  E-mail: <ovidiu.parvu[AT]gmail.com>
     15 //  Web: http://people.brunel.ac.uk/~cspgoop
     16 //
     17 //  These functions were implemented during Ovidiu Parvu's first year as a PhD student at
     18 //  Brunel University, London, UK. The PhD project is supervised by prof. David Gilbert (principal)
     19 //  and prof. Nigel Saunders (second).
     20 //
     21 //  THE IMPLEMENTATION OF THE MODULES IS BASED ON THE FOLLOWING PAPERS:
     22 //
     23 //  [1] V. Klee and M. C. Laskowski, "Finding the smallest triangles containing a given convex
     24 //  polygon", Journal of Algorithms, vol. 6, no. 3, pp. 359-375, Sep. 1985.
     25 //  [2] J. O'Rourke, A. Aggarwal, S. Maddila, and M. Baldwin, "An optimal algorithm for finding
     26 //  minimal enclosing triangles", Journal of Algorithms, vol. 7, no. 2, pp. 258-269, Jun. 1986.
     27 //
     28 //  The overall complexity of the algorithm is theta(n) where "n" represents the number
     29 //  of vertices in the convex polygon.
     30 //
     31 //
     32 //
     33 //                           License Agreement
     34 //                For Open Source Computer Vision Library
     35 //
     36 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     37 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
     38 // Copyright (C) 2013, Ovidiu Parvu, all rights reserved.
     39 // Third party copyrights are property of their respective owners.
     40 //
     41 // Redistribution and use in source and binary forms, with or without modification,
     42 // are permitted provided that the following conditions are met:
     43 //
     44 //   * Redistribution's of source code must retain the above copyright notice,
     45 //     this list of conditions and the following disclaimer.
     46 //
     47 //   * Redistribution's in binary form must reproduce the above copyright notice,
     48 //     this list of conditions and the following disclaimer in the documentation
     49 //     and/or other materials provided with the distribution.
     50 //
     51 //   * The name of the copyright holders may not be used to endorse or promote products
     52 //     derived from this software without specific prior written permission.
     53 //
     54 // This software is provided by the copyright holders and contributors "as is" and
     55 // any express or implied warranties, including, but not limited to, the implied
     56 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     57 // In no event shall the Intel Corporation or contributors be liable for any direct,
     58 // indirect, incidental, special, exemplary, or consequential damages
     59 // (including, but not limited to, procurement of substitute goods or services;
     60 // loss of use, data, or profits; or business interruption) however caused
     61 // and on any theory of liability, whether in contract, strict liability,
     62 // or tort (including negligence or otherwise) arising in any way out of
     63 // the use of this software, even if advised of the possibility of such damage.
     64 //
     65 //M*/
     66 
     67 #include "precomp.hpp"
     68 
     69 #include <algorithm>
     70 #include <cmath>
     71 #include <limits>
     72 #include <vector>
     73 
     74 
     75 ///////////////////////////////// Constants definitions //////////////////////////////////
     76 
     77 
     78 // Intersection of line and polygon
     79 
     80 #define INTERSECTS_BELOW        1
     81 #define INTERSECTS_ABOVE        2
     82 #define INTERSECTS_CRITICAL     3
     83 
     84 // Error messages
     85 
     86 #define ERR_SIDE_B_GAMMA        "The position of side B could not be determined, because gamma(b) could not be computed."
     87 #define ERR_VERTEX_C_ON_SIDE_B  "The position of the vertex C on side B could not be determined, because the considered lines do not intersect."
     88 
     89 // Possible values for validation flag
     90 
     91 #define VALIDATION_SIDE_A_TANGENT   0
     92 #define VALIDATION_SIDE_B_TANGENT   1
     93 #define VALIDATION_SIDES_FLUSH      2
     94 
     95 // Threshold value for comparisons
     96 
     97 #define EPSILON 1E-5
     98 
     99 
    100 ////////////////////////////// Helper functions declarations /////////////////////////////
    101 
    102 
    103 namespace minEnclosingTriangle {
    104 
    105 static void advance(unsigned int &index, unsigned int nrOfPoints);
    106 
    107 static void advanceBToRightChain(const std::vector<cv::Point2f> &polygon,
    108                                  unsigned int nrOfPoints, unsigned int &b,
    109                                  unsigned int c);
    110 
    111 static bool almostEqual(double number1, double number2);
    112 
    113 static double angleOfLineWrtOxAxis(const cv::Point2f &a, const cv::Point2f &b);
    114 
    115 static bool areEqualPoints(const cv::Point2f &point1, const cv::Point2f &point2);
    116 
    117 static bool areIdenticalLines(const std::vector<double> &side1Params,
    118                               const std::vector<double> &side2Params, double sideCExtraParam);
    119 
    120 static bool areIdenticalLines(double a1, double b1, double c1, double a2, double b2, double c2);
    121 
    122 static bool areIntersectingLines(const std::vector<double> &side1Params,
    123                                  const std::vector<double> &side2Params,
    124                                  double sideCExtraParam, cv::Point2f &intersectionPoint1,
    125                                  cv::Point2f &intersectionPoint2);
    126 
    127 static bool areOnTheSameSideOfLine(const cv::Point2f &p1, const cv::Point2f &p2,
    128                                    const cv::Point2f &a, const cv::Point2f &b);
    129 
    130 static double areaOfTriangle(const cv::Point2f &a, const cv::Point2f &b, const cv::Point2f &c);
    131 
    132 static void copyResultingTriangle(const std::vector<cv::Point2f> &resultingTriangle, cv::OutputArray triangle);
    133 
    134 static void createConvexHull(cv::InputArray points, std::vector<cv::Point2f> &polygon);
    135 
    136 static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b);
    137 
    138 static double distanceFromPointToLine(const cv::Point2f &a, const cv::Point2f &linePointB,
    139                                       const cv::Point2f &linePointC);
    140 
    141 static bool findGammaIntersectionPoints(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    142                                         unsigned int c, unsigned int polygonPointIndex,
    143                                         const cv::Point2f &side1StartVertex, const cv::Point2f &side1EndVertex,
    144                                         const cv::Point2f &side2StartVertex, const cv::Point2f &side2EndVertex,
    145                                         cv::Point2f &intersectionPoint1, cv::Point2f &intersectionPoint2);
    146 
    147 static void findMinEnclosingTriangle(cv::InputArray points,
    148                                      CV_OUT cv::OutputArray triangle, CV_OUT double &area);
    149 
    150 static void findMinEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    151                                      std::vector<cv::Point2f> &triangle, double &area);
    152 
    153 static void findMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    154                                              std::vector<cv::Point2f> &triangle, double &area);
    155 
    156 static cv::Point2f findVertexCOnSideB(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    157                                       unsigned int a, unsigned int c,
    158                                       const cv::Point2f &sideBStartVertex,
    159                                       const cv::Point2f &sideBEndVertex,
    160                                       const cv::Point2f &sideCStartVertex,
    161                                       const cv::Point2f &sideCEndVertex);
    162 
    163 static bool gamma(unsigned int polygonPointIndex, cv::Point2f &gammaPoint,
    164                   const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    165                   unsigned int a, unsigned int c);
    166 
    167 static bool greaterOrEqual(double number1, double number2);
    168 
    169 static double height(const cv::Point2f &polygonPoint, const std::vector<cv::Point2f> &polygon,
    170                      unsigned int nrOfPoints, unsigned int c);
    171 
    172 static double height(unsigned int polygonPointIndex, const std::vector<cv::Point2f> &polygon,
    173                      unsigned int nrOfPoints, unsigned int c);
    174 
    175 static void initialise(std::vector<cv::Point2f> &triangle, double &area);
    176 
    177 static unsigned int intersects(double angleGammaAndPoint, unsigned int polygonPointIndex,
    178                                const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    179                                unsigned int c);
    180 
    181 static bool intersectsAbove(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
    182                             const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    183                             unsigned int c);
    184 
    185 static unsigned int intersectsAboveOrBelow(unsigned int succPredIndex, unsigned int pointIndex,
    186                                            const std::vector<cv::Point2f> &polygon,
    187                                            unsigned int nrOfPoints, unsigned int c);
    188 
    189 static bool intersectsBelow(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
    190                             const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    191                             unsigned int c);
    192 
    193 static bool isAngleBetween(double angle1, double angle2, double angle3);
    194 
    195 static bool isAngleBetweenNonReflex(double angle1, double angle2, double angle3);
    196 
    197 static bool isFlushAngleBtwPredAndSucc(double &angleFlushEdge, double anglePred, double angleSucc);
    198 
    199 static bool isGammaAngleBtw(double &gammaAngle, double angle1, double angle2);
    200 
    201 static bool isGammaAngleEqualTo(double &gammaAngle, double angle);
    202 
    203 static bool isLocalMinimalTriangle(cv::Point2f &vertexA, cv::Point2f &vertexB,
    204                                    cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
    205                                    unsigned int nrOfPoints, unsigned int a, unsigned int b,
    206                                    unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
    207                                    const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    208                                    const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    209                                    const cv::Point2f &sideCEndVertex);
    210 
    211 static bool isNotBTangency(const std::vector<cv::Point2f> &polygon,
    212                            unsigned int nrOfPoints, unsigned int a, unsigned int b,
    213                            unsigned int c);
    214 
    215 static bool isOppositeAngleBetweenNonReflex(double angle1, double angle2, double angle3);
    216 
    217 static bool isPointOnLineSegment(const cv::Point2f &point, const cv::Point2f &lineSegmentStart,
    218                                  const cv::Point2f &lineSegmentEnd);
    219 
    220 static bool isValidMinimalTriangle(const cv::Point2f &vertexA, const cv::Point2f &vertexB,
    221                                    const cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
    222                                    unsigned int nrOfPoints, unsigned int a, unsigned int b,
    223                                    unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
    224                                    const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    225                                    const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    226                                    const cv::Point2f &sideCEndVertex);
    227 
    228 static bool lessOrEqual(double number1, double number2);
    229 
    230 static void lineEquationDeterminedByPoints(const cv::Point2f &p, const cv::Point2f &q,
    231                                            double &a, double &b, double &c);
    232 
    233 static std::vector<double> lineEquationParameters(const cv::Point2f& p, const cv::Point2f &q);
    234 
    235 static bool lineIntersection(const cv::Point2f &a1, const cv::Point2f &b1, const cv::Point2f &a2,
    236                              const cv::Point2f &b2, cv::Point2f &intersection);
    237 
    238 static bool lineIntersection(double a1, double b1, double c1, double a2, double b2, double c2,
    239                              cv::Point2f &intersection);
    240 
    241 static double maximum(double number1, double number2, double number3);
    242 
    243 static cv::Point2f middlePoint(const cv::Point2f &a, const cv::Point2f &b);
    244 
    245 static bool middlePointOfSideB(cv::Point2f &middlePointOfSideB, const cv::Point2f &sideAStartVertex,
    246                                const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    247                                const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    248                                const cv::Point2f &sideCEndVertex);
    249 
    250 static void moveAIfLowAndBIfHigh(const std::vector<cv::Point2f> &polygon,
    251                                  unsigned int nrOfPoints, unsigned int &a, unsigned int &b,
    252                                  unsigned int c);
    253 
    254 static double oppositeAngle(double angle);
    255 
    256 static unsigned int predecessor(unsigned int index, unsigned int nrOfPoints);
    257 
    258 static void returnMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    259                                                std::vector<cv::Point2f> &triangle, double &area);
    260 
    261 static void searchForBTangency(const std::vector<cv::Point2f> &polygon,
    262                                unsigned int nrOfPoints, unsigned int a, unsigned int &b,
    263                                unsigned int c);
    264 
    265 static int sign(double number);
    266 
    267 static unsigned int successor(unsigned int index, unsigned int nrOfPoints);
    268 
    269 static void updateMinimumAreaEnclosingTriangle(std::vector<cv::Point2f> &triangle, double &area,
    270                                                const cv::Point2f &vertexA, const cv::Point2f &vertexB,
    271                                                const cv::Point2f &vertexC);
    272 
    273 static void updateSideB(const std::vector<cv::Point2f> &polygon,
    274                         unsigned int nrOfPoints, unsigned int a, unsigned int b,
    275                         unsigned int c, unsigned int &validationFlag,
    276                         cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex);
    277 
    278 static void updateSidesBA(const std::vector<cv::Point2f> &polygon,
    279                           unsigned int nrOfPoints, unsigned int a, unsigned int b,
    280                           unsigned int c, unsigned int &validationFlag,
    281                           cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
    282                           cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex,
    283                           const cv::Point2f &sideCStartVertex, const cv::Point2f &sideCEndVertex);
    284 
    285 static void updateSidesCA(const std::vector<cv::Point2f> &polygon,
    286                           unsigned int nrOfPoints, unsigned int a, unsigned int c,
    287                           cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
    288                           cv::Point2f &sideCStartVertex, cv::Point2f &sideCEndVertex);
    289 
    290 }
    291 
    292 
    293 ///////////////////////////////////// Main functions /////////////////////////////////////
    294 
    295 
    296 //! Find the minimum enclosing triangle for the given set of points and return its area
    297 /*!
    298 * @param points         Set of points
    299 * @param triangle       Minimum area triangle enclosing the given set of points
    300 */
    301 double cv::minEnclosingTriangle(cv::InputArray points, CV_OUT cv::OutputArray triangle) {
    302     double area;
    303 
    304     minEnclosingTriangle::findMinEnclosingTriangle(points, triangle, area);
    305 
    306     return area;
    307 }
    308 
    309 
    310 /////////////////////////////// Helper functions definition //////////////////////////////
    311 
    312 
    313 namespace minEnclosingTriangle {
    314 
    315 //! Find the minimum enclosing triangle and its area
    316 /*!
    317 * @param points         Set of points
    318 * @param triangle       Minimum area triangle enclosing the given set of points
    319 * @param area           Area of the minimum area enclosing triangle
    320 */
    321 static void findMinEnclosingTriangle(cv::InputArray points,
    322                                      CV_OUT cv::OutputArray triangle, CV_OUT double &area) {
    323     std::vector<cv::Point2f> resultingTriangle, polygon;
    324 
    325     createConvexHull(points, polygon);
    326     findMinEnclosingTriangle(polygon, resultingTriangle, area);
    327     copyResultingTriangle(resultingTriangle, triangle);
    328 }
    329 
    330 //! Create the convex hull of the given set of points
    331 /*!
    332 * @param points     The provided set of points
    333 * @param polygon    The polygon representing the convex hull of the points
    334 */
    335 static void createConvexHull(cv::InputArray points, std::vector<cv::Point2f> &polygon) {
    336     cv::Mat pointsMat = points.getMat();
    337     std::vector<cv::Point2f> pointsVector;
    338 
    339     CV_Assert((pointsMat.checkVector(2) > 0) &&
    340               ((pointsMat.depth() == CV_32F) || (pointsMat.depth() == CV_32S)));
    341 
    342     pointsMat.convertTo(pointsVector, CV_32F);
    343 
    344     convexHull(pointsVector, polygon, true, true);
    345 }
    346 
    347 //! Find the minimum enclosing triangle and its area
    348 /*!
    349 * The overall complexity of the algorithm is theta(n) where "n" represents the number
    350 * of vertices in the convex polygon
    351 *
    352 * @param polygon    The polygon representing the convex hull of the points
    353 * @param triangle   Minimum area triangle enclosing the given polygon
    354 * @param area       Area of the minimum area enclosing triangle
    355 */
    356 static void findMinEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    357                                      std::vector<cv::Point2f> &triangle, double &area) {
    358     initialise(triangle, area);
    359 
    360     if (polygon.size() > 3) {
    361         findMinimumAreaEnclosingTriangle(polygon, triangle, area);
    362     } else {
    363         returnMinimumAreaEnclosingTriangle(polygon, triangle, area);
    364     }
    365 }
    366 
    367 //! Copy resultingTriangle to the OutputArray triangle
    368 /*!
    369 * @param resultingTriangle  Minimum area triangle enclosing the given polygon found by the algorithm
    370 * @param triangle           Minimum area triangle enclosing the given polygon returned to the user
    371 */
    372 static void copyResultingTriangle(const std::vector<cv::Point2f> &resultingTriangle,
    373                                   cv::OutputArray triangle) {
    374     cv::Mat(resultingTriangle).copyTo(triangle);
    375 }
    376 
    377 //! Initialisation function
    378 /*!
    379 * @param triangle       Minimum area triangle enclosing the given polygon
    380 * @param area           Area of the minimum area enclosing triangle
    381 */
    382 static void initialise(std::vector<cv::Point2f> &triangle, double &area) {
    383     area = std::numeric_limits<double>::max();
    384 
    385     // Clear all points previously stored in the vector
    386     triangle.clear();
    387 }
    388 
    389 //! Find the minimum area enclosing triangle for the given polygon
    390 /*!
    391 * @param polygon    The polygon representing the convex hull of the points
    392 * @param triangle   Minimum area triangle enclosing the given polygon
    393 * @param area       Area of the minimum area enclosing triangle
    394 */
    395 static void findMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    396                                              std::vector<cv::Point2f> &triangle, double &area) {
    397     // Algorithm specific variables
    398 
    399     unsigned int validationFlag;
    400 
    401     cv::Point2f vertexA, vertexB, vertexC;
    402 
    403     cv::Point2f sideAStartVertex, sideAEndVertex;
    404     cv::Point2f sideBStartVertex, sideBEndVertex;
    405     cv::Point2f sideCStartVertex, sideCEndVertex;
    406 
    407     unsigned int a, b, c;
    408     unsigned int nrOfPoints;
    409 
    410     // Variables initialisation
    411 
    412     nrOfPoints = static_cast<unsigned int>(polygon.size());
    413 
    414     a = 1;
    415     b = 2;
    416     c = 0;
    417 
    418     // Main algorithm steps
    419 
    420     for (c = 0; c < nrOfPoints; c++) {
    421         advanceBToRightChain(polygon, nrOfPoints, b, c);
    422         moveAIfLowAndBIfHigh(polygon, nrOfPoints, a, b, c);
    423         searchForBTangency(polygon, nrOfPoints, a ,b, c);
    424 
    425         updateSidesCA(polygon, nrOfPoints, a, c, sideAStartVertex, sideAEndVertex,
    426                       sideCStartVertex, sideCEndVertex);
    427 
    428         if (isNotBTangency(polygon, nrOfPoints, a, b, c)) {
    429             updateSidesBA(polygon, nrOfPoints, a, b, c, validationFlag, sideAStartVertex,
    430                           sideAEndVertex, sideBStartVertex, sideBEndVertex,
    431                           sideCStartVertex, sideCEndVertex);
    432         } else {
    433             updateSideB(polygon, nrOfPoints, a, b, c, validationFlag,
    434                         sideBStartVertex,  sideBEndVertex);
    435         }
    436 
    437         if (isLocalMinimalTriangle(vertexA, vertexB, vertexC, polygon, nrOfPoints, a, b,
    438                                    validationFlag, sideAStartVertex, sideAEndVertex,
    439                                    sideBStartVertex, sideBEndVertex, sideCStartVertex,
    440                                    sideCEndVertex)) {
    441             updateMinimumAreaEnclosingTriangle(triangle, area, vertexA, vertexB, vertexC);
    442         }
    443     }
    444 }
    445 
    446 //! Return the minimum area enclosing (pseudo-)triangle in case the convex polygon has at most three points
    447 /*!
    448 * @param polygon    The polygon representing the convex hull of the points
    449 * @param triangle   Minimum area triangle enclosing the given polygon
    450 * @param area       Area of the minimum area enclosing triangle
    451 */
    452 static void returnMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
    453                                                std::vector<cv::Point2f> &triangle, double &area) {
    454     unsigned int nrOfPoints = static_cast<unsigned int>(polygon.size());
    455 
    456     for (int i = 0; i < 3; i++) {
    457         triangle.push_back(polygon[i % nrOfPoints]);
    458     }
    459 
    460     area = areaOfTriangle(triangle[0], triangle[1], triangle[2]);
    461 }
    462 
    463 //! Advance b to the right chain
    464 /*!
    465 * See paper [2] for more details
    466 *
    467 * @param polygon            The polygon representing the convex hull of the points
    468 * @param nrOfPoints         Number of points defining the convex polygon
    469 * @param b                  Index b
    470 * @param c                  Index c
    471 */
    472 static void advanceBToRightChain(const std::vector<cv::Point2f> &polygon,
    473                                  unsigned int nrOfPoints, unsigned int &b,
    474                                  unsigned int c) {
    475     while (greaterOrEqual(height(successor(b, nrOfPoints), polygon, nrOfPoints, c),
    476                           height(b, polygon, nrOfPoints, c))) {
    477         advance(b, nrOfPoints);
    478     }
    479 }
    480 
    481 //! Move "a" if it is low and "b" if it is high
    482 /*!
    483 * See paper [2] for more details
    484 *
    485 * @param polygon            The polygon representing the convex hull of the points
    486 * @param nrOfPoints         Number of points defining the convex polygon
    487 * @param a                  Index a
    488 * @param b                  Index b
    489 * @param c                  Index c
    490 */
    491 static void moveAIfLowAndBIfHigh(const std::vector<cv::Point2f> &polygon,
    492                                  unsigned int nrOfPoints, unsigned int &a, unsigned int &b,
    493                                  unsigned int c) {
    494     cv::Point2f gammaOfA;
    495 
    496     while(height(b, polygon, nrOfPoints, c) > height(a, polygon, nrOfPoints, c)) {
    497         if ((gamma(a, gammaOfA, polygon, nrOfPoints, a, c)) && (intersectsBelow(gammaOfA, b, polygon, nrOfPoints, c))) {
    498             advance(b, nrOfPoints);
    499         } else {
    500             advance(a, nrOfPoints);
    501         }
    502     }
    503 }
    504 
    505 //! Search for the tangency of side B
    506 /*!
    507 * See paper [2] for more details
    508 *
    509 * @param polygon            The polygon representing the convex hull of the points
    510 * @param nrOfPoints         Number of points defining the convex polygon
    511 * @param a                  Index a
    512 * @param b                  Index b
    513 * @param c                  Index c
    514 */
    515 static void searchForBTangency(const std::vector<cv::Point2f> &polygon,
    516                                unsigned int nrOfPoints, unsigned int a, unsigned int &b,
    517                                unsigned int c) {
    518     cv::Point2f gammaOfB;
    519 
    520     while (((gamma(b, gammaOfB, polygon, nrOfPoints, a, c)) &&
    521             (intersectsBelow(gammaOfB, b, polygon, nrOfPoints, c))) &&
    522            (greaterOrEqual(height(b, polygon, nrOfPoints, c),
    523                            height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c)))
    524           ) {
    525         advance(b, nrOfPoints);
    526     }
    527 }
    528 
    529 //! Check if tangency for side B was not obtained
    530 /*!
    531 * See paper [2] for more details
    532 *
    533 * @param polygon            The polygon representing the convex hull of the points
    534 * @param nrOfPoints         Number of points defining the convex polygon
    535 * @param a                  Index a
    536 * @param b                  Index b
    537 * @param c                  Index c
    538 */
    539 static bool isNotBTangency(const std::vector<cv::Point2f> &polygon,
    540                            unsigned int nrOfPoints, unsigned int a, unsigned int b,
    541                            unsigned int c) {
    542     cv::Point2f gammaOfB;
    543 
    544     if (((gamma(b, gammaOfB, polygon, nrOfPoints, a, c)) &&
    545          (intersectsAbove(gammaOfB, b, polygon, nrOfPoints, c))) ||
    546         (height(b, polygon, nrOfPoints, c) < height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c))) {
    547         return true;
    548     }
    549 
    550     return false;
    551 }
    552 
    553 //! Update sides A and C
    554 /*!
    555 * Side C will have as start and end vertices the polygon points "c" and "c-1"
    556 * Side A will have as start and end vertices the polygon points "a" and "a-1"
    557 *
    558 * @param polygon            The polygon representing the convex hull of the points
    559 * @param nrOfPoints         Number of points defining the convex polygon
    560 * @param a                  Index a
    561 * @param c                  Index c
    562 * @param sideAStartVertex   Start vertex for defining side A
    563 * @param sideAEndVertex     End vertex for defining side A
    564 * @param sideCStartVertex   Start vertex for defining side C
    565 * @param sideCEndVertex     End vertex for defining side C
    566 */
    567 static void updateSidesCA(const std::vector<cv::Point2f> &polygon,
    568                           unsigned int nrOfPoints, unsigned int a, unsigned int c,
    569                           cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
    570                           cv::Point2f &sideCStartVertex, cv::Point2f &sideCEndVertex) {
    571     sideCStartVertex = polygon[predecessor(c, nrOfPoints)];
    572     sideCEndVertex = polygon[c];
    573 
    574     sideAStartVertex = polygon[predecessor(a, nrOfPoints)];
    575     sideAEndVertex = polygon[a];
    576 }
    577 
    578 //! Update sides B and possibly A if tangency for side B was not obtained
    579 /*!
    580 * See paper [2] for more details
    581 *
    582 * @param polygon            The polygon representing the convex hull of the points
    583 * @param nrOfPoints         Number of points defining the convex polygon
    584 * @param a                  Index a
    585 * @param b                  Index b
    586 * @param c                  Index c
    587 * @param validationFlag     Flag used for validation
    588 * @param sideAStartVertex   Start vertex for defining side A
    589 * @param sideAEndVertex     End vertex for defining side A
    590 * @param sideBStartVertex   Start vertex for defining side B
    591 * @param sideBEndVertex     End vertex for defining side B
    592 * @param sideCStartVertex   Start vertex for defining side C
    593 * @param sideCEndVertex     End vertex for defining side C
    594 */
    595 static void updateSidesBA(const std::vector<cv::Point2f> &polygon,
    596                           unsigned int nrOfPoints, unsigned int a, unsigned int b,
    597                           unsigned int c, unsigned int &validationFlag,
    598                           cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
    599                           cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex,
    600                           const cv::Point2f &sideCStartVertex, const cv::Point2f &sideCEndVertex) {
    601     // Side B is flush with edge [b, b-1]
    602     sideBStartVertex = polygon[predecessor(b, nrOfPoints)];
    603     sideBEndVertex = polygon[b];
    604 
    605     // Find middle point of side B
    606     cv::Point2f sideBMiddlePoint;
    607 
    608     if ((middlePointOfSideB(sideBMiddlePoint, sideAStartVertex, sideAEndVertex, sideBStartVertex,
    609                             sideBEndVertex, sideCStartVertex, sideCEndVertex)) &&
    610         (height(sideBMiddlePoint, polygon, nrOfPoints, c) <
    611          height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c))) {
    612         sideAStartVertex = polygon[predecessor(a, nrOfPoints)];
    613         sideAEndVertex = findVertexCOnSideB(polygon, nrOfPoints, a, c,
    614                                             sideBStartVertex, sideBEndVertex,
    615                                             sideCStartVertex, sideCEndVertex);
    616 
    617         validationFlag = VALIDATION_SIDE_A_TANGENT;
    618     } else {
    619         validationFlag = VALIDATION_SIDES_FLUSH;
    620     }
    621 }
    622 
    623 //! Set side B if tangency for side B was obtained
    624 /*!
    625 * See paper [2] for more details
    626 *
    627 * @param polygon            The polygon representing the convex hull of the points
    628 * @param nrOfPoints         Number of points defining the convex polygon
    629 * @param a                  Index a
    630 * @param b                  Index b
    631 * @param c                  Index c
    632 * @param validationFlag     Flag used for validation
    633 * @param sideBStartVertex   Start vertex for defining side B
    634 * @param sideBEndVertex     End vertex for defining side B
    635 */
    636 static void updateSideB(const std::vector<cv::Point2f> &polygon,
    637                         unsigned int nrOfPoints, unsigned int a, unsigned int b,
    638                         unsigned int c, unsigned int &validationFlag,
    639                         cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex) {
    640     if (!gamma(b, sideBStartVertex, polygon, nrOfPoints, a, c)) {
    641         CV_Error(cv::Error::StsInternal, ERR_SIDE_B_GAMMA);
    642     }
    643 
    644     sideBEndVertex = polygon[b];
    645 
    646     validationFlag = VALIDATION_SIDE_B_TANGENT;
    647 }
    648 
    649 //! Update the triangle vertices after all sides were set and check if a local minimal triangle was found or not
    650 /*!
    651 * See paper [2] for more details
    652 *
    653 * @param vertexA            Vertex A of the enclosing triangle
    654 * @param vertexB            Vertex B of the enclosing triangle
    655 * @param vertexC            Vertex C of the enclosing triangle
    656 * @param polygon            The polygon representing the convex hull of the points
    657 * @param nrOfPoints         Number of points defining the convex polygon
    658 * @param a                  Index a
    659 * @param b                  Index b
    660 * @param validationFlag     Flag used for validation
    661 * @param sideAStartVertex   Start vertex for defining side A
    662 * @param sideAEndVertex     End vertex for defining side A
    663 * @param sideBStartVertex   Start vertex for defining side B
    664 * @param sideBEndVertex     End vertex for defining side B
    665 * @param sideCStartVertex   Start vertex for defining side C
    666 * @param sideCEndVertex     End vertex for defining side C
    667 */
    668 static bool isLocalMinimalTriangle(cv::Point2f &vertexA, cv::Point2f &vertexB,
    669                                    cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
    670                                    unsigned int nrOfPoints, unsigned int a, unsigned int b,
    671                                    unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
    672                                    const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    673                                    const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    674                                    const cv::Point2f &sideCEndVertex) {
    675     if ((!lineIntersection(sideAStartVertex, sideAEndVertex,
    676                            sideBStartVertex, sideBEndVertex, vertexC)) ||
    677         (!lineIntersection(sideAStartVertex, sideAEndVertex,
    678                            sideCStartVertex, sideCEndVertex, vertexB)) ||
    679         (!lineIntersection(sideBStartVertex, sideBEndVertex,
    680                            sideCStartVertex, sideCEndVertex, vertexA))) {
    681         return false;
    682     }
    683 
    684     return isValidMinimalTriangle(vertexA, vertexB, vertexC, polygon, nrOfPoints, a, b,
    685                                   validationFlag, sideAStartVertex, sideAEndVertex,
    686                                   sideBStartVertex, sideBEndVertex, sideCStartVertex,
    687                                   sideCEndVertex);
    688 }
    689 
    690 //! Check if the found minimal triangle is valid
    691 /*!
    692 * This means that all midpoints of the triangle should touch the polygon
    693 *
    694 * See paper [2] for more details
    695 *
    696 * @param vertexA            Vertex A of the enclosing triangle
    697 * @param vertexB            Vertex B of the enclosing triangle
    698 * @param vertexC            Vertex C of the enclosing triangle
    699 * @param polygon            The polygon representing the convex hull of the points
    700 * @param nrOfPoints         Number of points defining the convex polygon
    701 * @param a                  Index a
    702 * @param b                  Index b
    703 * @param validationFlag     Flag used for validation
    704 * @param sideAStartVertex   Start vertex for defining side A
    705 * @param sideAEndVertex     End vertex for defining side A
    706 * @param sideBStartVertex   Start vertex for defining side B
    707 * @param sideBEndVertex     End vertex for defining side B
    708 * @param sideCStartVertex   Start vertex for defining side C
    709 * @param sideCEndVertex     End vertex for defining side C
    710 */
    711 static bool isValidMinimalTriangle(const cv::Point2f &vertexA, const cv::Point2f &vertexB,
    712                                    const cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
    713                                    unsigned int nrOfPoints, unsigned int a, unsigned int b,
    714                                    unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
    715                                    const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    716                                    const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    717                                    const cv::Point2f &sideCEndVertex) {
    718     cv::Point2f midpointSideA = middlePoint(vertexB, vertexC);
    719     cv::Point2f midpointSideB = middlePoint(vertexA, vertexC);
    720     cv::Point2f midpointSideC = middlePoint(vertexA, vertexB);
    721 
    722     bool sideAValid = (validationFlag == VALIDATION_SIDE_A_TANGENT)
    723                         ? (areEqualPoints(midpointSideA, polygon[predecessor(a, nrOfPoints)]))
    724                         : (isPointOnLineSegment(midpointSideA, sideAStartVertex, sideAEndVertex));
    725 
    726     bool sideBValid = (validationFlag == VALIDATION_SIDE_B_TANGENT)
    727                           ? (areEqualPoints(midpointSideB, polygon[b]))
    728                           : (isPointOnLineSegment(midpointSideB, sideBStartVertex, sideBEndVertex));
    729 
    730     bool sideCValid = isPointOnLineSegment(midpointSideC, sideCStartVertex, sideCEndVertex);
    731 
    732     return (sideAValid && sideBValid && sideCValid);
    733 }
    734 
    735 //! Update the current minimum area enclosing triangle if the newly obtained one has a smaller area
    736 /*!
    737 * @param triangle   Minimum area triangle enclosing the given polygon
    738 * @param area       Area of the minimum area triangle enclosing the given polygon
    739 * @param vertexA    Vertex A of the enclosing triangle
    740 * @param vertexB    Vertex B of the enclosing triangle
    741 * @param vertexC    Vertex C of the enclosing triangle
    742 */
    743 static void updateMinimumAreaEnclosingTriangle(std::vector<cv::Point2f> &triangle, double &area,
    744                                                const cv::Point2f &vertexA, const cv::Point2f &vertexB,
    745                                                const cv::Point2f &vertexC) {
    746     double triangleArea = areaOfTriangle(vertexA, vertexB, vertexC);
    747 
    748     if (triangleArea < area) {
    749         triangle.clear();
    750 
    751         triangle.push_back(vertexA);
    752         triangle.push_back(vertexB);
    753         triangle.push_back(vertexC);
    754 
    755         area = triangleArea;
    756     }
    757 }
    758 
    759 //! Return the middle point of side B
    760 /*!
    761 * @param middlePointOfSideB Middle point of side B
    762 * @param sideAStartVertex   Start vertex for defining side A
    763 * @param sideAEndVertex     End vertex for defining side A
    764 * @param sideBStartVertex   Start vertex for defining side B
    765 * @param sideBEndVertex     End vertex for defining side B
    766 * @param sideCStartVertex   Start vertex for defining side C
    767 * @param sideCEndVertex     End vertex for defining side C
    768 */
    769 static bool middlePointOfSideB(cv::Point2f &middlePointOfSideB, const cv::Point2f &sideAStartVertex,
    770                                const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
    771                                const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
    772                                const cv::Point2f &sideCEndVertex) {
    773     cv::Point2f vertexA, vertexC;
    774 
    775     if ((!lineIntersection(sideBStartVertex, sideBEndVertex, sideCStartVertex, sideCEndVertex, vertexA)) ||
    776         (!lineIntersection(sideBStartVertex, sideBEndVertex, sideAStartVertex, sideAEndVertex, vertexC))) {
    777         return false;
    778     }
    779 
    780     middlePointOfSideB = middlePoint(vertexA, vertexC);
    781 
    782     return true;
    783 }
    784 
    785 //! Check if the line intersects below
    786 /*!
    787 * Check if the line determined by gammaPoint and polygon[polygonPointIndex] intersects
    788 * the polygon below the point polygon[polygonPointIndex]
    789 *
    790 * @param gammaPoint         Gamma(p)
    791 * @param polygonPointIndex  Index of the polygon point which is considered when determining the line
    792 * @param polygon            The polygon representing the convex hull of the points
    793 * @param nrOfPoints         Number of points defining the convex polygon
    794 * @param c                  Index c
    795 */
    796 static bool intersectsBelow(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
    797                             const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    798                             unsigned int c) {
    799     double angleOfGammaAndPoint = angleOfLineWrtOxAxis(polygon[polygonPointIndex], gammaPoint);
    800 
    801     return (intersects(angleOfGammaAndPoint, polygonPointIndex, polygon, nrOfPoints, c) == INTERSECTS_BELOW);
    802 }
    803 
    804 //! Check if the line intersects above
    805 /*!
    806 * Check if the line determined by gammaPoint and polygon[polygonPointIndex] intersects
    807 * the polygon above the point polygon[polygonPointIndex]
    808 *
    809 * @param gammaPoint         Gamma(p)
    810 * @param polygonPointIndex  Index of the polygon point which is considered when determining the line
    811 * @param polygon            The polygon representing the convex hull of the points
    812 * @param nrOfPoints         Number of points defining the convex polygon
    813 * @param c                  Index c
    814 */
    815 static bool intersectsAbove(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
    816                             const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    817                             unsigned int c) {
    818     double angleOfGammaAndPoint = angleOfLineWrtOxAxis(gammaPoint, polygon[polygonPointIndex]);
    819 
    820     return (intersects(angleOfGammaAndPoint, polygonPointIndex, polygon, nrOfPoints, c) == INTERSECTS_ABOVE);
    821 }
    822 
    823 //! Check if/where the line determined by gammaPoint and polygon[polygonPointIndex] intersects the polygon
    824 /*!
    825 * @param angleGammaAndPoint     Angle determined by gammaPoint and polygon[polygonPointIndex] wrt Ox axis
    826 * @param polygonPointIndex      Index of the polygon point which is considered when determining the line
    827 * @param polygon                The polygon representing the convex hull of the points
    828 * @param nrOfPoints             Number of points defining the convex polygon
    829 * @param c                      Index c
    830 */
    831 static unsigned int intersects(double angleGammaAndPoint, unsigned int polygonPointIndex,
    832                                const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    833                                unsigned int c) {
    834     double anglePointPredecessor = angleOfLineWrtOxAxis(polygon[predecessor(polygonPointIndex, nrOfPoints)],
    835                                                         polygon[polygonPointIndex]);
    836     double anglePointSuccessor   = angleOfLineWrtOxAxis(polygon[successor(polygonPointIndex, nrOfPoints)],
    837                                                         polygon[polygonPointIndex]);
    838     double angleFlushEdge        = angleOfLineWrtOxAxis(polygon[predecessor(c, nrOfPoints)],
    839                                                         polygon[c]);
    840 
    841     if (isFlushAngleBtwPredAndSucc(angleFlushEdge, anglePointPredecessor, anglePointSuccessor)) {
    842         if ((isGammaAngleBtw(angleGammaAndPoint, anglePointPredecessor, angleFlushEdge)) ||
    843             (almostEqual(angleGammaAndPoint, anglePointPredecessor))) {
    844             return intersectsAboveOrBelow(predecessor(polygonPointIndex, nrOfPoints),
    845                                           polygonPointIndex, polygon, nrOfPoints, c);
    846         } else if ((isGammaAngleBtw(angleGammaAndPoint, anglePointSuccessor, angleFlushEdge)) ||
    847                   (almostEqual(angleGammaAndPoint, anglePointSuccessor))) {
    848             return intersectsAboveOrBelow(successor(polygonPointIndex, nrOfPoints),
    849                                           polygonPointIndex, polygon, nrOfPoints, c);
    850         }
    851     } else {
    852         if (
    853             (isGammaAngleBtw(angleGammaAndPoint, anglePointPredecessor, anglePointSuccessor)) ||
    854             (
    855                 (isGammaAngleEqualTo(angleGammaAndPoint, anglePointPredecessor)) &&
    856                 (!isGammaAngleEqualTo(angleGammaAndPoint, angleFlushEdge))
    857             ) ||
    858             (
    859                 (isGammaAngleEqualTo(angleGammaAndPoint, anglePointSuccessor)) &&
    860                 (!isGammaAngleEqualTo(angleGammaAndPoint, angleFlushEdge))
    861             )
    862            ) {
    863             return INTERSECTS_BELOW;
    864         }
    865     }
    866 
    867     return INTERSECTS_CRITICAL;
    868 }
    869 
    870 //! If (gamma(x) x) intersects P between successorOrPredecessorIndex and pointIntex is it above/below?
    871 /*!
    872 * @param succPredIndex  Index of the successor or predecessor
    873 * @param pointIndex     Index of the point x in the polygon
    874 * @param polygon        The polygon representing the convex hull of the points
    875 * @param nrOfPoints     Number of points defining the convex polygon
    876 * @param c              Index c
    877 */
    878 static unsigned int intersectsAboveOrBelow(unsigned int succPredIndex, unsigned int pointIndex,
    879                                            const std::vector<cv::Point2f> &polygon,
    880                                            unsigned int nrOfPoints, unsigned int c) {
    881     if (height(succPredIndex, polygon, nrOfPoints, c) > height(pointIndex, polygon, nrOfPoints, c)) {
    882         return INTERSECTS_ABOVE;
    883     } else {
    884         return INTERSECTS_BELOW;
    885     }
    886 }
    887 
    888 //! Find gamma for a given point "p" specified by its index
    889 /*!
    890 * The function returns true if gamma exists i.e. if lines (a a-1) and (x y) intersect
    891 * and false otherwise. In case the two lines intersect in point intersectionPoint, gamma is computed.
    892 *
    893 * Considering that line (x y) is a line parallel to (c c-1) and that the distance between the lines is equal
    894 * to 2 * height(p), we can have two possible (x y) lines.
    895 *
    896 * Therefore, we will compute two intersection points between the lines (x y) and (a a-1) and take the
    897 * point which is on the same side of line (c c-1) as the polygon.
    898 *
    899 * See paper [2] and formula for distance from point to a line for more details
    900 *
    901 * @param polygonPointIndex Index of the polygon point
    902 * @param gammaPoint        Point gamma(polygon[polygonPointIndex])
    903 * @param polygon           The polygon representing the convex hull of the points
    904 * @param nrOfPoints        Number of points defining the convex polygon
    905 * @param a                 Index a
    906 * @param c                 Index c
    907 */
    908 static bool gamma(unsigned int polygonPointIndex, cv::Point2f &gammaPoint,
    909                   const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    910                   unsigned int a, unsigned int c) {
    911     cv::Point2f intersectionPoint1, intersectionPoint2;
    912 
    913     // Get intersection points if they exist
    914     if (!findGammaIntersectionPoints(polygon, nrOfPoints, c, polygonPointIndex,
    915                                      polygon[a], polygon[predecessor(a, nrOfPoints)],
    916                                      polygon[c], polygon[predecessor(c, nrOfPoints)],
    917                                      intersectionPoint1, intersectionPoint2)) {
    918         return false;
    919     }
    920 
    921     // Select the point which is on the same side of line C as the polygon
    922     if (areOnTheSameSideOfLine(intersectionPoint1, polygon[successor(c, nrOfPoints)],
    923                                polygon[c], polygon[predecessor(c, nrOfPoints)])) {
    924         gammaPoint = intersectionPoint1;
    925     } else {
    926         gammaPoint = intersectionPoint2;
    927     }
    928 
    929     return true;
    930 }
    931 
    932 //! Find vertex C which lies on side B at a distance = 2 * height(a-1) from side C
    933 /*!
    934 * Considering that line (x y) is a line parallel to (c c-1) and that the distance between the lines is equal
    935 * to 2 * height(a-1), we can have two possible (x y) lines.
    936 *
    937 * Therefore, we will compute two intersection points between the lines (x y) and (b b-1) and take the
    938 * point which is on the same side of line (c c-1) as the polygon.
    939 *
    940 * See paper [2] and formula for distance from point to a line for more details
    941 *
    942 * @param polygon            The polygon representing the convex hull of the points
    943 * @param nrOfPoints         Number of points defining the convex polygon
    944 * @param a                  Index a
    945 * @param c                  Index c
    946 * @param sideBStartVertex   Start vertex for defining side B
    947 * @param sideBEndVertex     End vertex for defining side B
    948 * @param sideCStartVertex   Start vertex for defining side C
    949 * @param sideCEndVertex     End vertex for defining side C
    950 */
    951 static cv::Point2f findVertexCOnSideB(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    952                                       unsigned int a, unsigned int c,
    953                                       const cv::Point2f &sideBStartVertex,
    954                                       const cv::Point2f &sideBEndVertex,
    955                                       const cv::Point2f &sideCStartVertex,
    956                                       const cv::Point2f &sideCEndVertex) {
    957     cv::Point2f intersectionPoint1, intersectionPoint2;
    958 
    959     // Get intersection points if they exist
    960     if (!findGammaIntersectionPoints(polygon, nrOfPoints, c, predecessor(a, nrOfPoints),
    961                                      sideBStartVertex, sideBEndVertex,
    962                                      sideCStartVertex, sideCEndVertex,
    963                                      intersectionPoint1, intersectionPoint2)) {
    964         CV_Error(cv::Error::StsInternal, ERR_VERTEX_C_ON_SIDE_B);
    965     }
    966 
    967     // Select the point which is on the same side of line C as the polygon
    968     if (areOnTheSameSideOfLine(intersectionPoint1, polygon[successor(c, nrOfPoints)],
    969                                polygon[c], polygon[predecessor(c, nrOfPoints)])) {
    970         return intersectionPoint1;
    971     } else {
    972         return intersectionPoint2;
    973     }
    974 }
    975 
    976 //! Find the intersection points to compute gamma(point)
    977 /*!
    978 * @param polygon                The polygon representing the convex hull of the points
    979 * @param nrOfPoints             Number of points defining the convex polygon
    980 * @param c                      Index c
    981 * @param polygonPointIndex      Index of the polygon point for which the distance is known
    982 * @param side1StartVertex       Start vertex for side 1
    983 * @param side1EndVertex         End vertex for side 1
    984 * @param side2StartVertex       Start vertex for side 2
    985 * @param side2EndVertex         End vertex for side 2
    986 * @param intersectionPoint1     First intersection point between one pair of lines
    987 * @param intersectionPoint2     Second intersection point between other pair of lines
    988 */
    989 static bool findGammaIntersectionPoints(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
    990                                         unsigned int c, unsigned int polygonPointIndex,
    991                                         const cv::Point2f &side1StartVertex, const cv::Point2f &side1EndVertex,
    992                                         const cv::Point2f &side2StartVertex, const cv::Point2f &side2EndVertex,
    993                                         cv::Point2f &intersectionPoint1, cv::Point2f &intersectionPoint2) {
    994     std::vector<double> side1Params = lineEquationParameters(side1StartVertex, side1EndVertex);
    995     std::vector<double> side2Params = lineEquationParameters(side2StartVertex, side2EndVertex);
    996 
    997     // Compute side C extra parameter using the formula for distance from a point to a line
    998     double polygonPointHeight = height(polygonPointIndex, polygon, nrOfPoints, c);
    999     double distFormulaDenom = sqrt((side2Params[0] * side2Params[0]) + (side2Params[1] * side2Params[1]));
   1000     double sideCExtraParam = 2 * polygonPointHeight * distFormulaDenom;
   1001 
   1002     // Get intersection points if they exist or if lines are identical
   1003     if (!areIntersectingLines(side1Params, side2Params, sideCExtraParam, intersectionPoint1, intersectionPoint2)) {
   1004         return false;
   1005     } else if (areIdenticalLines(side1Params, side2Params, sideCExtraParam)) {
   1006         intersectionPoint1 = side1StartVertex;
   1007         intersectionPoint2 = side1EndVertex;
   1008     }
   1009 
   1010     return true;
   1011 }
   1012 
   1013 //! Check if the given lines are identical or not
   1014 /*!
   1015 * The lines are specified as:
   1016 *      ax + by + c = 0
   1017 *  OR
   1018 *      ax + by + c (+/-) sideCExtraParam = 0
   1019 *
   1020 * @param side1Params       Vector containing the values of a, b and c for side 1
   1021 * @param side2Params       Vector containing the values of a, b and c for side 2
   1022 * @param sideCExtraParam   Extra parameter for the flush edge C
   1023 */
   1024 static bool areIdenticalLines(const std::vector<double> &side1Params,
   1025                               const std::vector<double> &side2Params, double sideCExtraParam) {
   1026     return (
   1027         (areIdenticalLines(side1Params[0], side1Params[1], -(side1Params[2]),
   1028                            side2Params[0], side2Params[1], -(side2Params[2]) - sideCExtraParam)) ||
   1029         (areIdenticalLines(side1Params[0], side1Params[1], -(side1Params[2]),
   1030                            side2Params[0], side2Params[1], -(side2Params[2]) + sideCExtraParam))
   1031     );
   1032 }
   1033 
   1034 //! Check if the given lines intersect or not. If the lines intersect find their intersection points.
   1035 /*!
   1036 * The lines are specified as:
   1037 *      ax + by + c = 0
   1038 *  OR
   1039 *      ax + by + c (+/-) sideCExtraParam = 0
   1040 *
   1041 * @param side1Params           Vector containing the values of a, b and c for side 1
   1042 * @param side2Params           Vector containing the values of a, b and c for side 2
   1043 * @param sideCExtraParam       Extra parameter for the flush edge C
   1044 * @param intersectionPoint1    The first intersection point, if it exists
   1045 * @param intersectionPoint2    The second intersection point, if it exists
   1046 */
   1047 static bool areIntersectingLines(const std::vector<double> &side1Params,
   1048                                  const std::vector<double> &side2Params,
   1049                                  double sideCExtraParam, cv::Point2f &intersectionPoint1,
   1050                                  cv::Point2f &intersectionPoint2) {
   1051     return (
   1052         (lineIntersection(side1Params[0], side1Params[1], -(side1Params[2]),
   1053                           side2Params[0], side2Params[1], -(side2Params[2]) - sideCExtraParam,
   1054                           intersectionPoint1)) &&
   1055         (lineIntersection(side1Params[0], side1Params[1], -(side1Params[2]),
   1056                           side2Params[0], side2Params[1], -(side2Params[2]) + sideCExtraParam,
   1057                           intersectionPoint2))
   1058     );
   1059 }
   1060 
   1061 //! Get the line equation parameters "a", "b" and "c" for the line determined by points "p" and "q"
   1062 /*!
   1063 * The equation of the line is considered in the general form:
   1064 * ax + by + c = 0
   1065 *
   1066 * @param p One point for defining the equation of the line
   1067 * @param q Second point for defining the equation of the line
   1068 */
   1069 static std::vector<double> lineEquationParameters(const cv::Point2f& p, const cv::Point2f &q) {
   1070     std::vector<double> lineEquationParameters;
   1071     double a, b, c;
   1072 
   1073     lineEquationDeterminedByPoints(p, q, a, b, c);
   1074 
   1075     lineEquationParameters.push_back(a);
   1076     lineEquationParameters.push_back(b);
   1077     lineEquationParameters.push_back(c);
   1078 
   1079     return lineEquationParameters;
   1080 }
   1081 
   1082 //! Compute the height of the point
   1083 /*!
   1084 * See paper [2] for more details
   1085 *
   1086 * @param polygonPoint       Polygon point
   1087 * @param polygon            The polygon representing the convex hull of the points
   1088 * @param nrOfPoints         Number of points defining the convex polygon
   1089 * @param c                  Index c
   1090 */
   1091 static double height(const cv::Point2f &polygonPoint, const std::vector<cv::Point2f> &polygon,
   1092                      unsigned int nrOfPoints, unsigned int c) {
   1093     cv::Point2f pointC = polygon[c];
   1094     cv::Point2f pointCPredecessor = polygon[predecessor(c, nrOfPoints)];
   1095 
   1096     return distanceFromPointToLine(polygonPoint, pointC, pointCPredecessor);
   1097 }
   1098 
   1099 //! Compute the height of the point specified by the given index
   1100 /*!
   1101 * See paper [2] for more details
   1102 *
   1103 * @param polygonPointIndex  Index of the polygon point
   1104 * @param polygon            The polygon representing the convex hull of the points
   1105 * @param nrOfPoints         Number of points defining the convex polygon
   1106 * @param c                  Index c
   1107 */
   1108 static double height(unsigned int polygonPointIndex, const std::vector<cv::Point2f> &polygon,
   1109                      unsigned int nrOfPoints, unsigned int c) {
   1110     cv::Point2f pointC = polygon[c];
   1111     cv::Point2f pointCPredecessor = polygon[predecessor(c, nrOfPoints)];
   1112 
   1113     cv::Point2f polygonPoint = polygon[polygonPointIndex];
   1114 
   1115     return distanceFromPointToLine(polygonPoint, pointC, pointCPredecessor);
   1116 }
   1117 
   1118 //! Advance the given index with one position
   1119 /*!
   1120 * @param index          Index of the point
   1121 * @param nrOfPoints     Number of points defining the convex polygon
   1122 */
   1123 static void advance(unsigned int &index, unsigned int nrOfPoints) {
   1124     index = successor(index, nrOfPoints);
   1125 }
   1126 
   1127 //! Return the succesor of the provided point index
   1128 /*!
   1129 * The succesor of the last polygon point is the first polygon point
   1130 * (circular referencing)
   1131 *
   1132 * @param index          Index of the point
   1133 * @param nrOfPoints     Number of points defining the convex polygon
   1134 */
   1135 static unsigned int successor(unsigned int index, unsigned int nrOfPoints) {
   1136     return ((index + 1) % nrOfPoints);
   1137 }
   1138 
   1139 //! Return the predecessor of the provided point index
   1140 /*!
   1141 * The predecessor of the first polygon point is the last polygon point
   1142 * (circular referencing)
   1143 *
   1144 * @param index          Index of the point
   1145 * @param nrOfPoints     Number of points defining the convex polygon
   1146 */
   1147 static unsigned int predecessor(unsigned int index, unsigned int nrOfPoints) {
   1148     return (index == 0) ? (nrOfPoints - 1)
   1149                         : (index - 1);
   1150 }
   1151 
   1152 //! Check if the flush edge angle/opposite angle lie between the predecessor and successor angle
   1153 /*!
   1154 * Check if the angle of the flush edge or its opposite angle lie between the angle of
   1155 * the predecessor and successor
   1156 *
   1157 * @param angleFlushEdge    Angle of the flush edge
   1158 * @param anglePred         Angle of the predecessor
   1159 * @param angleSucc         Angle of the successor
   1160 */
   1161 static bool isFlushAngleBtwPredAndSucc(double &angleFlushEdge, double anglePred, double angleSucc) {
   1162     if (isAngleBetweenNonReflex(angleFlushEdge, anglePred, angleSucc)) {
   1163         return true;
   1164     } else if (isOppositeAngleBetweenNonReflex(angleFlushEdge, anglePred, angleSucc)) {
   1165         angleFlushEdge = oppositeAngle(angleFlushEdge);
   1166 
   1167         return true;
   1168     }
   1169 
   1170     return false;
   1171 }
   1172 
   1173 //! Check if the angle of the line (gamma(p) p) or its opposite angle is equal to the given angle
   1174 /*!
   1175 * @param gammaAngle    Angle of the line (gamma(p) p)
   1176 * @param angle         Angle to compare against
   1177 */
   1178 static bool isGammaAngleEqualTo(double &gammaAngle, double angle) {
   1179     return (almostEqual(gammaAngle, angle));
   1180 }
   1181 
   1182 //! Check if the angle of the line (gamma(p) p) or its opposite angle lie between angle1 and angle2
   1183 /*!
   1184 * @param gammaAngle    Angle of the line (gamma(p) p)
   1185 * @param angle1        One of the boundary angles
   1186 * @param angle2        Another boundary angle
   1187 */
   1188 static bool isGammaAngleBtw(double &gammaAngle, double angle1, double angle2) {
   1189     return (isAngleBetweenNonReflex(gammaAngle, angle1, angle2));
   1190 }
   1191 
   1192 //! Get the angle of the line measured from the Ox axis in counterclockwise direction
   1193 /*!
   1194 * The line is specified by points "a" and "b". The value of the angle is expressed in degrees.
   1195 *
   1196 * @param a Point a
   1197 * @param b Point b
   1198 */
   1199 static double angleOfLineWrtOxAxis(const cv::Point2f &a, const cv::Point2f &b) {
   1200     double y = b.y - a.y;
   1201     double x = b.x - a.x;
   1202 
   1203     double angle = (std::atan2(y, x) * 180 / CV_PI);
   1204 
   1205     return (angle < 0) ? (angle + 360)
   1206                        : angle;
   1207 }
   1208 
   1209 //! Check if angle1 lies between non reflex angle determined by angles 2 and 3
   1210 /*!
   1211 * @param angle1 The angle which lies between angle2 and angle3 or not
   1212 * @param angle2 One of the boundary angles
   1213 * @param angle3 The other boundary angle
   1214 */
   1215 static bool isAngleBetweenNonReflex(double angle1, double angle2, double angle3) {
   1216     if (std::abs(angle2 - angle3) > 180) {
   1217         if (angle2 > angle3) {
   1218             return (((angle2 < angle1) && (lessOrEqual(angle1, 360))) ||
   1219                     ((lessOrEqual(0, angle1)) && (angle1 < angle3)));
   1220         } else {
   1221             return (((angle3 < angle1) && (lessOrEqual(angle1, 360))) ||
   1222                     ((lessOrEqual(0, angle1)) && (angle1 < angle2)));
   1223         }
   1224     } else {
   1225         return isAngleBetween(angle1, angle2, angle3);
   1226     }
   1227 }
   1228 
   1229 //! Check if the opposite of angle1, ((angle1 + 180) % 360), lies between non reflex angle determined by angles 2 and 3
   1230 /*!
   1231 * @param angle1 The angle which lies between angle2 and angle3 or not
   1232 * @param angle2 One of the boundary angles
   1233 * @param angle3 The other boundary angle
   1234 */
   1235 static bool isOppositeAngleBetweenNonReflex(double angle1, double angle2, double angle3) {
   1236     double angle1Opposite = oppositeAngle(angle1);
   1237 
   1238     return (isAngleBetweenNonReflex(angle1Opposite, angle2, angle3));
   1239 }
   1240 
   1241 //! Check if angle1 lies between angles 2 and 3
   1242 /*!
   1243 * @param angle1 The angle which lies between angle2 and angle3 or not
   1244 * @param angle2 One of the boundary angles
   1245 * @param angle3 The other boundary angle
   1246 */
   1247 static bool isAngleBetween(double angle1, double angle2, double angle3) {
   1248     if ((((int)(angle2 - angle3)) % 180) > 0) {
   1249         return ((angle3 < angle1) && (angle1 < angle2));
   1250     } else {
   1251         return ((angle2 < angle1) && (angle1 < angle3));
   1252     }
   1253 }
   1254 
   1255 //! Return the angle opposite to the given angle
   1256 /*!
   1257 * if (angle < 180) then
   1258 *      return (angle + 180);
   1259 * else
   1260 *      return (angle - 180);
   1261 * endif
   1262 *
   1263 * @param angle Angle
   1264 */
   1265 static double oppositeAngle(double angle) {
   1266     return (angle > 180) ? (angle - 180)
   1267                          : (angle + 180);
   1268 }
   1269 
   1270 //! Compute the distance from a point "a" to a line specified by two points "B" and "C"
   1271 /*!
   1272 * Formula used:
   1273 *
   1274 *     |(x_c - x_b) * (y_b - y_a) - (x_b - x_a) * (y_c - y_b)|
   1275 * d = -------------------------------------------------------
   1276 *            sqrt(((x_c - x_b)^2) + ((y_c - y_b)^2))
   1277 *
   1278 * Reference: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
   1279 * (Last access: 15.09.2013)
   1280 *
   1281 * @param a             Point from which the distance is measures
   1282 * @param linePointB    One of the points determining the line
   1283 * @param linePointC    One of the points determining the line
   1284 */
   1285 static double distanceFromPointToLine(const cv::Point2f &a, const cv::Point2f &linePointB,
   1286                                       const cv::Point2f &linePointC) {
   1287     double term1 = linePointC.x - linePointB.x;
   1288     double term2 = linePointB.y - a.y;
   1289     double term3 = linePointB.x - a.x;
   1290     double term4 = linePointC.y - linePointB.y;
   1291 
   1292     double nominator = std::abs((term1 * term2) - (term3 * term4));
   1293     double denominator = std::sqrt((term1 * term1) + (term4 * term4));
   1294 
   1295     return (denominator != 0) ? (nominator / denominator)
   1296                               : 0;
   1297 }
   1298 
   1299 //! Compute the distance between two points
   1300 /*! Compute the Euclidean distance between two points
   1301 *
   1302 * @param a Point a
   1303 * @param b Point b
   1304 */
   1305 static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b) {
   1306     double xDiff = a.x - b.x;
   1307     double yDiff = a.y - b.y;
   1308 
   1309     return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
   1310 }
   1311 
   1312 //! Compute the area of a triangle defined by three points
   1313 /*!
   1314 * The area is computed using the determinant method.
   1315 * An example is depicted at http://demonstrations.wolfram.com/TheAreaOfATriangleUsingADeterminant/
   1316 * (Last access: 15.09.2013)
   1317 *
   1318 * @param a Point a
   1319 * @param b Point b
   1320 * @param c Point c
   1321 */
   1322 static double areaOfTriangle(const cv::Point2f &a, const cv::Point2f &b, const cv::Point2f &c) {
   1323     double posTerm = (a.x * b.y) + (a.y * c.x) + (b.x * c.y);
   1324     double negTerm = (b.y * c.x) + (a.x * c.y) + (a.y * b.x);
   1325 
   1326     double determinant = posTerm - negTerm;
   1327 
   1328     return std::abs(determinant) / 2;
   1329 }
   1330 
   1331 //! Get the point in the middle of the segment determined by points "a" and "b"
   1332 /*!
   1333 * @param a Point a
   1334 * @param b Point b
   1335 */
   1336 static cv::Point2f middlePoint(const cv::Point2f &a, const cv::Point2f &b) {
   1337     double middleX = static_cast<double>((a.x + b.x) / 2);
   1338     double middleY = static_cast<double>((a.y + b.y) / 2);
   1339 
   1340     return cv::Point2f(static_cast<float>(middleX), static_cast<float>(middleY));
   1341 }
   1342 
   1343 //! Determine the intersection point of two lines, if this point exists
   1344 /*! Two lines intersect if they are not parallel (Parallel lines intersect at
   1345 * +/- infinity, but we do not consider this case here).
   1346 *
   1347 * The lines are specified in the following form:
   1348 *      A1x + B1x = C1
   1349 *      A2x + B2x = C2
   1350 *
   1351 * If det (= A1*B2 - A2*B1) == 0, then lines are parallel
   1352 *                                else they intersect
   1353 *
   1354 * If they intersect, then let us denote the intersection point with P(x, y) where:
   1355 *      x = (C1*B2 - C2*B1) / (det)
   1356 *      y = (C2*A1 - C1*A2) / (det)
   1357 *
   1358 * @param a1 A1
   1359 * @param b1 B1
   1360 * @param c1 C1
   1361 * @param a2 A2
   1362 * @param b2 B2
   1363 * @param c2 C2
   1364 * @param intersection The intersection point, if this point exists
   1365 */
   1366 static bool lineIntersection(double a1, double b1, double c1, double a2, double b2, double c2,
   1367                              cv::Point2f &intersection) {
   1368     double det = (a1 * b2) - (a2 * b1);
   1369 
   1370     if (!(almostEqual(det, 0))) {
   1371         intersection.x = static_cast<float>(((c1 * b2) - (c2 * b1)) / (det));
   1372         intersection.y = static_cast<float>(((c2 * a1) - (c1 * a2)) / (det));
   1373 
   1374         return true;
   1375     }
   1376 
   1377     return false;
   1378 }
   1379 
   1380 //! Determine the intersection point of two lines, if this point exists
   1381 /*! Two lines intersect if they are not parallel (Parallel lines intersect at
   1382 * +/- infinity, but we do not consider this case here).
   1383 *
   1384 * The lines are specified by a pair of points each. If they intersect, then
   1385 * the function returns true, else it returns false.
   1386 *
   1387 * Lines can be specified in the following form:
   1388 *      A1x + B1x = C1
   1389 *      A2x + B2x = C2
   1390 *
   1391 * If det (= A1*B2 - A2*B1) == 0, then lines are parallel
   1392 *                                else they intersect
   1393 *
   1394 * If they intersect, then let us denote the intersection point with P(x, y) where:
   1395 *      x = (C1*B2 - C2*B1) / (det)
   1396 *      y = (C2*A1 - C1*A2) / (det)
   1397 *
   1398 * @param a1 First point for determining the first line
   1399 * @param b1 Second point for determining the first line
   1400 * @param a2 First point for determining the second line
   1401 * @param b2 Second point for determining the second line
   1402 * @param intersection The intersection point, if this point exists
   1403 */
   1404 static bool lineIntersection(const cv::Point2f &a1, const cv::Point2f &b1, const cv::Point2f &a2,
   1405                              const cv::Point2f &b2, cv::Point2f &intersection) {
   1406     double A1 = b1.y - a1.y;
   1407     double B1 = a1.x - b1.x;
   1408     double C1 = (a1.x * A1) + (a1.y * B1);
   1409 
   1410     double A2 = b2.y - a2.y;
   1411     double B2 = a2.x - b2.x;
   1412     double C2 = (a2.x * A2) + (a2.y * B2);
   1413 
   1414     double det = (A1 * B2) - (A2 * B1);
   1415 
   1416     if (!almostEqual(det, 0)) {
   1417         intersection.x = static_cast<float>(((C1 * B2) - (C2 * B1)) / (det));
   1418         intersection.y = static_cast<float>(((C2 * A1) - (C1 * A2)) / (det));
   1419 
   1420         return true;
   1421     }
   1422 
   1423     return false;
   1424 }
   1425 
   1426 //! Get the values of "a", "b" and "c" of the line equation ax + by + c = 0 knowing that point "p" and "q" are on the line
   1427 /*!
   1428 * a = q.y - p.y
   1429 * b = p.x - q.x
   1430 * c = - (p.x * a) - (p.y * b)
   1431 *
   1432 * @param p Point p
   1433 * @param q Point q
   1434 * @param a Parameter "a" from the line equation
   1435 * @param b Parameter "b" from the line equation
   1436 * @param c Parameter "c" from the line equation
   1437 */
   1438 static void lineEquationDeterminedByPoints(const cv::Point2f &p, const cv::Point2f &q,
   1439                                            double &a, double &b, double &c) {
   1440     CV_Assert(areEqualPoints(p, q) == false);
   1441 
   1442     a = q.y - p.y;
   1443     b = p.x - q.x;
   1444     c = ((-p.y) * b) - (p.x * a);
   1445 }
   1446 
   1447 //! Check if p1 and p2 are on the same side of the line determined by points a and b
   1448 /*!
   1449 * @param p1    Point p1
   1450 * @param p2    Point p2
   1451 * @param a     First point for determining line
   1452 * @param b     Second point for determining line
   1453 */
   1454 static bool areOnTheSameSideOfLine(const cv::Point2f &p1, const cv::Point2f &p2,
   1455                                    const cv::Point2f &a, const cv::Point2f &b) {
   1456     double a1, b1, c1;
   1457 
   1458     lineEquationDeterminedByPoints(a, b, a1, b1, c1);
   1459 
   1460     double p1OnLine = (a1 * p1.x) + (b1 * p1.y) + c1;
   1461     double p2OnLine = (a1 * p2.x) + (b1 * p2.y) + c1;
   1462 
   1463     return (sign(p1OnLine) == sign(p2OnLine));
   1464 }
   1465 
   1466 //! Check if one point lies between two other points
   1467 /*!
   1468 * @param point             Point lying possibly outside the line segment
   1469 * @param lineSegmentStart  First point determining the line segment
   1470 * @param lineSegmentEnd    Second point determining the line segment
   1471 */
   1472 static bool isPointOnLineSegment(const cv::Point2f &point, const cv::Point2f &lineSegmentStart,
   1473                                  const cv::Point2f &lineSegmentEnd) {
   1474     double d1 = distanceBtwPoints(point, lineSegmentStart);
   1475     double d2 = distanceBtwPoints(point, lineSegmentEnd);
   1476     double lineSegmentLength = distanceBtwPoints(lineSegmentStart, lineSegmentEnd);
   1477 
   1478     return (almostEqual(d1 + d2, lineSegmentLength));
   1479 }
   1480 
   1481 //! Check if two lines are identical
   1482 /*!
   1483 * Lines are be specified in the following form:
   1484 *      A1x + B1x = C1
   1485 *      A2x + B2x = C2
   1486 *
   1487 * If (A1/A2) == (B1/B2) == (C1/C2), then the lines are identical
   1488 *                                   else they are not
   1489 *
   1490 * @param a1 A1
   1491 * @param b1 B1
   1492 * @param c1 C1
   1493 * @param a2 A2
   1494 * @param b2 B2
   1495 * @param c2 C2
   1496 */
   1497 static bool areIdenticalLines(double a1, double b1, double c1, double a2, double b2, double c2) {
   1498     double a1B2 = a1 * b2;
   1499     double a2B1 = a2 * b1;
   1500     double a1C2 = a1 * c2;
   1501     double a2C1 = a2 * c1;
   1502     double b1C2 = b1 * c2;
   1503     double b2C1 = b2 * c1;
   1504 
   1505     return ((almostEqual(a1B2, a2B1)) && (almostEqual(b1C2, b2C1)) && (almostEqual(a1C2, a2C1)));
   1506 }
   1507 
   1508 //! Check if points point1 and point2 are equal or not
   1509 /*!
   1510 * @param point1 One point
   1511 * @param point2 The other point
   1512 */
   1513 static bool areEqualPoints(const cv::Point2f &point1, const cv::Point2f &point2) {
   1514     return (almostEqual(point1.x, point2.x) && almostEqual(point1.y, point2.y));
   1515 }
   1516 
   1517 //! Return the sign of the number
   1518 /*!
   1519 * The sign function returns:
   1520 *  -1, if number < 0
   1521 *  +1, if number > 0
   1522 *  0, otherwise
   1523 */
   1524 static int sign(double number) {
   1525     return (number > 0) ? 1 : ((number < 0) ? -1 : 0);
   1526 }
   1527 
   1528 //! Return the maximum of the provided numbers
   1529 static double maximum(double number1, double number2, double number3) {
   1530     return std::max(std::max(number1, number2), number3);
   1531 }
   1532 
   1533 //! Check if the two numbers are equal (almost)
   1534 /*!
   1535 * The expression for determining if two real numbers are equal is:
   1536 * if (Abs(x - y) <= EPSILON * Max(1.0f, Abs(x), Abs(y))).
   1537 *
   1538 * @param number1 First number
   1539 * @param number2 Second number
   1540 */
   1541 static bool almostEqual(double number1, double number2) {
   1542     return (std::abs(number1 - number2) <= (EPSILON * maximum(1.0, std::abs(number1), std::abs(number2))));
   1543 }
   1544 
   1545 //! Check if the first number is greater than or equal to the second number
   1546 /*!
   1547 * @param number1 First number
   1548 * @param number2 Second number
   1549 */
   1550 static bool greaterOrEqual(double number1, double number2) {
   1551     return ((number1 > number2) || (almostEqual(number1, number2)));
   1552 }
   1553 
   1554 //! Check if the first number is less than or equal to the second number
   1555 /*!
   1556 * @param number1 First number
   1557 * @param number2 Second number
   1558 */
   1559 static bool lessOrEqual(double number1, double number2) {
   1560     return ((number1 < number2) || (almostEqual(number1, number2)));
   1561 }
   1562 
   1563 }
   1564