<commit_before>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 <NAME> <<EMAIL>>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

//! @example

#include <DO/Sara/Core/TicToc.hpp>
#include <DO/Sara/DisjointSets/DisjointSets.hpp>
#include <DO/Sara/FeatureDetectors/EdgeDetector.hpp>
#include <DO/Sara/FeatureDetectors/EdgePostProcessing.hpp>
#include <DO/Sara/FeatureDetectors/EdgeUtilities.hpp>
#include <DO/Sara/Geometry/Algorithms/Polyline.hpp>
#include <DO/Sara/Geometry/Tools/Utilities.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/VideoIO.hpp>

#include <future>

#include <omp.h>


using namespace std;
using namespace DO::Sara;


constexpr long double operator"" _percent(long double x)
{
  return x / 100;
}

constexpr long double operator"" _deg(long double x)
{
  return x * M_PI / 180;
}


// ========================================================================== //
// Shape Statistics of the Edge.
// ========================================================================== //
struct Rectangle
{
  const Eigen::Vector2d& center;
  const Eigen::Matrix2d& axes;
  const Eigen::Vector2d& lengths;

  Rectangle(const Eigen::Vector2d& c,  //
            const Eigen::Matrix2d& a,  //
            const Eigen::Vector2d& l)
    : center{c}
    , axes{a}
    , lengths{l}
  {
  }

  auto length_ratio() const
  {
    return lengths(0) / lengths(1);
  }

  auto line() const
  {
    return Projective::line(center.homogeneous().eval(),
                            (center + axes.col(0)).homogeneous().eval());
  }

  auto draw(ImageView<Rgb8>& detection, const Rgb8& color,  //
            const Point2d& c1, const double s) const -> void
  {
    const Vector2d u = axes.col(0);
    const Vector2d v = axes.col(1);
    auto p = std::array<Vector2d, 4>{
        c1 + s * (center + (lengths(0) + 0) * u + (lengths(1) + 0) * v),
        c1 + s * (center - (lengths(0) + 0) * u + (lengths(1) + 0) * v),
        c1 + s * (center - (lengths(0) + 0) * u - (lengths(1) + 0) * v),
        c1 + s * (center + (lengths(0) + 0) * u - (lengths(1) + 0) * v),
    };

    draw_line(detection, p[0].x(), p[0].y(), p[1].x(), p[1].y(), color, 2);
    draw_line(detection, p[1].x(), p[1].y(), p[2].x(), p[2].y(), color, 2);
    draw_line(detection, p[2].x(), p[2].y(), p[3].x(), p[3].y(), color, 2);
    draw_line(detection, p[3].x(), p[3].y(), p[0].x(), p[0].y(), color, 2);
  }
};


// ========================================================================== //
// Edge Grouping By Alignment
// ========================================================================== //
using Edge = std::vector<Eigen::Vector2d>;

struct EdgeAttributes
{
  const std::vector<Edge>& edges;
  const std::vector<Eigen::Vector2d>& centers;
  const std::vector<Eigen::Matrix2d>& axes;
  const std::vector<Eigen::Vector2d>& lengths;
};

struct EndPointGraph
{
  const EdgeAttributes& edge_attrs;

  // List of end points.
  std::vector<Point2d> endpoints;
  // Edge IDs to which the end point belongs to.
  std::vector<std::size_t> edge_ids;

  // Connect the end point to another point.
  // Cannot be in the same edge ids.
  Eigen::MatrixXd score;


  EndPointGraph(const EdgeAttributes& attrs)
    : edge_attrs{attrs}
  {
    endpoints.reserve(2 * edge_attrs.edges.size());
    edge_ids.reserve(2 * edge_attrs.edges.size());
    for (auto i = 0u; i < edge_attrs.edges.size(); ++i)
    {
      const auto& e = edge_attrs.edges[i];
      if (e.size() < 2)
        continue;

      if (length(e) < 5)
        continue;

      const auto& theta = std::abs(std::atan2(edge_attrs.axes[i](1, 0),  //
                                              edge_attrs.axes[i](0, 0)));
      if (theta < 5._deg || std::abs(M_PI - theta) < 5._deg)
        continue;

      endpoints.emplace_back(e.front());
      endpoints.emplace_back(e.back());

      edge_ids.emplace_back(i);
      edge_ids.emplace_back(i);
    }

    score = Eigen::MatrixXd(endpoints.size(), endpoints.size());
    score.fill(std::numeric_limits<double>::infinity());
  }

  auto edge(std::size_t i) const -> const Edge&
  {
    const auto& edge_id = edge_ids[i];
    return edge_attrs.edges[edge_id];
  }

  auto rect(std::size_t i) const
  {
    const auto& edge_id = edge_ids[i];
    return Rectangle{
        edge_attrs.centers[edge_id],  //
        edge_attrs.axes[edge_id],     //
        edge_attrs.lengths[edge_id]   //
    };
  }

  auto mark_plausible_alignments() -> void
  {
    // Tolerance of X degrees in the alignment error.<commit_msg>MAINT: tentative fix for VS 2017.<commit_after>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 <NAME> <<EMAIL>>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

//! @example

#include <DO/Sara/Core/TicToc.hpp>
#include <DO/Sara/DisjointSets/DisjointSets.hpp>
#include <DO/Sara/FeatureDetectors/EdgeDetector.hpp>
#include <DO/Sara/FeatureDetectors/EdgePostProcessing.hpp>
#include <DO/Sara/FeatureDetectors/EdgeUtilities.hpp>
#include <DO/Sara/Geometry/Algorithms/Polyline.hpp>
#include <DO/Sara/Geometry/Tools/Utilities.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/VideoIO.hpp>

#include <future>

#include <omp.h>


using namespace std;
using namespace DO::Sara;


constexpr long double operator"" _percent(long double x)
{
  return x / 100;
}

constexpr long double operator"" _deg(long double x)
{
  return x * M_PI / 180;
}


// ========================================================================== //
// Shape Statistics of the Edge.
// ========================================================================== //
struct Rectangle
{
  const Eigen::Vector2d& center;
  const Eigen::Matrix2d& axes;
  const Eigen::Vector2d& lengths;

  Rectangle(const Eigen::Vector2d& c,  //
            const Eigen::Matrix2d& a,  //
            const Eigen::Vector2d& l)
    : center{c}
    , axes{a}
    , lengths{l}
  {
  }

  auto length_ratio() const
  {
    return lengths(0) / lengths(1);
  }

  auto line() const
  {
    return Projective::line(center.homogeneous().eval(),
                            (center + axes.col(0)).homogeneous().eval());
  }

  auto draw(ImageView<Rgb8>& detection, const Rgb8& color,  //
            const Point2d& c1, const double s) const -> void
  {
    const Vector2d u = axes.col(0);
    const Vector2d v = axes.col(1);
    auto p = std::array<Vector2d, 4>{
        c1 + s * (center + (lengths(0) + 0) * u + (lengths(1) + 0) * v),
        c1 + s * (center - (lengths(0) + 0) * u + (lengths(1) + 0) * v),
        c1 + s * (center - (lengths(0) + 0) * u - (lengths(1) + 0) * v),
        c1 + s * (center + (lengths(0) + 0) * u - (lengths(1) + 0) * v),
    };

    draw_line(detection, p[0].x(), p[0].y(), p[1].x(), p[1].y(), color, 2);
    draw_line(detection, p[1].x(), p[1].y(), p[2].x(), p[2].y(), color, 2);
    draw_line(detection, p[2].x(), p[2].y(), p[3].x(), p[3].y(), color, 2);
    draw_line(detection, p[3].x(), p[3].y(), p[0].x(), p[0].y(), color, 2);
  }
};


// ========================================================================== //
// Edge Grouping By Alignment
// ========================================================================== //
using Edge = std::vector<Eigen::Vector2d>;

struct EdgeAttributes
{
  const std::vector<Edge>& edges;
  const std::vector<Eigen::Vector2d>& centers;
  const std::vector<Eigen::Matrix2d>& axes;
  const std::vector<Eigen::Vector2d>& lengths;
};

struct EndPointGraph
{
  const EdgeAttributes& edge_attrs;

  // List of end points.
  std::vector<Point2d> endpoints;
  // Edge IDs to which the end point belongs to.
  std::vector<std::size_t> edge_ids;

  // Connect the end point to another point.
  // Cannot be in the same edge ids.
  Eigen::MatrixXd score;


  EndPointGraph(const EdgeAttributes& attrs)
    : edge_attrs{attrs}
  {
    endpoints.reserve(2 * edge_attrs.edges.size());
    edge_ids.reserve(2 * edge_attrs.edges.size());
    for (auto i = 0u; i < edge_attrs.edges.size(); ++i)
    {
      const auto& e = edge_attrs.edges[i];
      if (e.size() < 2)
        continue;

      if (length(e) < 5)
        continue;

      const auto& theta = std::abs(std::atan2(edge_attrs.axes[i](1, 0),  //
                                              edge_attrs.axes[i](0, 0)));
      if (theta < 5._deg || std::abs(M_PI - theta) < 5._deg)
        continue;

      endpoints.emplace_back(e.front());
      endpoints.emplace_back(e.back());

      edge_ids.emplace_back(i);
      edge_ids.emplace_back(i);
    }

    score = Eigen::MatrixXd(endpoints.size(), endpoints.size());
    score.fill(std::numeric_limits<double>::infinity());
  }

  auto edge(std::size_t i) const -> const Edge&
  {
    const auto& edge_id = edge_ids[i];
    return edge_attrs.edges[edge_id];
  }

  auto rect(std::size_t i) const -> Rectangle
  {
    const auto& edge_id = edge_ids[i];
    return Rectangle{
        edge_attrs.centers[edge_id],  //
        edge_attrs.axes[edge_id],     //
        edge_attrs.lengths[edge_id]   //
    };
  }

  auto mark_plausible_alignments() -> void
  {
    // Tolerance of X degrees in the alignment error.
{'fraction_non_alphanumeric': 0.24362206312392862, 'fraction_numerical': 0.018553998184934962, 'mean_word_length': 3.177759056444819, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5449702', 'n_tokens_mistral': 3508, 'n_tokens_neox': 3269, 'n_words': 777}