Skip to content

Clipper2 slower than clipper1 #839

@Sachaaaaaa

Description

@Sachaaaaaa

Hi there,

I've been using Clipper for generating GDS files, and recently I migrated my code from Clipper 1 to Clipper 2. However, I've noticed a significant decrease in performance for certain operations, especially union.

Interestingly, when I perform random operations, Clipper 2 shows much better performance compared to Clipper 1. However, when I try to generate a "grid cover," which essentially creates a grid with numerous repetitions of a square shape, the performance seems to degrade significantly (Clipper2 two times slower than Clipper1).

grid cover :
Capture d’écran_2024-05-16_10-00-11

I've come across some discussions on this issue, but unfortunately, I haven't found a solution yet, even after trying optimization flags like -O3.

I'm hoping that the problem lies within my code and that there might be some optimizations that could be implemented to improve performance.

Any suggestions or insights would be greatly appreciated.

Clipper2 code :

    Paths64 subj, clip;
    PolyTree64 solution;

    Clipper64 c64;


    subj = makePathsFromFile("clip.txt");
    clip = makePathsFromFile("subj.txt");


    c64.AddSubject(subj);
    c64.AddClip(clip);


    auto start = std::chrono::steady_clock::now();

    c64.Execute(ClipType::Union, FillRule::NonZero, solution);

    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::cout << "Temps d'exécution : " << elapsed_seconds.count() << " secondes" << std::endl;
    

Clipper 1 :

    Paths subj, clip;
    PolyTree solution;

    Clipper c64;

    subj = makePathsFromFile("clip.txt");
    clip = makePathsFromFile("subj.txt");

    c64.AddPaths(subj, ptSubject, true);
    c64.AddPaths(clip, ptClip, true);

    auto start = std::chrono::steady_clock::now();

    c64.Execute(ClipType::ctUnion, solution, pftNonZero, pftNonZero);

    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::cout << "Temps d'exécution : " << elapsed_seconds.count() << " secondes" << std::endl;

code of makePathsFromFile for Clipper2 :
/!\ I know the following codes are very inefficient but it doesn't matter i just did that for testing purpose

Paths64 makePathsFromFile(const std::string& filename){
  
  Paths64 benchmark; 

  // Open the file
  std::ifstream infile(filename); 
  
  // Check if the file is not already in use
  if (!infile.is_open()) {
      std::cerr << "Erreur lors de l'ouverture du fichier." << std::endl;
  }

  int he=0;
  std::string line;
  std::vector<std::vector<int>> allValues;
  while (std::getline(infile, line)) { // Go across each line
      Paths64 path;
      std::istringstream iss(line);
      int x, y;
      char comma;
      std::vector<int> values;
      while (iss >> x >> comma >> y >> comma) { // Read the int x, y
          values.push_back(x);
          values.push_back(y);
      }

      values.push_back(x);
      values.push_back(y);   

      allValues.push_back(values);
  }


  // Close the file
  infile.close();

  for (const auto& values : allValues) {
      benchmark.push_back(MakePath(values)); 
  }
  

  return benchmark;
}

code of makePathsFromFile for Clipper1 :

Path makePath(const std::vector<int>& points) {
    Path path;
    for (size_t i = 0; i < points.size(); i += 2) {
        path.push_back(IntPoint(points[i], points[i + 1]));
    }
    return path;
}


Paths makePathsFromFile(const std::string& filename){
  
  Paths benchmark; 

  // Open the file
  std::ifstream infile(filename); 
  
  // Check if the file is not already in use
  if (!infile.is_open()) {
      std::cerr << "Erreur lors de l'ouverture du fichier." << std::endl;
  }

  int he=0;
  std::string line;
  std::vector<std::vector<int>> allValues;
  while (std::getline(infile, line)) { // Go across each line
      Paths path;
      std::istringstream iss(line);
      int x, y;
      char comma;
      std::vector<int> values;
      while (iss >> x >> comma >> y >> comma) { // Read the int x, y
          values.push_back(x);
          values.push_back(y);
      }

      values.push_back(x);
      values.push_back(y);   

      allValues.push_back(values);
  }


  // Close the file
  infile.close();

  for (const auto& values : allValues) {
      benchmark.push_back(makePath(values)); 
  }
  

  return benchmark;
}

And the data :
(Note that those Paths are not random it is real case scenario)
archiveCompressed.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions