Advertisement
Guest User

123

a guest
Jan 24th, 2018
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.46 KB | None | 0 0
  1.  
  2. #define sqrt5 2.236067977499789696
  3.  
  4. static int Stopping_Rule(double x0, double x1, double tolerance)
  5. {
  6.    double xm = 0.5 * fabs( x1 + x0 );
  7.  
  8.    if ( xm <= 1.0 ) return ( fabs( x1 - x0 ) < tolerance ) ? 1 : 0;
  9.    return ( fabs( x1 - x0 ) < tolerance * xm ) ? 1 : 0;
  10. }
  11. void ScanViewer::Min_Search_Golden_Section
  12. (
  13.         qreal* a, qreal *fa , /// угол и значение площади для минимальноо угла + результат работы    ( 0 радиан    )
  14.         qreal* b, qreal* fb , /// угол и значение площади для максимального угла + результат работы  ( Pi/2 радиан )
  15.         qreal tolerance, QVector < int > x , QVector < int > y   /// Точность + массивы данных от линеек и энкодера (  vector x ( encoder in mm ) , vector y ( beams in mm ) )
  16.         /// in case of light grid vector < int > y => QVector <QPair < int , int > limit;
  17. )
  18. {
  19.  
  20.  
  21.     /// auto metrics = [this,x,y](qreal A)->qreal  ->  функция , принимающая на вход вектора x , y скрытно и угол поворота явно
  22.     /// результат - double функционал - площадь
  23.  
  24.    auto metrics = [this,x,y](qreal A)->qreal   /// После поворота системы координат на А радиан найдем функционал
  25.                                                /// Функционал - площадь или периметр построенный на [ Xmax-Xmin , Ymax - Ymin ]
  26.     {
  27.         //// Выделим переменные под предельные значения координат
  28.         qreal xmax  , xmin;
  29.         qreal ymax  , ymin;
  30.         QPoint AS = rotate(QPoint(x[0],y[0]),A);  /// повернем первую точку из множества чтобы инициализировать максимумы и минимумы
  31.  
  32.         xmax = xmin = AS.x();
  33.         ymax = ymin = AS.y();
  34.  
  35.         /// пройдемся по всем точкам для определения реальных максимумов и минимумов
  36.             for ( int m = 0 ; m < x.size() ; m++ )
  37.             {
  38.                 QPoint AS = rotate(QPoint(x[m],y[m]),A);
  39.                 if (AS.x()>xmax) xmax = AS.x();
  40.                 if (AS.x()<xmin) xmin = AS.x();
  41.                 if (AS.y()>ymax) ymax = AS.y();
  42.                 if (AS.y()<ymin) ymin = AS.y();
  43.                 // #form first optimization factor
  44.             }
  45.  
  46.     return fabs(xmax-xmin)*(ymax-ymin); /// функционал - площадь
  47.     };
  48.  
  49.    static const double lambda = 0.5 * (sqrt5 - 1.0);     /// Константа формулы золотого сечения
  50.    static const double mu = 0.5 * (3.0 - sqrt5);         /// Константа формулы золотого сечения
  51.  
  52.    double x1;  /// внутренняя левая точка поискового интервала ( угол )
  53.    double x2;  /// внутренняя правая точка поискового интервала ( угол )
  54.    double fx1; /// внутренняя правая точка поискового интервала ( площадь или периметр )
  55.    double fx2; /// внутренняя правая точка поискового интервала ( плозадь или периметр )
  56.  
  57.    /// Поиск угла и плозади для внутренних точек отрезка
  58.  
  59.    /// x1 делит отрезок [A,B] в золотом сечении
  60.    /// x2 делит отрезок [B,A] в золотом сечении
  61.  
  62.    x1 = *b - lambda * (*b - *a);
  63.    x2 = *a + lambda * (*b - *a);
  64.  
  65.    /// Определим функционал внутренних точек ( площадь и периметр )
  66.  
  67.    fx1 = metrics(x1);
  68.    fx2 = metrics(x2);
  69.  
  70.    while (  ! Stopping_Rule( *a, *b, tolerance) ) {   /// Пока не достигнута заданная точность
  71.  
  72.  
  73.       if (fx1 > fx2) { /// если площадь прямоугольника со сторонами \\ осям в точке 1 > 2
  74.          *a = x1;      /// сужаем поисковый интервал слева до точки X1 + захват результата на выход
  75.          *fa = fx1;    /// пересчет левого значения площади не нужен - он известен и так
  76.          if ( Stopping_Rule( *a, *b, tolerance) ) break;   /// Если поисковый интервал стал подходить по точности выходим
  77.          x1 = x2;       /// левая внутренняя точка стала правой
  78.          fx1 = fx2;     /// соответствующая запись значения площади
  79.          x2 = *b - mu * (*b - *a);   /// пересчет правой точки ( ее значение и плозадь заранее неизвестны )
  80.          fx2 = metrics(x2);
  81.       }
  82.  
  83.  
  84.       else {          /// если площадь прямоугольника со сторонами \\ осям в точке 1 < 2
  85.          *b = x2;       /// сужаем поисковый интервал справа до точки X2 + захват результата на выход
  86.          *fb = fx2;     /// пересчет правого значения площади не нужен - он известен и так
  87.          if ( Stopping_Rule( *a, *b, tolerance) ) break;   /// Если поисковый интервал стал подходить по точности выходим
  88.          x2 = x1;       /// правая внутренняя точка стала левой
  89.          fx2 = fx1;     /// соответствующая запись значения площади
  90.          x1 = *a + mu * (*b - *a); /// пересчет левой точки ( ее значение и плозадь заранее неизвестны )
  91.          fx1 = metrics(x1);
  92.       }
  93.    }
  94.  
  95.  
  96.  
  97.    return;
  98. }
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110. /// Вектора с данными + переменные под размеры и угол
  111.  
  112. void ScanViewer::getSizes(QVector <int> x , QVector < int > y , QSize * return_size  ,qreal *Angular)
  113. {
  114.  
  115.     /// Аналог функции из Min_Search_Golden_Section
  116.     auto metrics = [this,x,y](qreal A)->qreal
  117.     {
  118.         qreal xmax,xmin;
  119.         qreal ymax , ymin;
  120.         QPoint AS = rotate(QPoint(x[0],y[0]),A);
  121.         xmax = xmin = AS.x();
  122.         ymax = ymin = AS.y();
  123.  
  124.             for ( int m = 0 ; m < x.size() ; m++ )
  125.             {
  126.                 QPoint AS = rotate(QPoint(x[m],y[m]),A);
  127.                 if (AS.x()>xmax) xmax = AS.x();
  128.                 if (AS.x()<xmin) xmin = AS.x();
  129.                 if (AS.y()>ymax) ymax = AS.y();
  130.                 if (AS.y()<ymin) ymin = AS.y();
  131.                 // #form first optimization factor
  132.             }
  133.  
  134.     return fabs(xmax-xmin)*(ymax-ymin);
  135.     };
  136.  
  137.     /// начальный и конечный угол , начальное и конечное значение функционала ( см . Min_Search_Golden_Section )
  138.     /// 0.005 радиана - точность поиска угла
  139.     /// x , y -> данные с линеек
  140.  
  141.     qreal eps = 0.005;
  142.     qreal a = 0-3*eps; /// Расширенный интервал из-за особенностей метода поиска
  143.     qreal b = M_PI/2.0+3*eps;
  144.     qreal fa = metrics(a);
  145.     qreal fb = metrics(b);
  146.  
  147.     Min_Search_Golden_Section(&a,&fa,&b,&fb,0.005,x,y);
  148.  
  149.     /// Получив значение угла , минимизирующего площадь , осталось определить размеры
  150.  
  151.     /// выделим переменные под максимумы и минимумы и инициализируем их первой точкой после поворота на угол
  152.  
  153.     qreal xmax,xmin;
  154.     qreal ymax , ymin;
  155.     QPoint AT = rotate(QPoint(x[0],y[0]),a);
  156.     xmax = xmin = AT.x();
  157.     ymax = ymin = AT.y();
  158.  
  159.  
  160.     /// пройдемся по всем данным чтобы определить габариты
  161.  
  162.     for ( int m = 0 ; m < x.size() ; m++ )
  163.     {
  164.         QPoint AT = rotate(QPoint(x[m],y[m]),a);
  165.         if (AT.x()>xmax) xmax = AT.x();
  166.         if (AT.x()<xmin) xmin = AT.x();
  167.         if (AT.y()>ymax) ymax = AT.y();
  168.         if (AT.y()<ymin) ymin = AT.y();
  169.         // #form first optimization factor
  170.     }
  171.  
  172. /// вернем щначение размеров , углов и точки для построения .
  173. *return_size = QSize(abs(xmax-xmin),abs(ymax-ymin));
  174. *Angular = a;
  175.  
  176.  
  177.     return ;
  178.  
  179.  
  180.  
  181. }
  182.  
  183. /// Поворот точки вокруг начала координат на угол Ang радиан
  184.  
  185. QPoint ScanViewer::rotate(QPoint Z,qreal Ang)
  186. {
  187.     /// сохраним на будущее синус и косинус чтобы лишний раз не считать
  188.  
  189.     qreal C = cos(Ang);
  190.     qreal S = sin(Ang);
  191.  
  192.     /// домножение на матрицу поворота в раскрытом виде
  193.     /// приведение типов необходимо чтобы перемножать координаты в целых мм на вещественные синусы и косинусы
  194.     /// не теряя информации
  195.  
  196.     qreal X = qreal(Z.x())*C-qreal(Z.y())*S;
  197.     qreal Y = qreal(Z.x())*S+qreal(Z.y())*C;
  198.  
  199.     /// Возвращаем точку .
  200.     return QPoint(X,Y);
  201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement