AngusJohnson / Clipper2

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

Positive offset produces unexpected hole #780

Closed frenoMax closed 8 months ago

frenoMax commented 8 months ago

Hi,

I am currently updating code that has been using clipper1 to use clipper2 in c++. I have been adding union operation to make sure offsets are not done on self intersecting paths as well as SimplifyPath to clean up.

I have this closed Path(see below) which is the result of a difference operation. I want to "clean" this up by using a positive offsets, then a negative offsets and then a smaller positive offset. My problem is after after the first positive offset it returns two paths where one is a hole which ruined the following paths.

Code to reproduce: Paths is Clipper::Paths64

double gain = 2327.737159110849;
  double delta = 10.0
  double miterLimit = 20.0;
  double simply_delta = gain * 0.01;
  double morph_delta = delta * gain;
  Clipper::Paths64 union_paths;
  {
    Clipper::Clipper64 clpr_union;
    #ifdef USINGZ
    clpr_union.SetZCallback(mean_z_int);
    #endif
    clpr_union.AddSubject(Paths);
    clpr_union.Execute(Clipper::ClipType::Union, Clipper::FillRule::NonZero, union_paths);
  }
  union_paths = Clipper::SimplifyPaths(union_paths, simply_delta);
  Clipper::Paths64 dilation_paths;
  {
    Clipper::ClipperOffset co1;
    co1.MiterLimit(miterLimit);
    #ifdef USINGZ
    co1.SetZCallback(mean_z_int);
    #endif
    co1.AddPaths(union_paths, jtype, Clipper::EndType::Polygon);
    co1.Execute(morph_delta, dilation_paths);
  }

note: the height value can be disregard.

I think point 9 and 11 is the cause for the hole.

Any help with this is appreciated.

Path: 15439077.0000000000 -131318224.0000000000 28300.0000000000 15441845.0000000000 -132161708.0000000000 28400.0000000000 15444646.0000000000 -133005195.0000000000 28500.0000000000 15447017.0000000000 -133719255.0000000000 28600.0000000000 15698277.0000000000 -133759537.0000000000 28700.0000000000 15730384.0000000000 -133759425.0000000000 28800.0000000000 15860976.0000000000 -133770832.0000000000 28900.0000000000 15981260.0000000000 -133804283.0000000000 29000.0000000000 15980355.0000000000 -133803132.0000000000 29100.0000000000 15984379.0000000000 -133805150.0000000000 29200.0000000000 15986549.0000000000 -133805754.0000000000 29300.0000000000 15985128.0000000000 -133805526.0000000000 29400.0000000000 16094944.0000000000 -133860609.0000000000 29500.0000000000 16187107.0000000000 -133934275.0000000000 29600.0000000000 16256321.0000000000 -134022277.0000000000 29700.0000000000 16299323.0000000000 -134120114.0000000000 29800.0000000000 16315008.0000000000 -134228610.0000000000 29900.0000000000 16314344.0000000000 -134227765.0000000000 30000.0000000000 16314377.0000000000 -134236905.0000000000 30100.0000000000 15448744.0000000000 -134239330.0000000000 30200.0000000000 16329675.0000000000 -134236863.0000000000 0.0000000000 39293035.0000000000 -129704386.0000000000 100.0000000000 39293216.0000000000 -129759545.0000000000 200.0000000000 39292539.0000000000 -129552633.0000000000 300.0000000000 39288425.0000000000 -128287891.0000000000 400.0000000000 39284337.0000000000 -127023150.0000000000 500.0000000000 39280273.0000000000 -125758409.0000000000 600.0000000000 39276234.0000000000 -124493670.0000000000 700.0000000000

frenoMax commented 8 months ago

Here is a zoomed in picture of the path. The white is the original and it gets expanded to become the red with a green hole. The image is viewed in 3D from the side with height values added to be able to differentiate overlapping coordinates from different paths dgui_hole_croped

Same image from above dgui_hole_lock_z

frenoMax commented 8 months ago

I think I have found my problem. cos_a is -0.993693, which then doesnt treat it as a concave corner https://github.com/AngusJohnson/Clipper2/blob/a4ae9e4871245e396aaccfad7f760e2fc1d4cbf4/CPP/Clipper2Lib/src/clipper.offset.cpp#L328

AngusJohnson commented 8 months ago

I can't make sense of your sample code since there are missing variable definitions. Also, please simplify the problem from multiple stages (union, simplify & offset) to a single stage. IOW, just provide the path data and clipping or offsetting operation (with parameters) where you're encountering the problem.

frenoMax commented 8 months ago

Ah it seems the gainvariable disappeared. It is there now. I will provide a better version of my problem

frenoMax commented 8 months ago
  Clipper::Paths64 Paths = {{
        {15439077, -131318224}, {15441845, -132161708},
        {15444646, -133005195}, {15447017, -133719255},
        {15698277, -133759537}, {15730384, -133759425},
        {15860976, -133770832}, {15981260, -133804283},
        {15980355, -133803132}, {15984379, -133805150},
        {15986549, -133805754}, {15985128, -133805526},
        {16094944, -133860609}, {16187107, -133934275},
        {16256321, -134022277}, {16299323, -134120114},
        {16315008, -134228610}, {16314344, -134227765},
        {16314377, -134236905}, {15448744, -134239330},
        {16329675, -134236863}, {39293035, -129704386},
        {39293216, -129759545}, {39292539, -129552633},
        {39288425, -128287891}, {39284337, -127023150},
        {39280273, -125758409}, {39276234, -124493670}}};

  double gain = 2327.737159110849;
  double delta = 10.0;
  double miterLimit = 20.0;
  double morph_delta = delta * gain;
  Clipper::Paths64 dilation_paths;
  {
    Clipper::ClipperOffset co1;
    co1.MiterLimit(miterLimit);
    co1.AddPaths(Paths, Clipper::JoinType::Miter, Clipper::EndType::Polygon);
    co1.Execute(morph_delta, dilation_paths);
  }
AngusJohnson commented 8 months ago

You need to 'clean' (ie SimplifyPaths()) your starting path, and perhaps also reduce you MiterLimit to a sensible ratio of your offset distance (eg 2 not 20).

frenoMax commented 8 months ago

I aggree with lowering the MiterLimit, and it does work, but as I am updating older code from using clipper1 this change would impact alot of different polygon. I have tried to add both a union operation and SimplifyPaths before the offset operation and still get the resulting hole. I did go into the clipper2 code for offsetting and and saw that one of the concave "points" did not become classified as such. I did help to lower the checked value of cos_a > -0.99 to cos_a > -0.999, which would also make i look similar to the check in the next if statement cos_a > 0.999

https://github.com/AngusJohnson/Clipper2/blob/1df29405b9c2176293db9783c61f7b09c2fe66d8/CPP/Clipper2Lib/src/clipper.offset.cpp#L328-L337

@AngusJohnson

frenoMax commented 8 months ago

@AngusJohnson Could I get a comment on my latest comment after you closed the issues? I maybe should move this to discussion and not issues. I can also comment that this problem did not happend when clipper1 was used, on this Path. How mush has the offset part of clipper changed between 1 and 2?

AngusJohnson commented 8 months ago

I did help to lower the checked value of cos_a > -0.99 to cos_a > -0.999

I'm happy to consider (and test) that.