-
-
Notifications
You must be signed in to change notification settings - Fork 19.4k
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
Fix#23250 rounding error in world_to_map function in tile_map #23315
Conversation
If I make a tilemap with cell size of 32x32, and run |
Yes u are right. I didn't test other use-cases and 32x32 map with points between (16,16) and (31,31) are not correct since they get rounded up to (1,1) which seems to be invalid as you mentioned. Thanks for pointing that out. |
Sorry this fix does not make any sense, transform2D is used in plenty of other things and this would break it. Why not just rounding the result in tile map? |
ok this actuall fix might not be very well thought out. I still wonder why |
@soockee: the answer is float precision... |
That's completely normal with floating-point arithmetic. |
Yes i understand. Just asking how would you handle it in the world_to_map function. Guess my solution isn't going to work. My thought was: There is this float precision which causes the number to be just a little bit off. It returns to the world_to_map function where it's used again. But because it's just that little bit of the result of world_to_map is not what we expect -> issue |
Off my cuff, I would check whether the number falls in certain range (e.g. 0.25 +- epsilon or 0.75 +- epsilon) and decide whether to floor() or ceil() based on the range it's in. |
We need to floor as everything in the range |
Another way to solve this would be to transform the world coordinate using a Transform which doesn't include cell size. This gives a tilemap-space coordinate in pixels. You round that to an integer, and only then, you unscale the cell size to return a grid-space coordinate. Only drawback is, you may not make a tilemap with non-integer cell sizes ;p |
@Zylann Well isn't this what's done already? The issue is "you unscale the cell size to return a grid-space coordinate." -> that's where the precision error can mean that you're off by one when going back to an int cell coordinate. |
@akien-mga no that wasn't the case. The original code is using only one transform which gave the result in grid coordinate directly (see the |
@Zylann Well if you could implement your idea, that would be nice. Even with a hack to workaround the precision error before calling If we don't care about huge cell sizes, here's a brute force fix: diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 67e25ec50..a7ac2bb98 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1445,6 +1445,11 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
default: {}
}
+ // Account for precision errors on the border (GH-23250).
+ // 0.00005 is 5*CMP_EPSILON, results would start being unpredictible if
+ // cell size is > 15,000, but we can hardly have more precision anyway with
+ // floating point.
+ ret += Vector2(0.00005, 0.00005);
return ret.floor();
} |
We should probably continue the discussion in the original issue #23250 as this PR changing |
[deprecated]Problem: Returning Vector2D always get round down. Vector2D round off is the solution.
Used this script for testing:
Edit:
![codecogseqn](https://user-images.githubusercontent.com/24325735/47611134-72f1d600-da5f-11e8-820f-df05d864604f.gif)
Problem is indeed a rounding error. The Function affine_inverse in transform_2d.cpp got problems with TileMap-cell_sizes which are one of those numbers:
the variable idet doesn't evaluate to the desired number
as example:
The commit provides some workaround in a way that only some of these digits are considered significant to avoid the representational error.
Bug-Reproduction Project
from #23250 (comment)
bug.zip