AngusJohnson / Clipper2

Polygon Clipping and Offsetting - C++, C# and Delphi
Boost Software License 1.0
1.45k stars 266 forks source link

Can't get RectClip to work, even with minimal example #821

Closed szakeetm closed 5 months ago

szakeetm commented 5 months ago

I try to clip a large square with a smaller square. I made an absolute minimal example to demonstrate. The returned paths vector is empty.

clipperbug.cpp:

#define USINGZ
#include <clipper2/clipper.h>
#include <iostream>

int main() {

    Clipper2Lib::PathD subject(4);
    subject[0].x = 0.0;
    subject[0].y = 0.0;
    subject[1].x = 1.0;
    subject[1].y = 0.0;
    subject[2].x = 1.0;
    subject[2].y = 1.0;
    subject[3].x = 0.0;
    subject[3].y = 1.0;
    Clipper2Lib::PathsD subjects; subjects.push_back(subject);

    Clipper2Lib::RectD rect;
    rect.left = 0.0;
    rect.right = 0.1;
    rect.bottom = 0.1; //bottom>top in Clipper2
    rect.top = 0.0;

    auto solution = Clipper2Lib::RectClip(rect, subjects,8);

    std::cout<<"solutions: "<<solution.size()<<"\n";
    auto pts = solution[0];
    std::cout<<"points: "<<pts.size()<<"\n";
    for (int j = 0; j < pts.size(); j++) {
        std::cout<<pts[j].x<<" "<<pts[j].y<<"\n";
    }

    std::cout << "finished." << std::endl;
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(clipperbug)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# Add the executable
add_executable(clipperbug clipperbug.cpp)

#Clipper2Z
find_package(PkgConfig REQUIRED)
pkg_check_modules(Clipper2Z REQUIRED IMPORTED_TARGET Clipper2Z)
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::Clipper2Z)

Output:

./clipperbug
solutions: 0
zsh: segmentation fault

(The segfault is expected when trying to access solution[0])

Expected output:

solutions: 1
points: 4
0.0 0.0
0.1 0.0
0.1 0.1
0.0 0.1

Please note that this issue is part of a larger repository that fails to work after upgrading from 1.2.2 to 1.3.0. Clipper2 is installed with vcpkg.

AngusJohnson commented 5 months ago

[!IMPORTANT] So it's important that library users appropriately scale paths in clipping operations when you would otherwise expect polygons with very small areas. (Alternatively, use the PathsD structure instead of Paths64 when clipping, since the library will perform the required scaling internally.)

See: https://angusj.com/clipper2/Docs/Robustness.htm

szakeetm commented 5 months ago

Sorry, I don’t understand: my example does use PathsD (and not Paths64). I’ve read your link about robustness and still don’t understand why there’s no solution.

AngusJohnson commented 5 months ago

Your paths coordinates are too small and hence define very small polygons. And very small polygons in your solutions will be ignored. You need to scale you paths (eg by 10 or 100).

szakeetm commented 5 months ago

Your code already does the scaling by pow(10,8) since I set precision to 8 digits. I literally see it being converted to a Path64 with the coordinates... (0,100000000) (100000000,0) etc.

Screenshot 2024-04-26 at 08 03 51
AngusJohnson commented 5 months ago

Your code already does the scaling by pow(10,8) since I set precision to 8 digits. I literally see it being converted to a Path64 with the coordinates... (0,100000000) (100000000,0) etc.

Oops, you're right. Sorry! I didn't look at your code properly 😱. I will look at your problem much more carefully and reply again soonish (< 24hrs).

AngusJohnson commented 5 months ago
#include <iostream>
#include "clipper2/clipper.h"
#include "clipper2/clipper.rectclip.h"

int main()
{
    using namespace std;
    using namespace Clipper2Lib;

        PathsD subjects = { MakePathD({ 0.0,0.0, 1.0,0.0, 1.0,1.0, 0.0,1.0 }) };
    RectD rect(0.0, 0.0, 0.1, 0.1);
    PathsD solution = RectClip(rect, subjects, 2);

    std::cout << solution[0] << "\n";
    return 0;
}

Produces ... 0.1,0.1, 0,0.1, 0,0, 0.1,0

Clipper2_sample.zip

szakeetm commented 5 months ago

Thank you. I’ll be next to a computer on Tuesday, I’ll have a look what is different, and get back to you.

szakeetm commented 5 months ago

With your Visual Studio solution, both your code and mine work. If I #define USINGZ before including clipper.h, I get an unhandled error (last function on the stack is ScalePath), both with your code and mine. Could you please check if it's the same for you?

AngusJohnson commented 5 months ago

clipper

Output: 0.1,0.1,0, 0,0.1,0, 0,0,0, 0.1,0,0

szakeetm commented 5 months ago

After your screenshots I played around: The crash was caused because Visual Studio first compiles clipper.rectclip.cpp, which also includes clipper.h, but doesn't have the #define USINGZ directive. So once it was included with, and once without USINGZ. Setting the solution-wide preprocessor macro (your first screenshot) OR adding #define USINGZ in clipper.rectclip.cpp as well fixes the issue. If possible, please keep this ticket open until I confirm that it works with the CMake and vcpkg-based project as well. Thank you for your work so far.

szakeetm commented 5 months ago

I have tested with the large solution, and indeed, the problems were caused by manual USINGZ definitions, which are inconsistent (since it's hard to know which file will include clipper.h first).

If someone else contacts you about similar issue, the solution is:

Thank you again for taking your time to debug this, and good luck for the project!