Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offset produces incorrect output #593

Closed
olologin opened this issue Jul 20, 2023 · 33 comments
Closed

Offset produces incorrect output #593

olologin opened this issue Jul 20, 2023 · 33 comments

Comments

@olologin
Copy link

olologin commented Jul 20, 2023

Hi, could you please check the attached test, something is wrong with offset:

TEST(Clipper2Tests, TestOffsets5)
{
    Paths64 subjects = {
        {{-616909947, 520339465}, {-616770911, 519140059}, {-616088223, 516235000},
         {-615738591, 515224142}, {-615429468, 514559225}, {-615167287, 514065887},
         {-614776478, 513416556}, {-614154420, 512583051}, {-612274666, 510526392},
         {-611683294, 509972214}, {-611013578, 509515799}, {-608052680, 507817208},
         {-607126678, 507399448}, {-607024767, 507364908}, {-606830072, 507303124},
         {-606775561, 507286987}, {-605927010, 507110504}, {-603051565, 506757050},
         {-602411915, 506717884}, {-601545978, 506789889}, {-598819464, 507246481},
         {-597870106, 507498768}, {-596984472, 507923716}, {-593828452, 509820654},
         {-593086024, 510360673}, {-592449173, 511021916}, {-590386749, 513577845},
         {-589821895, 514438911}, {-589686472, 514697638}, {-589528201, 515027551},
         {-589419699, 515275559}, {-589119787, 516174960}, {-588427237, 519115244},
         {-588287588, 520317255}, {-588295425, 520603824}, {-588442347, 523287799},
         {-588627877, 524411982}, {-588949515, 525563228}, {-589236024, 526343731},
         {-589777630, 527520992}, {-590494229, 528663568}, {-592787049, 531446465},
         {-593848637, 532422937}, {-595217903, 533371136}, {-596131953, 533877449},
         {-597630255, 534521605}, {-598832795, 534875490}, {-601546079, 535331109},
         {-602414318, 535403500}, {-603057709, 535363873}, {-605709063, 535036029},
         {-606968467, 534718181}, {-608674076, 534053872}, {-609696343, 533519540},
         {-611401961, 532372920}, {-612380337, 531521992}, {-614083835, 529622220},
         {-614805493, 528591155}, {-615692287, 526930012}, {-616089432, 525965919},
         {-616542803, 524453004}, {-616755206, 523241979}, {-616901699, 520633437}} };

    const double scaledTol = 41943.139999999999;
    const double scale = 4194314.0000000000;
    const double offset = -10.000000000000000;
    Clipper2Lib::ClipperOffset offseter(2, scaledTol);
    Clipper2Lib::Paths64 tmpSubject;

    offseter.AddPaths(subjects, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
    Clipper2Lib::Paths64 paths;
    offseter.Execute(offset * scale, paths);

    EXPECT_EQ(paths.size(), 0);
}

The input is red circle, and I dont see any obvious self-intersection there, the output are these two green things
image

@AngusJohnson
Copy link
Owner

AngusJohnson commented Jul 20, 2023

  const Rect64 rec = GetBounds(subjects[0]);
  std::cout << (offset * scale) / rec.Width() << std::endl;

-1.4654

So you're negative offsetting by approaching 3 times the radius of your circle.

Yes, ideally you should be getting an empty solution.
But it's costly to offsetting performance to more carefully check for and clean up these abnormal conditions.

@olologin
Copy link
Author

olologin commented Jul 21, 2023

@AngusJohnson
I understand your concern in performance, and in extensive performance testing I have confirmed that Clipper2 is on average 20-30% faster than Clipper1 in boolean operations (which was already faster than any other library for polygon boolean operations), thanks for that. I have not tested offsetter performance unfortunately.

But there are other things:

  1. Clipper1 correctly collapses such inputs, and I found this issue when I tried to migrate from clipper1 to clipper2. I dont see this mentioned in documentation. And this also blocks me (and can potentially block other people) from migration.
  2. Caring about performance is good, but there is no point in good performance if the algorithm doesn't work for your use case.
  3. I believe that collapsing polygons correctly is one of the main requirements of any offsetting algorithm, otherwise I cannot think of a simpler way to filter out polygons that are too narrow (more narrow than some width). I have often seen such use cases where people offset such polygons with negative offset, and then offset result back with the same offset value, and what they get in result is only part of initial polygon where some circular body can pass through freely, filtering out all narrow parts. That also applies to whole polygons which are too narrow (that is why we cannot filter by area, because narrow polygon can have huge area but still be too narrow)

I think if you don't feel like this scenario is frequently used, maybe all these expensive checks can be activated by additional flag (turned off by default)?

@olologin
Copy link
Author

If you decide to implement this I can help you with testing, I have huge sets of inputs and outputs dumped for Clipper1, I can compare performance and results of Clipper2 and Clipper1 in offsetting.

@AngusJohnson
Copy link
Owner

With negative offsets, I believe at one time I did check path bounds to ensure offsetting wasn't excessive (ie relative to the path so that path would disappear in the solution). This doesn't seem to be in the current implementation and I probably removed that check because mostly it was unnecessary, nor was it foolproof in preventing these rare offsetting artefacts. Anyhow, I could be persuaded to reintroduce this additional checking.

@niki-sp
Copy link

niki-sp commented Jul 21, 2023

One important algorithm for removing small details is:

  1. negative offset with R
  2. positive offset with same R

this depends crucially on negative offset removing all small pieces.

In our testing Clipper1 handles this case well.
Please reconsider additional checking.

@olologin
Copy link
Author

olologin commented Jul 21, 2023

Another problem is that user may never guarantee thickness of his input polygons (because input may come from some human, or from another noisy algorithm), and if at least 1 polygon out of 10 is too thin and trashes result of whole operation for the rest 9 polys - it is bad.
And there is no simple way to exclude that 1 narrow polygon from offseter input (in fact for this you need another offseter with correctly working negative offset).

@olologin olologin changed the title Offset produces incorrect output Negative offset produces incorrect output Jul 21, 2023
@olologin
Copy link
Author

olologin commented Jul 21, 2023

And actually you can even reproduce this with positive offset, if you offset polygon with small holes (holes will have to collapse correctly).
I created this input out of initial testcase, outer red circle is red circle from the initial testcase offseted by any positive value, inner red circle is exactly the inital red circle (but now it is hole).
If you offset this whole body by positive offset (-offset * scale) - hole has to collapse.

image

@olologin olologin changed the title Negative offset produces incorrect output Offset produces incorrect output Jul 21, 2023
@AngusJohnson
Copy link
Owner

Replace the following:

void ClipperOffset::OffsetPolygon(Group& group, Path64& path)
{
for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
OffsetPoint(group, path, j, k);
group.paths_out.push_back(group.path);
}

with:

void ClipperOffset::OffsetPolygon(Group& group, Path64& path)
{
	for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
		OffsetPoint(group, path, j, k);

	//when the path is contracting,
	//make sure inpath and outpath have the same orientation
	//nb: this will have a small impact on performance
	double a = Area(path);
	if (a < 0 != group_delta_ < 0)
	{
		double a2 = Area(group.path);
		if (a2 < 0 != a < 0) return;
	}

	group.paths_out.push_back(group.path);
}

@olologin
Copy link
Author

olologin commented Aug 6, 2023

@AngusJohnson
Thank you very much!
I will get back with testing results, maybe even today.

@olologin
Copy link
Author

olologin commented Aug 6, 2023

It was not easy to find, but I found couple of problems:
This one creates huge arc during offset inside (red is input, purple is output)
image

TEST(Clipper2Tests, TestOffsets6)
{
    Paths64 subjects = { {{506270570, -335400744}, {510335877, -345922004}, {514185227, -356253683},
                         {517851111, -366469584}, {521355277, -376625435}, {524648287, -386576219},
                         {527765003, -396413333}, {530680776, -406047298}, {533441859, -415630871},
                         {536029571, -425094878}, {538402213, -434274702}, {540602557, -443314686},
                         {542618965, -452150636}, {544474020, -460878940}, {546158964, -469444422},
                         {547663631, -477781462}, {549010923, -485994418}, {550176472, -493902584},
                         {551195980, -501722711}, {552057067, -509336669}, {552769195, -516807173},
                         {553333710, -524107091}, {553752931, -531234555}, {554036512, -538328985},
                         {554175909, -545084343}, {554182295, -551809317}, {554055155, -558432231},
                         {553802509, -564786954}, {553417854, -571105325}, {552905635, -577316442},
                         {552281643, -583296151}, {551531591, -589204401}, {550662548, -595000105},
                         {549681230, -600663660}, {548581714, -606227627}, {547369656, -611680589},
                         {546026941, -617104757}, {544599764, -622318933}, {543050259, -627477439},
                         {541394599, -632529104}, {539619317, -637520160}, {537759925, -642351290},
                         {535772267, -647144663}, {533691533, -651815680}, {531490143, -656431036},
                         {529211650, -660898668}, {526819111, -665297679}, {524334325, -669589290},
                         {521735601, -673812879}, {519056435, -677915821}, {516275304, -681931019},
                         {513390664, -685862176}, {510418136, -689688325}, {507341533, -693431300},
                         {504168576, -697082184}, {500930887, -700605190}, {497596307, -704036629},
                         {494167423, -707373837}, {490662912, -710599361}, {487073643, -713722055},
                         {483398474, -716743180}, {479642127, -719658963}, {475815078, -722461140},
                         {471910782, -725154646}, {467932324, -727737352}, {463884796, -730206068},
                         {459772196, -732558642}, {455595179, -734794848}, {451341465, -736920690},
                         {447013217, -738935033}, {442630509, -740827961}, {438178548, -742605456},
                         {433670526, -744262449}, {429115045, -745795322}, {424442669, -747226244},
                         {423210277, -747580617}, {436704105, -750131226}, {449269506, -752376896},
                         {461416627, -754415876}, {473049679, -756238573}, {484266535, -757861518},
                         {495125407, -759298657}, {505289752, -760513003}, {515171462, -761562415},
                         {524578599, -762433494}, {533787985, -763152970}, {542737522, -763718648},
                         {551152946, -764119401}, {559322433, -764378079}, {567158786, -764497975},
                         {574782091, -764482243}, {582234434, -764333626}, {589280125, -764061010},
                         {596088946, -763666911}, {602575309, -763164157}, {608910160, -762541809},
                         {615098855, -761801294}, {621001862, -760961369}, {626729922, -760012801},
                         {632176210, -758980403}, {637502960, -757835724}, {642694800, -756583701},
                         {647621944, -755259400}, {652383140, -753844184}, {657030015, -752326051},
                         {661489199, -750729502}, {665817539, -749039664}, {670025263, -747256490},
                         {674089514, -745389771}, {678059974, -743420650}, {681973657, -741330417},
                         {685942114, -739058087}, {689872689, -736652539}, {693776355, -734107068},
                         {697728694, -731368016}, {701635825, -728497257}, {705488844, -725501695},
                         {709394332, -722294020}, {713238390, -718963244}, {717017757, -715512977},
                         {720818960, -711859882}, {724554000, -708084686}, {728225317, -704184351},
                         {731883783, -700098995}, {735442875, -695925451}, {738950367, -691606290},
                         {742368614, -687184469}, {745726824, -682622364}, {748992285, -677961310},
                         {752165539, -673200044}, {755240464, -668345263}, {758224935, -663384675},
                         {761099985, -658347734}, {763864377, -653236201}, {766510814, -648062614},
                         {769037905, -642829695}, {771444322, -637540197}, {773720716, -632215479},
                         {775865188, -626860859}, {777870459, -621498871}, {779738804, -616122666},
                         {781471006, -610734318}, {783069518, -605325925}, {784506679, -599999562},
                         {785808728, -594664577}, {786968633, -589352177}, {787978994, -584110633},
                         {788846141, -578909158}, {789569891, -573765068}, {790150083, -568704643},
                         {790591171, -563683156}, {790890849, -558757691}, {791052780, -553949102},
                         {791079392, -549205284}, {790972085, -544530142}, {790738658, -540048017},
                         {790377292, -535640128}, {789889323, -531308375}, {789286070, -527140179},
                         {788565743, -523082812}, {787742574, -519187158}, {786808111, -515399424},
                         {785759603, -511699607}, {784620204, -508163732}, {783374711, -504729242},
                         {782047225, -501449452}, {780621493, -498277597}, {779087098, -495188336},
                         {777478839, -492243285}, {775769273, -489389932}, {773960609, -486629548},
                         {772041893, -483944495}, {770006999, -481327091}, {767721546, -478611993},
                         {765166314, -475788396}, {762302096, -472833338}, {759201695, -469830730},
                         {755750116, -466682252}, {752071938, -463510371}, {747994664, -460175942},
                         {743693052, -456831757}, {738932040, -453303396}, {733890754, -449736195},
                         {728368186, -445996317}, {722514038, -442195931}, {716088132, -438190164},
                         {709274070, -434103707}, {701770294, -429768919}, {693789093, -425318028},
                         {684950267, -420553954}, {675528637, -415633224}, {664888047, -410240552},
                         {653397814, -404574333}, {640202819, -398224764}, {624100289, -390644197},
                         {601552399, -380217967}, {562700389, -362355097}, {543642782, -353463749},
                         {528162998, -346104612}, {514532275, -339487817}} };

    const double scaledTol = 0.838904;
    const double scale = 1.67781e+07;
    const double offset = -858.993;
    Clipper2Lib::ClipperOffset offseter(2, scaledTol);
    Clipper2Lib::Paths64 tmpSubject;

    offseter.AddPaths(subjects, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
    Clipper2Lib::Paths64 paths;
    offseter.Execute(offset * scale, paths);

    EXPECT_EQ(paths.size(), 0);
}

@olologin
Copy link
Author

olologin commented Aug 6, 2023

Second example (maybe a duplicate of previous issue)
image

Unfortunately it is huge, so I will attach it as txt file.
TestOffset7.txt

@AngusJohnson
Copy link
Owner

AngusJohnson commented Aug 6, 2023

void ClipperOffset::OffsetPolygon(Group& group, Path64& path)
{
	// when the path is contracting, make sure 
	// there is sufficient space to do so.                //#593
	// nb: this will have a small impact on performance
	double a = Area(path);
	if ((a < 0) != (group_delta_ < 0))
	{
		Rect64 rec = GetBounds(path);
		if (std::fabs(group_delta_) * 2 > rec.Width()) return;
	}

	for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
		OffsetPoint(group, path, j, k);
	group.paths_out.push_back(group.path);
}

@olologin
Copy link
Author

olologin commented Aug 6, 2023

void ClipperOffset::OffsetPolygon(Group& group, Path64& path)
{
	// when the path is contracting, make sure 
	// there is sufficient space to do so.                //#593
	// nb: this will have a small impact on performance
	double a = Area(path);
	if ((a < 0) != (group_delta_ < 0))
	{
		Rect64 rec = GetBounds(path);
		if (std::fabs(group_delta_) * 2 > rec.Width()) return;
	}

	for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
		OffsetPoint(group, path, j, k);
	group.paths_out.push_back(group.path);
}

That helped, but here is another issue, result should only have 2 contours, but instead it contains a lot of 4-point noise.
Although I am not sure it is related to this issue, because in this case we are not collapsing.
image

TestOffset8.txt

@olologin
Copy link
Author

olologin commented Aug 6, 2023

@AngusJohnson
Also, could you please include all unit tests from this issue into your testsuite? I think it might be helpful for you to have such inputs (and for me to reduce likelihood of something breaking in upstream).

@olologin
Copy link
Author

olologin commented Aug 6, 2023

I will play more with collapsing tomorrow, but so far it looks good.

@AngusJohnson
Copy link
Owner

that helped, but here is another issue, result should only have 2 contours, but instead it contains a lot of 4-point noise.

subjects = SimplifyPaths(subjects, 100000);

@olologin
Copy link
Author

olologin commented Aug 7, 2023

Maybe another issue: Here nested red poly has area, but one of its ends is very acute, result doesnt look right from the first glance:
image

TEST(Clipper2Tests, TestOffsets9)
{
	Paths64 subjects = {
		{
			{620365300, 620445827},
			{-620387577, 620440421},
			{-620394495, -620379939},
			{620379354, -620395505},
		},
		{
			{20239443, -277494546},  {41537506, -275049242},  {58543080, -271976947},
			{79799000, -266480328},  {96804435, -260833992},  {113810069, -253809205},
			{134716732, -243380771}, {149049022, -234877718}, {167497914, -222124560},
			{181829616, -210566200}, {196841985, -196616652}, {211588186, -180575231},
			{222631828, -166857863}, {234389172, -149852894}, {244436172, -132847720},
			{252955255, -115842769}, {260013207, -98837258},  {267153373, -77583125},
			{271504741, -60576250},  {275357421, -39834871},  {277603343, -18021122},
			{275614547, -39340001},  {271693562, -60605588},  {266974990, -78930986},
			{260213004, -98884220},  {253135222, -115897083}, {244628880, -132909487},
			{234579402, -149918850}, {222814253, -166935083}, {211685388, -180754807},
			{197028960, -196707288}, {181910316, -210745820}, {167675335, -222223500},
			{152139391, -233107086}, {134893603, -243491062}, {113859229, -254008090},
			{96846243, -261019139},  {79837350, -266683233},  {58567544, -272166834},
			{41556228, -275240119},  {20293071, -277665467},
		},
	};

	const double scaledTol = 41943.2;
	const double scale = 4.19432e+06;
	const double offset = -17.6;
	Clipper2Lib::ClipperOffset offseter(2, scaledTol);
	Clipper2Lib::Paths64 tmpSubject;

	offseter.AddPaths(subjects, Clipper2Lib::JoinType::Round, Clipper2Lib::EndType::Polygon);
	Clipper2Lib::Paths64 paths;
	offseter.Execute(offset * scale, paths);

	EXPECT_EQ(paths.size(), 0);
}

@olologin
Copy link
Author

olologin commented Aug 7, 2023

that helped, but here is another issue, result should only have 2 contours, but instead it contains a lot of 4-point noise.

subjects = SimplifyPaths(subjects, 100000);

  1. SimplifyPaths seems to do unnecessary copies of its arguments. It looks like it can take them by const reference
  2. Do you think it is possible to estimate this epsilon for SimplifyPaths in some meaningful way? The issue here is that small epsilon will not help, and huge will add self-intersections, acute corners like in the input above and might just butcher input geometry in a way that was not expected by user. Maybe there is some expensive way to filter this garbage from inside the algorithm, or from outside? I am thinking about quickly measuring distance to input geometries and checking if this noise is not closer and not further than offset distance, but I think some of this noise will still pass such filter.

@AngusJohnson
Copy link
Owner

SimplifyPaths seems to do unnecessary copies of its arguments. It looks like it can take them by const reference

Yep. I've amended the code ready for the next upload.

@AngusJohnson
Copy link
Owner

AngusJohnson commented Aug 7, 2023

Do you think it is possible to estimate this epsilon for SimplifyPaths in some meaningful way?

It may be possible, but I don't know how.
I think it's really up to the library user to determine a sensible precision for their data.
The important thing is to smooth out any curve imprecision (artefacts) in the input paths.

@AngusJohnson
Copy link
Owner

Maybe another issue: Here nested red poly has area, but one of its ends is very acute, result doesnt look right from the first glance

Noted, thanks. That needs fixing.

@olologin
Copy link
Author

olologin commented Aug 8, 2023

The important thing is to smooth out any curve imprecision (artefacts) in the input paths.

This is very informal definition, especially in this case.
Lets imagine that I am user of ClipperLib2:

  1. I don't see how this input is containing any irregularities or problems, it is already simple and very basic. Therefore I would not use Simplify, simply because "that line in documentation is not about me", my input does not contain self-intersections, high-frequency noise, etc.
  2. I have my own precision budget and I cannot simplify my geometry because I will not stay within that budget.
  3. Clipper1 does not produce this noise on the same input

The most "Simplified" input I can give you is this one, I cannot simplify it more:
(It is simplified version of TestOffset8.txt)
Test10.txt
image

@olologin
Copy link
Author

olologin commented Aug 8, 2023

To be fair, it seems offsetter in Clipper2 is MUCH faster than in Clipper1, but Clipper1 never generates that kind of noise.

@AngusJohnson
Copy link
Owner

but Clipper1 never generates that kind of noise.

I will investigate further.

@SebastianDirks
Copy link
Contributor

There is still a bug in the new bounds check implementation, you need to check both the heigth and width of the bounding box. I can comfirm this fixes all cases of this problem I have in my unit test suite, that previously did not pass. I do check this by comparing the bounding boxes of the original poylgon and the offset one polygon to be smaller/bigger than expected with this offset whithin arcTolerance (JoinType.Round).

fixed:

        double offsetMinDim = Math.Abs(_groupDelta) * 2;
        if (offsetMinDim > rec.Width || offsetMinDim > rec.Height) return;

currently:

void ClipperOffset::OffsetPolygon(Group& group, Path64& path)
{
	// when the path is contracting, make sure 
	// there is sufficient space to do so.                //#593
	// nb: this will have a small impact on performance
	double a = Area(path);
	if ((a < 0) != (group_delta_ < 0))
	{
		Rect64 rec = GetBounds(path);
		if (std::fabs(group_delta_) * 2 > rec.Width()) return;
	}

	for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
		OffsetPoint(group, path, j, k);
	group.paths_out.push_back(group.path);
}

@AngusJohnson
Copy link
Owner

There is still a bug in the new bounds check implementation

Sebastian, I don't understand what exactly you're changing and how this relates to the discussion above. Please explain.

@olologin
Copy link
Author

@AngusJohnson
I see you fixed some issue in offsetter. Thanks for that!
Not sure if that fixes all mentioned issues here, but let me know if you think it is ready for testing again.

@AngusJohnson
Copy link
Owner

Yep, give it another go.

@olologin
Copy link
Author

olologin commented Sep 17, 2023

@AngusJohnson
Almost no noise now, but this one seems to fail still: #593 (comment)
It seems remaining noise is caused by the same problem as in this comment. I can provide more examples if you want, but it is most of the time just 3-4 point polyline without area which just lacks arcs after offsetting of some very small body.

SebastianDirks added a commit to SebastianDirks/Clipper2 that referenced this issue Sep 18, 2023
…ish in the output), not only test the bounding box width but also the height.

If either dimension is smaller than 2 times offset, the group will vanish when contracting.
Suspected to fix issue AngusJohnson#593.
All tests passed locally in C# and C++. Delphi is missing yet, I am not familiar with that language.
@SebastianDirks
Copy link
Contributor

There is still a bug in the new bounds check implementation

Sebastian, I don't understand what exactly you're changing and how this relates to the discussion above. Please explain.

I'm sorry, I have now created a pull request for the proposed bug fix. I have tested C# and C++, don't know Delphi.
I think the bug fix may resolve the problem in this issue, since the commit adding the code referenced this issue.
Also the artifacts shown look similar to artifacts that are caused by wrong normals from vanishing paths that I got in my codebase.

@SebastianDirks
Copy link
Contributor

@olologin adding to the discussion:
I have managed to get rid of artifacts in the offset with the following steps (within a desired tolerance):

  1. if the desired offset is smaller than the tolerance, lower the tolerance
  2. use JoinType.Round with arcTolerance set to the desired tolerance of the offset [note there is a hard coded minmal limit of 0.01 in clipper2lib, when arcTolerance is smaller than or equal to 0.01, 0.25 will be used instead]
  3. use Douglas Peucker Simplification with a line deviation tolerance of arcTolerance on the input polygons
  4. if there are "spikes" in the input where the vertex angle is smaller ("sharper") than the arcTolerance, this might cause artifacts. I collapse some spikes by removing the offending vertex if the spike origin points distance is smaller than tolerance, however this kind of high frequency data is usually an artifact itself

I have verified this in my code like this:

var oldBounds = polygons.Bounds();
var newBounds = resultPolys.Bounds();
Polygon2d[] shouldBeNothing;
if (offset >= 0)
{
    oldBounds.Expand(Math.Abs(offset) * (1 + tolerance / 2));
    shouldBeNothing = polygons.ClipBy(resultPolys);
}
else
{
    oldBounds.Contract(Math.Abs(offset) * (1 - tolerance / 2));
    shouldBeNothing = resultPolys.ClipBy(polygons);
}
if (!oldBounds.Contains(newBounds) || shouldBeNothing.Length > 0) Fail();

@AngusJohnson
Copy link
Owner

I have managed to get rid of artifacts in the offset with the following steps (within a desired tolerance):

Are these artifacts still present (please check the latest commit)?
If so, please open a new Issue with an example or two. Thanks.

AngusJohnson pushed a commit that referenced this issue Sep 18, 2023
…ish in the output), not only test the bounding box width but also the height. (#651)

If either dimension is smaller than 2 times offset, the group will vanish when contracting.
Suspected to fix issue #593.
All tests passed locally in C# and C++. Delphi is missing yet, I am not familiar with that language.
@olologin
Copy link
Author

olologin commented Sep 19, 2023

@AngusJohnson
Thanks for fixing all this. Now I don't see regressions compared to Clipper1 (In terms of offsetting).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants