-
Notifications
You must be signed in to change notification settings - Fork 111
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
Lazy transformations for CrossSection #355
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #355 +/- ##
==========================================
+ Coverage 89.43% 89.46% +0.03%
==========================================
Files 33 33
Lines 3974 3968 -6
==========================================
- Hits 3554 3550 -4
+ Misses 420 418 -2
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report in Codecov by Sentry. |
Did you implement shared cache when users copy the path? If not, we will need to do n transformations instead of 1 when the path is copied n times, for example for other boolean operation or something. Otherwise this looks good to me. |
It could be that I'm not totally familiar with when copies are happening due to my C++ inexperience, but I thought that in this setup there wouldn't be multiple repeated transformation copies of the vector for separate booleans on the same parent manifold since I also could be wrong in my assumption that |
Ah, no, I mean the copy constructor. manifold/src/cross_section/src/cross_section.cpp Lines 121 to 124 in f92667e
The new manifold/src/manifold/src/csg_tree.h Line 58 in 83131c6
the |
Oh right. Well it wouldn't be too much effort to convert |
Thinking about this a bit more, is there a point of having a copy constructor for these objects that don't expose any mutable state to the outside anyway? (there's probably some reason it's good to have that doesn't come to mind for me as a C++ novice, hence the stupid question) |
Looking at std::shared_ptr<const Manifold::Impl> CsgLeafNode::GetImpl() const {
if (transform_ == glm::mat4x3(1.0f)) return pImpl_;
pImpl_ =
std::make_shared<const Manifold::Impl>(pImpl_->Transform(transform_));
transform_ = glm::mat4x3(1.0f);
return pImpl_;
} Also, since transform isn't similarly sitting behind a shared pointer, if application of transformation was shared between the copies, the reset of |
@geoffder I'll defer to @pca006132 who understands this part of the code better than I do, though I'd guess he's asleep now. It might help to make a little example and throw in print statements where transforms are actually applied to verts. The results would probably make for nice documentation as well. |
In the meantime, here is a bit more thinking out loud, plus an experiment. The Running this with the fresh ptr and const data version based on
So, as expected the same transformation is applied on the as yet un-transformed |
Oh, nice, I forgot to add a |
I found that the old me is partially correct: the cache for But for the |
I finally went and re-read the reference page for vectors and was reminded (or TIL'd, I'm not sure) that the assignment operator for does indeed copy the contents. Something that was not obvious to me coming from languages where that is not the case 🤦♂️. I've updated |
A (final?) note on the topic of the copy constructor again, I don't know that there is necessarily a better solution than what we are doing currently. auto a = CrossSection::Circle(10).Scale({2, 0});
auto b = CrossSection(a);
auto ex_a = a.Extrude(5);
auto ex_b = b.Rotate(90).Extrude(5); Even if the additional machinery was implemented to allow the transformation of a to be propagated to b, the same number of transformations is going to occur. Alternatively, if the copy constructor was changed to preemptively apply the transformations in a to cut off the possibility of re-doing the same The solution is really to just not use the copy constructor, since there is nothing to be gained from it (just do what you want to a, don't make a copy of it to do things to). |
Rebased thinking I was going to use the |
Yes, you don't need |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Is it ready to merge? |
Add transformation composition with lazy application when needed, similar to the arrangement used in the CSG tree backing Manifold.
After reading through the transformation code more for Manifold (csg_tree and impl), I decided try bringing CrossSection more in line with the lazy transformation semantics expressed there. Only copying and applying the transformations when needed cuts out some of the repeated iteration and point type conversion that pervaded the wrapper.
Similar to the CSG nodes and
GetImpl
, the privateGetPaths
applies the transformation wheneverpaths_
is needed, and updates the object so that the same operation won't be repeated.