<commit_before>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"

#include <iostream>

using namespace cv;
using namespace std;

void help(char** argv)
{
    cout << "\nThis program demonstrats keypoint finding and matching between 2 images using features2d framework.\n"
     << "   In one case, the 2nd image is synthesized by homography from the first, in the second case, there are 2 images\n"
     << "\n"
     << "Case1: second image is obtained from the first (given) image using random generated homography matrix\n"
     << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image] [evaluate(0 or 1)]\n"
     << "Example of case1:\n"
     << "./descriptor_extractor_matcher SURF SURF FlannBased NoneFilter cola.jpg 0\n"
     << "\n"
     << "Case2: both images are given. If ransacReprojThreshold>=0 then homography matrix are calculated\n"
     << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image1] [image2] [ransacReprojThreshold]\n"
     << "\n"
     << "Matches are filtered using homography matrix in case1 and case2 (if ransacReprojThreshold>=0)\n"
     << "Example of case2:\n"
     << "./descriptor_extractor_matcher SURF SURF BruteForce CrossCheckFilter cola1.jpg cola2.jpg 3\n"
     << "\n"
     << "Possible detectorType values: see in documentation on createFeatureDetector().\n"
     << "Possible descriptorType values: see in documentation on createDescriptorExtractor().\n"
     << "Possible matcherType values: see in documentation on createDescriptorMatcher().\n"
     << "Possible matcherFilterType values: NoneFilter, CrossCheckFilter." << endl;
}

#define DRAW_RICH_KEYPOINTS_MODE     0
#define DRAW_OUTLIERS_MODE           0

const string winName = "correspondences";

enum { NONE_FILTER = 0, CROSS_CHECK_FILTER = 1 };

int getMatcherFilterType( const string& str )
{
    if( str == "NoneFilter" )
        return NONE_FILTER;
    if( str == "CrossCheckFilter" )
        return CROSS_CHECK_FILTER;
    CV_Error(CV_StsBadArg, "Invalid filter name");
    return -1;
}

void simpleMatching( Ptr<DescriptorMatcher>& descriptorMatcher,
                     const Mat& descriptors1, const Mat& descriptors2,
                     vector<DMatch>& matches12 )
{
    vector<DMatch> matches;
    descriptorMatcher->match( descriptors1, descriptors2, matches12 );
}

void crossCheckMatching( Ptr<DescriptorMatcher>& descriptorMatcher,
                         const Mat& descriptors1, const Mat& descriptors2,
                         vector<DMatch>& filteredMatches12, int knn=1 )
{
    filteredMatches12.clear();
    vector<vector<DMatch> > matches12, matches21;
    descriptorMatcher->knnMatch( descriptors1, descriptors2, matches12, knn );
    descriptorMatcher->knnMatch( descriptors2, descriptors1, matches21, knn );
    for( size_t m = 0; m < matches12.size(); m++ )
    {
        bool findCrossCheck = false;
        for( size_t fk = 0; fk < matches12[m].size(); fk++ )
        {
            DMatch forward = matches12[m][fk];

            for( size_t bk = 0; bk < matches21[forward.trainIdx].size(); bk++ )
            {
                DMatch backward = matches21[forward.trainIdx][bk];
                if( backward.trainIdx == forward.queryIdx )
                {
                    filteredMatches12.push_back(forward);
                    findCrossCheck = true;
                    break;
                }
            }
            if( findCrossCheck ) break;
        }
    }
}

void warpPerspectiveRand( const Mat& src, Mat& dst, Mat& H, RNG& rng )
{
    H.create(3, 3, CV_32FC1);
    H.at<float>(0,0) = rng.uniform( 0.8f, 1.2f);
    H.at<float>(0,1) = rng.uniform(-0.1f, 0.1f);
    H.at<float>(0,2) = rng.uniform(-0.1f, 0.1f)*src.cols;
    H.at<float>(1,0) = rng.uniform(-0.1f, 0.1f);
    H.at<float>(1,1) = rng.uniform( 0.8f, 1.2f);
    H.at<float>(1,2) = rng.uniform(-0.1f, 0.1f)*src.rows;
    H.at<float>(2,0) = rng.uniform( -1e-4f, 1e-4f);
    H.at<float>(2,1) = rng.uniform( -1e-4f, 1e-4f);
    H.at<float>(2,2) = rng.uniform( 0.8f, 1.2f);

    warpPerspective( src, dst, H, src.size() );
}

void doIteration( const Mat& img1, Mat& img2, bool isWarpPerspective,
                  vector<KeyPoint>& keypoints1, const Mat& descriptors1,
                  Ptr<FeatureDetector>& detector, Ptr<DescriptorExtractor>& descriptorExtractor,
                  Ptr<DescriptorMatcher>& descriptorMatcher, int matcherFilter, bool eval,
                  double ransacReprojThreshold, RNG& rng )
{
    assert( !img1.empty() );
    Mat H12;
    if( isWarpPerspective )
        warpPerspectiveRand(img1, img2, H12, rng );
    else
        assert( !img2.empty()/* && img2.cols==img1.cols && img2.rows==img1.rows*/ );

    cout << endl << "< Extracting keypoints from second image..." << endl;
    vector<KeyPoint> keypoints2;
    detector->detect( img2, keypoints2 );
    cout << keypoints2.size() << " points" << endl << ">" << endl;

    if( !H12.empty() && eval )
    {
        cout << "< Evaluate feature detector..." << endl;
        float repeatability;
        int correspCount;
        evaluateFeatureDetector( img1, img2, H12, &keypoints1, &keypoints2, repeatability, correspCount );
        cout << "repeatability = " << repeatability << endl;
        cout << "correspCount = " << correspCount << endl;
        cout << ">" << endl;
    }

    cout << "< Computing descriptors for keypoints from second image..." << endl;
    Mat descriptors2;
    descriptorExtractor->compute( img2, keypoints2, descriptors2 );
    cout << ">" << endl;

    cout << "< Matching descriptors..." << endl;
    vector<DMatch> filteredMatches;
    switch( matcherFilter )
    {
    case CROSS_CHECK_FILTER :
        crossCheckMatching( descriptorMatcher, descriptors1, descriptors2, filteredMatches, 1 );
        break;
    default :
        simpleMatching( descriptorMatcher, descriptors1, descriptors2, filteredMatches );
    }
    cout << ">" << endl;

    if( !H12.empty() && eval )
    {
        cout << "< Evaluate descriptor matcher..." << endl;
        vector<Point2f> curve;
        Ptr<GenericDescriptorMatcher> gdm = new VectorDescriptorMatcher( descriptorExtractor, descriptorMatcher );
        evaluateGenericDescriptorMatcher( img1, img2, H12, keypoints1, keypoints2, 0, 0, curve, gdm );

        for( float l_p = 0; l_p <= 1; l_p+=0.05f )
        {
            int nearest = getNearestPoint( curve, l_p );
            cout << "1-precision = " << curve[nearest].x << "; recall = " << curve[nearest].y << endl;
        }
        cout << ">" << endl;
    }

    vector<int> queryIdxs( filteredMatches.size() ), trainIdxs( filteredMatches.size() );
    for( size_t i = 0; i < filteredMatches.size(); i++ )
    {
        queryIdxs[i] = filteredMatches[i].queryIdx;
        trainIdxs[i] = filteredMatches[i].trainIdx;
    }

    if( !isWarpPerspective && ransacReprojThreshold >= 0 )
    {
        cout << "< Computing homography (RANSAC)..." << endl;
        vector<Point2f> points1; KeyPoint::convert(keypoints1, points1, queryIdxs);
        vector<Point2f> points2; KeyPoint::convert(keypoints2, points2, trainIdxs);
        H12 = findHomography( Mat(points1), Mat(points2), CV_RANSAC, ransacReprojThreshold );
        cout << ">" << endl;
    }

    Mat drawImg;
    if( !H12.empty() ) // filter outliers
    {
        vector<char> matchesMask( filteredMatches.size(), 0 );
        vector<Point2f> points1; KeyPoint::convert(keypoints1, points1, queryIdxs);
        vector<Point2f> points2; KeyPoint::convert(keypoints2, points2, trainIdxs);
        Mat points1t; perspectiveTransform(Mat(points1), points1t, H12);
        for( size_t i1 = 0; i1 < points1.size(); i1++ )
        {
            if( norm(points2[i1] - points1t.at<Point2f>((int)i1,0)) < 4 ) // inlier
                matchesMask[i1] = 1;
        }
        // draw inliers
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255), matchesMask
#if DRAW_RICH_KEYPOINTS_MODE
                     , DrawMatchesFlags::DRAW_RICH_KEYPOINTS
#endif
                   );

#if DRAW_OUTLIERS_MODE
        // draw outliers
        for( size_t i1 = 0; i1 < matchesMask.size(); i1++ )
            matchesMask[i1] = !matchesMask[i1];
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg, CV_RGB(0, 0, 255), CV_RGB(255, 0, 0), matchesMask,
                     DrawMatchesFlags::DRAW_OVER_OUTIMG | DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
#endif
    }
    else
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg );

    imshow( winName, drawImg );
}

int main(int argc, char** argv)
{
    if( argc != 7 && argc != 8 )
    {
    	help(argv);
        return -1;
    }
    bool isWarpPerspective = argc == 7;
    double ransacReprojThreshold = -1;
    if( !isWarpPerspective )
        ransacReprojThreshold = atof(argv[7]);

    cout << "< Creating detector, descriptor extractor and descriptor matcher ..." << endl;
    Ptr<FeatureDetector> detector = FeatureDetector::create( argv[1] );
    Ptr<DescriptorExtractor> descriptorExtractor = DescriptorExtractor::create( argv[2] );
    Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( argv[3] );
    int mactherFilterType = getMatcherFilterType( argv[4] );
    bool eval = !isWarpPerspective ? false : (atoi(argv[6]) == 0 ? false : true);
    cout << ">" << endl;
    if( detector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty()  )
    {
        cout << "Can not create detector or descriptor exstractor or descriptor matcher of given types" << endl;
        return -1;
    }

    cout << "< Reading the images..." << endl;
    Mat img1 = imread( argv[5] ), img2;
    if( !isWarpPerspective )
        img2 = imread( argv[6] );
    cout << ">" << endl;
    if( img1.empty() || (!isWarpPerspective && img2.empty()) )
    {
        cout << "Can not read images" << endl;
        return -1;
    }

    cout << endl << "< Extracting keypoints from first image..." << endl;
    vector<KeyPoint> keypoints1;
    detector->detect( img1, keypoints1 );
    cout << keypoints1.size() << " points" << endl << ">" << endl;

    cout << "< Computing descriptors for keypoints from first image..." << endl;
    Mat descriptors1;
    descriptorExtractor->compute( img1, keypoints1, descriptors1 );
    cout << ">" << endl;

    namedWindow(winName, 1);
    RNG rng = theRNG();
    doIteration( img1, img2, isWarpPerspective, keypoints1, descriptors1,
                 detector, descriptorExtractor, descriptorMatcher, mactherFilterType, eval,
                 ransacReprojThreshold, rng );
    for(;;)
    {
        char c = (char)waitKey(0);
        if( c == '\x1b' ) // esc
        {
            cout << "Exiting ..." << endl;
            break;
        }
        else if( isWarpPerspective )
        {
            doIteration( img1, img2, isWarpPerspective, keypoints1, descriptors1,
                         detector, descriptorExtractor, descriptorMatcher, mactherFilterType, eval,
                         ransacReprojThreshold, rng );
        }
    }
    return 0;
}
<commit_msg>fixed sample<commit_after>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"

#include <iostream>

using namespace cv;
using namespace std;

void help(char** argv)
{
    cout << "\nThis program demonstrats keypoint finding and matching between 2 images using features2d framework.\n"
     << "   In one case, the 2nd image is synthesized by homography from the first, in the second case, there are 2 images\n"
     << "\n"
     << "Case1: second image is obtained from the first (given) image using random generated homography matrix\n"
     << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image] [evaluate(0 or 1)]\n"
     << "Example of case1:\n"
     << "./descriptor_extractor_matcher SURF SURF FlannBased NoneFilter cola.jpg 0\n"
     << "\n"
     << "Case2: both images are given. If ransacReprojThreshold>=0 then homography matrix are calculated\n"
     << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image1] [image2] [ransacReprojThreshold]\n"
     << "\n"
     << "Matches are filtered using homography matrix in case1 and case2 (if ransacReprojThreshold>=0)\n"
     << "Example of case2:\n"
     << "./descriptor_extractor_matcher SURF SURF BruteForce CrossCheckFilter cola1.jpg cola2.jpg 3\n"
     << "\n"
     << "Possible detectorType values: see in documentation on createFeatureDetector().\n"
     << "Possible descriptorType values: see in documentation on createDescriptorExtractor().\n"
     << "Possible matcherType values: see in documentation on createDescriptorMatcher().\n"
     << "Possible matcherFilterType values: NoneFilter, CrossCheckFilter." << endl;
}

#define DRAW_RICH_KEYPOINTS_MODE     0
#define DRAW_OUTLIERS_MODE           0

const string winName = "correspondences";

enum { NONE_FILTER = 0, CROSS_CHECK_FILTER = 1 };

int getMatcherFilterType( const string& str )
{
    if( str == "NoneFilter" )
        return NONE_FILTER;
    if( str == "CrossCheckFilter" )
        return CROSS_CHECK_FILTER;
    CV_Error(CV_StsBadArg, "Invalid filter name");
    return -1;
}

void simpleMatching( Ptr<DescriptorMatcher>& descriptorMatcher,
                     const Mat& descriptors1, const Mat& descriptors2,
                     vector<DMatch>& matches12 )
{
    vector<DMatch> matches;
    descriptorMatcher->match( descriptors1, descriptors2, matches12 );
}

void crossCheckMatching( Ptr<DescriptorMatcher>& descriptorMatcher,
                         const Mat& descriptors1, const Mat& descriptors2,
                         vector<DMatch>& filteredMatches12, int knn=1 )
{
    filteredMatches12.clear();
    vector<vector<DMatch> > matches12, matches21;
    descriptorMatcher->knnMatch( descriptors1, descriptors2, matches12, knn );
    descriptorMatcher->knnMatch( descriptors2, descriptors1, matches21, knn );
    for( size_t m = 0; m < matches12.size(); m++ )
    {
        bool findCrossCheck = false;
        for( size_t fk = 0; fk < matches12[m].size(); fk++ )
        {
            DMatch forward = matches12[m][fk];

            for( size_t bk = 0; bk < matches21[forward.trainIdx].size(); bk++ )
            {
                DMatch backward = matches21[forward.trainIdx][bk];
                if( backward.trainIdx == forward.queryIdx )
                {
                    filteredMatches12.push_back(forward);
                    findCrossCheck = true;
                    break;
                }
            }
            if( findCrossCheck ) break;
        }
    }
}

void warpPerspectiveRand( const Mat& src, Mat& dst, Mat& H, RNG& rng )
{
    H.create(3, 3, CV_32FC1);
    H.at<float>(0,0) = rng.uniform( 0.8f, 1.2f);
    H.at<float>(0,1) = rng.uniform(-0.1f, 0.1f);
    H.at<float>(0,2) = rng.uniform(-0.1f, 0.1f)*src.cols;
    H.at<float>(1,0) = rng.uniform(-0.1f, 0.1f);
    H.at<float>(1,1) = rng.uniform( 0.8f, 1.2f);
    H.at<float>(1,2) = rng.uniform(-0.1f, 0.1f)*src.rows;
    H.at<float>(2,0) = rng.uniform( -1e-4f, 1e-4f);
    H.at<float>(2,1) = rng.uniform( -1e-4f, 1e-4f);
    H.at<float>(2,2) = rng.uniform( 0.8f, 1.2f);

    warpPerspective( src, dst, H, src.size() );
}

void doIteration( const Mat& img1, Mat& img2, bool isWarpPerspective,
                  vector<KeyPoint>& keypoints1, const Mat& descriptors1,
                  Ptr<FeatureDetector>& detector, Ptr<DescriptorExtractor>& descriptorExtractor,
                  Ptr<DescriptorMatcher>& descriptorMatcher, int matcherFilter, bool eval,
                  double ransacReprojThreshold, RNG& rng )
{
    assert( !img1.empty() );
    Mat H12;
    if( isWarpPerspective )
        warpPerspectiveRand(img1, img2, H12, rng );
    else
        assert( !img2.empty()/* && img2.cols==img1.cols && img2.rows==img1.rows*/ );

    cout << endl << "< Extracting keypoints from second image..." << endl;
    vector<KeyPoint> keypoints2;
    detector->detect( img2, keypoints2 );
    cout << keypoints2.size() << " points" << endl << ">" << endl;

    if( !H12.empty() && eval )
    {
        cout << "< Evaluate feature detector..." << endl;
        float repeatability;
        int correspCount;
        evaluateFeatureDetector( img1, img2, H12, &keypoints1, &keypoints2, repeatability, correspCount );
        cout << "repeatability = " << repeatability << endl;
        cout << "correspCount = " << correspCount << endl;
        cout << ">" << endl;
    }

    cout << "< Computing descriptors for keypoints from second image..." << endl;
    Mat descriptors2;
    descriptorExtractor->compute( img2, keypoints2, descriptors2 );
    cout << ">" << endl;

    cout << "< Matching descriptors..." << endl;
    vector<DMatch> filteredMatches;
    switch( matcherFilter )
    {
    case CROSS_CHECK_FILTER :
        crossCheckMatching( descriptorMatcher, descriptors1, descriptors2, filteredMatches, 1 );
        break;
    default :
        simpleMatching( descriptorMatcher, descriptors1, descriptors2, filteredMatches );
    }
    cout << ">" << endl;

    if( !H12.empty() && eval )
    {
        cout << "< Evaluate descriptor matcher..." << endl;
        vector<Point2f> curve;
        Ptr<GenericDescriptorMatcher> gdm = new VectorDescriptorMatcher( descriptorExtractor, descriptorMatcher );
        evaluateGenericDescriptorMatcher( img1, img2, H12, keypoints1, keypoints2, 0, 0, curve, gdm );

        for( float l_p = 0; l_p <= 1 + FLT_EPSILON; l_p+=0.05f )
        {
            int nearest = getNearestPoint( curve, l_p );
            if( nearest >= 0 )
                cout << "1-precision = " << curve[nearest].x << "; recall = " << curve[nearest].y << endl;
        }
        cout << ">" << endl;
    }

    vector<int> queryIdxs( filteredMatches.size() ), trainIdxs( filteredMatches.size() );
    for( size_t i = 0; i < filteredMatches.size(); i++ )
    {
        queryIdxs[i] = filteredMatches[i].queryIdx;
        trainIdxs[i] = filteredMatches[i].trainIdx;
    }

    if( !isWarpPerspective && ransacReprojThreshold >= 0 )
    {
        cout << "< Computing homography (RANSAC)..." << endl;
        vector<Point2f> points1; KeyPoint::convert(keypoints1, points1, queryIdxs);
        vector<Point2f> points2; KeyPoint::convert(keypoints2, points2, trainIdxs);
        H12 = findHomography( Mat(points1), Mat(points2), CV_RANSAC, ransacReprojThreshold );
        cout << ">" << endl;
    }

    Mat drawImg;
    if( !H12.empty() ) // filter outliers
    {
        vector<char> matchesMask( filteredMatches.size(), 0 );
        vector<Point2f> points1; KeyPoint::convert(keypoints1, points1, queryIdxs);
        vector<Point2f> points2; KeyPoint::convert(keypoints2, points2, trainIdxs);
        Mat points1t; perspectiveTransform(Mat(points1), points1t, H12);
        for( size_t i1 = 0; i1 < points1.size(); i1++ )
        {
            if( norm(points2[i1] - points1t.at<Point2f>((int)i1,0)) < 4 ) // inlier
                matchesMask[i1] = 1;
        }
        // draw inliers
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg, CV_RGB(0, 255, 0), CV_RGB(0, 0, 255), matchesMask
#if DRAW_RICH_KEYPOINTS_MODE
                     , DrawMatchesFlags::DRAW_RICH_KEYPOINTS
#endif
                   );

#if DRAW_OUTLIERS_MODE
        // draw outliers
        for( size_t i1 = 0; i1 < matchesMask.size(); i1++ )
            matchesMask[i1] = !matchesMask[i1];
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg, CV_RGB(0, 0, 255), CV_RGB(255, 0, 0), matchesMask,
                     DrawMatchesFlags::DRAW_OVER_OUTIMG | DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
#endif
    }
    else
        drawMatches( img1, keypoints1, img2, keypoints2, filteredMatches, drawImg );

    imshow( winName, drawImg );
}

int main(int argc, char** argv)
{
    if( argc != 7 && argc != 8 )
    {
    	help(argv);
        return -1;
    }
    bool isWarpPerspective = argc == 7;
    double ransacReprojThreshold = -1;
    if( !isWarpPerspective )
        ransacReprojThreshold = atof(argv[7]);

    cout << "< Creating detector, descriptor extractor and descriptor matcher ..." << endl;
    Ptr<FeatureDetector> detector = FeatureDetector::create( argv[1] );
    Ptr<DescriptorExtractor> descriptorExtractor = DescriptorExtractor::create( argv[2] );
    Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( argv[3] );
    int mactherFilterType = getMatcherFilterType( argv[4] );
    bool eval = !isWarpPerspective ? false : (atoi(argv[6]) == 0 ? false : true);
    cout << ">" << endl;
    if( detector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty()  )
    {
        cout << "Can not create detector or descriptor exstractor or descriptor matcher of given types" << endl;
        return -1;
    }

    cout << "< Reading the images..." << endl;
    Mat img1 = imread( argv[5] ), img2;
    if( !isWarpPerspective )
        img2 = imread( argv[6] );
    cout << ">" << endl;
    if( img1.empty() || (!isWarpPerspective && img2.empty()) )
    {
        cout << "Can not read images" << endl;
        return -1;
    }

    cout << endl << "< Extracting keypoints from first image..." << endl;
    vector<KeyPoint> keypoints1;
    detector->detect( img1, keypoints1 );
    cout << keypoints1.size() << " points" << endl << ">" << endl;

    cout << "< Computing descriptors for keypoints from first image..." << endl;
    Mat descriptors1;
    descriptorExtractor->compute( img1, keypoints1, descriptors1 );
    cout << ">" << endl;

    namedWindow(winName, 1);
    RNG rng = theRNG();
    doIteration( img1, img2, isWarpPerspective, keypoints1, descriptors1,
                 detector, descriptorExtractor, descriptorMatcher, mactherFilterType, eval,
                 ransacReprojThreshold, rng );
    for(;;)
    {
        char c = (char)waitKey(0);
        if( c == '\x1b' ) // esc
        {
            cout << "Exiting ..." << endl;
            break;
        }
        else if( isWarpPerspective )
        {
            doIteration( img1, img2, isWarpPerspective, keypoints1, descriptors1,
                         detector, descriptorExtractor, descriptorMatcher, mactherFilterType, eval,
                         ransacReprojThreshold, rng );
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH
#define DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/grid/provider/cube.hh>
#include <dune/stuff/la/container/common.hh>

#include <dune/gdt/spaces/tools.hh>
#include <dune/gdt/discretefunction/default.hh>
#include <dune/gdt/operators/oswaldinterpolation.hh>

using namespace Dune;
using namespace GDT;

template <class SpaceType>
struct Oswald_Interpolation_Operator : public ::testing::Test
{
  typedef Dune::Stuff::LA::CommonDenseVector<double> VectorType;
  typedef typename SpaceType::GridViewType GridViewType;
  typedef typename GridViewType::Grid GridType;
  typedef Dune::Stuff::Grid::Providers::Cube<GridType> GridProviderType;
  static const unsigned int dimDomain = SpaceType::dimDomain;

  /**
   * \note This is not a test for correct results yet!
   */
  void produces_correct_results() const
  {
    // prepare
    const size_t num_partitions = 2;
    GridProviderType grid_provider(0.0, 1.0, num_partitions);
    auto& grid = grid_provider.grid();
    grid.globalRefine(1);
    const auto grid_part_view = SpaceTools::GridPartView<SpaceType>::create_leaf(grid);
    const SpaceType space(grid_part_view);
    typedef DiscreteFunction<SpaceType, VectorType> DiscreteFunctionType;
    VectorType source_vector(space.mapper().size());
    DiscreteFunctionType source(space, source_vector);
    for (auto entity_ptr = grid_part_view.template begin<0>(); entity_ptr != grid_part_view.template end<0>();
         ++entity_ptr) {
      const auto& entity = *entity_ptr;
      const auto center  = entity.geometry().center();
      double value = 0.0;
      if (center[0] > 0.5)
        value                      = 1.0;
      auto local_source            = source.local_discrete_function(entity);
      auto local_source_DoF_vector = local_source->vector();
      for (size_t local_DoF = 0; local_DoF < local_source_DoF_vector.size(); ++local_DoF)
        local_source_DoF_vector.set(local_DoF, value);
    }
    VectorType range_vector(space.mapper().size());
    DiscreteFunctionType range(space, range_vector);
    Operators::OswaldInterpolation<typename SpaceType::GridViewType> oswald_operator(space.grid_view());
    oswald_operator.apply(source, range);
  } // ... produces_correct_results()
}; // struct Oswald_Interpolation_Operator

#endif // DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH
<commit_msg>[test.operators.oswaldinterpolation] add TODO, refs #38<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH
#define DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/grid/provider/cube.hh>
#include <dune/stuff/la/container/common.hh>

#include <dune/gdt/spaces/tools.hh>
#include <dune/gdt/discretefunction/default.hh>
#include <dune/gdt/operators/oswaldinterpolation.hh>

using namespace Dune;
using namespace GDT;

template <class SpaceType>
struct Oswald_Interpolation_Operator : public ::testing::Test
{
  typedef Dune::Stuff::LA::CommonDenseVector<double> VectorType;
  typedef typename SpaceType::GridViewType GridViewType;
  typedef typename GridViewType::Grid GridType;
  typedef Dune::Stuff::Grid::Providers::Cube<GridType> GridProviderType;
  static const unsigned int dimDomain = SpaceType::dimDomain;

  /**
   * \note This is not a test for correct results yet!
   */
  void produces_correct_results() const
  {
    // prepare the source function
    const size_t num_partitions = 2;
    GridProviderType grid_provider(0.0, 1.0, num_partitions);
    auto& grid = grid_provider.grid();
    grid.globalRefine(1);
    const auto grid_part_view = SpaceTools::GridPartView<SpaceType>::create_leaf(grid);
    const SpaceType space(grid_part_view);
    typedef DiscreteFunction<SpaceType, VectorType> DiscreteFunctionType;
    VectorType source_vector(space.mapper().size());
    DiscreteFunctionType source(space, source_vector);
    for (auto entity_ptr = grid_part_view.template begin<0>(); entity_ptr != grid_part_view.template end<0>();
         ++entity_ptr) {
      const auto& entity = *entity_ptr;
      const auto center  = entity.geometry().center();
      double value = 0.0;
      if (center[0] > 0.5)
        value                      = 1.0;
      auto local_source            = source.local_discrete_function(entity);
      auto local_source_DoF_vector = local_source->vector();
      for (size_t local_DoF = 0; local_DoF < local_source_DoF_vector.size(); ++local_DoF)
        local_source_DoF_vector.set(local_DoF, value);
    }
    // apply operator
    VectorType range_vector(space.mapper().size());
    DiscreteFunctionType range(space, range_vector);
    Operators::OswaldInterpolation<typename SpaceType::GridViewType> oswald_operator(space.grid_view());
    oswald_operator.apply(source, range);
    // TODO: test result
  } // ... produces_correct_results()
}; // struct Oswald_Interpolation_Operator

#endif // DUNE_GDT_TEST_OPERATORS_OSWALDINTERPOLATION_HH
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 2006-07, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Class describing TPC temperature sensors (including pointers to graphs/fits//
// Authors: Marian Ivanov, Haavard Helstrup and Martin Siska                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// Running instructions:
/*
  TClonesArray * arr = AliTPCSensorTemp::ReadList("TempSensor.txt");
  TFile f("TempSensors.root","RECREATE");
  TTree * tree = new TTree("TempSensor", "TempSensor");
  tree->Branch("Temp",&arr);
  tree->Fill();
  tree->Write();

 */
//

#include "AliTPCSensorTemp.h"
ClassImp(AliTPCSensorTemp)

AliTPCSensorTemp::AliTPCSensorTemp(): AliDCSSensor(),
  fType(0),
  fSide(0),
  fSector(0),
  fNum(0)
{
  //
  //  Standard constructor
  //
}

AliTPCSensorTemp::AliTPCSensorTemp(const AliTPCSensorTemp& source) :
  AliDCSSensor(source),
   fType(source.fType),
   fSide(source.fSide),
   fSector(source.fSector),
   fNum(source.fNum)

//
//  Copy constructor
//
{ }

AliTPCSensorTemp& AliTPCSensorTemp::operator=(const AliTPCSensorTemp& source){
//
// assignment operator
//
  if (&source == this) return *this;
  new (this) AliTPCSensorTemp(source);

  return *this;
}

TClonesArray * AliTPCSensorTemp::ReadList(const char *fname) {

   Int_t firstSensor, lastSensor;
   return ReadListInd(fname,firstSensor,lastSensor);
}

TClonesArray * AliTPCSensorTemp::ReadListInd(const char *fname,
                                          Int_t& firstSensor,
					  Int_t& lastSensor ){
  //
  // read values from ascii file
  //
  TTree * tree = new TTree("asci","asci");
  tree->ReadFile(fname,"");

  Int_t nentries = tree->GetEntries();
  Int_t sensor=0;
  Int_t sector=0;
  char  type[100];
  char  side[100];
  Int_t num=0;
  Int_t echa=0;
  //Double_t x=0;
  //Double_t y=0;
  //Double_t z=0;
  //String_t namedtp[100];

  tree->SetBranchAddress("Sensor",&sensor);
  tree->SetBranchAddress("Type",&type);
  tree->SetBranchAddress("Side",&side);
  tree->SetBranchAddress("Sec",&sector);
  tree->SetBranchAddress("Num",&num);
  tree->SetBranchAddress("ECha",&echa);
  //tree->SetBranchAddress("X",&x);
  //tree->SetBranchAddress("Y",&y);
  //tree->SetBranchAddress("Z",&z);

  firstSensor = (Int_t)tree->GetMinimum("ECha");
  lastSensor = (Int_t)tree->GetMaximum("ECha");

  TClonesArray * array = new TClonesArray("AliTPCSensorTemp",nentries);

  for (Int_t isensor=0; isensor<nentries; isensor++){
    AliTPCSensorTemp * temp = new ((*array)[isensor])AliTPCSensorTemp;
    tree->GetEntry(isensor);
    temp->SetId(sensor);
    temp->SetIdDCS(echa);
    if (side[0]=='C') temp->SetSide(1);
    temp->SetSector(sector);
    temp->SetNum(num);
    //temp->SetType(type);
    if (bcmp(type,"ROC",3)==0) temp->SetType(0);
    if (bcmp(type,"OFC",3)==0) temp->SetType(1);
    if (bcmp(type,"IFC",3)==0) temp->SetType(2);
    if (bcmp(type,"TPC",3)==0) temp->SetType(3);
    if (bcmp(type,"ELM",3)==0) temp->SetType(4);
    if (bcmp(type,"TS",2)==0)  temp->SetType(5);
    if (bcmp(type,"COOL",3)==0)temp->SetType(6);
    //temp->SetX(x);

    if (temp->GetType()==0){
	temp->SetX(TMath::Cos((2*sector+1)*0.1745)*(83+(num+1)*30));
    }
    if ((temp->GetType()==1) || (temp->GetType()==4)){
      temp->SetX(TMath::Cos((2*sector+1)*0.1745)*260);
    }
    if ((temp->GetType()==2) || (temp->GetType()==3)){
      temp->SetX(TMath::Cos((2*sector+1)*0.1745)*83);
    }
    if ((temp->GetType()==5) || (temp->GetType()==6)){
      temp->SetX(0);
    }

    //temp->SetY(y);
    if (temp->GetType()==0){
	  temp->SetY(TMath::Sin((2*sector+1)*0.1745)*(83+(num+1)*30));
    }
    if ((temp->GetType()==1) || (temp->GetType()==4)){
      temp->SetY(TMath::Sin((2*sector+1)*0.1745)*260);
    }
    if ((temp->GetType()==2) || (temp->GetType()==3)){
      temp->SetY(TMath::Sin((2*sector+1)*0.1745)*83);
    }
    if ((temp->GetType()==5) || (temp->GetType()==6)){
      temp->SetY(0);
    }
    //temp->SetZ(z);
    if ((temp->GetType()==0 || temp->GetType()==3 || temp->GetType()==4 || temp->GetType()==5 || temp->GetType()==6) && temp->GetSide()==0) {
      temp->SetZ(260);
      }
    if ((temp->GetType()==0 || temp->GetType()==3 || temp->GetType()==4 || temp->GetType()==5 || temp->GetType()==6) && temp->GetSide()==1){
      temp->SetZ(-260);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==0)) {
      temp->SetZ(250);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==1)) {
      temp->SetZ(180);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==2)) {
      temp->SetZ(60);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==3)) {
      temp->SetZ(-60);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==4)) {
      temp->SetZ(-180);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==5)) {
      temp->SetZ(-250);
      }
    Char_t chname[1000];
    sprintf(chname,"tpc_temp:PT_%i.Temperature",echa);
    temp->SetName(chname);
  }
  delete tree;
  return array;
}
<commit_msg>Including strings.h to declare bcmp (Solaris x86)<commit_after>/**************************************************************************
 * Copyright(c) 2006-07, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// Class describing TPC temperature sensors (including pointers to graphs/fits//
// Authors: Marian Ivanov, Haavard Helstrup and Martin Siska                  //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// Running instructions:
/*
  TClonesArray * arr = AliTPCSensorTemp::ReadList("TempSensor.txt");
  TFile f("TempSensors.root","RECREATE");
  TTree * tree = new TTree("TempSensor", "TempSensor");
  tree->Branch("Temp",&arr);
  tree->Fill();
  tree->Write();

 */
//

#include <strings.h>
#include "AliTPCSensorTemp.h"
ClassImp(AliTPCSensorTemp)

AliTPCSensorTemp::AliTPCSensorTemp(): AliDCSSensor(),
  fType(0),
  fSide(0),
  fSector(0),
  fNum(0)
{
  //
  //  Standard constructor
  //
}

AliTPCSensorTemp::AliTPCSensorTemp(const AliTPCSensorTemp& source) :
  AliDCSSensor(source),
   fType(source.fType),
   fSide(source.fSide),
   fSector(source.fSector),
   fNum(source.fNum)

//
//  Copy constructor
//
{ }

AliTPCSensorTemp& AliTPCSensorTemp::operator=(const AliTPCSensorTemp& source){
//
// assignment operator
//
  if (&source == this) return *this;
  new (this) AliTPCSensorTemp(source);

  return *this;
}

TClonesArray * AliTPCSensorTemp::ReadList(const char *fname) {

   Int_t firstSensor, lastSensor;
   return ReadListInd(fname,firstSensor,lastSensor);
}

TClonesArray * AliTPCSensorTemp::ReadListInd(const char *fname,
                                          Int_t& firstSensor,
					  Int_t& lastSensor ){
  //
  // read values from ascii file
  //
  TTree * tree = new TTree("asci","asci");
  tree->ReadFile(fname,"");

  Int_t nentries = tree->GetEntries();
  Int_t sensor=0;
  Int_t sector=0;
  char  type[100];
  char  side[100];
  Int_t num=0;
  Int_t echa=0;
  //Double_t x=0;
  //Double_t y=0;
  //Double_t z=0;
  //String_t namedtp[100];

  tree->SetBranchAddress("Sensor",&sensor);
  tree->SetBranchAddress("Type",&type);
  tree->SetBranchAddress("Side",&side);
  tree->SetBranchAddress("Sec",&sector);
  tree->SetBranchAddress("Num",&num);
  tree->SetBranchAddress("ECha",&echa);
  //tree->SetBranchAddress("X",&x);
  //tree->SetBranchAddress("Y",&y);
  //tree->SetBranchAddress("Z",&z);

  firstSensor = (Int_t)tree->GetMinimum("ECha");
  lastSensor = (Int_t)tree->GetMaximum("ECha");

  TClonesArray * array = new TClonesArray("AliTPCSensorTemp",nentries);

  for (Int_t isensor=0; isensor<nentries; isensor++){
    AliTPCSensorTemp * temp = new ((*array)[isensor])AliTPCSensorTemp;
    tree->GetEntry(isensor);
    temp->SetId(sensor);
    temp->SetIdDCS(echa);
    if (side[0]=='C') temp->SetSide(1);
    temp->SetSector(sector);
    temp->SetNum(num);
    //temp->SetType(type);
    if (bcmp(type,"ROC",3)==0) temp->SetType(0);
    if (bcmp(type,"OFC",3)==0) temp->SetType(1);
    if (bcmp(type,"IFC",3)==0) temp->SetType(2);
    if (bcmp(type,"TPC",3)==0) temp->SetType(3);
    if (bcmp(type,"ELM",3)==0) temp->SetType(4);
    if (bcmp(type,"TS",2)==0)  temp->SetType(5);
    if (bcmp(type,"COOL",3)==0)temp->SetType(6);
    //temp->SetX(x);

    if (temp->GetType()==0){
	temp->SetX(TMath::Cos((2*sector+1)*0.1745)*(83+(num+1)*30));
    }
    if ((temp->GetType()==1) || (temp->GetType()==4)){
      temp->SetX(TMath::Cos((2*sector+1)*0.1745)*260);
    }
    if ((temp->GetType()==2) || (temp->GetType()==3)){
      temp->SetX(TMath::Cos((2*sector+1)*0.1745)*83);
    }
    if ((temp->GetType()==5) || (temp->GetType()==6)){
      temp->SetX(0);
    }

    //temp->SetY(y);
    if (temp->GetType()==0){
	  temp->SetY(TMath::Sin((2*sector+1)*0.1745)*(83+(num+1)*30));
    }
    if ((temp->GetType()==1) || (temp->GetType()==4)){
      temp->SetY(TMath::Sin((2*sector+1)*0.1745)*260);
    }
    if ((temp->GetType()==2) || (temp->GetType()==3)){
      temp->SetY(TMath::Sin((2*sector+1)*0.1745)*83);
    }
    if ((temp->GetType()==5) || (temp->GetType()==6)){
      temp->SetY(0);
    }
    //temp->SetZ(z);
    if ((temp->GetType()==0 || temp->GetType()==3 || temp->GetType()==4 || temp->GetType()==5 || temp->GetType()==6) && temp->GetSide()==0) {
      temp->SetZ(260);
      }
    if ((temp->GetType()==0 || temp->GetType()==3 || temp->GetType()==4 || temp->GetType()==5 || temp->GetType()==6) && temp->GetSide()==1){
      temp->SetZ(-260);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==0)) {
      temp->SetZ(250);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==1)) {
      temp->SetZ(180);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==2)) {
      temp->SetZ(60);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==3)) {
      temp->SetZ(-60);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==4)) {
      temp->SetZ(-180);
      }
    if((temp->GetType()==1 || temp->GetType()==2) && (num==5)) {
      temp->SetZ(-250);
      }
    Char_t chname[1000];
    sprintf(chname,"tpc_temp:PT_%i.Temperature",echa);
    temp->SetName(chname);
  }
  delete tree;
  return array;
}
<|endoftext|>


<commit_before>/***********************************************************************************
** MIT License                                                                    **
**                                                                                **
** Copyright (c) 2018 Victor DENIS (victordenis01@gmail.com)                      **
**                                                                                **
** Permission is hereby granted, free of charge, to any person obtaining a copy   **
** of this software and associated documentation files (the "Software"), to deal  **
** in the Software without restriction, including without limitation the rights   **
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      **
** copies of the Software, and to permit persons to whom the Software is          **
** furnished to do so, subject to the following conditions:                       **
**                                                                                **
** The above copyright notice and this permission notice shall be included in all **
** copies or substantial portions of the Software.                                **
**                                                                                **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       **
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    **
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         **
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  **
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  **
** SOFTWARE.                                                                      **
***********************************************************************************/

#include "TitleBar.hpp"

#include <QDesktopWidget>
#include <QScreen>

#include <QSettings>
#include <QtWidgets/QMessageBox>

#include "Application.hpp"

#include "Bookmarks/AddBookmarkDialog.hpp"
#include "Bookmarks/BookmarksToolBar.hpp"

#include "Widgets/Tab/TabWidget.hpp"

namespace Sn {
TitleBar::TitleBar(BookmarksModel* model, BrowserWindow* window, bool showBookmarks) :
		QWidget(window),
		m_window(window),
		m_showBookmarks(showBookmarks)
{
	m_bookmarksToolbar = new BookmarksToolBar(model, m_window);
	m_controlsToolbar = new QToolBar(m_window);

	m_bookmarksToolbar->setFloatable(false);
	m_bookmarksToolbar->installEventFilter(this);
	m_bookmarksToolbar->setContextMenuPolicy(Qt::CustomContextMenu);
	m_controlsToolbar->setFloatable(false);
	m_controlsToolbar->installEventFilter(this);
	m_controlsToolbar->setObjectName(QLatin1String("title-bar"));
	m_controlsToolbar->setContextMenuPolicy(Qt::CustomContextMenu);

	connect(m_bookmarksToolbar, &BookmarksToolBar::orientationChanged, this, &TitleBar::build);
	connect(m_controlsToolbar, &QToolBar::orientationChanged, this, &TitleBar::build);

	restoreToolBarsPositions();

	m_sizePreview = new QFrame(this);
	m_sizePreview->setObjectName(QLatin1String("window-sizepreview"));
	m_sizePreview->setStyleSheet("window-sizepreview{background: rgba(66, 134, 244, 0.5);}");
	m_sizePreview->setAttribute(Qt::WA_TransparentForMouseEvents);
	m_sizePreview->hide();

	build();
}

TitleBar::~TitleBar()
{
	// Empty
}

void TitleBar::setTitle(const QString& title)
{
	if (!m_title)
		return;

	m_title->setText(title);
}

void TitleBar::setShowBookmark(bool show)
{
	m_showBookmarks = show;
	build();
}

void TitleBar::saveToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	settings.setValue("bookmarks/area", static_cast<int>(m_window->toolBarArea(m_bookmarksToolbar)));
	settings.setValue("bookmarks/locked", m_bookmarksToolbar->isMovable());
	settings.setValue("controls/area", static_cast<int>(m_window->toolBarArea(m_controlsToolbar)));
	settings.setValue("controls/locked", m_controlsToolbar->isMovable());

	settings.endGroup();
}

void TitleBar::restoreToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("bookmarks/area", Qt::TopToolBarArea).toInt()), m_bookmarksToolbar);
	m_bookmarksToolbar->setMovable(settings.value("bookmarks/locked", true).toBool());
	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("controls/area", Qt::TopToolBarArea).toInt()), m_controlsToolbar);
	m_controlsToolbar->setMovable(settings.value("controls/locked", true).toBool());

	settings.endGroup();
}

bool TitleBar::isWindowMaximized() const
{
	//return m_window->geometry() == Application::desktop()->availableGeometry(m_window);
	return m_isMaximized;
}

bool TitleBar::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == QEvent::MouseButtonPress) {
		mousePressEvent(static_cast<QToolBar*>(obj), static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseMove) {
		mouseMoveEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonRelease) {
		mouseReleaseEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonDblClick) {
		mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::ContextMenu) {
		contextMenuEvent(obj, static_cast<QContextMenuEvent*>(event));
	}
	return QObject::eventFilter(obj, event);
}

void TitleBar::mousePressEvent(QToolBar* toolBar, QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton && ((event->x() >= 10 && toolBar->orientation() == Qt::Horizontal) ||
											  (event->y() >= 10 && toolBar->orientation() == Qt::Vertical))) {
		m_offset = event->globalPos() - m_window->frameGeometry().topLeft();
		m_canMove = true;
		event->accept();
	}
	else
		m_canMove = false;

	QWidget::mousePressEvent(event);
}

void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton && m_canMove) {
		if (isWindowMaximized() || m_isOnSide) {
			m_window->resize(m_geometry.size());
			m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
			m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));

			m_isMaximized = false;
			m_isOnSide = false;
		}

		m_window->move(event->globalPos() - m_offset);
		event->accept();
	}

	if (QCursor::pos(Application::screenAt(QCursor::pos())).y() <= 0) {
		m_sizePreview->move(0, 0);
		m_sizePreview->resize(1920, 1080);
		m_sizePreview->show();
	}
	else {
		m_sizePreview->hide();
	}

	QWidget::mouseMoveEvent(event);
}

void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
	QScreen *screen = Application::screenAt(QCursor::pos());
	if (QCursor::pos(screen).y() <= 0) {
		toggleMaximize(true);
	}

	// The move function don't move properly, i need to remove 6 and 8 pixels.
	if (QCursor::pos(screen).x() <= 0) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move((screen->size().width() * Application::screens().indexOf(screen)) - 6, 0);

		m_isOnSide = true;
	}
	// There is 1 px missing on Windows for mouse position
	else if (QCursor::pos(screen).x() >= screen->size().width() - 2) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move((screen->size().width() / 2 * (Application::screens().indexOf(screen) + 1)) - 8, 0);

		m_isOnSide = true;
	}

	m_sizePreview->hide();

	QWidget::mouseReleaseEvent(event);
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton) {
		toggleMaximize();
	}
}

void TitleBar::contextMenuEvent(QObject* obj, QContextMenuEvent* event)
{
	QMenu menu{};
	QAction* hideShowAction{menu.addAction(tr("Show Bookmarks Bar"))};

	hideShowAction->setCheckable(true);
	hideShowAction->setChecked(m_showBookmarks);
	connect(hideShowAction, &QAction::toggled, this, [=]() {
		setShowBookmark(!m_showBookmarks);
		emit toggleBookmarksBar(m_showBookmarks);
	});

	QAction* addBookmark(menu.addAction(tr("Add Bookmark")));

	connect(addBookmark, &QAction::toggled, this, []() {
		TabWidget* tabWidget = Application::instance()->getWindow()->tabWidget();
		AddBookmarkDialog* dialog{
				new AddBookmarkDialog(tabWidget->weTab()->url().toString(), tabWidget->weTab()->title(), tabWidget,
									  Application::instance()->bookmarksManager())};
	});

	if (obj != nullptr) {
		QToolBar* toolbar = qobject_cast<QToolBar*>(obj);
		QAction* lockToolbar(menu.addAction(tr("Lock Toolbar")));

		lockToolbar->setCheckable(true);
		lockToolbar->setChecked(!toolbar->isMovable());

		connect(lockToolbar, &QAction::toggled, this, [=]() {
			toolbar->setMovable(!toolbar->isMovable());
			Application::instance()->saveSession();
		});
	}

	const QPoint position{ event->globalPos() };
	QPoint point{ position.x(), position.y() + 1 };
	menu.exec(point);
}

void TitleBar::build()
{
#ifdef Q_OS_WIN
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();

	m_controlsToolbar->clear();

	m_title = new QLabel(m_window->windowTitle(), m_controlsToolbar);
	m_closeButton = new QToolButton(m_controlsToolbar);
	m_toggleMaximize = new QToolButton(m_controlsToolbar);
	m_minimize = new QToolButton(m_controlsToolbar);

	m_title->setObjectName(QLatin1String("titlebar-title"));

	m_closeButton->setObjectName(QLatin1String("titlebar-button-close"));
	m_closeButton->setIcon(Application::getAppIcon("tb-close", "titlebar"));

	m_toggleMaximize->setObjectName(
			QLatin1String(isWindowMaximized() ? "titlebar-button-reverse-maximize" : "titlebar-button-maximize"));
	m_toggleMaximize->setIcon(isWindowMaximized() ? Application::getAppIcon("tb-revert-maximize", "titlebar") :
							  Application::getAppIcon("tb-maximize", "titlebar"));

	m_minimize->setObjectName(QLatin1String("titlebar-button-minimize"));
	m_minimize->setIcon(Application::getAppIcon("tb-minimize", "titlebar"));

	connect(m_closeButton, &QToolButton::clicked, this, &TitleBar::closeWindow);
	connect(m_toggleMaximize, &QToolButton::clicked, this, &TitleBar::toggleMaximize);
	connect(m_minimize, &QToolButton::clicked, this, &TitleBar::minimize);

	QWidget* firstSpacer{new QWidget(m_controlsToolbar)};
	QWidget* secondSpacer{new QWidget(m_controlsToolbar)};

	if (m_controlsToolbar->orientation() == Qt::Horizontal) {
		firstSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
		secondSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
	}
	else if (m_controlsToolbar->orientation() == Qt::Vertical) {
		firstSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
		secondSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
	}

	m_controlsToolbar->addWidget(firstSpacer);
	m_controlsToolbar->addWidget(m_title);
	m_controlsToolbar->addWidget(secondSpacer);
	m_controlsToolbar->addWidget(m_minimize);
	m_controlsToolbar->addWidget(m_toggleMaximize);
	m_controlsToolbar->addWidget(m_closeButton);
#else
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();
#endif

	Application::instance()->saveSession();
}

void TitleBar::closeWindow()
{
	m_window->close();
}

void TitleBar::toggleMaximize(bool forceMaximize)
{
	if (isWindowMaximized() && !forceMaximize) {
		if (m_window->isFullScreen())
			m_window->showNormal();

		m_window->setGeometry(m_geometry);
		m_isMaximized = false;

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));
	}
	else {
		if (!m_isOnSide)
			m_geometry = m_window->geometry();

		m_window->setGeometry(Application::desktop()->availableGeometry(m_window));
		m_isMaximized = true;

		m_window->showNormal();

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-reverse-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-revert-maximize", "titlebar"));
	}
}

void TitleBar::minimize()
{
	m_window->showMinimized();
}
}
<commit_msg>[Try] To fix multiple screen issue<commit_after>/***********************************************************************************
** MIT License                                                                    **
**                                                                                **
** Copyright (c) 2018 Victor DENIS (victordenis01@gmail.com)                      **
**                                                                                **
** Permission is hereby granted, free of charge, to any person obtaining a copy   **
** of this software and associated documentation files (the "Software"), to deal  **
** in the Software without restriction, including without limitation the rights   **
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      **
** copies of the Software, and to permit persons to whom the Software is          **
** furnished to do so, subject to the following conditions:                       **
**                                                                                **
** The above copyright notice and this permission notice shall be included in all **
** copies or substantial portions of the Software.                                **
**                                                                                **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       **
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    **
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         **
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  **
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  **
** SOFTWARE.                                                                      **
***********************************************************************************/

#include "TitleBar.hpp"

#include <QDesktopWidget>
#include <QScreen>

#include <QSettings>
#include <QtWidgets/QMessageBox>

#include "Application.hpp"

#include "Bookmarks/AddBookmarkDialog.hpp"
#include "Bookmarks/BookmarksToolBar.hpp"

#include "Widgets/Tab/TabWidget.hpp"

namespace Sn {
TitleBar::TitleBar(BookmarksModel* model, BrowserWindow* window, bool showBookmarks) :
		QWidget(window),
		m_window(window),
		m_showBookmarks(showBookmarks)
{
	m_bookmarksToolbar = new BookmarksToolBar(model, m_window);
	m_controlsToolbar = new QToolBar(m_window);

	m_bookmarksToolbar->setFloatable(false);
	m_bookmarksToolbar->installEventFilter(this);
	m_bookmarksToolbar->setContextMenuPolicy(Qt::CustomContextMenu);
	m_controlsToolbar->setFloatable(false);
	m_controlsToolbar->installEventFilter(this);
	m_controlsToolbar->setObjectName(QLatin1String("title-bar"));
	m_controlsToolbar->setContextMenuPolicy(Qt::CustomContextMenu);

	connect(m_bookmarksToolbar, &BookmarksToolBar::orientationChanged, this, &TitleBar::build);
	connect(m_controlsToolbar, &QToolBar::orientationChanged, this, &TitleBar::build);

	restoreToolBarsPositions();

	m_sizePreview = new QFrame(this);
	m_sizePreview->setObjectName(QLatin1String("window-sizepreview"));
	m_sizePreview->setStyleSheet("window-sizepreview{background: rgba(66, 134, 244, 0.5);}");
	m_sizePreview->setAttribute(Qt::WA_TransparentForMouseEvents);
	m_sizePreview->hide();

	build();
}

TitleBar::~TitleBar()
{
	// Empty
}

void TitleBar::setTitle(const QString& title)
{
	if (!m_title)
		return;

	m_title->setText(title);
}

void TitleBar::setShowBookmark(bool show)
{
	m_showBookmarks = show;
	build();
}

void TitleBar::saveToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	settings.setValue("bookmarks/area", static_cast<int>(m_window->toolBarArea(m_bookmarksToolbar)));
	settings.setValue("bookmarks/locked", m_bookmarksToolbar->isMovable());
	settings.setValue("controls/area", static_cast<int>(m_window->toolBarArea(m_controlsToolbar)));
	settings.setValue("controls/locked", m_controlsToolbar->isMovable());

	settings.endGroup();
}

void TitleBar::restoreToolBarsPositions()
{
	QSettings settings{};

	settings.beginGroup("TitleBar");

	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("bookmarks/area", Qt::TopToolBarArea).toInt()), m_bookmarksToolbar);
	m_bookmarksToolbar->setMovable(settings.value("bookmarks/locked", true).toBool());
	m_window->addToolBar(static_cast<Qt::ToolBarArea>(settings.value("controls/area", Qt::TopToolBarArea).toInt()), m_controlsToolbar);
	m_controlsToolbar->setMovable(settings.value("controls/locked", true).toBool());

	settings.endGroup();
}

bool TitleBar::isWindowMaximized() const
{
	//return m_window->geometry() == Application::desktop()->availableGeometry(m_window);
	return m_isMaximized;
}

bool TitleBar::eventFilter(QObject* obj, QEvent* event)
{
	if (event->type() == QEvent::MouseButtonPress) {
		mousePressEvent(static_cast<QToolBar*>(obj), static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseMove) {
		mouseMoveEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonRelease) {
		mouseReleaseEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::MouseButtonDblClick) {
		mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
	}
	else if (event->type() == QEvent::ContextMenu) {
		contextMenuEvent(obj, static_cast<QContextMenuEvent*>(event));
	}
	return QObject::eventFilter(obj, event);
}

void TitleBar::mousePressEvent(QToolBar* toolBar, QMouseEvent* event)
{
	if (event->button() == Qt::LeftButton && ((event->x() >= 10 && toolBar->orientation() == Qt::Horizontal) ||
											  (event->y() >= 10 && toolBar->orientation() == Qt::Vertical))) {
		m_offset = event->globalPos() - m_window->frameGeometry().topLeft();
		m_canMove = true;
		event->accept();
	}
	else
		m_canMove = false;

	QWidget::mousePressEvent(event);
}

void TitleBar::mouseMoveEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton && m_canMove) {
		if (isWindowMaximized() || m_isOnSide) {
			m_window->resize(m_geometry.size());
			m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
			m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));

			m_isMaximized = false;
			m_isOnSide = false;
		}

		m_window->move(event->globalPos() - m_offset);
		event->accept();
	}

	if (QCursor::pos(Application::screenAt(QCursor::pos())).y() <= 0) {
		m_sizePreview->move(0, 0);
		m_sizePreview->resize(1920, 1080);
		m_sizePreview->show();
	}
	else {
		m_sizePreview->hide();
	}

	QWidget::mouseMoveEvent(event);
}

void TitleBar::mouseReleaseEvent(QMouseEvent* event)
{
	QScreen *screen = Application::screenAt(QCursor::pos());
	if (QCursor::pos(screen).y() <= 0) {
		toggleMaximize(true);
	}

	// The move function don't move properly, i need to remove 6 and 8 pixels.
	if (QCursor::pos(screen).x() <= 0) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move(screen->geometry().topLeft().x() - 6, 0);

		m_isOnSide = true;
	}
	// There is 1 px missing on Windows for mouse position
	else if (QCursor::pos(screen).x() >= screen->size().width() - 2) {
		m_geometry = m_window->geometry();
		m_window->resize(screen->size().width() / 2, screen->availableGeometry().height());
		m_window->move((screen->geometry().topRight().x() / 2) - 8, 0);

		m_isOnSide = true;
	}

	m_sizePreview->hide();

	QWidget::mouseReleaseEvent(event);
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
	if (event->buttons() & Qt::LeftButton) {
		toggleMaximize();
	}
}

void TitleBar::contextMenuEvent(QObject* obj, QContextMenuEvent* event)
{
	QMenu menu{};
	QAction* hideShowAction{menu.addAction(tr("Show Bookmarks Bar"))};

	hideShowAction->setCheckable(true);
	hideShowAction->setChecked(m_showBookmarks);
	connect(hideShowAction, &QAction::toggled, this, [=]() {
		setShowBookmark(!m_showBookmarks);
		emit toggleBookmarksBar(m_showBookmarks);
	});

	QAction* addBookmark(menu.addAction(tr("Add Bookmark")));

	connect(addBookmark, &QAction::toggled, this, []() {
		TabWidget* tabWidget = Application::instance()->getWindow()->tabWidget();
		AddBookmarkDialog* dialog{
				new AddBookmarkDialog(tabWidget->weTab()->url().toString(), tabWidget->weTab()->title(), tabWidget,
									  Application::instance()->bookmarksManager())};
	});

	if (obj != nullptr) {
		QToolBar* toolbar = qobject_cast<QToolBar*>(obj);
		QAction* lockToolbar(menu.addAction(tr("Lock Toolbar")));

		lockToolbar->setCheckable(true);
		lockToolbar->setChecked(!toolbar->isMovable());

		connect(lockToolbar, &QAction::toggled, this, [=]() {
			toolbar->setMovable(!toolbar->isMovable());
			Application::instance()->saveSession();
		});
	}

	const QPoint position{ event->globalPos() };
	QPoint point{ position.x(), position.y() + 1 };
	menu.exec(point);
}

void TitleBar::build()
{
#ifdef Q_OS_WIN
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();

	m_controlsToolbar->clear();

	m_title = new QLabel(m_window->windowTitle(), m_controlsToolbar);
	m_closeButton = new QToolButton(m_controlsToolbar);
	m_toggleMaximize = new QToolButton(m_controlsToolbar);
	m_minimize = new QToolButton(m_controlsToolbar);

	m_title->setObjectName(QLatin1String("titlebar-title"));

	m_closeButton->setObjectName(QLatin1String("titlebar-button-close"));
	m_closeButton->setIcon(Application::getAppIcon("tb-close", "titlebar"));

	m_toggleMaximize->setObjectName(
			QLatin1String(isWindowMaximized() ? "titlebar-button-reverse-maximize" : "titlebar-button-maximize"));
	m_toggleMaximize->setIcon(isWindowMaximized() ? Application::getAppIcon("tb-revert-maximize", "titlebar") :
							  Application::getAppIcon("tb-maximize", "titlebar"));

	m_minimize->setObjectName(QLatin1String("titlebar-button-minimize"));
	m_minimize->setIcon(Application::getAppIcon("tb-minimize", "titlebar"));

	connect(m_closeButton, &QToolButton::clicked, this, &TitleBar::closeWindow);
	connect(m_toggleMaximize, &QToolButton::clicked, this, &TitleBar::toggleMaximize);
	connect(m_minimize, &QToolButton::clicked, this, &TitleBar::minimize);

	QWidget* firstSpacer{new QWidget(m_controlsToolbar)};
	QWidget* secondSpacer{new QWidget(m_controlsToolbar)};

	if (m_controlsToolbar->orientation() == Qt::Horizontal) {
		firstSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
		secondSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
	}
	else if (m_controlsToolbar->orientation() == Qt::Vertical) {
		firstSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
		secondSpacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
	}

	m_controlsToolbar->addWidget(firstSpacer);
	m_controlsToolbar->addWidget(m_title);
	m_controlsToolbar->addWidget(secondSpacer);
	m_controlsToolbar->addWidget(m_minimize);
	m_controlsToolbar->addWidget(m_toggleMaximize);
	m_controlsToolbar->addWidget(m_closeButton);
#else
	if (m_showBookmarks)
		m_bookmarksToolbar->show();
	else
		m_bookmarksToolbar->hide();
#endif

	Application::instance()->saveSession();
}

void TitleBar::closeWindow()
{
	m_window->close();
}

void TitleBar::toggleMaximize(bool forceMaximize)
{
	if (isWindowMaximized() && !forceMaximize) {
		if (m_window->isFullScreen())
			m_window->showNormal();

		m_window->setGeometry(m_geometry);
		m_isMaximized = false;

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-maximize", "titlebar"));
	}
	else {
		if (!m_isOnSide)
			m_geometry = m_window->geometry();

		m_window->setGeometry(Application::desktop()->availableGeometry(m_window));
		m_isMaximized = true;

		m_window->showNormal();

		m_toggleMaximize->setObjectName(QLatin1String("titlebar-button-reverse-maximize"));
		m_toggleMaximize->setIcon(Application::getAppIcon("tb-revert-maximize", "titlebar"));
	}
}

void TitleBar::minimize()
{
	m_window->showMinimized();
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mirants Lu. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "voyager/core/eventloop.h"

#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <algorithm>
#include <utility>

#include "voyager/core/dispatch.h"
#include "voyager/core/event_poll.h"
#include "voyager/core/event_select.h"
#include "voyager/core/tcp_connection.h"
#include "voyager/core/timerlist.h"
#include "voyager/util/logging.h"
#include "voyager/util/timeops.h"

#ifdef __linux__
#include "voyager/core/event_epoll.h"
#else
#include "voyager/core/event_kqueue.h"
#endif

namespace voyager {
namespace {

thread_local EventLoop* runloop = nullptr;

class IgnoreSIGPIPE {
 public:
  IgnoreSIGPIPE() { ::signal(SIGPIPE, SIG_IGN); }
};

IgnoreSIGPIPE ignore;

}  // anonymous namespace

static EventPoller* CreatePoller(PollType type, EventLoop* loop) {
  EventPoller* poller = nullptr;
  switch (type) {
    case kSelect:
      poller = new EventSelect(loop);
      break;
    case kPoll:
      poller = new EventPoll(loop);
      break;
    case kEpoll:
#ifdef __linux__
      poller = new EventEpoll(loop);
#else
      poller = new EventKqueue(loop);
#endif
      break;
    default:
      VOYAGER_LOG(FATAL) << "error poll type.";
      assert(false);
      break;
  }
  return poller;
}

std::atomic<int> EventLoop::all_connection_size_;

EventLoop* EventLoop::RunLoop() { return runloop; }

EventLoop::EventLoop(PollType type)
    : tid_(std::this_thread::get_id()),
      type_(type),
      exit_(false),
      run_(false),
      connection_size_(0),
      poller_(CreatePoller(type, this)),
      timers_(new TimerList(this)) {
  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, wakeup_fd_) == -1) {
    VOYAGER_LOG(FATAL) << "socketpair failed";
  }
  wakeup_dispatch_.reset(new Dispatch(this, wakeup_fd_[0]));

  VOYAGER_LOG(DEBUG) << "EventLoop " << this << " created in thread " << tid_;
  if (runloop) {
    VOYAGER_LOG(FATAL) << "Another EventLoop " << runloop
                       << " exists in this thread " << tid_;
  } else {
    runloop = this;
  }

  wakeup_dispatch_->SetReadCallback(std::bind(&EventLoop::HandleRead, this));
  wakeup_dispatch_->EnableRead();
}

EventLoop::~EventLoop() {
  runloop = nullptr;
  VOYAGER_LOG(DEBUG) << "EventLoop " << this << " of thread " << tid_
                     << " destructs in thread " << std::this_thread::get_id();

  wakeup_dispatch_->DisableAll();
  wakeup_dispatch_->RemoveEvents();
  ::close(wakeup_fd_[0]);
  ::close(wakeup_fd_[1]);
}

void EventLoop::Loop() {
  AssertInMyLoop();
  exit_ = false;
  std::vector<Dispatch*> dispatches;

  while (!exit_) {
    dispatches.clear();
    static const uint64_t kPollTimeMs = 5000;
    uint64_t t = (timers_->TimeoutMicros() / 1000);
    int timeout = static_cast<int>(std::min(t, kPollTimeMs));
    poller_->Poll(timeout, &dispatches);
    timers_->RunTimerProcs();

    for (std::vector<Dispatch*>::iterator it = dispatches.begin();
         it != dispatches.end(); ++it) {
      (*it)->HandleEvent();
    }
    RunFuncs();
  }
}

void EventLoop::Exit() {
  RunInLoop([this]() { this->exit_ = true; });
}

void EventLoop::RunInLoop(const Func& func) {
  if (IsInMyLoop()) {
    func();
  } else {
    QueueInLoop(func);
  }
}

void EventLoop::QueueInLoop(const Func& func) {
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs_.push_back(func);
  }

  // "必要时"有两种情况：
  // 1、如果调用QueueInLoop()的线程不是IO线程，那么唤醒是必需的；
  // 2、如果在IO线程调用QueueInLoop(),而此时正在调用RunFuncQueue
  if (!IsInMyLoop() || run_) {
    WakeUp();
  }
}

void EventLoop::RunInLoop(Func&& func) {
  if (IsInMyLoop()) {
    func();
  } else {
    QueueInLoop(std::move(func));
  }
}

void EventLoop::QueueInLoop(Func&& func) {
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs_.push_back(std::move(func));
  }
  // "必要时"有两种情况：
  // 1、如果调用QueueInLoop()的线程不是IO线程，那么唤醒是必需的；
  // 2、如果在IO线程调用QueueInLoop(),而此时正在调用RunFuncQueue
  if (!IsInMyLoop() || run_) {
    WakeUp();
  }
}

TimerId EventLoop::RunAt(uint64_t micros_value, const TimerProcCallback& cb) {
  return timers_->Insert(micros_value, 0, cb);
}

TimerId EventLoop::RunAfter(uint64_t micros_delay,
                            const TimerProcCallback& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_delay;
  return timers_->Insert(micros_value, 0, cb);
}

TimerId EventLoop::RunEvery(uint64_t micros_interval,
                            const TimerProcCallback& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_interval;
  return timers_->Insert(micros_value, micros_interval, cb);
}

TimerId EventLoop::RunAt(uint64_t micros_value, TimerProcCallback&& cb) {
  return timers_->Insert(micros_value, 0, std::move(cb));
}

TimerId EventLoop::RunAfter(uint64_t micros_delay, TimerProcCallback&& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_delay;
  return timers_->Insert(micros_value, 0, std::move(cb));
}

TimerId EventLoop::RunEvery(uint64_t micros_interval, TimerProcCallback&& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_interval;
  return timers_->Insert(micros_value, micros_interval, std::move(cb));
}

void EventLoop::RemoveTimer(TimerId t) { timers_->Erase(t); }

void EventLoop::RemoveDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  poller_->RemoveDispatch(dispatch);
}

void EventLoop::UpdateDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  poller_->UpdateDispatch(dispatch);
}

bool EventLoop::HasDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  return poller_->HasDispatch(dispatch);
}

void EventLoop::AddConnection(const TcpConnectionPtr& ptr) {
  assert(ptr->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  assert(connections_.find(ptr->name()) == connections_.end());
  connections_[ptr->name()] = ptr;
  ++connection_size_;
  ++all_connection_size_;
}

void EventLoop::RemoveConnection(const TcpConnectionPtr& ptr) {
  assert(ptr->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  assert(connections_.find(ptr->name()) != connections_.end());
  connections_.erase(ptr->name());
  --connection_size_;
  --all_connection_size_;
}

void EventLoop::RunFuncs() {
  std::vector<Func> funcs;
  run_ = true;
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs.swap(funcs_);
  }
  for (std::vector<Func>::iterator it = funcs.begin(); it != funcs.end();
       ++it) {
    (*it)();
  }
  run_ = false;
}

void EventLoop::WakeUp() {
  uint64_t one = 0;
  ssize_t n = ::write(wakeup_fd_[1], &one, sizeof(one));
  if (n != sizeof(one)) {
    VOYAGER_LOG(ERROR) << "EventLoop::WakeUp - " << wakeup_fd_ << " writes "
                       << n << " bytes instead of 8";
  }
}

void EventLoop::HandleRead() {
  uint64_t one = 0;
  ssize_t n = ::read(wakeup_fd_[0], &one, sizeof(one));
  if (n != sizeof(one)) {
    VOYAGER_LOG(ERROR) << "EventLoop::HandleRead - " << wakeup_fd_ << " reads "
                       << n << " bytes instead of 8";
  }
}

void EventLoop::Abort() {
  VOYAGER_LOG(FATAL) << "EventLoop::Abort - (EventLoop " << this
                     << ") was created in tid_ = " << tid_
                     << ", current thread's tid_ = "
                     << std::this_thread::get_id();
}

}  // namespace voyager
<commit_msg>use __thread to replace thread_local<commit_after>// Copyright (c) 2016 Mirants Lu. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "voyager/core/eventloop.h"

#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <algorithm>
#include <utility>

#include "voyager/core/dispatch.h"
#include "voyager/core/event_poll.h"
#include "voyager/core/event_select.h"
#include "voyager/core/tcp_connection.h"
#include "voyager/core/timerlist.h"
#include "voyager/util/logging.h"
#include "voyager/util/timeops.h"

#ifdef __linux__
#include "voyager/core/event_epoll.h"
#else
#include "voyager/core/event_kqueue.h"
#endif

namespace voyager {
namespace {

__thread EventLoop* runloop = nullptr;

class IgnoreSIGPIPE {
 public:
  IgnoreSIGPIPE() { ::signal(SIGPIPE, SIG_IGN); }
};

IgnoreSIGPIPE ignore;

}  // anonymous namespace

static EventPoller* CreatePoller(PollType type, EventLoop* loop) {
  EventPoller* poller = nullptr;
  switch (type) {
    case kSelect:
      poller = new EventSelect(loop);
      break;
    case kPoll:
      poller = new EventPoll(loop);
      break;
    case kEpoll:
#ifdef __linux__
      poller = new EventEpoll(loop);
#else
      poller = new EventKqueue(loop);
#endif
      break;
    default:
      VOYAGER_LOG(FATAL) << "error poll type.";
      assert(false);
      break;
  }
  return poller;
}

std::atomic<int> EventLoop::all_connection_size_;

EventLoop* EventLoop::RunLoop() { return runloop; }

EventLoop::EventLoop(PollType type)
    : tid_(std::this_thread::get_id()),
      type_(type),
      exit_(false),
      run_(false),
      connection_size_(0),
      poller_(CreatePoller(type, this)),
      timers_(new TimerList(this)) {
  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, wakeup_fd_) == -1) {
    VOYAGER_LOG(FATAL) << "socketpair failed";
  }
  wakeup_dispatch_.reset(new Dispatch(this, wakeup_fd_[0]));

  VOYAGER_LOG(DEBUG) << "EventLoop " << this << " created in thread " << tid_;
  if (runloop) {
    VOYAGER_LOG(FATAL) << "Another EventLoop " << runloop
                       << " exists in this thread " << tid_;
  } else {
    runloop = this;
  }

  wakeup_dispatch_->SetReadCallback(std::bind(&EventLoop::HandleRead, this));
  wakeup_dispatch_->EnableRead();
}

EventLoop::~EventLoop() {
  runloop = nullptr;
  VOYAGER_LOG(DEBUG) << "EventLoop " << this << " of thread " << tid_
                     << " destructs in thread " << std::this_thread::get_id();

  wakeup_dispatch_->DisableAll();
  wakeup_dispatch_->RemoveEvents();
  ::close(wakeup_fd_[0]);
  ::close(wakeup_fd_[1]);
}

void EventLoop::Loop() {
  AssertInMyLoop();
  exit_ = false;
  std::vector<Dispatch*> dispatches;

  while (!exit_) {
    dispatches.clear();
    static const uint64_t kPollTimeMs = 5000;
    uint64_t t = (timers_->TimeoutMicros() / 1000);
    int timeout = static_cast<int>(std::min(t, kPollTimeMs));
    poller_->Poll(timeout, &dispatches);
    timers_->RunTimerProcs();

    for (std::vector<Dispatch*>::iterator it = dispatches.begin();
         it != dispatches.end(); ++it) {
      (*it)->HandleEvent();
    }
    RunFuncs();
  }
}

void EventLoop::Exit() {
  RunInLoop([this]() { this->exit_ = true; });
}

void EventLoop::RunInLoop(const Func& func) {
  if (IsInMyLoop()) {
    func();
  } else {
    QueueInLoop(func);
  }
}

void EventLoop::QueueInLoop(const Func& func) {
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs_.push_back(func);
  }

  // "必要时"有两种情况：
  // 1、如果调用QueueInLoop()的线程不是IO线程，那么唤醒是必需的；
  // 2、如果在IO线程调用QueueInLoop(),而此时正在调用RunFuncQueue
  if (!IsInMyLoop() || run_) {
    WakeUp();
  }
}

void EventLoop::RunInLoop(Func&& func) {
  if (IsInMyLoop()) {
    func();
  } else {
    QueueInLoop(std::move(func));
  }
}

void EventLoop::QueueInLoop(Func&& func) {
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs_.push_back(std::move(func));
  }
  // "必要时"有两种情况：
  // 1、如果调用QueueInLoop()的线程不是IO线程，那么唤醒是必需的；
  // 2、如果在IO线程调用QueueInLoop(),而此时正在调用RunFuncQueue
  if (!IsInMyLoop() || run_) {
    WakeUp();
  }
}

TimerId EventLoop::RunAt(uint64_t micros_value, const TimerProcCallback& cb) {
  return timers_->Insert(micros_value, 0, cb);
}

TimerId EventLoop::RunAfter(uint64_t micros_delay,
                            const TimerProcCallback& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_delay;
  return timers_->Insert(micros_value, 0, cb);
}

TimerId EventLoop::RunEvery(uint64_t micros_interval,
                            const TimerProcCallback& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_interval;
  return timers_->Insert(micros_value, micros_interval, cb);
}

TimerId EventLoop::RunAt(uint64_t micros_value, TimerProcCallback&& cb) {
  return timers_->Insert(micros_value, 0, std::move(cb));
}

TimerId EventLoop::RunAfter(uint64_t micros_delay, TimerProcCallback&& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_delay;
  return timers_->Insert(micros_value, 0, std::move(cb));
}

TimerId EventLoop::RunEvery(uint64_t micros_interval, TimerProcCallback&& cb) {
  uint64_t micros_value = timeops::NowMicros() + micros_interval;
  return timers_->Insert(micros_value, micros_interval, std::move(cb));
}

void EventLoop::RemoveTimer(TimerId t) { timers_->Erase(t); }

void EventLoop::RemoveDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  poller_->RemoveDispatch(dispatch);
}

void EventLoop::UpdateDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  poller_->UpdateDispatch(dispatch);
}

bool EventLoop::HasDispatch(Dispatch* dispatch) {
  assert(dispatch->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  return poller_->HasDispatch(dispatch);
}

void EventLoop::AddConnection(const TcpConnectionPtr& ptr) {
  assert(ptr->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  assert(connections_.find(ptr->name()) == connections_.end());
  connections_[ptr->name()] = ptr;
  ++connection_size_;
  ++all_connection_size_;
}

void EventLoop::RemoveConnection(const TcpConnectionPtr& ptr) {
  assert(ptr->OwnerEventLoop() == this);
  this->AssertInMyLoop();
  assert(connections_.find(ptr->name()) != connections_.end());
  connections_.erase(ptr->name());
  --connection_size_;
  --all_connection_size_;
}

void EventLoop::RunFuncs() {
  std::vector<Func> funcs;
  run_ = true;
  {
    std::lock_guard<std::mutex> lock(mutex_);
    funcs.swap(funcs_);
  }
  for (std::vector<Func>::iterator it = funcs.begin(); it != funcs.end();
       ++it) {
    (*it)();
  }
  run_ = false;
}

void EventLoop::WakeUp() {
  uint64_t one = 0;
  ssize_t n = ::write(wakeup_fd_[1], &one, sizeof(one));
  if (n != sizeof(one)) {
    VOYAGER_LOG(ERROR) << "EventLoop::WakeUp - " << wakeup_fd_ << " writes "
                       << n << " bytes instead of 8";
  }
}

void EventLoop::HandleRead() {
  uint64_t one = 0;
  ssize_t n = ::read(wakeup_fd_[0], &one, sizeof(one));
  if (n != sizeof(one)) {
    VOYAGER_LOG(ERROR) << "EventLoop::HandleRead - " << wakeup_fd_ << " reads "
                       << n << " bytes instead of 8";
  }
}

void EventLoop::Abort() {
  VOYAGER_LOG(FATAL) << "EventLoop::Abort - (EventLoop " << this
                     << ") was created in tid_ = " << tid_
                     << ", current thread's tid_ = "
                     << std::this_thread::get_id();
}

}  // namespace voyager
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <Context.h>
#include <Filter.h>
#include <Eval.h>
#include <Dates.h>
#include <main.h>
#include <i18n.h>
#include <CmdCalc.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdCalc::CmdCalc ()
{
  _keyword     = "calc";
  _usage       = "task          calc <expression>";
  _description = STRING_CMD_CALC_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdCalc::execute (std::string& output)
{
  // Configurable infix/postfix
  bool infix = true;
  if (context.config.get ("expressions") == "infix")
    infix = true;
  else if (context.config.get ("expressions") == "postfix")
    infix = false;

  // Create an evaluator with DOM access.
  Eval e;
  e.addSource (namedDates);
  e.addSource (domSource);
  e.ambiguity (false);  // TODO Could/should be configurable.
  e.debug (context.config.getBoolean ("debug"));

  // Compile all the args into one expression.
  std::string expression;
  std::vector <std::string> words = context.parser.getWords ();
  std::vector <std::string>::iterator word;
  for (word = words.begin (); word != words.end (); ++word)
    expression += *word + " ";

  // Evaluate according to preference.
  Variant result;
  if (infix)
    e.evaluateInfixExpression (expression, result);
  else
    e.evaluatePostfixExpression (expression, result);

  output = (std::string) result + "\n";
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>CmdCalc<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2014, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <Context.h>
#include <Filter.h>
#include <Eval.h>
#include <Dates.h>
#include <main.h>
#include <i18n.h>
#include <CmdCalc.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdCalc::CmdCalc ()
{
  _keyword     = "calc";
  _usage       = "task          calc <expression>";
  _description = STRING_CMD_CALC_USAGE;
  _read_only   = true;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdCalc::execute (std::string& output)
{
  // Configurable infix/postfix
  bool infix = true;
  if (context.config.get ("expressions") == "infix")
    infix = true;
  else if (context.config.get ("expressions") == "postfix")
    infix = false;

  // Create an evaluator with DOM access.
  Eval e;
  e.addSource (namedDates);
  e.addSource (domSource);
  e.ambiguity (false);  // TODO Configurable?
  e.debug (context.config.getBoolean ("debug"));

  // Compile all the args into one expression.
  std::string expression;
  std::vector <std::string> words = context.parser.getWords ();
  std::vector <std::string>::iterator word;
  for (word = words.begin (); word != words.end (); ++word)
    expression += *word + " ";

  // Evaluate according to preference.
  Variant result;
  if (infix)
    e.evaluateInfixExpression (expression, result);
  else
    e.evaluatePostfixExpression (expression, result);

  output = (std::string) result + "\n";
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include <agency/new_executor_traits.hpp>
#include <cassert>
#include <iostream>

#include "test_executors.hpp"

template<class Executor>
void test()
{
  using executor_type = Executor;

  {
    // returning void
    executor_type exec;

    int set_me_to_thirteen = 0;

    agency::new_executor_traits<executor_type>::execute(exec, [&]
    {
      set_me_to_thirteen = 13;
    });

    assert(set_me_to_thirteen == 13);
    assert(exec.valid());
  }

  {
    // returning int
    executor_type exec;

    auto result = agency::new_executor_traits<executor_type>::execute(exec, []
    {
      return 13;
    });

    assert(result == 13);
    assert(exec.valid());
  }
}

int main()
{
  using namespace test_executors;

  test<empty_executor>();
  test<single_agent_when_all_execute_and_select_executor>();
  test<multi_agent_when_all_execute_and_select_executor>();
  test<single_agent_then_execute_executor>();
  test<multi_agent_execute_returning_user_defined_container_executor>();

  std::cout << "OK" << std::endl;

  return 0;
}

<commit_msg>Test multi_agent_execute_returning_default_container executor with test_single_agent_execute.cpp.<commit_after>#include <agency/new_executor_traits.hpp>
#include <cassert>
#include <iostream>

#include "test_executors.hpp"

template<class Executor>
void test()
{
  using executor_type = Executor;

  {
    // returning void
    executor_type exec;

    int set_me_to_thirteen = 0;

    agency::new_executor_traits<executor_type>::execute(exec, [&]
    {
      set_me_to_thirteen = 13;
    });

    assert(set_me_to_thirteen == 13);
    assert(exec.valid());
  }

  {
    // returning int
    executor_type exec;

    auto result = agency::new_executor_traits<executor_type>::execute(exec, []
    {
      return 13;
    });

    assert(result == 13);
    assert(exec.valid());
  }
}

int main()
{
  using namespace test_executors;

  test<empty_executor>();
  test<single_agent_when_all_execute_and_select_executor>();
  test<multi_agent_when_all_execute_and_select_executor>();
  test<single_agent_then_execute_executor>();
  test<multi_agent_execute_returning_user_defined_container_executor>();
  test<multi_agent_execute_returning_default_container_executor>();

  std::cout << "OK" << std::endl;

  return 0;
}

<|endoftext|>