/*********************************************************************/
/* */
/* Copyright 2022-2023 Rémi Synave - remi.synave@univ-littoral.fr */
/* */
/* This file is part of DSL. */
/* This software uses Qt to build the Graphical User Interface */
/* https://www.qt.io/ */
/* */
/* DSL is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published */
/* by the Free Software Foundation, either version 3 of the License, */
/* or (at your option) any later version. */
/* */
/* DSL is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with DSL. If not, see . */
/* */
/*********************************************************************/
#include
#include
#include
#include
#include "StrengthLine.hpp"
StrengthLine::StrengthLine (double ax, double ay, double bx, double by)
{
if (p1 == NULL || p2 == NULL)
throw std::
invalid_argument ("Points defining a strength line can't be NULL.");
if (ax == bx && ay == by)
throw std::
invalid_argument ("Points defining a strength line can't be equals.");
this->p1 = new QPoint(ax, ay);
this->p2 = new QPoint(bx, by);
}
StrengthLine::StrengthLine (QPoint * p1, QPoint * p2)
{
if (p1 == NULL || p2 == NULL)
throw std::
invalid_argument ("Points defining a strength line can't be NULL.");
if (p1->x () == p2->x () && p1->y () == p2->y ())
throw std::
invalid_argument ("Points defining a strength line can't be equals.");
this->p1 = p1;
this->p2 = p2;
}
QPoint*
StrengthLine::getP1() const
{
return new QPoint(*p1);
}
QPoint*
StrengthLine::getP2() const
{
return new QPoint(*p2);
}
std::pair < float, float >
StrengthLine::equation () const
{
// This method can be called only if a and b are
// not aligned into a vertical or horizontal line
float a = ((p1->y () - p2->y ()) * 1.0) / (p1->x () - p2->x ());
float b = p1->y () - a * p1->x ();
return std::make_pair (a, b);
}
std::pair < QPoint *, QPoint * >StrengthLine::toDraw (QImage * img) const
{
return this->toDraw(img->width(), img->height());
}
std::pair < QPoint *, QPoint * >StrengthLine::toDraw (int imgWidth, int imgHeight) const
{
// Methode qui va calculer les points pour l'affichage des droites
// sur l'image passées en paramètre. Calcul rapide donc
// les points peuvent sortir de l'image.
// ligne verticale
if (p1->x () == p2->x ())
return std::make_pair (new QPoint (p1->x (), 0),
new QPoint (p1->x (), imgHeight));
// ligne horizontale
if (p1->y () == p2->y ())
return std::make_pair (new QPoint (0, p1->y ()),
new QPoint (imgWidth, p1->y ()));
// Equation de la droite et on prend les points gauche et droite de la ligne
std::pair < float, float >
eq = this->equation ();
float
a = std::get < 0 > (eq);
float
b = std::get < 1 > (eq);
return std::make_pair (new QPoint (0, b),
new QPoint (imgWidth, imgWidth * a + b));
}
std::pair < QPoint *, QPoint * >StrengthLine::interpolateToEdge (QImage * img) const
{
return this->interpolateToEdge(img->width(), img->height());
}
std::pair < QPoint *, QPoint * >StrengthLine::interpolateToEdge (int imgWidth, int imgHeight) const
{
// Methode qui va calculer les points sur les bords des images
// en fonction des deux points attributs qui définissent
// la ligne.
// ligne verticale
if (p1->x () == p2->x ())
return std::make_pair (new QPoint (p1->x (), 0),
new QPoint (p1->x (), imgHeight));
// ligne horizontale
if (p1->y () == p2->y ())
return std::make_pair (new QPoint (0, p1->y ()),
new QPoint (imgWidth, p1->y ()));
// Equation de la droite et on prend les points gauche et droite de la ligne
std::pair < float, float >
eq = this->equation ();
float
a = std::get < 0 > (eq);
float
b = std::get < 1 > (eq);
QPoint *p1 = new QPoint(0, b);
QPoint *p2 = new QPoint(imgWidth, imgWidth * a + b);
// Si le point de gauche est trop bas
if(b < 0)
{
p1->setX(-b/a);
p1->setY(0);
}
// Si le point de gauche est trop haut
if(b > imgHeight)
{
p1->setX((imgHeight-b)/a);
p1->setY(imgHeight);
}
// Si le point de droite est trop bas
if((imgWidth * a + b) < 0)
{
p2->setX(-b/a);
p2->setY(0);
}
// Si le point de droite est trop haut
if((imgWidth * a + b) > imgHeight)
{
p2->setX((imgHeight-b)/a);
p2->setY(imgHeight);
}
return std::make_pair (p1, p2);
}
float StrengthLine::ea_score(const StrengthLine *sl, double imgWidth, double imgHeight) const
{
std::pair < QPoint*, QPoint* > pointsSL1 = this->interpolateToEdge (imgWidth, imgHeight);
std::pair < QPoint*, QPoint* > pointsSL2 = sl->interpolateToEdge (imgWidth, imgHeight);
QPoint* p1SL1 = std::get < 0 > (pointsSL1);
QPoint* p2SL1 = std::get < 1 > (pointsSL1);
QPoint* p1SL2 = std::get < 0 > (pointsSL2);
QPoint* p2SL2 = std::get < 1 > (pointsSL2);
float u[2] = {p2SL1->x()-p1SL1->x(), p2SL1->y()-p1SL1->y()};
float v[2] = {p2SL2->x()-p1SL2->x(), p2SL2->y()-p1SL2->y()};
float normU = sqrt(u[0]*u[0]+u[1]*u[1]);
float normV = sqrt(v[0]*v[0]+v[1]*v[1]);
u[0]=u[0]/normU;
u[1]=u[1]/normU;
v[0]=v[0]/normV;
v[1]=v[1]/normV;
float angle = 0;
if((u[0]!=v[0]) || (u[1]!=v[1]))
{
float prodScal=u[0]*v[0]+u[1]*v[1];
// In case of number approximation...
if(prodScal>1)
prodScal=1;
if(prodScal<-1)
prodScal=-1;
angle = acos(prodScal);
}
float sT = 1 - (angle/(M_PI/2));
float midSL1X = ((p1SL1->x() + p2SL1->x())/2.0)/(imgWidth*1.0);
float midSL1Y = ((p1SL1->y() + p2SL1->y())/2.0)/(imgHeight*1.0);
float midSL2X = ((p1SL2->x() + p2SL2->x())/2.0)/(imgWidth*1.0);
float midSL2Y = ((p1SL2->y() + p2SL2->y())/2.0)/(imgHeight*1.0);
float sd = 1 - sqrt(((midSL1X-midSL2X)*(midSL1X-midSL2X))+((midSL1Y-midSL2Y)*(midSL1Y-midSL2Y)));
return ((sT*sd)*(sT*sd));
}
StrengthLine* StrengthLine::getRandomLine (QImage * img)
{
std::srand(static_cast(std::time(nullptr)+std::rand()));
int x1rand = std::rand() % img->width();
int x2rand = std::rand() % img->width();
int y1rand = std::rand() % img->height();
int y2rand = std::rand() % img->height();
while ( x1rand == x2rand && y1rand==y2rand )
{
x2rand = std::rand() % img->width();
y2rand = std::rand() % img->height();
}
return new StrengthLine( new QPoint(x1rand, y1rand), new QPoint(x2rand, y2rand) );
}
StrengthLine* StrengthLine::getRandomLine (int width, int height)
{
std::srand(static_cast(std::time(nullptr)+std::rand()));
int x1rand = std::rand() % width;
int x2rand = std::rand() % width;
int y1rand = std::rand() % height;
int y2rand = std::rand() % height;
while ( x1rand == x2rand && y1rand==y2rand )
{
x2rand = std::rand() % width;
y2rand = std::rand() % height;
}
return new StrengthLine( new QPoint(x1rand, y1rand), new QPoint(x2rand, y2rand) );
}