This source file includes following definitions.
- minEnclosingTriangle
- findMinEnclosingTriangle
- createConvexHull
- findMinEnclosingTriangle
- copyResultingTriangle
- initialise
- findMinimumAreaEnclosingTriangle
- returnMinimumAreaEnclosingTriangle
- advanceBToRightChain
- moveAIfLowAndBIfHigh
- searchForBTangency
- isNotBTangency
- updateSidesCA
- updateSidesBA
- updateSideB
- isLocalMinimalTriangle
- isValidMinimalTriangle
- updateMinimumAreaEnclosingTriangle
- middlePointOfSideB
- intersectsBelow
- intersectsAbove
- intersects
- intersectsAboveOrBelow
- gamma
- findVertexCOnSideB
- findGammaIntersectionPoints
- areIdenticalLines
- areIntersectingLines
- lineEquationParameters
- height
- height
- advance
- successor
- predecessor
- isFlushAngleBtwPredAndSucc
- isGammaAngleEqualTo
- isGammaAngleBtw
- angleOfLineWrtOxAxis
- isAngleBetweenNonReflex
- isOppositeAngleBetweenNonReflex
- isAngleBetween
- oppositeAngle
- distanceFromPointToLine
- distanceBtwPoints
- areaOfTriangle
- middlePoint
- lineIntersection
- lineIntersection
- lineEquationDeterminedByPoints
- areOnTheSameSideOfLine
- isPointOnLineSegment
- areIdenticalLines
- areEqualPoints
- sign
- maximum
- almostEqual
- greaterOrEqual
- lessOrEqual
#include "precomp.hpp"
#include <algorithm>
#include <cmath>
#include <limits>
#include <vector>
#define INTERSECTS_BELOW 1
#define INTERSECTS_ABOVE 2
#define INTERSECTS_CRITICAL 3
#define ERR_SIDE_B_GAMMA "The position of side B could not be determined, because gamma(b) could not be computed."
#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."
#define VALIDATION_SIDE_A_TANGENT 0
#define VALIDATION_SIDE_B_TANGENT 1
#define VALIDATION_SIDES_FLUSH 2
#define EPSILON 1E-5
namespace minEnclosingTriangle {
static void advance(unsigned int &index, unsigned int nrOfPoints);
static void advanceBToRightChain(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int &b,
unsigned int c);
static bool almostEqual(double number1, double number2);
static double angleOfLineWrtOxAxis(const cv::Point2f &a, const cv::Point2f &b);
static bool areEqualPoints(const cv::Point2f &point1, const cv::Point2f &point2);
static bool areIdenticalLines(const std::vector<double> &side1Params,
const std::vector<double> &side2Params, double sideCExtraParam);
static bool areIdenticalLines(double a1, double b1, double c1, double a2, double b2, double c2);
static bool areIntersectingLines(const std::vector<double> &side1Params,
const std::vector<double> &side2Params,
double sideCExtraParam, cv::Point2f &intersectionPoint1,
cv::Point2f &intersectionPoint2);
static bool areOnTheSameSideOfLine(const cv::Point2f &p1, const cv::Point2f &p2,
const cv::Point2f &a, const cv::Point2f &b);
static double areaOfTriangle(const cv::Point2f &a, const cv::Point2f &b, const cv::Point2f &c);
static void copyResultingTriangle(const std::vector<cv::Point2f> &resultingTriangle, cv::OutputArray triangle);
static void createConvexHull(cv::InputArray points, std::vector<cv::Point2f> &polygon);
static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b);
static double distanceFromPointToLine(const cv::Point2f &a, const cv::Point2f &linePointB,
const cv::Point2f &linePointC);
static bool findGammaIntersectionPoints(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c, unsigned int polygonPointIndex,
const cv::Point2f &side1StartVertex, const cv::Point2f &side1EndVertex,
const cv::Point2f &side2StartVertex, const cv::Point2f &side2EndVertex,
cv::Point2f &intersectionPoint1, cv::Point2f &intersectionPoint2);
static void findMinEnclosingTriangle(cv::InputArray points,
CV_OUT cv::OutputArray triangle, CV_OUT double &area);
static void findMinEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area);
static void findMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area);
static cv::Point2f findVertexCOnSideB(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int a, unsigned int c,
const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex,
const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex);
static bool gamma(unsigned int polygonPointIndex, cv::Point2f &gammaPoint,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int a, unsigned int c);
static bool greaterOrEqual(double number1, double number2);
static double height(const cv::Point2f &polygonPoint, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c);
static double height(unsigned int polygonPointIndex, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c);
static void initialise(std::vector<cv::Point2f> &triangle, double &area);
static unsigned int intersects(double angleGammaAndPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c);
static bool intersectsAbove(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c);
static unsigned int intersectsAboveOrBelow(unsigned int succPredIndex, unsigned int pointIndex,
const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c);
static bool intersectsBelow(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c);
static bool isAngleBetween(double angle1, double angle2, double angle3);
static bool isAngleBetweenNonReflex(double angle1, double angle2, double angle3);
static bool isFlushAngleBtwPredAndSucc(double &angleFlushEdge, double anglePred, double angleSucc);
static bool isGammaAngleBtw(double &gammaAngle, double angle1, double angle2);
static bool isGammaAngleEqualTo(double &gammaAngle, double angle);
static bool isLocalMinimalTriangle(cv::Point2f &vertexA, cv::Point2f &vertexB,
cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex);
static bool isNotBTangency(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c);
static bool isOppositeAngleBetweenNonReflex(double angle1, double angle2, double angle3);
static bool isPointOnLineSegment(const cv::Point2f &point, const cv::Point2f &lineSegmentStart,
const cv::Point2f &lineSegmentEnd);
static bool isValidMinimalTriangle(const cv::Point2f &vertexA, const cv::Point2f &vertexB,
const cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex);
static bool lessOrEqual(double number1, double number2);
static void lineEquationDeterminedByPoints(const cv::Point2f &p, const cv::Point2f &q,
double &a, double &b, double &c);
static std::vector<double> lineEquationParameters(const cv::Point2f& p, const cv::Point2f &q);
static bool lineIntersection(const cv::Point2f &a1, const cv::Point2f &b1, const cv::Point2f &a2,
const cv::Point2f &b2, cv::Point2f &intersection);
static bool lineIntersection(double a1, double b1, double c1, double a2, double b2, double c2,
cv::Point2f &intersection);
static double maximum(double number1, double number2, double number3);
static cv::Point2f middlePoint(const cv::Point2f &a, const cv::Point2f &b);
static bool middlePointOfSideB(cv::Point2f &middlePointOfSideB, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex);
static void moveAIfLowAndBIfHigh(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int &a, unsigned int &b,
unsigned int c);
static double oppositeAngle(double angle);
static unsigned int predecessor(unsigned int index, unsigned int nrOfPoints);
static void returnMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area);
static void searchForBTangency(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int &b,
unsigned int c);
static int sign(double number);
static unsigned int successor(unsigned int index, unsigned int nrOfPoints);
static void updateMinimumAreaEnclosingTriangle(std::vector<cv::Point2f> &triangle, double &area,
const cv::Point2f &vertexA, const cv::Point2f &vertexB,
const cv::Point2f &vertexC);
static void updateSideB(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c, unsigned int &validationFlag,
cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex);
static void updateSidesBA(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c, unsigned int &validationFlag,
cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex,
const cv::Point2f &sideCStartVertex, const cv::Point2f &sideCEndVertex);
static void updateSidesCA(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int c,
cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
cv::Point2f &sideCStartVertex, cv::Point2f &sideCEndVertex);
}
double cv::minEnclosingTriangle(cv::InputArray points, CV_OUT cv::OutputArray triangle) {
double area;
minEnclosingTriangle::findMinEnclosingTriangle(points, triangle, area);
return area;
}
namespace minEnclosingTriangle {
static void findMinEnclosingTriangle(cv::InputArray points,
CV_OUT cv::OutputArray triangle, CV_OUT double &area) {
std::vector<cv::Point2f> resultingTriangle, polygon;
createConvexHull(points, polygon);
findMinEnclosingTriangle(polygon, resultingTriangle, area);
copyResultingTriangle(resultingTriangle, triangle);
}
static void createConvexHull(cv::InputArray points, std::vector<cv::Point2f> &polygon) {
cv::Mat pointsMat = points.getMat();
std::vector<cv::Point2f> pointsVector;
CV_Assert((pointsMat.checkVector(2) > 0) &&
((pointsMat.depth() == CV_32F) || (pointsMat.depth() == CV_32S)));
pointsMat.convertTo(pointsVector, CV_32F);
convexHull(pointsVector, polygon, true, true);
}
static void findMinEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area) {
initialise(triangle, area);
if (polygon.size() > 3) {
findMinimumAreaEnclosingTriangle(polygon, triangle, area);
} else {
returnMinimumAreaEnclosingTriangle(polygon, triangle, area);
}
}
static void copyResultingTriangle(const std::vector<cv::Point2f> &resultingTriangle,
cv::OutputArray triangle) {
cv::Mat(resultingTriangle).copyTo(triangle);
}
static void initialise(std::vector<cv::Point2f> &triangle, double &area) {
area = std::numeric_limits<double>::max();
triangle.clear();
}
static void findMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area) {
unsigned int validationFlag;
cv::Point2f vertexA, vertexB, vertexC;
cv::Point2f sideAStartVertex, sideAEndVertex;
cv::Point2f sideBStartVertex, sideBEndVertex;
cv::Point2f sideCStartVertex, sideCEndVertex;
unsigned int a, b, c;
unsigned int nrOfPoints;
nrOfPoints = static_cast<unsigned int>(polygon.size());
a = 1;
b = 2;
c = 0;
for (c = 0; c < nrOfPoints; c++) {
advanceBToRightChain(polygon, nrOfPoints, b, c);
moveAIfLowAndBIfHigh(polygon, nrOfPoints, a, b, c);
searchForBTangency(polygon, nrOfPoints, a ,b, c);
updateSidesCA(polygon, nrOfPoints, a, c, sideAStartVertex, sideAEndVertex,
sideCStartVertex, sideCEndVertex);
if (isNotBTangency(polygon, nrOfPoints, a, b, c)) {
updateSidesBA(polygon, nrOfPoints, a, b, c, validationFlag, sideAStartVertex,
sideAEndVertex, sideBStartVertex, sideBEndVertex,
sideCStartVertex, sideCEndVertex);
} else {
updateSideB(polygon, nrOfPoints, a, b, c, validationFlag,
sideBStartVertex, sideBEndVertex);
}
if (isLocalMinimalTriangle(vertexA, vertexB, vertexC, polygon, nrOfPoints, a, b,
validationFlag, sideAStartVertex, sideAEndVertex,
sideBStartVertex, sideBEndVertex, sideCStartVertex,
sideCEndVertex)) {
updateMinimumAreaEnclosingTriangle(triangle, area, vertexA, vertexB, vertexC);
}
}
}
static void returnMinimumAreaEnclosingTriangle(const std::vector<cv::Point2f> &polygon,
std::vector<cv::Point2f> &triangle, double &area) {
unsigned int nrOfPoints = static_cast<unsigned int>(polygon.size());
for (int i = 0; i < 3; i++) {
triangle.push_back(polygon[i % nrOfPoints]);
}
area = areaOfTriangle(triangle[0], triangle[1], triangle[2]);
}
static void advanceBToRightChain(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int &b,
unsigned int c) {
while (greaterOrEqual(height(successor(b, nrOfPoints), polygon, nrOfPoints, c),
height(b, polygon, nrOfPoints, c))) {
advance(b, nrOfPoints);
}
}
static void moveAIfLowAndBIfHigh(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int &a, unsigned int &b,
unsigned int c) {
cv::Point2f gammaOfA;
while(height(b, polygon, nrOfPoints, c) > height(a, polygon, nrOfPoints, c)) {
if ((gamma(a, gammaOfA, polygon, nrOfPoints, a, c)) && (intersectsBelow(gammaOfA, b, polygon, nrOfPoints, c))) {
advance(b, nrOfPoints);
} else {
advance(a, nrOfPoints);
}
}
}
static void searchForBTangency(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int &b,
unsigned int c) {
cv::Point2f gammaOfB;
while (((gamma(b, gammaOfB, polygon, nrOfPoints, a, c)) &&
(intersectsBelow(gammaOfB, b, polygon, nrOfPoints, c))) &&
(greaterOrEqual(height(b, polygon, nrOfPoints, c),
height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c)))
) {
advance(b, nrOfPoints);
}
}
static bool isNotBTangency(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c) {
cv::Point2f gammaOfB;
if (((gamma(b, gammaOfB, polygon, nrOfPoints, a, c)) &&
(intersectsAbove(gammaOfB, b, polygon, nrOfPoints, c))) ||
(height(b, polygon, nrOfPoints, c) < height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c))) {
return true;
}
return false;
}
static void updateSidesCA(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int c,
cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
cv::Point2f &sideCStartVertex, cv::Point2f &sideCEndVertex) {
sideCStartVertex = polygon[predecessor(c, nrOfPoints)];
sideCEndVertex = polygon[c];
sideAStartVertex = polygon[predecessor(a, nrOfPoints)];
sideAEndVertex = polygon[a];
}
static void updateSidesBA(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c, unsigned int &validationFlag,
cv::Point2f &sideAStartVertex, cv::Point2f &sideAEndVertex,
cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex,
const cv::Point2f &sideCStartVertex, const cv::Point2f &sideCEndVertex) {
sideBStartVertex = polygon[predecessor(b, nrOfPoints)];
sideBEndVertex = polygon[b];
cv::Point2f sideBMiddlePoint;
if ((middlePointOfSideB(sideBMiddlePoint, sideAStartVertex, sideAEndVertex, sideBStartVertex,
sideBEndVertex, sideCStartVertex, sideCEndVertex)) &&
(height(sideBMiddlePoint, polygon, nrOfPoints, c) <
height(predecessor(a, nrOfPoints), polygon, nrOfPoints, c))) {
sideAStartVertex = polygon[predecessor(a, nrOfPoints)];
sideAEndVertex = findVertexCOnSideB(polygon, nrOfPoints, a, c,
sideBStartVertex, sideBEndVertex,
sideCStartVertex, sideCEndVertex);
validationFlag = VALIDATION_SIDE_A_TANGENT;
} else {
validationFlag = VALIDATION_SIDES_FLUSH;
}
}
static void updateSideB(const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int c, unsigned int &validationFlag,
cv::Point2f &sideBStartVertex, cv::Point2f &sideBEndVertex) {
if (!gamma(b, sideBStartVertex, polygon, nrOfPoints, a, c)) {
CV_Error(cv::Error::StsInternal, ERR_SIDE_B_GAMMA);
}
sideBEndVertex = polygon[b];
validationFlag = VALIDATION_SIDE_B_TANGENT;
}
static bool isLocalMinimalTriangle(cv::Point2f &vertexA, cv::Point2f &vertexB,
cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex) {
if ((!lineIntersection(sideAStartVertex, sideAEndVertex,
sideBStartVertex, sideBEndVertex, vertexC)) ||
(!lineIntersection(sideAStartVertex, sideAEndVertex,
sideCStartVertex, sideCEndVertex, vertexB)) ||
(!lineIntersection(sideBStartVertex, sideBEndVertex,
sideCStartVertex, sideCEndVertex, vertexA))) {
return false;
}
return isValidMinimalTriangle(vertexA, vertexB, vertexC, polygon, nrOfPoints, a, b,
validationFlag, sideAStartVertex, sideAEndVertex,
sideBStartVertex, sideBEndVertex, sideCStartVertex,
sideCEndVertex);
}
static bool isValidMinimalTriangle(const cv::Point2f &vertexA, const cv::Point2f &vertexB,
const cv::Point2f &vertexC, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int a, unsigned int b,
unsigned int validationFlag, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex) {
cv::Point2f midpointSideA = middlePoint(vertexB, vertexC);
cv::Point2f midpointSideB = middlePoint(vertexA, vertexC);
cv::Point2f midpointSideC = middlePoint(vertexA, vertexB);
bool sideAValid = (validationFlag == VALIDATION_SIDE_A_TANGENT)
? (areEqualPoints(midpointSideA, polygon[predecessor(a, nrOfPoints)]))
: (isPointOnLineSegment(midpointSideA, sideAStartVertex, sideAEndVertex));
bool sideBValid = (validationFlag == VALIDATION_SIDE_B_TANGENT)
? (areEqualPoints(midpointSideB, polygon[b]))
: (isPointOnLineSegment(midpointSideB, sideBStartVertex, sideBEndVertex));
bool sideCValid = isPointOnLineSegment(midpointSideC, sideCStartVertex, sideCEndVertex);
return (sideAValid && sideBValid && sideCValid);
}
static void updateMinimumAreaEnclosingTriangle(std::vector<cv::Point2f> &triangle, double &area,
const cv::Point2f &vertexA, const cv::Point2f &vertexB,
const cv::Point2f &vertexC) {
double triangleArea = areaOfTriangle(vertexA, vertexB, vertexC);
if (triangleArea < area) {
triangle.clear();
triangle.push_back(vertexA);
triangle.push_back(vertexB);
triangle.push_back(vertexC);
area = triangleArea;
}
}
static bool middlePointOfSideB(cv::Point2f &middlePointOfSideB, const cv::Point2f &sideAStartVertex,
const cv::Point2f &sideAEndVertex, const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex, const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex) {
cv::Point2f vertexA, vertexC;
if ((!lineIntersection(sideBStartVertex, sideBEndVertex, sideCStartVertex, sideCEndVertex, vertexA)) ||
(!lineIntersection(sideBStartVertex, sideBEndVertex, sideAStartVertex, sideAEndVertex, vertexC))) {
return false;
}
middlePointOfSideB = middlePoint(vertexA, vertexC);
return true;
}
static bool intersectsBelow(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c) {
double angleOfGammaAndPoint = angleOfLineWrtOxAxis(polygon[polygonPointIndex], gammaPoint);
return (intersects(angleOfGammaAndPoint, polygonPointIndex, polygon, nrOfPoints, c) == INTERSECTS_BELOW);
}
static bool intersectsAbove(const cv::Point2f &gammaPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c) {
double angleOfGammaAndPoint = angleOfLineWrtOxAxis(gammaPoint, polygon[polygonPointIndex]);
return (intersects(angleOfGammaAndPoint, polygonPointIndex, polygon, nrOfPoints, c) == INTERSECTS_ABOVE);
}
static unsigned int intersects(double angleGammaAndPoint, unsigned int polygonPointIndex,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c) {
double anglePointPredecessor = angleOfLineWrtOxAxis(polygon[predecessor(polygonPointIndex, nrOfPoints)],
polygon[polygonPointIndex]);
double anglePointSuccessor = angleOfLineWrtOxAxis(polygon[successor(polygonPointIndex, nrOfPoints)],
polygon[polygonPointIndex]);
double angleFlushEdge = angleOfLineWrtOxAxis(polygon[predecessor(c, nrOfPoints)],
polygon[c]);
if (isFlushAngleBtwPredAndSucc(angleFlushEdge, anglePointPredecessor, anglePointSuccessor)) {
if ((isGammaAngleBtw(angleGammaAndPoint, anglePointPredecessor, angleFlushEdge)) ||
(almostEqual(angleGammaAndPoint, anglePointPredecessor))) {
return intersectsAboveOrBelow(predecessor(polygonPointIndex, nrOfPoints),
polygonPointIndex, polygon, nrOfPoints, c);
} else if ((isGammaAngleBtw(angleGammaAndPoint, anglePointSuccessor, angleFlushEdge)) ||
(almostEqual(angleGammaAndPoint, anglePointSuccessor))) {
return intersectsAboveOrBelow(successor(polygonPointIndex, nrOfPoints),
polygonPointIndex, polygon, nrOfPoints, c);
}
} else {
if (
(isGammaAngleBtw(angleGammaAndPoint, anglePointPredecessor, anglePointSuccessor)) ||
(
(isGammaAngleEqualTo(angleGammaAndPoint, anglePointPredecessor)) &&
(!isGammaAngleEqualTo(angleGammaAndPoint, angleFlushEdge))
) ||
(
(isGammaAngleEqualTo(angleGammaAndPoint, anglePointSuccessor)) &&
(!isGammaAngleEqualTo(angleGammaAndPoint, angleFlushEdge))
)
) {
return INTERSECTS_BELOW;
}
}
return INTERSECTS_CRITICAL;
}
static unsigned int intersectsAboveOrBelow(unsigned int succPredIndex, unsigned int pointIndex,
const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c) {
if (height(succPredIndex, polygon, nrOfPoints, c) > height(pointIndex, polygon, nrOfPoints, c)) {
return INTERSECTS_ABOVE;
} else {
return INTERSECTS_BELOW;
}
}
static bool gamma(unsigned int polygonPointIndex, cv::Point2f &gammaPoint,
const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int a, unsigned int c) {
cv::Point2f intersectionPoint1, intersectionPoint2;
if (!findGammaIntersectionPoints(polygon, nrOfPoints, c, polygonPointIndex,
polygon[a], polygon[predecessor(a, nrOfPoints)],
polygon[c], polygon[predecessor(c, nrOfPoints)],
intersectionPoint1, intersectionPoint2)) {
return false;
}
if (areOnTheSameSideOfLine(intersectionPoint1, polygon[successor(c, nrOfPoints)],
polygon[c], polygon[predecessor(c, nrOfPoints)])) {
gammaPoint = intersectionPoint1;
} else {
gammaPoint = intersectionPoint2;
}
return true;
}
static cv::Point2f findVertexCOnSideB(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int a, unsigned int c,
const cv::Point2f &sideBStartVertex,
const cv::Point2f &sideBEndVertex,
const cv::Point2f &sideCStartVertex,
const cv::Point2f &sideCEndVertex) {
cv::Point2f intersectionPoint1, intersectionPoint2;
if (!findGammaIntersectionPoints(polygon, nrOfPoints, c, predecessor(a, nrOfPoints),
sideBStartVertex, sideBEndVertex,
sideCStartVertex, sideCEndVertex,
intersectionPoint1, intersectionPoint2)) {
CV_Error(cv::Error::StsInternal, ERR_VERTEX_C_ON_SIDE_B);
}
if (areOnTheSameSideOfLine(intersectionPoint1, polygon[successor(c, nrOfPoints)],
polygon[c], polygon[predecessor(c, nrOfPoints)])) {
return intersectionPoint1;
} else {
return intersectionPoint2;
}
}
static bool findGammaIntersectionPoints(const std::vector<cv::Point2f> &polygon, unsigned int nrOfPoints,
unsigned int c, unsigned int polygonPointIndex,
const cv::Point2f &side1StartVertex, const cv::Point2f &side1EndVertex,
const cv::Point2f &side2StartVertex, const cv::Point2f &side2EndVertex,
cv::Point2f &intersectionPoint1, cv::Point2f &intersectionPoint2) {
std::vector<double> side1Params = lineEquationParameters(side1StartVertex, side1EndVertex);
std::vector<double> side2Params = lineEquationParameters(side2StartVertex, side2EndVertex);
double polygonPointHeight = height(polygonPointIndex, polygon, nrOfPoints, c);
double distFormulaDenom = sqrt((side2Params[0] * side2Params[0]) + (side2Params[1] * side2Params[1]));
double sideCExtraParam = 2 * polygonPointHeight * distFormulaDenom;
if (!areIntersectingLines(side1Params, side2Params, sideCExtraParam, intersectionPoint1, intersectionPoint2)) {
return false;
} else if (areIdenticalLines(side1Params, side2Params, sideCExtraParam)) {
intersectionPoint1 = side1StartVertex;
intersectionPoint2 = side1EndVertex;
}
return true;
}
static bool areIdenticalLines(const std::vector<double> &side1Params,
const std::vector<double> &side2Params, double sideCExtraParam) {
return (
(areIdenticalLines(side1Params[0], side1Params[1], -(side1Params[2]),
side2Params[0], side2Params[1], -(side2Params[2]) - sideCExtraParam)) ||
(areIdenticalLines(side1Params[0], side1Params[1], -(side1Params[2]),
side2Params[0], side2Params[1], -(side2Params[2]) + sideCExtraParam))
);
}
static bool areIntersectingLines(const std::vector<double> &side1Params,
const std::vector<double> &side2Params,
double sideCExtraParam, cv::Point2f &intersectionPoint1,
cv::Point2f &intersectionPoint2) {
return (
(lineIntersection(side1Params[0], side1Params[1], -(side1Params[2]),
side2Params[0], side2Params[1], -(side2Params[2]) - sideCExtraParam,
intersectionPoint1)) &&
(lineIntersection(side1Params[0], side1Params[1], -(side1Params[2]),
side2Params[0], side2Params[1], -(side2Params[2]) + sideCExtraParam,
intersectionPoint2))
);
}
static std::vector<double> lineEquationParameters(const cv::Point2f& p, const cv::Point2f &q) {
std::vector<double> lineEquationParameters;
double a, b, c;
lineEquationDeterminedByPoints(p, q, a, b, c);
lineEquationParameters.push_back(a);
lineEquationParameters.push_back(b);
lineEquationParameters.push_back(c);
return lineEquationParameters;
}
static double height(const cv::Point2f &polygonPoint, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c) {
cv::Point2f pointC = polygon[c];
cv::Point2f pointCPredecessor = polygon[predecessor(c, nrOfPoints)];
return distanceFromPointToLine(polygonPoint, pointC, pointCPredecessor);
}
static double height(unsigned int polygonPointIndex, const std::vector<cv::Point2f> &polygon,
unsigned int nrOfPoints, unsigned int c) {
cv::Point2f pointC = polygon[c];
cv::Point2f pointCPredecessor = polygon[predecessor(c, nrOfPoints)];
cv::Point2f polygonPoint = polygon[polygonPointIndex];
return distanceFromPointToLine(polygonPoint, pointC, pointCPredecessor);
}
static void advance(unsigned int &index, unsigned int nrOfPoints) {
index = successor(index, nrOfPoints);
}
static unsigned int successor(unsigned int index, unsigned int nrOfPoints) {
return ((index + 1) % nrOfPoints);
}
static unsigned int predecessor(unsigned int index, unsigned int nrOfPoints) {
return (index == 0) ? (nrOfPoints - 1)
: (index - 1);
}
static bool isFlushAngleBtwPredAndSucc(double &angleFlushEdge, double anglePred, double angleSucc) {
if (isAngleBetweenNonReflex(angleFlushEdge, anglePred, angleSucc)) {
return true;
} else if (isOppositeAngleBetweenNonReflex(angleFlushEdge, anglePred, angleSucc)) {
angleFlushEdge = oppositeAngle(angleFlushEdge);
return true;
}
return false;
}
static bool isGammaAngleEqualTo(double &gammaAngle, double angle) {
return (almostEqual(gammaAngle, angle));
}
static bool isGammaAngleBtw(double &gammaAngle, double angle1, double angle2) {
return (isAngleBetweenNonReflex(gammaAngle, angle1, angle2));
}
static double angleOfLineWrtOxAxis(const cv::Point2f &a, const cv::Point2f &b) {
double y = b.y - a.y;
double x = b.x - a.x;
double angle = (std::atan2(y, x) * 180 / CV_PI);
return (angle < 0) ? (angle + 360)
: angle;
}
static bool isAngleBetweenNonReflex(double angle1, double angle2, double angle3) {
if (std::abs(angle2 - angle3) > 180) {
if (angle2 > angle3) {
return (((angle2 < angle1) && (lessOrEqual(angle1, 360))) ||
((lessOrEqual(0, angle1)) && (angle1 < angle3)));
} else {
return (((angle3 < angle1) && (lessOrEqual(angle1, 360))) ||
((lessOrEqual(0, angle1)) && (angle1 < angle2)));
}
} else {
return isAngleBetween(angle1, angle2, angle3);
}
}
static bool isOppositeAngleBetweenNonReflex(double angle1, double angle2, double angle3) {
double angle1Opposite = oppositeAngle(angle1);
return (isAngleBetweenNonReflex(angle1Opposite, angle2, angle3));
}
static bool isAngleBetween(double angle1, double angle2, double angle3) {
if ((((int)(angle2 - angle3)) % 180) > 0) {
return ((angle3 < angle1) && (angle1 < angle2));
} else {
return ((angle2 < angle1) && (angle1 < angle3));
}
}
static double oppositeAngle(double angle) {
return (angle > 180) ? (angle - 180)
: (angle + 180);
}
static double distanceFromPointToLine(const cv::Point2f &a, const cv::Point2f &linePointB,
const cv::Point2f &linePointC) {
double term1 = linePointC.x - linePointB.x;
double term2 = linePointB.y - a.y;
double term3 = linePointB.x - a.x;
double term4 = linePointC.y - linePointB.y;
double nominator = std::abs((term1 * term2) - (term3 * term4));
double denominator = std::sqrt((term1 * term1) + (term4 * term4));
return (denominator != 0) ? (nominator / denominator)
: 0;
}
static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b) {
double xDiff = a.x - b.x;
double yDiff = a.y - b.y;
return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}
static double areaOfTriangle(const cv::Point2f &a, const cv::Point2f &b, const cv::Point2f &c) {
double posTerm = (a.x * b.y) + (a.y * c.x) + (b.x * c.y);
double negTerm = (b.y * c.x) + (a.x * c.y) + (a.y * b.x);
double determinant = posTerm - negTerm;
return std::abs(determinant) / 2;
}
static cv::Point2f middlePoint(const cv::Point2f &a, const cv::Point2f &b) {
double middleX = static_cast<double>((a.x + b.x) / 2);
double middleY = static_cast<double>((a.y + b.y) / 2);
return cv::Point2f(static_cast<float>(middleX), static_cast<float>(middleY));
}
static bool lineIntersection(double a1, double b1, double c1, double a2, double b2, double c2,
cv::Point2f &intersection) {
double det = (a1 * b2) - (a2 * b1);
if (!(almostEqual(det, 0))) {
intersection.x = static_cast<float>(((c1 * b2) - (c2 * b1)) / (det));
intersection.y = static_cast<float>(((c2 * a1) - (c1 * a2)) / (det));
return true;
}
return false;
}
static bool lineIntersection(const cv::Point2f &a1, const cv::Point2f &b1, const cv::Point2f &a2,
const cv::Point2f &b2, cv::Point2f &intersection) {
double A1 = b1.y - a1.y;
double B1 = a1.x - b1.x;
double C1 = (a1.x * A1) + (a1.y * B1);
double A2 = b2.y - a2.y;
double B2 = a2.x - b2.x;
double C2 = (a2.x * A2) + (a2.y * B2);
double det = (A1 * B2) - (A2 * B1);
if (!almostEqual(det, 0)) {
intersection.x = static_cast<float>(((C1 * B2) - (C2 * B1)) / (det));
intersection.y = static_cast<float>(((C2 * A1) - (C1 * A2)) / (det));
return true;
}
return false;
}
static void lineEquationDeterminedByPoints(const cv::Point2f &p, const cv::Point2f &q,
double &a, double &b, double &c) {
CV_Assert(areEqualPoints(p, q) == false);
a = q.y - p.y;
b = p.x - q.x;
c = ((-p.y) * b) - (p.x * a);
}
static bool areOnTheSameSideOfLine(const cv::Point2f &p1, const cv::Point2f &p2,
const cv::Point2f &a, const cv::Point2f &b) {
double a1, b1, c1;
lineEquationDeterminedByPoints(a, b, a1, b1, c1);
double p1OnLine = (a1 * p1.x) + (b1 * p1.y) + c1;
double p2OnLine = (a1 * p2.x) + (b1 * p2.y) + c1;
return (sign(p1OnLine) == sign(p2OnLine));
}
static bool isPointOnLineSegment(const cv::Point2f &point, const cv::Point2f &lineSegmentStart,
const cv::Point2f &lineSegmentEnd) {
double d1 = distanceBtwPoints(point, lineSegmentStart);
double d2 = distanceBtwPoints(point, lineSegmentEnd);
double lineSegmentLength = distanceBtwPoints(lineSegmentStart, lineSegmentEnd);
return (almostEqual(d1 + d2, lineSegmentLength));
}
static bool areIdenticalLines(double a1, double b1, double c1, double a2, double b2, double c2) {
double a1B2 = a1 * b2;
double a2B1 = a2 * b1;
double a1C2 = a1 * c2;
double a2C1 = a2 * c1;
double b1C2 = b1 * c2;
double b2C1 = b2 * c1;
return ((almostEqual(a1B2, a2B1)) && (almostEqual(b1C2, b2C1)) && (almostEqual(a1C2, a2C1)));
}
static bool areEqualPoints(const cv::Point2f &point1, const cv::Point2f &point2) {
return (almostEqual(point1.x, point2.x) && almostEqual(point1.y, point2.y));
}
static int sign(double number) {
return (number > 0) ? 1 : ((number < 0) ? -1 : 0);
}
static double maximum(double number1, double number2, double number3) {
return std::max(std::max(number1, number2), number3);
}
static bool almostEqual(double number1, double number2) {
return (std::abs(number1 - number2) <= (EPSILON * maximum(1.0, std::abs(number1), std::abs(number2))));
}
static bool greaterOrEqual(double number1, double number2) {
return ((number1 > number2) || (almostEqual(number1, number2)));
}
static bool lessOrEqual(double number1, double number2) {
return ((number1 < number2) || (almostEqual(number1, number2)));
}
}