/*********************************************************************/ /* */ /* 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 (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)); } float StrengthLine::distance(const StrengthLine *sl, double imgWidth, double imgHeight) const { return (1 - ea_score(sl, imgWidth, imgHeight)); } 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) ); } std::ostream& operator<<(std::ostream &o, const StrengthLine sl) { return o << "(" << sl.p1->x() << " , " << sl.p1->y() << ") - (" << sl.p2->x() << " , " << sl.p2->y() << ")"; }