There's a place in ProcessEdgesAtTopOfScanbeamf() where a new intersection is sometimes calculated, but it erroneously inherits any previously set Z value on the edge->Curr point.
When this comes out as an intersection, and not an end point, the Z value should be set to 0.
Proposed fix around line 3038 in r498:
else
{
e->Curr.X = TopX( *e, topY );
e->Curr.Y = topY;
#ifdef use_xyz
e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0);
#endif
}
Whether you can do a proper SetZ() at this point, with the proper edges, I'm not sure.
But in the case I was looking at, a new SetZ() needed to be added in some fairly new code,
in ProcessHorizontal(), around line 2716:
if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
{
#ifdef use_xyz
if (dir == dLeftToRight) SetZ(e->Curr, *horzEdge, *e);
else SetZ(e->Curr, *e, *horzEdge);
#endif
op1 = AddOutPt(horzEdge, e->Curr);
TEdge* eNextHorz = m_SortedEdges;
Although IntersectEdges() will be called several lines later on essentially the same point (in my test case), the SetZ() that happens inside IntersectEdges() won't affect the point just added here with AddOutPt().
The if/else here for the edge param order just mimics what you do several lines later.
Hopefully that's right, but I'm just guessing.
This second fix is dependant upon the first, since SetZ() won't set Z if it's already set to the wrong thing.
But the first fix also corrects other wrong Z values at intersections that don't depend on the second fix.
My test polygons for this are:
p1 = [
[10, 0, 1],
[10, 10, 2],
[ 0, 10, 3],
[ 0, 0, 4],
]
p2 = [
[ 5, 5, 5],
[15, 5, 6],
[15, 15, 7],
[ 5, 15, 8],
]
Execute options are UNION with both squares in subjects and fill type NONZERO.
When zfill callback is not set, I get this:
[10, 5, 0] <-- correct, z==0 at intersection
[15, 5, 7] <-- wrong at a preserved input point, z should be 6
[15, 15, 7]
[5, 15, 8]
[5, 10, 8] <-- wrong at intersection, z should be 0
[0, 10, 3]
[0, 0, 4]
[10, 0, 2] <-- wrong at a preserved input point, z should be 1
The first fix fixes those three problems, when no zfill callback is set.
With that first fix in place we can see the remaining problem without the second fix.
When the zfill callback is essentially: intersectionPoint.Z = 23, the result is
[10, 5, 23] <-- correct again at intersection
[15, 5, 6] <-- correct because of first fix
[15, 15, 7]
[5, 15, 8]
[5, 10, 0] <-- wrong at intersection, should be 23
[0, 10, 3]
[0, 0, 4]
[10, 0, 1] <-- correct because of first fix
The second fix corrects that.
Thanks for you time Angus.
Discussion: SetZ - being lost in the returned list?
Anonymous
View and moderate all "bugs Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Bugs"
Seems to address the problem for me. Nicely done, Mike!
Thanks Mike. I'm about to add this fix to version 6.4.2
It was finally added to version 6.4.2? I'm getting all z values set to 0 with #define use_xyz
Sorry I didn't realize this is about Clipper class and I was using ClipperOffset, which is not in Clipper's class hierarchy.
It's using a Clipper object as a local variable in ClipperOffset::Execute, I'd suggest to promote that local variable to a member variable and give public access to it, so a user can set its ZFillFunction as well it can be done with Clipper