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

Fixed computation of intersectsRay() for Cylinder, Box and ConvexMesh #109

Merged
merged 21 commits into from
Apr 26, 2020

Conversation

peci1
Copy link
Contributor

@peci1 peci1 commented May 28, 2019

This PR fixes a multitude of problems the current implementations of intersectsRay() had.

In Box, even according to the link to the used method, the approach should only work for axis-aligned boxes. But bodies::Box can be arbitrarily transformed. So I instead strip rotation from both the box and the ray, which gives the same results. The old implementation would fail every time the untransformed min corner ceased to be the min corner of the transformed box.

For Cylinder, there were a few cornercases when incorrect number of intersections were returned (e.g. when the ray is tangential to the cylinder or when it goes through the edge between base and sides).

For ConvexMesh, there were several problems. Many of them arose from a wrong approach to incorporate padding. Also, if a ray hit the edge of two triangles, it was reported twice.

I also restructured the tests for both containsPoint() and intersectsRay() and added a lot of new tests - both randomized and testing corner cases. There is also a regression test BoxRayIntersection::Regression109 which fails on current melodic-devel and succeeds with this test.

Aside from the fixes in intersectsRay(), I also fixed Cylinder::samplePointInside() and ConvexMesh::containsPoint() whose correct working is needed by the unit tests.

@peci1
Copy link
Contributor Author

peci1 commented May 28, 2019

This would deserve a few tests, they're coming tomorrow. For the time being I verified the algorithm in RViz.

@peci1 peci1 force-pushed the fix-box-ray-intersection branch 2 times, most recently from 82ec8c0 to fcf33ca Compare May 29, 2019 11:03
Copy link
Contributor

@rhaschke rhaschke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, this looks good to me.
Please provide a description for this PR, mentioning that this depends on other PRs.
Please also provide the promised unit tests (one of them should be failing before this fix).

src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Show resolved Hide resolved
@peci1 peci1 force-pushed the fix-box-ray-intersection branch 2 times, most recently from 9f2429b to d0d5b72 Compare August 9, 2019 14:21
@peci1
Copy link
Contributor Author

peci1 commented Aug 9, 2019

I added PR description and separated this PR from the others as it doesn't depend on them semantically. I'll have a look at the tests.

@peci1 peci1 force-pushed the fix-box-ray-intersection branch 3 times, most recently from a1fa4da to 522340c Compare March 24, 2020 23:01
@peci1 peci1 changed the title Fixed computation of ray-box intersections. Fixed computation of intersectsRay() for Cylinder, Box and ConvexMesh Mar 24, 2020
@peci1 peci1 force-pushed the fix-box-ray-intersection branch 2 times, most recently from 4be04c6 to 828c146 Compare March 24, 2020 23:23
@peci1
Copy link
Contributor Author

peci1 commented Mar 25, 2020

I had a look at this again, rebased on current melodic-devel, and added a lot of tests. First, I only added box-ray tests, but then I decided to add tests for all bodies. And along the way, I've discovered and fixed a lot of other bugs in various more or less related functions, like containsPoint() and samplePoint(). Check out the updated title and description of this PR.

I would've sent these other fixes as another PRs, but the tests in this one would fail without them. But if it's desired, I can take the effort and split this into more PRs - I just do not want to take this effort with the tests, so I'd separate them as the "final" PR, and the prior ones would come without tests.

I did some API/ABI breaks here.

  1. First, as requested by @rhaschke , I removed the unnecessary internal fields normalL_, normalW_ and normalH_ of bodies::Box. I instead added invPose_.
  2. When I was already breaking API/ABI, I also changed MeshData by adding one more field.
  3. Not really API/ABI break, but I changed the meaning of corner1_ and corner2_ protected members of bodies::Box. It should not affect anything but potential user code that would access these fields. But as they had no docs before, I think the chance there is some other code using them is pretty minimal.

If API/ABI breaks are not desired for melodic-devel, 1) can be avoided completely (and the API break be left to noetic), and 2) can also be worked around somehow (last resort would be the translation-unit-private global variable ugly trick).

For some reason, CI did not trigger here (maybe because of the pending requested changes?), but here's mine which shows okay: https://travis-ci.com/github/peci1/geometric_shapes . I've also run a local test with this PR and the whole Moveit repo. It ran fine, except for a few ushort_test/MeshFilterTestUnsignedShort.unsigned_short tests, which however fail for me even on melodic-devel branch of geometric_shapes.

As with my other PRs, this may of course break user code that counted with the buggy behavior. But (thanks to the tests), I'm pretty sure that if the library is used correctly, it should not bring any new problems.

Copy link
Contributor

@v4hn v4hn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the inline comments. Aside from them, I approve.

src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
@v4hn
Copy link
Contributor

v4hn commented Apr 24, 2020

Lastly, this patch conflicted with one of the others I merged. Could you please rebase?

@peci1
Copy link
Contributor Author

peci1 commented Apr 24, 2020

I've made the requested changes.

@peci1
Copy link
Contributor Author

peci1 commented Apr 24, 2020

Thanks for the reviews, @v4hn ;)

@v4hn
Copy link
Contributor

v4hn commented Apr 24, 2020 via email

@peci1
Copy link
Contributor Author

peci1 commented Apr 24, 2020

I think insisting on good tests for PRs is the way to prevent most of such errors for the future. I've seen moveit repos already report some kind of test coverage... What about this repo? Is it planned?

@v4hn
Copy link
Contributor

v4hn commented Apr 24, 2020

#120 :-)

Copy link
Contributor

@rhaschke rhaschke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dear @peci1,
please adapt multiple consecutive uses of set*() to set*Dirty() after having merged #126. Otherwise, this looks good. Thanks a lot for all your effort on this!


Eigen::Vector3d corner1_;
Eigen::Vector3d corner2_;
Eigen::Vector3d corner1_; //!< The translated, but not rotated min corner
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about renaming these vectors to min_corner_ and max_corner_?
As you renamed normal[L,W,H] anyway, ABI and API is broken anyway and we need to target this to Noetic only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I can rename them for noetic. As I'd still like to see this in melodic, should I split this PR into two and try to make this one compatible with melodic? In my view, this approach would be easier than first merging to noetic and then backporting...

As discussed earlier, the API/ABI breaks can be avoided at the cost of minor uglification of code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To maintain ABI you would need to keep the axis vectors instead of invRot_. More ugly, but ok.
The other addition I have seen is std::map<unsigned int, unsigned int> triangle_for_plane_.
Didn't look for what it is actually used. Replacing this by a global variable, I would actually not support. Why is it needed now? Just to be faster?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walking on a thin ice, I guess a Matrix3d could take up the same amount of memory as three Vector3ds. But that could run in many issues once memory alignment comes into play. So I rather give up this idea.

invRot would have to be recomputed every time it is used, but as it is only a transpose, it shouldn't be that bad in melodic. I can also imagine storing the rows/cols of the inverted matrix in the abandoned vectors, but I bet the performance could be even worse than transposing it where needed.

The triangle_for_plane is really required for efficiency - otherwise mesh-ray intersection tests would need to re-enumrate over all triangles to find which plane the current one belongs to. The global variable trick is something Gazebo people are willing to accept if it is just "temporary" to get a feature to a released version; the development version then implements the nicer, but ABI-breaking version. An example is here: gazebosim/gazebo-classic@415be40 . It creates a global map, which stores references to created objects (ConvexMesh in this case) and maps them to the structure that is needed to be added. Ugly, but works.

Actually, I'd consider making the whole MeshData PIMPL for noetic (i.e. moving it to the .cpp file), so that storing additional data will not cause an ABI break any more. The same could be done for the other bodies, too, but there would be the additional cost of dynamic memory allocation. The ConvexMesh allocates memory anyways, so adding one more unique_ptr should not be a problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented ABI compatibility using the global variable.

include/geometric_shapes/bodies.h Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
Even according to the link to the used method, the approach should only
work for axis-aligned boxes. But bodies::Box can be arbitrarily transformed.
So I instead strip rotation from both the box and the ray, which gives
the same results.

The old implementation would fail every time the untransformed min corner
ceased to be the min corner of the transformed box.

# Conflicts:
#	src/bodies.cpp
…within the box.

A false second intersection was returned in that case, but as the ray starts inside the box, there should only be one intersection.
@codecov-io
Copy link

codecov-io commented Apr 26, 2020

Codecov Report

Merging #109 into melodic-devel will increase coverage by 2.98%.
The diff coverage is 97.77%.

Impacted file tree graph

@@                Coverage Diff                @@
##           melodic-devel     #109      +/-   ##
=================================================
+ Coverage          46.24%   49.22%   +2.98%     
=================================================
  Files                 11       11              
  Lines               1691     1684       -7     
=================================================
+ Hits                 782      829      +47     
+ Misses               909      855      -54     
Impacted Files Coverage Δ
include/geometric_shapes/bodies.h 86.44% <ø> (-0.66%) ⬇️
src/bodies.cpp 71.13% <97.77%> (+9.01%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update adacb1c...ed4cf13. Read the comment docs.

@peci1
Copy link
Contributor Author

peci1 commented Apr 26, 2020

@rhaschke I did all the changes you requested. ABI compatibility with melodic is achieved by the very last commit.

Thanks for the deep insights. The code looks much better now.

@peci1
Copy link
Contributor Author

peci1 commented Apr 26, 2020

I also restructured the commit history. Now I consider all the commits valuable and further squashing is not needed.

Copy link
Contributor

@rhaschke rhaschke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor remarks left.
As I will not cherry-pick to noetic, but revert the last commit, please remove the comment
Do not cherry-pick this commit to noetic. from it.
Thanks a lot for all this work. Hope, we can merge this later today.

src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
src/bodies.cpp Outdated Show resolved Hide resolved
@peci1
Copy link
Contributor Author

peci1 commented Apr 26, 2020

@rhaschke I addressed your comments.

@rhaschke rhaschke merged commit 54fbcf1 into moveit:melodic-devel Apr 26, 2020
@rhaschke
Copy link
Contributor

@peci1, thank you very much. All your PRs are a great improvement of this code base!
If I may ask for even more, here are my suggested next steps:

@rhaschke
Copy link
Contributor

I added a noetic-devel branch, just in case you need it ...

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

Successfully merging this pull request may close these issues.

5 participants